Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 25 Sep 2014 16:46:51 -0400
changeset 230526 9e3d649b80a224b48bc4a28d3d46c1e2e929ebc0
parent 230463 2a4cc563fffc495827964b0068a6b02fefb4f3e5 (current diff)
parent 230525 171afe599b294d15243758eeeea1095d590e4e09 (diff)
child 230529 35a60a93ee42c6cb1ae647507149a8e81803243c
child 230574 936e869ce11c7dc8683741f748da45a2493e93d0
child 230627 bcd0d2b817a849aafb3081c0e0081ec9a102d3a4
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone35.0a1
first release with
nightly linux32
9e3d649b80a2 / 35.0a1 / 20140926030202 / files
nightly linux64
9e3d649b80a2 / 35.0a1 / 20140926030202 / files
nightly mac
9e3d649b80a2 / 35.0a1 / 20140926030202 / files
nightly win32
9e3d649b80a2 / 35.0a1 / 20140926030202 / files
nightly win64
9e3d649b80a2 / 35.0a1 / 20140926030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
content/base/test/csp/file_csp_regexp_parsing.html
content/base/test/csp/file_csp_regexp_parsing.js
content/base/test/csp/test_csp_regexp_parsing.html
dom/mobileconnection/MobileConnectionInfo.cpp
gfx/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp.orig
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp.orig
js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-01.js
js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-02.js
js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-03.js
media/libvpx/mingw.patch
media/libvpx/unified.patch
--- a/accessible/jsat/TraversalRules.jsm
+++ b/accessible/jsat/TraversalRules.jsm
@@ -99,31 +99,31 @@ var gSimpleTraversalRoles =
    // Used for traversing in to child OOP frames.
    Roles.INTERNAL_FRAME];
 
 var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
   // An object is simple, if it either has a single child lineage,
   // or has a flat subtree.
   function isSingleLineage(acc) {
     for (let child = acc; child; child = child.firstChild) {
-      if (child.childCount > 1) {
+      if (Utils.visibleChildCount(child) > 1) {
         return false;
       }
     }
     return true;
   }
 
   function isFlatSubtree(acc) {
     for (let child = acc.firstChild; child; child = child.nextSibling) {
       // text leafs inherit the actionCount of any ancestor that has a click
       // listener.
       if ([Roles.TEXT_LEAF, Roles.STATICTEXT].indexOf(child.role) >= 0) {
         continue;
       }
-      if (child.childCount > 0 || child.actionCount > 0) {
+      if (Utils.visibleChildCount(child) > 0 || child.actionCount > 0) {
         return false;
       }
     }
     return true;
   }
 
   switch (aAccessible.role) {
   case Roles.COMBOBOX:
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -355,16 +355,26 @@ this.Utils = { // jshint ignore:line
 
   isHidden: function isHidden(aAccessible) {
     // Need to account for aria-hidden, so can't just check for INVISIBLE
     // state.
     let hidden = Utils.getAttributes(aAccessible).hidden;
     return hidden && hidden === 'true';
   },
 
+  visibleChildCount: function visibleChildCount(aAccessible) {
+    let count = 0;
+    for (let child = aAccessible.firstChild; child; child = child.nextSibling) {
+      if (!this.isHidden(child)) {
+        ++count;
+      }
+    }
+    return count;
+  },
+
   inHiddenSubtree: function inHiddenSubtree(aAccessible) {
     for (let acc=aAccessible; acc; acc=acc.parent) {
       if (this.isHidden(acc)) {
         return true;
       }
     }
     return false;
   },
--- a/accessible/tests/mochitest/jsat/doc_traversal.html
+++ b/accessible/tests/mochitest/jsat/doc_traversal.html
@@ -1,13 +1,18 @@
 <!DOCTYPE html>
 <html>
 <head>
   <title>Traversal Rule test document</title>
   <meta charset="utf-8" />
+  <style>
+    .content:before {
+      content: "Content";
+    }
+  </style>
 </head>
 <body>
   <h3 id="heading-1">A small first heading</h3>
   <form>
     <label for="input-1-1">Name:</label>
     <input id="input-1-1">
     <label id="label-1-2">Favourite Ice Cream Flavour:<input id="input-1-2"></label>
     <button id="button-1-1">Magic Button</button>
@@ -91,16 +96,35 @@
     <td>3</td>
     <td>1</td>
   </tr>
   <tr>
     <td>4</td>
     <td>1</td>
   </tr>
   </table>
+  <section id="grid" role="grid">
+    <ol role="row">
+      <li role="presentation"></li>
+      <li role="columnheader" aria-label="Sunday">S</li>
+      <li role="columnheader">M</li>
+    </ol>
+    <ol role="row">
+      <li role="rowheader" aria-label="Week 1">1</li>
+      <li role="gridcell"><span>3</span><div></div></li>
+      <li role="gridcell"><span>4</span><div>7</div></li>
+    </ol>
+    <ol role="row">
+      <li role="rowheader">2</li>
+      <li role="gridcell"><span>5</span><div role="presentation">8</div></li>
+      <li id="gridcell4" role="gridcell">
+        <span>6</span><div aria-hidden="true"><div class="content"></div></div>
+      </li>
+    </ol>
+  </section>
   <div id="separator-2" role="separator">Just an innocuous separator</div>
   <table id="table-2">
     <thead>
       <tr>
         <th>Dirty Words</th>
         <th>Meaning</th>
       </tr>
     </thead>
--- a/accessible/tests/mochitest/jsat/test_traversal.html
+++ b/accessible/tests/mochitest/jsat/test_traversal.html
@@ -89,17 +89,17 @@
 
       queueTraversalSequence(gQueue, docAcc, TraversalRules.Anchor, null,
                              ['anchor-1', 'anchor-2']);
 
       queueTraversalSequence(gQueue, docAcc, TraversalRules.Separator, null,
                              ['separator-1', 'separator-2']);
 
       queueTraversalSequence(gQueue, docAcc, TraversalRules.Table, null,
-                             ['table-1', 'table-2']);
+                             ['table-1', 'grid', 'table-2']);
 
       queueTraversalSequence(gQueue, docAcc, TraversalRules.Simple, null,
                              ['heading-1', 'Name:', 'input-1-1', 'label-1-2',
                               'button-1-1', 'Radios are old: ', 'radio-1-1',
                               'Radios are new: ', 'radio-1-2', 'Password:',
                               'input-1-3', 'Unlucky number:', 'input-1-4',
                               'button-1-2', 'Check me: ', 'checkbox-1-1',
                               'select-1-1', 'Value 1', 'Value 2', 'Value 3',
@@ -109,23 +109,25 @@
                               'button-1-3', 'heading-2', 'heading-3',
                               'button-2-1', 'button-2-2', 'button-2-3',
                               'button-2-4', 'Programming Language',
                               'A esoteric weapon wielded by only the most ' +
                               'formidable warriors, for its unrelenting strict' +
                               ' power is unfathomable.',
                               '• Lists of Programming Languages', 'Lisp ',
                               '1. Scheme', '2. Racket', '3. Clojure',
-                              '4. Standard Lisp', 'link-0', ' Lisp', 'checkbox-1-5',
-                              ' LeLisp', '• JavaScript', 'heading-5',
-                              'image-2', 'image-3', 'Not actually an image',
-                              'link-1', 'anchor-1', 'link-2', 'anchor-2', 'link-3',
-                              '3', '1', '4', '1', 'Just an innocuous separator',
-                              'Dirty Words', 'Meaning', 'Mud', 'Wet Dirt',
-                              'Dirt', 'Messy Stuff']);
+                              '4. Standard Lisp', 'link-0', ' Lisp',
+                              'checkbox-1-5', ' LeLisp', '• JavaScript',
+                              'heading-5', 'image-2', 'image-3',
+                              'Not actually an image', 'link-1', 'anchor-1',
+                              'link-2', 'anchor-2', 'link-3', '3', '1', '4',
+                              '1', 'S', 'M', '1', '3', '4', '7', '2', '5', '8',
+                              '6', 'Just an innocuous separator', 'Dirty Words',
+                              'Meaning', 'Mud', 'Wet Dirt', 'Dirt',
+                              'Messy Stuff']);
 
       gQueue.invoke();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(function () {
       /* We open a new browser because we need to test with a top-level content
          document. */
--- a/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js
@@ -100,17 +100,17 @@ function test() {
       "There should be 0 hidden nodes in the watch expressions container");
     is(gDebugger.document.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
       "There should be 27 visible nodes in the watch expressions container");
   }
 
   function test1(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
       checkWatchExpressions(26, {
-        a: "ReferenceError: a is not defined, did you mean 'z'?",
+        a: "ReferenceError: a is not defined",
         this: { type: "object", class: "Object" },
         prop: { type: "object", class: "String" },
         args: { type: "undefined" }
       });
       aCallback();
     });
 
     gDebuggee.test();
--- a/content/base/src/nsCSPContext.cpp
+++ b/content/base/src/nsCSPContext.cpp
@@ -168,16 +168,19 @@ nsCSPContext::ShouldLoad(nsContentPolicy
     }
   }
 
   nsAutoString violatedDirective;
   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
     if (!mPolicies[p]->permits(aContentType,
                                aContentLocation,
                                nonce,
+                               // aExtra is only non-null if
+                               // the channel got redirected.
+                               (aExtra != nullptr),
                                violatedDirective)) {
       // If the policy is violated and not report-only, reject the load and
       // report to the console
       if (!mPolicies[p]->getReportOnlyFlag()) {
         CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, nsIContentPolicy::REJECT_SERVER"));
         *outDecision = nsIContentPolicy::REJECT_SERVER;
       }
 
@@ -787,17 +790,18 @@ class CSPReportSenderRunnable MOZ_FINAL 
                             const nsAString& aViolatedDirective,
                             const nsAString& aObserverSubject,
                             const nsAString& aSourceFile,
                             const nsAString& aScriptSample,
                             uint32_t aLineNum,
                             uint64_t aInnerWindowID,
                             nsCSPContext* aCSPContext)
       : mBlockedContentSource(aBlockedContentSource)
-      , mOriginalURI(aOriginalURI) , mViolatedPolicyIndex(aViolatedPolicyIndex)
+      , mOriginalURI(aOriginalURI)
+      , mViolatedPolicyIndex(aViolatedPolicyIndex)
       , mReportOnlyFlag(aReportOnlyFlag)
       , mViolatedDirective(aViolatedDirective)
       , mSourceFile(aSourceFile)
       , mScriptSample(aScriptSample)
       , mLineNum(aLineNum)
       , mInnerWindowID(aInnerWindowID)
       , mCSPContext(aCSPContext)
     {
@@ -1019,16 +1023,17 @@ nsCSPContext::PermitsAncestry(nsIDocShel
       nsAutoCString spec;
       ancestorsArray[a]->GetSpec(spec);
       CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s", spec.get()));
       }
 #endif
       if (!mPolicies[i]->permits(nsIContentPolicy::TYPE_DOCUMENT,
                                  ancestorsArray[a],
                                  EmptyString(), // no nonce
+                                 false, // no redirect
                                  violatedDirective)) {
         // Policy is violated
         // Send reports, but omit the ancestor URI if cross-origin as per spec
         // (it is a violation of the same-origin policy).
         bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
 
         this->AsyncReportViolation((okToSendAncestor ? ancestorsArray[a] : nullptr),
                                    mSelfURI,
--- a/content/base/src/nsCSPParser.cpp
+++ b/content/base/src/nsCSPParser.cpp
@@ -25,28 +25,31 @@ GetCspParserLog()
   if (!gCspParserPRLog)
     gCspParserPRLog = PR_NewLogModule("CSPParser");
   return gCspParserPRLog;
 }
 #endif
 
 #define CSPPARSERLOG(args) PR_LOG(GetCspParserLog(), 4, args)
 
-static const char16_t COLON       = ':';
-static const char16_t SEMICOLON   = ';';
-static const char16_t SLASH       = '/';
-static const char16_t PLUS        = '+';
-static const char16_t DASH        = '-';
-static const char16_t DOT         = '.';
-static const char16_t UNDERLINE   = '_';
-static const char16_t WILDCARD    = '*';
-static const char16_t WHITESPACE  = ' ';
-static const char16_t SINGLEQUOTE = '\'';
-static const char16_t OPEN_CURL   = '{';
-static const char16_t CLOSE_CURL  = '}';
+static const char16_t COLON        = ':';
+static const char16_t SEMICOLON    = ';';
+static const char16_t SLASH        = '/';
+static const char16_t PLUS         = '+';
+static const char16_t DASH         = '-';
+static const char16_t DOT          = '.';
+static const char16_t UNDERLINE    = '_';
+static const char16_t TILDE        = '~';
+static const char16_t WILDCARD     = '*';
+static const char16_t WHITESPACE   = ' ';
+static const char16_t SINGLEQUOTE  = '\'';
+static const char16_t OPEN_CURL    = '{';
+static const char16_t CLOSE_CURL   = '}';
+static const char16_t NUMBER_SIGN  = '#';
+static const char16_t QUESTIONMARK = '?';
 
 static uint32_t kSubHostPathCharacterCutoff = 512;
 
 static const char* kHashSourceValidFns [] = { "sha256", "sha384", "sha512" };
 static const uint32_t kHashSourceValidFnsLen = 3;
 
 /* ===== nsCSPTokenizer ==================== */
 
@@ -140,16 +143,33 @@ isNumberToken(char16_t aSymbol)
 void
 nsCSPParser::resetCurChar(const nsAString& aToken)
 {
   mCurChar = aToken.BeginReading();
   mEndChar = aToken.EndReading();
   resetCurValue();
 }
 
+// The path is terminated by the first question mark ("?") or
+// number sign ("#") character, or by the end of the URI.
+// http://tools.ietf.org/html/rfc3986#section-3.3
+bool
+nsCSPParser::atEndOfPath()
+{
+  return (atEnd() || peek(QUESTIONMARK) || peek(NUMBER_SIGN));
+}
+
+bool
+nsCSPParser::atValidPathChar()
+{
+  return (peek(isCharacterToken) || peek(isNumberToken) ||
+          peek(DASH) || peek(DOT) ||
+          peek(UNDERLINE) || peek(TILDE));
+}
+
 void
 nsCSPParser::logWarningErrorToConsole(uint32_t aSeverityFlag,
                                       const char* aProperty,
                                       const char16_t* aParams[],
                                       uint32_t aParamsLength)
 {
   CSPPARSERLOG(("nsCSPParser::logWarningErrorToConsole: %s", aProperty));
 
@@ -184,35 +204,16 @@ nsCSPParser::schemeChar()
   }
   return accept(isCharacterToken) ||
          accept(isNumberToken) ||
          accept(PLUS) ||
          accept(DASH) ||
          accept(DOT);
 }
 
-bool
-nsCSPParser::fileAndArguments()
-{
-  CSPPARSERLOG(("nsCSPParser::fileAndArguments, mCurToken: %s, mCurValue: %s",
-               NS_ConvertUTF16toUTF8(mCurToken).get(),
-               NS_ConvertUTF16toUTF8(mCurValue).get()));
-
-  // Possibly we already parsed part of the file in path(), therefore accepting "."
-  if (accept(DOT) && !accept(isCharacterToken)) {
-    return false;
-  }
-
-  // From now on, accept pretty much anything to avoid unnecessary errors
-  while (!atEnd()) {
-    advance();
-  }
-  return true;
-}
-
 // port = ":" ( 1*DIGIT / "*" )
 bool
 nsCSPParser::port()
 {
   CSPPARSERLOG(("nsCSPParser::port, mCurToken: %s, mCurValue: %s",
                NS_ConvertUTF16toUTF8(mCurToken).get(),
                NS_ConvertUTF16toUTF8(mCurValue).get()));
 
@@ -248,34 +249,33 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspH
                NS_ConvertUTF16toUTF8(mCurToken).get(),
                NS_ConvertUTF16toUTF8(mCurValue).get()));
 
   // Emergency exit to avoid endless loops in case a path in a CSP policy
   // is longer than 512 characters, or also to avoid endless loops
   // in case we are parsing unrecognized characters in the following loop.
   uint32_t charCounter = 0;
 
-  while (!atEnd() && !peek(DOT)) {
-    ++charCounter;
-    while (hostChar() || accept(UNDERLINE)) {
-      /* consume */
-      ++charCounter;
-    }
-    if (accept(SLASH)) {
-      ++charCounter;
+  while (!atEndOfPath()) {
+    if (peek(SLASH)) {
       aCspHost->appendPath(mCurValue);
       // Resetting current value since we are appending parts of the path
       // to aCspHost, e.g; "http://www.example.com/path1/path2" then the
       // first part is "/path1", second part "/path2"
       resetCurValue();
     }
-    if (atEnd()) {
-      return true;
+    else if (!atValidPathChar()) {
+      const char16_t* params[] = { mCurToken.get() };
+      logWarningErrorToConsole(nsIScriptError::warningFlag,
+                               "couldntParseInvalidSource",
+                               params, ArrayLength(params));
+      return false;
     }
-    if (charCounter > kSubHostPathCharacterCutoff) {
+    advance();
+    if (++charCounter > kSubHostPathCharacterCutoff) {
       return false;
     }
   }
   aCspHost->appendPath(mCurValue);
   resetCurValue();
   return true;
 }
 
@@ -293,17 +293,20 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost
   resetCurValue();
 
   if (!accept(SLASH)) {
     const char16_t* params[] = { mCurToken.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
                              params, ArrayLength(params));
     return false;
   }
-  if (atEnd()) {
+  if (atEndOfPath()) {
+    // one slash right after host [port] is also considered a path, e.g.
+    // www.example.com/ should result in www.example.com/
+    aCspHost->appendPath(mCurValue);
     return true;
   }
   // path can begin with "/" but not "//"
   // see http://tools.ietf.org/html/rfc3986#section-3.3
   if (!hostChar()) {
     const char16_t* params[] = { mCurToken.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
                              params, ArrayLength(params));
@@ -319,17 +322,17 @@ nsCSPParser::subHost()
                NS_ConvertUTF16toUTF8(mCurToken).get(),
                NS_ConvertUTF16toUTF8(mCurValue).get()));
 
   // Emergency exit to avoid endless loops in case a host in a CSP policy
   // is longer than 512 characters, or also to avoid endless loops
   // in case we are parsing unrecognized characters in the following loop.
   uint32_t charCounter = 0;
 
-  while (!atEnd() && !peek(COLON) && !peek(SLASH)) {
+  while (!atEndOfPath() && !peek(COLON) && !peek(SLASH)) {
     ++charCounter;
     while (hostChar()) {
       /* consume */
       ++charCounter;
     }
     if (accept(DOT) && !hostChar()) {
       return false;
     }
@@ -463,38 +466,30 @@ nsCSPParser::hostSource()
   if (peek(COLON)) {
     if (!port()) {
       delete cspHost;
       return nullptr;
     }
     cspHost->setPort(mCurValue);
   }
 
-  if (atEnd()) {
+  if (atEndOfPath()) {
     return cspHost;
   }
 
   // Calling path() to see if there is a path to parse, if an error
   // occurs, path() reports the error; handing cspHost as an argument
   // which simplifies parsing of several paths.
   if (!path(cspHost)) {
     // If the host [port] is followed by a path, it has to be a valid path,
     // otherwise we pass the nullptr, indicating an error, up the callstack.
     // see also http://www.w3.org/TR/CSP11/#source-list
     delete cspHost;
     return nullptr;
   }
-
-  // Calling fileAndArguments to see if there are any files to parse;
-  // if an error occurs, fileAndArguments() reports the error; if
-  // fileAndArguments returns true, we have a valid file, so we add it.
-  if (fileAndArguments()) {
-    cspHost->setFileAndArguments(mCurValue);
-  }
-
   return cspHost;
 }
 
 // scheme-source = scheme ":"
 nsCSPSchemeSrc*
 nsCSPParser::schemeSource()
 {
   CSPPARSERLOG(("nsCSPParser::schemeSource, mCurToken: %s, mCurValue: %s",
--- a/content/base/src/nsCSPParser.h
+++ b/content/base/src/nsCSPParser.h
@@ -121,17 +121,16 @@ class nsCSPParser {
     nsCSPNonceSrc*  nonceSource();
     nsCSPHashSrc*   hashSource();
     nsCSPHostSrc*   appHost(); // helper function to support app specific hosts
     nsCSPHostSrc*   host();
     bool            hostChar();
     bool            schemeChar();
     bool            port();
     bool            path(nsCSPHostSrc* aCspHost);
-    bool            fileAndArguments();
 
     bool subHost();                                       // helper function to parse subDomains
     bool subPath(nsCSPHostSrc* aCspHost);                 // helper function to parse paths
     void reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs); // helper function to parse report-uris
 
     inline bool atEnd()
     {
       return mCurChar >= mEndChar;
@@ -168,16 +167,19 @@ class nsCSPParser {
       return true;
     }
 
     inline void resetCurValue()
     {
       mCurValue.Truncate();
     }
 
+    bool atEndOfPath();
+    bool atValidPathChar();
+
     void resetCurChar(const nsAString& aToken);
 
     void logWarningErrorToConsole(uint32_t aSeverityFlag,
                                   const char* aProperty,
                                   const char16_t* aParams[],
                                   uint32_t aParamsLength);
 
 /**
--- a/content/base/src/nsCSPUtils.cpp
+++ b/content/base/src/nsCSPUtils.cpp
@@ -209,17 +209,17 @@ nsCSPBaseSrc::nsCSPBaseSrc()
 nsCSPBaseSrc::~nsCSPBaseSrc()
 {
 }
 
 // ::permits is only called for external load requests, therefore:
 // nsCSPKeywordSrc and nsCSPHashSource fall back to this base class
 // implementation which will never allow the load.
 bool
-nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce) const
+nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
 {
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPBaseSrc::permits, aUri: %s", spec.get()));
   }
 #endif
@@ -246,17 +246,17 @@ nsCSPSchemeSrc::nsCSPSchemeSrc(const nsA
   ToLowerCase(mScheme);
 }
 
 nsCSPSchemeSrc::~nsCSPSchemeSrc()
 {
 }
 
 bool
-nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce) const
+nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
 {
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s", spec.get()));
   }
 #endif
@@ -283,17 +283,17 @@ nsCSPHostSrc::nsCSPHostSrc(const nsAStri
   ToLowerCase(mHost);
 }
 
 nsCSPHostSrc::~nsCSPHostSrc()
 {
 }
 
 bool
-nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce) const
+nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
 {
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPHostSrc::permits, aUri: %s", spec.get()));
   }
 #endif
@@ -337,16 +337,44 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
       return false;
     }
   }
   // Check if hosts match.
   else if (!mHost.Equals(NS_ConvertUTF8toUTF16(uriHost))) {
     return false;
   }
 
+  // If there is a path, we have to enforce path-level matching,
+  // unless the channel got redirected, see:
+  // http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
+  if (!aWasRedirected && !mPath.IsEmpty()) {
+    // cloning uri so we can ignore the ref
+    nsCOMPtr<nsIURI> uri;
+    aUri->CloneIgnoringRef(getter_AddRefs(uri));
+
+    nsAutoCString uriPath;
+    rv = uri->GetPath(uriPath);
+    NS_ENSURE_SUCCESS(rv, false);
+    // check if the last character of mPath is '/'; if so
+    // we just have to check loading resource is within
+    // the allowed path.
+    if (mPath.Last() == '/') {
+      if (!StringBeginsWith(NS_ConvertUTF8toUTF16(uriPath), mPath)) {
+        return false;
+      }
+    }
+    // otherwise mPath whitelists a specific file, and we have to
+    // check if the loading resource matches that whitelisted file.
+    else {
+      if (!mPath.Equals(NS_ConvertUTF8toUTF16(uriPath))) {
+        return false;
+      }
+    }
+  }
+
   // If port uses wildcard, allow the load.
   if (mPort.EqualsASCII("*")) {
     return true;
   }
 
   // Check if ports match
   int32_t uriPort;
   rv = aUri->GetPort(&uriPort);
@@ -364,17 +392,17 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
   else {
     nsString portStr;
     portStr.AppendInt(uriPort);
     if (!mPort.Equals(portStr)) {
       return false;
     }
   }
 
-  // At the end: scheme, host, port, match; allow the load.
+  // At the end: scheme, host, path, and port match -> allow the load.
   return true;
 }
 
 void
 nsCSPHostSrc::toString(nsAString& outStr) const
 {
   // If mHost is a single "*", we append the wildcard and return.
   if (mHost.EqualsASCII("*") &&
@@ -392,19 +420,18 @@ nsCSPHostSrc::toString(nsAString& outStr
   outStr.Append(mHost);
 
   // append port
   if (!mPort.IsEmpty()) {
     outStr.AppendASCII(":");
     outStr.Append(mPort);
   }
 
-  // in CSP 1.1, paths are ignoed
-  // outStr.Append(mPath);
-  // outStr.Append(mFileAndArguments);
+  // append path
+  outStr.Append(mPath);
 }
 
 void
 nsCSPHostSrc::setScheme(const nsAString& aScheme)
 {
   mScheme = aScheme;
   ToLowerCase(mScheme);
 }
@@ -418,23 +445,16 @@ nsCSPHostSrc::setPort(const nsAString& a
 
 void
 nsCSPHostSrc::appendPath(const nsAString& aPath)
 {
   mPath.Append(aPath);
   ToLowerCase(mPath);
 }
 
-void
-nsCSPHostSrc::setFileAndArguments(const nsAString& aFile)
-{
-  mFileAndArguments = aFile;
-  ToLowerCase(mFileAndArguments);
-}
-
 /* ===== nsCSPKeywordSrc ===================== */
 
 nsCSPKeywordSrc::nsCSPKeywordSrc(CSPKeyword aKeyword)
 {
   NS_ASSERTION((aKeyword != CSP_SELF),
                "'self' should have been replaced in the parser");
   mKeyword = aKeyword;
 }
@@ -464,17 +484,17 @@ nsCSPNonceSrc::nsCSPNonceSrc(const nsASt
 {
 }
 
 nsCSPNonceSrc::~nsCSPNonceSrc()
 {
 }
 
 bool
-nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce) const
+nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
 {
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPNonceSrc::permits, aUri: %s, aNonce: %s",
                 spec.get(), NS_ConvertUTF16toUTF8(aNonce).get()));
   }
@@ -594,39 +614,39 @@ nsCSPDirective::nsCSPDirective(enum CSPD
 nsCSPDirective::~nsCSPDirective()
 {
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
     delete mSrcs[i];
   }
 }
 
 bool
-nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce) const
+nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
 {
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPDirective::permits, aUri: %s", spec.get()));
   }
 #endif
 
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
-    if (mSrcs[i]->permits(aUri, aNonce)) {
+    if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected)) {
       return true;
     }
   }
   return false;
 }
 
 bool
 nsCSPDirective::permits(nsIURI* aUri) const
 {
   nsString dummyNonce;
-  return permits(aUri, dummyNonce);
+  return permits(aUri, dummyNonce, false);
 }
 
 bool
 nsCSPDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
 {
   CSPUTILSLOG(("nsCSPDirective::allows, aKeyWord: %s, a HashOrNonce: %s",
               CSP_EnumToKeyword(aKeyword), NS_ConvertUTF16toUTF8(aHashOrNonce).get()));
 
@@ -749,16 +769,17 @@ nsCSPPolicy::~nsCSPPolicy()
     delete mDirectives[i];
   }
 }
 
 bool
 nsCSPPolicy::permits(nsContentPolicyType aContentType,
                      nsIURI* aUri,
                      const nsAString& aNonce,
+                     bool aWasRedirected,
                      nsAString& outViolatedDirective) const
 {
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
     CSPUTILSLOG(("nsCSPPolicy::permits, aContentType: %d, aUri: %s, aNonce: %s",
                 aContentType, spec.get(), NS_ConvertUTF16toUTF8(aNonce).get()));
@@ -769,17 +790,17 @@ nsCSPPolicy::permits(nsContentPolicyType
 
   nsCSPDirective* defaultDir = nullptr;
 
   // These directive arrays are short (1-5 elements), not worth using a hashtable.
 
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     // Check if the directive name matches
     if (mDirectives[i]->restrictsContentType(aContentType)) {
-      if (!mDirectives[i]->permits(aUri, aNonce)) {
+      if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected)) {
         mDirectives[i]->toString(outViolatedDirective);
         return false;
       }
       return true;
     }
     if (mDirectives[i]->isDefaultDirective()) {
       defaultDir = mDirectives[i];
     }
@@ -790,17 +811,17 @@ nsCSPPolicy::permits(nsContentPolicyType
   // TODO: currently [frame-ancestors] is mapped to TYPE_DOCUMENT (needs to be fixed)
   if (aContentType == nsIContentPolicy::TYPE_DOCUMENT) {
     return true;
   }
 
   // If the above loop runs through, we haven't found a matching directive.
   // Avoid relooping, just store the result of default-src while looping.
   if (defaultDir) {
-    if (!defaultDir->permits(aUri, aNonce)) {
+    if (!defaultDir->permits(aUri, aNonce, aWasRedirected)) {
       defaultDir->toString(outViolatedDirective);
       return false;
     }
     return true;
   }
 
   // unspecified default-src should default to no restrictions
   // see bug 764937
--- a/content/base/src/nsCSPUtils.h
+++ b/content/base/src/nsCSPUtils.h
@@ -186,56 +186,54 @@ bool CSP_IsQuotelessKeyword(const nsAStr
 
 /* =============== nsCSPSrc ================== */
 
 class nsCSPBaseSrc {
   public:
     nsCSPBaseSrc();
     virtual ~nsCSPBaseSrc();
 
-    virtual bool permits(nsIURI* aUri, const nsAString& aNonce) const;
+    virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
     virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
     virtual void toString(nsAString& outStr) const = 0;
 };
 
 /* =============== nsCSPSchemeSrc ============ */
 
 class nsCSPSchemeSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPSchemeSrc(const nsAString& aScheme);
     virtual ~nsCSPSchemeSrc();
 
-    bool permits(nsIURI* aUri, const nsAString& aNonce) const;
+    bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
     void toString(nsAString& outStr) const;
 
   private:
     nsString mScheme;
 };
 
 /* =============== nsCSPHostSrc ============== */
 
 class nsCSPHostSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPHostSrc(const nsAString& aHost);
     virtual ~nsCSPHostSrc();
 
-    bool permits(nsIURI* aUri, const nsAString& aNonce) const;
+    bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
     void toString(nsAString& outStr) const;
 
     void setScheme(const nsAString& aScheme);
     void setPort(const nsAString& aPort);
     void appendPath(const nsAString &aPath);
-    void setFileAndArguments(const nsAString& aFile);
 
   private:
     nsString mScheme;
     nsString mHost;
     nsString mPort;
     nsString mPath;
-    nsString mFileAndArguments;
 };
 
 /* =============== nsCSPKeywordSrc ============ */
 
 class nsCSPKeywordSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPKeywordSrc(CSPKeyword aKeyword);
     virtual ~nsCSPKeywordSrc();
@@ -249,17 +247,17 @@ class nsCSPKeywordSrc : public nsCSPBase
 
 /* =============== nsCSPNonceSource =========== */
 
 class nsCSPNonceSrc : public nsCSPBaseSrc {
   public:
     explicit nsCSPNonceSrc(const nsAString& aNonce);
     virtual ~nsCSPNonceSrc();
 
-    bool permits(nsIURI* aUri, const nsAString& aNonce) const;
+    bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
     bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
     void toString(nsAString& outStr) const;
 
   private:
     nsString mNonce;
 };
 
 /* =============== nsCSPHashSource ============ */
@@ -293,17 +291,17 @@ class nsCSPReportURI : public nsCSPBaseS
 /* =============== nsCSPDirective ============= */
 
 class nsCSPDirective {
   public:
     nsCSPDirective();
     explicit nsCSPDirective(enum CSPDirective aDirective);
     virtual ~nsCSPDirective();
 
-    bool permits(nsIURI* aUri, const nsAString& aNonce) const;
+    bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
     bool permits(nsIURI* aUri) const;
     bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
     void toString(nsAString& outStr) const;
 
     inline void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
       { mSrcs = aSrcs; }
 
     bool restrictsContentType(nsContentPolicyType aContentType) const;
@@ -326,16 +324,17 @@ class nsCSPDirective {
 class nsCSPPolicy {
   public:
     nsCSPPolicy();
     virtual ~nsCSPPolicy();
 
     bool permits(nsContentPolicyType aContentType,
                  nsIURI* aUri,
                  const nsAString& aNonce,
+                 bool aWasRedirected,
                  nsAString& outViolatedDirective) const;
     bool permitsBaseURI(nsIURI* aUri) const;
     bool allows(nsContentPolicyType aContentType,
                 enum CSPKeyword aKeyword,
                 const nsAString& aHashOrNonce) const;
     bool allows(nsContentPolicyType aContentType,
                 enum CSPKeyword aKeyword) const;
     void toString(nsAString& outStr) const;
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1028,17 +1028,17 @@ nsFrameMessageManager::ReceiveMessage(ns
         JS::Rooted<JS::Value> principalValue(cx);
         rv = nsContentUtils::WrapNative(cx, aPrincipal, &NS_GET_IID(nsIPrincipal), &principalValue);
         JS_DefineProperty(cx, param, "principal", principalValue, JSPROP_ENUMERATE);
       }
 
       JS::Rooted<JS::Value> thisValue(cx, JS::UndefinedValue());
 
       JS::Rooted<JS::Value> funval(cx);
-      if (JS_ObjectIsCallable(cx, object)) {
+      if (JS::IsCallable(object)) {
         // If the listener is a JS function:
         funval.setObject(*object);
 
         // A small hack to get 'this' value right on content side where
         // messageManager is wrapped in TabChildGlobal.
         nsCOMPtr<nsISupports> defaultThisValue;
         if (mChrome) {
           defaultThisValue = do_QueryObject(this);
@@ -1050,17 +1050,17 @@ nsFrameMessageManager::ReceiveMessage(ns
         NS_ENSURE_SUCCESS(rv, rv);
       } else {
         // If the listener is a JS object which has receiveMessage function:
         if (!JS_GetProperty(cx, object, "receiveMessage", &funval) ||
             !funval.isObject())
           return NS_ERROR_UNEXPECTED;
 
         // Check if the object is even callable.
-        NS_ENSURE_STATE(JS_ObjectIsCallable(cx, &funval.toObject()));
+        NS_ENSURE_STATE(JS::IsCallable(&funval.toObject()));
         thisValue.setObject(*object);
       }
 
       JS::Rooted<JS::Value> rval(cx, JSVAL_VOID);
       JS::Rooted<JS::Value> argv(cx, JS::ObjectValue(*param));
 
       {
         JS::Rooted<JSObject*> thisObject(cx, thisValue.toObjectOrNull());
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -3975,17 +3975,17 @@ ArrayBufferBuilder::reset()
   mCapacity = mLength = 0;
 }
 
 bool
 ArrayBufferBuilder::setCapacity(uint32_t aNewCap)
 {
   MOZ_ASSERT(!mMapPtr);
 
-  uint8_t *newdata = (uint8_t *) realloc(mDataPtr, aNewCap);
+  uint8_t *newdata = (uint8_t *) js_realloc(mDataPtr, aNewCap);
   if (!newdata) {
     return false;
   }
 
   if (aNewCap > mCapacity) {
     memset(newdata + mCapacity, 0, aNewCap - mCapacity);
   }
 
--- a/content/base/test/TestCSPParser.cpp
+++ b/content/base/test/TestCSPParser.cpp
@@ -282,62 +282,80 @@ nsresult TestIgnoreUpperLowerCasePolicie
 
 nsresult TestIgnorePaths() {
 
   static const PolicyTest policies[] =
   {
     { "script-src http://www.example.com",
       "script-src http://www.example.com" },
     { "script-src http://www.example.com/",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/" },
     { "script-src http://www.example.com/path-1",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1" },
     { "script-src http://www.example.com/path-1/",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1/" },
     { "script-src http://www.example.com/path-1/path_2",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1/path_2" },
     { "script-src http://www.example.com/path-1/path_2/",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1/path_2/" },
     { "script-src http://www.example.com/path-1/path_2/file.js",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1/path_2/file.js" },
     { "script-src http://www.example.com/path-1/path_2/file_1.js",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1/path_2/file_1.js" },
     { "script-src http://www.example.com/path-1/path_2/file-2.js",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1/path_2/file-2.js" },
     { "script-src http://www.example.com/path-1/path_2/f.js",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1/path_2/f.js" },
     { "script-src http://www.example.com:88",
       "script-src http://www.example.com:88" },
     { "script-src http://www.example.com:88/",
-      "script-src http://www.example.com:88" },
+      "script-src http://www.example.com:88/" },
     { "script-src http://www.example.com:88/path-1",
-      "script-src http://www.example.com:88" },
+      "script-src http://www.example.com:88/path-1" },
     { "script-src http://www.example.com:88/path-1/",
-      "script-src http://www.example.com:88" },
+      "script-src http://www.example.com:88/path-1/" },
     { "script-src http://www.example.com:88/path-1/path_2",
-      "script-src http://www.example.com:88" },
+      "script-src http://www.example.com:88/path-1/path_2" },
     { "script-src http://www.example.com:88/path-1/path_2/",
-      "script-src http://www.example.com:88" },
+      "script-src http://www.example.com:88/path-1/path_2/" },
     { "script-src http://www.example.com:88/path-1/path_2/file.js",
-      "script-src http://www.example.com:88" },
+      "script-src http://www.example.com:88/path-1/path_2/file.js" },
     { "script-src http://www.example.com:*",
       "script-src http://www.example.com:*" },
     { "script-src http://www.example.com:*/",
-      "script-src http://www.example.com:*" },
+      "script-src http://www.example.com:*/" },
     { "script-src http://www.example.com:*/path-1",
-      "script-src http://www.example.com:*" },
+      "script-src http://www.example.com:*/path-1" },
     { "script-src http://www.example.com:*/path-1/",
-      "script-src http://www.example.com:*" },
+      "script-src http://www.example.com:*/path-1/" },
     { "script-src http://www.example.com:*/path-1/path_2",
-      "script-src http://www.example.com:*" },
+      "script-src http://www.example.com:*/path-1/path_2" },
     { "script-src http://www.example.com:*/path-1/path_2/",
-      "script-src http://www.example.com:*" },
+      "script-src http://www.example.com:*/path-1/path_2/" },
     { "script-src http://www.example.com:*/path-1/path_2/file.js",
-      "script-src http://www.example.com:*" },
-    { "report-uri http://www.example.com",
+      "script-src http://www.example.com:*/path-1/path_2/file.js" },
+    { "script-src http://www.example.com#foo",
+      "script-src http://www.example.com" },
+    { "script-src http://www.example.com?foo=bar",
+      "script-src http://www.example.com" },
+    { "script-src http://www.example.com:8888#foo",
+      "script-src http://www.example.com:8888" },
+    { "script-src http://www.example.com:8888?foo",
+      "script-src http://www.example.com:8888" },
+    { "script-src http://www.example.com/#foo",
+      "script-src http://www.example.com/" },
+    { "script-src http://www.example.com/?foo",
+      "script-src http://www.example.com/" },
+    { "script-src http://www.example.com/path-1/file.js#foo",
+      "script-src http://www.example.com/path-1/file.js" },
+    { "script-src http://www.example.com/path-1/file.js?foo",
+      "script-src http://www.example.com/path-1/file.js" },
+    { "script-src http://www.example.com/path-1/file.js?foo#bar",
+      "script-src http://www.example.com/path-1/file.js" },
+    { "report-uri http://www.example.com/",
       "report-uri http://www.example.com/" },
     { "report-uri http://www.example.com:8888/asdf",
       "report-uri http://www.example.com:8888/asdf" },
     { "report-uri http://www.example.com:8888/path_1/path_2",
       "report-uri http://www.example.com:8888/path_1/path_2" },
     { "report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301",
       "report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301" },
     { "report-uri /examplepath",
@@ -396,19 +414,19 @@ nsresult TestSimplePolicies() {
       "default-src app://{app-host-is-uid}" },
     { "   ;   default-src abc",
       "default-src http://abc" },
     { " ; ; ; ;     default-src            abc    ; ; ; ;",
       "default-src http://abc" },
     { "script-src 'none' 'none' 'none';",
       "script-src 'none'" },
     { "script-src http://www.example.com/path-1//",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1//" },
     { "script-src http://www.example.com/path-1//path_2",
-      "script-src http://www.example.com" },
+      "script-src http://www.example.com/path-1//path_2" },
     { "default-src 127.0.0.1",
       "default-src http://127.0.0.1" },
     { "default-src 127.0.0.1:*",
       "default-src http://127.0.0.1:*" },
     { "default-src -; ",
       "default-src http://-" },
     { "script-src 1",
       "script-src http://1" }
@@ -614,31 +632,31 @@ nsresult TestGoodGeneratedPolicies() {
       "media-src https://self:34" },
     { "frame-src https://bar",
       "frame-src https://bar" },
     { "font-src http://three:81",
       "font-src http://three:81" },
     { "connect-src https://three:81",
       "connect-src https://three:81" },
     { "script-src http://self.com:80/foo",
-      "script-src http://self.com:80" },
+      "script-src http://self.com:80/foo" },
     { "object-src http://self.com/foo",
-      "object-src http://self.com" },
+      "object-src http://self.com/foo" },
     { "report-uri /report.py",
       "report-uri http://www.selfuri.com/report.py"},
     { "img-src http://foo.org:34/report.py",
-      "img-src http://foo.org:34" },
+      "img-src http://foo.org:34/report.py" },
     { "media-src foo/bar/report.py",
-      "media-src http://foo" },
+      "media-src http://foo/bar/report.py" },
     { "report-uri /",
       "report-uri http://www.selfuri.com/"},
     { "font-src https://self.com/report.py",
-      "font-src https://self.com" },
+      "font-src https://self.com/report.py" },
     { "connect-src https://foo.com/report.py",
-      "connect-src https://foo.com" },
+      "connect-src https://foo.com/report.py" },
     { "default-src *; report-uri  http://www.reporturi.com/",
       "default-src *; report-uri http://www.reporturi.com/" },
     { "default-src http://first.com",
       "default-src http://first.com" },
     { "script-src http://second.com",
       "script-src http://second.com" },
     { "object-src http://third.com",
       "object-src http://third.com" },
@@ -646,25 +664,25 @@ nsresult TestGoodGeneratedPolicies() {
       "style-src https://foobar.com:4443" },
     { "img-src http://foobar.com:4443",
       "img-src http://foobar.com:4443" },
     { "media-src bar.com",
       "media-src http://bar.com" },
     { "frame-src http://bar.com",
       "frame-src http://bar.com" },
     { "font-src http://self.com/",
-      "font-src http://self.com" },
+      "font-src http://self.com/" },
     { "script-src 'self'",
       "script-src http://www.selfuri.com" },
     { "default-src http://self.com/foo.png",
-      "default-src http://self.com" },
+      "default-src http://self.com/foo.png" },
     { "script-src http://self.com/foo.js",
-      "script-src http://self.com" },
+      "script-src http://self.com/foo.js" },
     { "object-src http://bar.com/foo.js",
-      "object-src http://bar.com" },
+      "object-src http://bar.com/foo.js" },
     { "style-src http://FOO.COM",
       "style-src http://foo.com" },
     { "img-src HTTP",
       "img-src http://http" },
     { "media-src http",
       "media-src http://http" },
     { "frame-src 'SELF'",
       "frame-src http://www.selfuri.com" },
@@ -692,21 +710,21 @@ nsresult TestGoodGeneratedPolicies() {
       "frame-ancestors http://a.b.c.d.e.f.g.h.i.j.k.l.x.com" },
     { "frame-ancestors https://self.com:34",
       "frame-ancestors https://self.com:34" },
     { "default-src 'none'; frame-ancestors 'self'",
       "default-src 'none'; frame-ancestors http://www.selfuri.com" },
     { "frame-ancestors http://self:80",
       "frame-ancestors http://self:80" },
     { "frame-ancestors http://self.com/bar",
-      "frame-ancestors http://self.com" },
+      "frame-ancestors http://self.com/bar" },
     { "default-src 'self'; frame-ancestors 'self'",
       "default-src http://www.selfuri.com; frame-ancestors http://www.selfuri.com" },
     { "frame-ancestors http://bar.com/foo.png",
-      "frame-ancestors http://bar.com" },
+      "frame-ancestors http://bar.com/foo.png" },
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 1);
 }
 
 // ============================= TestBadGeneratedPolicies ========================
 
@@ -742,121 +760,121 @@ nsresult TestGoodGeneratedPoliciesForPat
   // Once bug 808292 (Implement path-level host-source matching to CSP)
   // lands we have to update the expected output to include the parsed path
 
   static const PolicyTest policies[] =
   {
     { "img-src http://test1.example.com",
       "img-src http://test1.example.com" },
     { "img-src http://test1.example.com/",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/" },
     { "img-src http://test1.example.com/path-1",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1" },
     { "img-src http://test1.example.com/path-1/",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/" },
     { "img-src http://test1.example.com/path-1/path_2/",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/" },
     { "img-src http://test1.example.com/path-1/path_2/file.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/file.js" },
     { "img-src http://test1.example.com/path-1/path_2/file_1.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/file_1.js" },
     { "img-src http://test1.example.com/path-1/path_2/file-2.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/file-2.js" },
     { "img-src http://test1.example.com/path-1/path_2/f.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/f.js" },
     { "img-src http://test1.example.com/path-1/path_2/f.oo.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/f.oo.js" },
     { "img-src test1.example.com",
       "img-src http://test1.example.com" },
     { "img-src test1.example.com/",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/" },
     { "img-src test1.example.com/path-1",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1" },
     { "img-src test1.example.com/path-1/",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/" },
     { "img-src test1.example.com/path-1/path_2/",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/" },
     { "img-src test1.example.com/path-1/path_2/file.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/file.js" },
     { "img-src test1.example.com/path-1/path_2/file_1.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/file_1.js" },
     { "img-src test1.example.com/path-1/path_2/file-2.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/file-2.js" },
     { "img-src test1.example.com/path-1/path_2/f.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/f.js" },
     { "img-src test1.example.com/path-1/path_2/f.oo.js",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/path-1/path_2/f.oo.js" },
     { "img-src *.example.com",
       "img-src http://*.example.com" },
     { "img-src *.example.com/",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/" },
     { "img-src *.example.com/path-1",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1" },
     { "img-src *.example.com/path-1/",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1/" },
     { "img-src *.example.com/path-1/path_2/",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1/path_2/" },
     { "img-src *.example.com/path-1/path_2/file.js",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1/path_2/file.js" },
     { "img-src *.example.com/path-1/path_2/file_1.js",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1/path_2/file_1.js" },
     { "img-src *.example.com/path-1/path_2/file-2.js",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1/path_2/file-2.js" },
     { "img-src *.example.com/path-1/path_2/f.js",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1/path_2/f.js" },
     { "img-src *.example.com/path-1/path_2/f.oo.js",
-      "img-src http://*.example.com" },
+      "img-src http://*.example.com/path-1/path_2/f.oo.js" },
     { "img-src test1.example.com:80",
       "img-src http://test1.example.com:80" },
     { "img-src test1.example.com:80/",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/" },
     { "img-src test1.example.com:80/path-1",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/path-1" },
     { "img-src test1.example.com:80/path-1/",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/path-1/" },
     { "img-src test1.example.com:80/path-1/path_2",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/path-1/path_2" },
     { "img-src test1.example.com:80/path-1/path_2/",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/path-1/path_2/" },
     { "img-src test1.example.com:80/path-1/path_2/file.js",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/path-1/path_2/file.js" },
     { "img-src test1.example.com:80/path-1/path_2/f.ile.js",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/path-1/path_2/f.ile.js" },
     { "img-src test1.example.com:*",
       "img-src http://test1.example.com:*" },
     { "img-src test1.example.com:*/",
-      "img-src http://test1.example.com:*" },
+      "img-src http://test1.example.com:*/" },
     { "img-src test1.example.com:*/path-1",
-      "img-src http://test1.example.com:*" },
+      "img-src http://test1.example.com:*/path-1" },
     { "img-src test1.example.com:*/path-1/",
-      "img-src http://test1.example.com:*" },
+      "img-src http://test1.example.com:*/path-1/" },
     { "img-src test1.example.com:*/path-1/path_2",
-      "img-src http://test1.example.com:*" },
+      "img-src http://test1.example.com:*/path-1/path_2" },
     { "img-src test1.example.com:*/path-1/path_2/",
-      "img-src http://test1.example.com:*" },
+      "img-src http://test1.example.com:*/path-1/path_2/" },
     { "img-src test1.example.com:*/path-1/path_2/file.js",
-      "img-src http://test1.example.com:*" },
+      "img-src http://test1.example.com:*/path-1/path_2/file.js" },
     { "img-src test1.example.com:*/path-1/path_2/f.ile.js",
-      "img-src http://test1.example.com:*" },
+      "img-src http://test1.example.com:*/path-1/path_2/f.ile.js" },
     { "img-src http://test1.example.com/abc//",
-      "img-src http://test1.example.com" },
+      "img-src http://test1.example.com/abc//" },
     { "img-src https://test1.example.com/abc/def//",
-      "img-src https://test1.example.com" },
+      "img-src https://test1.example.com/abc/def//" },
     { "img-src https://test1.example.com/abc/def/ghi//",
-      "img-src https://test1.example.com" },
+      "img-src https://test1.example.com/abc/def/ghi//" },
     { "img-src http://test1.example.com:80/abc//",
-      "img-src http://test1.example.com:80" },
+      "img-src http://test1.example.com:80/abc//" },
     { "img-src https://test1.example.com:80/abc/def//",
-      "img-src https://test1.example.com:80" },
+      "img-src https://test1.example.com:80/abc/def//" },
     { "img-src https://test1.example.com:80/abc/def/ghi//",
-      "img-src https://test1.example.com:80" },
+      "img-src https://test1.example.com:80/abc/def/ghi//" },
     { "img-src https://test1.example.com/abc////////////def/",
-      "img-src https://test1.example.com" },
+      "img-src https://test1.example.com/abc////////////def/" },
     { "img-src https://test1.example.com/abc////////////",
-      "img-src https://test1.example.com" },
+      "img-src https://test1.example.com/abc////////////" },
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 1);
 }
 
 // ============ TestBadGeneratedPoliciesForPathHandling ============
 
--- a/content/base/test/chrome/cpows_parent.xul
+++ b/content/base/test/chrome/cpows_parent.xul
@@ -218,17 +218,17 @@
       let cpowLocation = Cu.getCompartmentLocation(getUnprivilegedObject);
       ok(/Privileged Junk/.test(cpowLocation),
          "parent->child CPOWs should live in the privileged junk scope: " + cpowLocation);
 
       // Make sure that parent->child CPOWs point through a privileged scope in the child
       // (the privileged junk scope, but we don't have a good way to test for that
       // specifically).
       is(unprivilegedObject.expando, undefined, "parent->child references should get Xrays");
-      todo_is(unprivilegedObject.wrappedJSObject.expando, 42, "parent->child references should get waivable Xrays - see bug 1065811");
+      is(unprivilegedObject.wrappedJSObject.expando, 42, "parent->child references should get waivable Xrays");
 
       // Send an object to the child to let it verify invariants in the other direction.
       function passMe() { return 42; };
       passMe.expando = 42;
       let results = testParentObject(passMe);
       ok(results.length > 0, "Need results");
       results.forEach((x) => is(x.result, "PASS", x.message));
     }
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_csp_path_matching.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 808292 - Implement path-level host-source matching to CSP</title>
+  </head>
+  <body>
+  <div id="testdiv">blocked</div>
+  <script src="http://test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js#foo"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_csp_path_matching.js
@@ -0,0 +1,1 @@
+document.getElementById("testdiv").innerHTML = "allowed";
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_csp_path_matching_redirect.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 808292 - Implement path-level host-source matching to CSP</title>
+  </head>
+  <body>
+  <div id="testdiv">blocked</div>
+  <script src="http://example.com/tests/content/base/test/csp/file_csp_path_matching_redirect_server.sjs"></script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/file_csp_path_matching_redirect_server.sjs
@@ -0,0 +1,13 @@
+// Redirect server specifically to handle redirects
+// for path-level host-source matching
+// see https://bugzilla.mozilla.org/show_bug.cgi?id=808292
+
+function handleRequest(request, response)
+{
+
+  var newLocation = "http://test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js";
+
+  response.setStatusLine("1.1", 302, "Found");
+  response.setHeader("Cache-Control", "no-cache", false);
+  response.setHeader("Location", newLocation, false);
+}
deleted file mode 100644
--- a/content/base/test/csp/file_csp_regexp_parsing.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-  <head>
-    <title>Bug 916054 - URLs with path are ignored by FF's CSP parser</title>
-  </head>
-  <body>
-  <div id="testdiv">blocked</div>
-  <script src="http://test1.example.com/tests/content/base/test/csp/file_csp_regexp_parsing.js"></script>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/csp/file_csp_regexp_parsing.js
+++ /dev/null
@@ -1,1 +0,0 @@
-document.getElementById("testdiv").innerHTML = "allowed";
--- a/content/base/test/csp/mochitest.ini
+++ b/content/base/test/csp/mochitest.ini
@@ -76,19 +76,21 @@ support-files =
   file_nonce_source.html^headers^
   file_CSP_bug941404.html
   file_CSP_bug941404_xhr.html
   file_CSP_bug941404_xhr.html^headers^
   file_hash_source.html
   file_hash_source.html^headers^
   file_self_none_as_hostname_confusion.html
   file_self_none_as_hostname_confusion.html^headers^
+  file_csp_path_matching.html
+  file_csp_path_matching.js
+  file_csp_path_matching_redirect.html
+  file_csp_path_matching_redirect_server.sjs
   file_csp_testserver.sjs
-  file_csp_regexp_parsing.html
-  file_csp_regexp_parsing.js
   file_report_uri_missing_in_report_only_header.html
   file_report_uri_missing_in_report_only_header.html^headers^
   file_csp_report.html
   file_redirect_content.sjs
   file_redirect_report.sjs
   file_subframe_run_js_if_allowed.html
   file_subframe_run_js_if_allowed.html^headers^
   file_leading_wildcard.html
@@ -116,17 +118,18 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_CSP_bug909029.html]
 [test_policyuri_regression_from_multipolicy.html]
 [test_nonce_source.html]
 [test_CSP_bug941404.html]
 [test_hash_source.html]
 skip-if = e10s || buildapp == 'b2g' # can't compute hashes in child process (bug 958702)
 [test_self_none_as_hostname_confusion.html]
 [test_bug949549.html]
-[test_csp_regexp_parsing.html]
+[test_csp_path_matching.html]
+[test_csp_path_matching_redirect.html]
 [test_report_uri_missing_in_report_only_header.html]
 [test_csp_report.html]
 skip-if = e10s || buildapp == 'b2g' # http-on-opening-request observer not supported in child process (bug 1009632)
 [test_301_redirect.html]
 skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
 [test_302_redirect.html]
 skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
 [test_303_redirect.html]
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/test_csp_path_matching.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 808292 - Implement path-level host-source matching to CSP</title>
+  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="visibility: hidden">
+    <iframe style="width:100%;" id="testframe"></iframe>
+  </div>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We are loading the following url (including a fragment portion):
+ * http://test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js#foo
+ * using different policies and verify that the applied policy is accurately enforced.
+ */
+
+var policies = [
+  ["allowed", "*"],
+  ["allowed", "test1.example.com"],
+  ["allowed", "test1.example.com/"],
+  ["allowed", "test1.example.com/tests/content/base/test/csp/"],
+  ["allowed", "test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js"],
+
+  ["allowed", "test1.example.com?foo=val"],
+  ["allowed", "test1.example.com/?foo=val"],
+  ["allowed", "test1.example.com/tests/content/base/test/csp/?foo=val"],
+  ["allowed", "test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js?foo=val"],
+
+  ["allowed", "test1.example.com#foo"],
+  ["allowed", "test1.example.com/#foo"],
+  ["allowed", "test1.example.com/tests/content/base/test/csp/#foo"],
+  ["allowed", "test1.example.com/tests/content/base/test/csp/file_csp_path_matching.js#foo"],
+
+  ["allowed", "*.example.com"],
+  ["allowed", "*.example.com/"],
+  ["allowed", "*.example.com/tests/content/base/test/csp/"],
+  ["allowed", "*.example.com/tests/content/base/test/csp/file_csp_path_matching.js"],
+
+  ["allowed", "test1.example.com:80"],
+  ["allowed", "test1.example.com:80/"],
+  ["allowed", "test1.example.com:80/tests/content/base/test/csp/"],
+  ["allowed", "test1.example.com:80/tests/content/base/test/csp/file_csp_path_matching.js"],
+
+  ["allowed", "test1.example.com:*"],
+  ["allowed", "test1.example.com:*/"],
+  ["allowed", "test1.example.com:*/tests/content/base/test/csp/"],
+  ["allowed", "test1.example.com:*/tests/content/base/test/csp/file_csp_path_matching.js"],
+
+  ["blocked", "test1.example.com/tests"],
+  ["blocked", "test1.example.com/tests/content/base/test/csp"],
+  ["blocked", "test1.example.com/tests/content/base/test/csp/file_csp_path_matching.py"],
+
+  ["blocked", "test1.example.com:8888/tests"],
+  ["blocked", "test1.example.com:8888/tests/content/base/test/csp"],
+  ["blocked", "test1.example.com:8888/tests/content/base/test/csp/file_csp_path_matching.py"],
+]
+
+var counter = 0;
+var policy;
+
+function loadNextTest() {
+  if (counter == policies.length) {
+    SimpleTest.finish();
+  }
+  else {
+    policy = policies[counter++];
+    var src = "file_csp_testserver.sjs";
+    // append the file that should be served
+    src += "?file=" + escape("tests/content/base/test/csp/file_csp_path_matching.html");
+    // append the CSP that should be used to serve the file
+    src += "&csp=" + escape("default-src 'none'; script-src " + policy[1]);
+
+    document.getElementById("testframe").addEventListener("load", test, false);
+    document.getElementById("testframe").src = src;
+  }
+}
+
+function test() {
+  try {
+    document.getElementById("testframe").removeEventListener('load', test, false);
+    var testframe = document.getElementById("testframe");
+    var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+    is(divcontent, policy[0], "should be " + policy[0] + " in test " + (counter - 1) + "!");
+  }
+  catch (e) {
+    ok(false, "ERROR: could not access content in test " + (counter - 1) + "!");
+  }
+  loadNextTest();
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/csp/test_csp_path_matching_redirect.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 808292 - Implement path-level host-source matching to CSP (redirects)</title>
+  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="visibility: hidden">
+    <iframe style="width:100%;" id="testframe"></iframe>
+  </div>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * First, we try to load a script where the *path* does not match.
+ * Second, we try to load a script which is allowed by the CSPs
+ * script-src directive. The script then gets redirected to
+ * an URL where the host matches, but the path wouldn't.
+ * Since 'paths' should not be taken into account after redirects,
+ * that load should succeed. We are using a similar test setup
+ * as described in the spec, see:
+ * http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
+ */
+
+var policy = "script-src http://example.com http://test1.example.com/CSPAllowsScriptsInThatFolder";
+
+var tests = [
+  {
+    // the script in file_csp_path_matching.html
+    // <script src="http://test1.example.com/tests/content/base/..">
+    // is not within the whitelisted path by the csp-policy
+    // hence the script is 'blocked' by CSP.
+    expected: "blocked",
+    uri: "tests/content/base/test/csp/file_csp_path_matching.html"
+  },
+  {
+    // the script in file_csp_path_matching_redirect.html
+    // <script src="http://example.com/tests/content/..">
+    // gets redirected to: http://test1.example.com/tests/content
+    // where after the redirect the path of the policy is not enforced
+    // anymore and hence execution of the script is 'allowed'.
+    expected: "allowed",
+    uri: "tests/content/base/test/csp/file_csp_path_matching_redirect.html"
+  },
+];
+
+var counter = 0;
+var curTest;
+
+function checkResult() {
+  try {
+    document.getElementById("testframe").removeEventListener('load', checkResult, false);
+    var testframe = document.getElementById("testframe");
+    var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+    is(divcontent, curTest.expected, "should be blocked in test " + (counter - 1) + "!");
+  }
+  catch (e) {
+    ok(false, "ERROR: could not access content in test " + (counter - 1) + "!");
+  }
+  loadNextTest();
+}
+
+function loadNextTest() {
+  if (counter == tests.length) {
+    SimpleTest.finish();
+  }
+  else {
+    curTest = tests[counter++];
+    var src = "file_csp_testserver.sjs";
+    // append the file that should be served
+    src += "?file=" + escape(curTest.uri);
+    // append the CSP that should be used to serve the file
+    src += "&csp=" + escape(policy);
+
+    document.getElementById("testframe").addEventListener("load", checkResult, false);
+    document.getElementById("testframe").src = src;
+  }
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
deleted file mode 100644
--- a/content/base/test/csp/test_csp_regexp_parsing.html
+++ /dev/null
@@ -1,101 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Bug 916054 - URLs with path are ignored by FF's CSP parser</title>
-  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-  <p id="display"></p>
-  <div id="content" style="visibility: hidden">
-    <iframe style="width:100%;" id="testframe"></iframe>
-  </div>
-
-<script class="testbody" type="text/javascript">
-
-SimpleTest.waitForExplicitFinish();
-
-var policies = [
-  ["allowed", "*"],
-  ["allowed", "test1.example.com"],
-  ["allowed", "test1.example.com/"],
-  ["allowed", "test1.example.com/path-1"],
-  ["allowed", "test1.example.com/path-1/"],
-  ["allowed", "test1.example.com/path-1/path_2/"],
-  ["allowed", "test1.example.com/path-1/path_2/file.js"],
-  ["allowed", "test1.example.com/path-1/path_2/file_1.js"],
-  ["allowed", "test1.example.com/path-1/path_2/file-2.js"],
-  ["allowed", "test1.example.com/path-1/path_2/f.js"],
-  ["allowed", "test1.example.com/path-1/path_2/f.oo.js"],
-  ["allowed", "*.example.com"],
-  ["allowed", "*.example.com/"],
-  ["allowed", "*.example.com/path-1"],
-  ["allowed", "*.example.com/path-1/"],
-  ["allowed", "*.example.com/path-1/path_2/"],
-  ["allowed", "*.example.com/path-1/path_2/file.js"],
-  ["allowed", "*.example.com/path-1/path_2/file_1.js"],
-  ["allowed", "*.example.com/path-1/path_2/file-2.js"],
-  ["allowed", "*.example.com/path-1/path_2/f.js"],
-  ["allowed", "*.example.com/path-1/path_2/f.oo.js"],
-  ["allowed", "test1.example.com:80"],
-  ["allowed", "test1.example.com:80/"],
-  ["allowed", "test1.example.com:80/path-1"],
-  ["allowed", "test1.example.com:80/path-1/"],
-  ["allowed", "test1.example.com:80/path-1/path_2"],
-  ["allowed", "test1.example.com:80/path-1/path_2/"],
-  ["allowed", "test1.example.com:80/path-1/path_2/file.js"],
-  ["allowed", "test1.example.com:80/path-1/path_2/f.ile.js"],
-  ["allowed", "test1.example.com:*"],
-  ["allowed", "test1.example.com:*/"],
-  ["allowed", "test1.example.com:*/path-1"],
-  ["allowed", "test1.example.com:*/path-1/"],
-  ["allowed", "test1.example.com:*/path-1/path_2"],
-  ["allowed", "test1.example.com:*/path-1/path_2/"],
-  ["allowed", "test1.example.com:*/path-1/path_2/file.js"],
-  ["allowed", "test1.example.com:*/path-1/path_2/f.ile.js"],
-  // the following tests should fail
-  ["blocked", "test1.example.com:88path-1/"],
-  ["blocked", "test1.example.com:80.js"],
-  ["blocked", "test1.example.com:*.js"],
-  ["blocked", "test1.example.com:*."]
-]
-
-var counter = 0;
-var policy;
-
-function loadNextTest() {
-  if (counter == policies.length) {
-    SimpleTest.finish();
-  }
-  else {
-    policy = policies[counter++];
-    var src = "file_csp_testserver.sjs";
-    // append the file that should be served
-    src += "?file=" + escape("tests/content/base/test/csp/file_csp_regexp_parsing.html");
-    // append the CSP that should be used to serve the file
-    src += "&csp=" + escape("default-src 'none'; script-src " + policy[1]);
-
-    document.getElementById("testframe").addEventListener("load", test, false);
-    document.getElementById("testframe").src = src;
-  }
-}
-
-function test() {
-  try {
-    document.getElementById("testframe").removeEventListener('load', test, false);
-    var testframe = document.getElementById("testframe");
-    var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
-    is(divcontent, policy[0], "should be " + policy[0] + " in test " + (counter - 1) + "!");
-  }
-  catch (e) {
-    ok(false, "ERROR: could not access content in test " + (counter - 1) + "!");
-  }
-  loadNextTest();
-}
-
-loadNextTest();
-
-</script>
-</body>
-</html>
--- a/content/base/test/test_bug461735.html
+++ b/content/base/test/test_bug461735.html
@@ -28,18 +28,17 @@ window.onerror = function(message, uri, 
 </script>
 <script src="bug461735-redirect1.sjs"></script>
 <script>
   is(errorFired, true, "Should have error in redirected different origin script");
   errorFired = false;
 </script>
 <script type="application/javascript">
 window.onerror = function(message, uri, line) {
-  ok(message.contains("ReferenceError: c is not defined"),
-     "Should have correct error message");
+  is(message, "ReferenceError: c is not defined", "Should have correct error message");
   is(uri,
      "http://mochi.test:8888/tests/content/base/test/bug461735-redirect2.sjs",
      "Unexpected error location URI");
   is(line, 3, "Should have a line here");
   errorFired = true;
 }
 </script>
 <script src="bug461735-redirect2.sjs"></script>
--- a/content/base/test/test_bug696301-1.html
+++ b/content/base/test/test_bug696301-1.html
@@ -33,18 +33,17 @@ window.onerror = function(message, uri, 
   is(errorFired, true, "Should have error in different origin script");
   is(global, "ran", "Different origin script should have run");
 </script>
 
 <script type="application/javascript">
 errorFired = false;
 global = "";
 window.onerror = function(message, uri, line) {
-  ok(message.contains("ReferenceError: c is not defined"),
-     "Should have correct error message");
+  is(message, "ReferenceError: c is not defined", "Should have correct error message");
   is(uri,
      "http://example.com/tests/content/base/test/bug696301-script-1.js",
      "Should also have correct script URI");
   is(line, 3, "Should have a line here");
   errorFired = true;
 }
 </script>
 <script src="http://example.com/tests/content/base/test/bug696301-script-1.js"
--- a/content/base/test/test_bug696301-2.html
+++ b/content/base/test/test_bug696301-2.html
@@ -35,18 +35,17 @@ window.onerror = function(message, uri, 
   is(errorFired, true, "Should have error in different origin script");
   is(global, "ran", "Different origin script should have run");
 </script>
 
 <script type="application/javascript">
 errorFired = false;
 global = "";
 window.onerror = function(message, uri, line) {
-  ok(message.contains("ReferenceError: c is not defined"),
-     "Should have correct error message");
+  is(message, "ReferenceError: c is not defined", "Should have correct error message");
   is(uri,
      "http://example.com/tests/content/base/test/bug696301-script-1.js",
      "Should also have correct script URI");
   is(line, 3, "Should have a line here");
   errorFired = true;
 }
 </script>
 <script xlink:href="http://example.com/tests/content/base/test/bug696301-script-1.js"
--- a/dom/animation/AnimationUtils.h
+++ b/dom/animation/AnimationUtils.h
@@ -1,13 +1,16 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef mozilla_dom_AnimationUtils_h
+#define mozilla_dom_AnimationUtils_h
+
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/Nullable.h"
 
 namespace mozilla {
 namespace dom {
 
 class AnimationUtils
 {
@@ -22,8 +25,10 @@ public:
     }
 
     return result;
   }
 };
 
 } // namespace dom
 } // namespace mozilla
+
+#endif
--- a/dom/animation/moz.build
+++ b/dom/animation/moz.build
@@ -9,17 +9,17 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chr
 
 EXPORTS.mozilla.dom += [
     'Animation.h',
     'AnimationEffect.h',
     'AnimationPlayer.h',
     'AnimationTimeline.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'Animation.cpp',
     'AnimationEffect.cpp',
     'AnimationPlayer.cpp',
     'AnimationTimeline.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1530,17 +1530,17 @@ BaseStubConstructor(nsIWeakReference* aW
 
       JS::Rooted<JS::Value> funval(cx);
       if (!JS_GetProperty(cx, thisObject, "constructor", &funval) ||
           !funval.isObject()) {
         return NS_ERROR_UNEXPECTED;
       }
 
       // Check if the object is even callable.
-      NS_ENSURE_STATE(JS_ObjectIsCallable(cx, &funval.toObject()));
+      NS_ENSURE_STATE(JS::IsCallable(&funval.toObject()));
       {
         // wrap parameters in the target compartment
         // we also pass in the calling window as the first argument
         unsigned argc = args.length() + 1;
         JS::AutoValueVector argv(cx);
         if (!argv.resize(argc)) {
           return NS_ERROR_OUT_OF_MEMORY;
         }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -5269,17 +5269,17 @@ nsGlobalWindow::RequestAnimationFrame(co
   return handle;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::RequestAnimationFrame(JS::Handle<JS::Value> aCallback,
                                       JSContext* cx,
                                       int32_t* aHandle)
 {
-  if (!aCallback.isObject() || !JS_ObjectIsCallable(cx, &aCallback.toObject())) {
+  if (!aCallback.isObject() || !JS::IsCallable(&aCallback.toObject())) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JS::Rooted<JSObject*> callbackObj(cx, &aCallback.toObject());
   nsRefPtr<FrameRequestCallback> callback =
     new FrameRequestCallback(callbackObj, GetIncumbentGlobal());
 
   ErrorResult rv;
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1694,17 +1694,17 @@ NativeToString(JSContext* cx, JS::Handle
   JS::Rooted<JSString*> str(cx);
   {
     JSAutoCompartment ac(cx, obj);
     if (toStringDesc.object()) {
       JS::Rooted<JS::Value> toString(cx, toStringDesc.value());
       if (!JS_WrapValue(cx, &toString)) {
         return false;
       }
-      MOZ_ASSERT(JS_ObjectIsCallable(cx, &toString.toObject()));
+      MOZ_ASSERT(JS::IsCallable(&toString.toObject()));
       JS::Rooted<JS::Value> toStringResult(cx);
       if (JS_CallFunctionValue(cx, obj, toString, JS::HandleValueArray::empty(),
                                &toStringResult)) {
         str = toStringResult.toString();
       } else {
         str = nullptr;
       }
     } else {
--- a/dom/bindings/CallbackInterface.cpp
+++ b/dom/bindings/CallbackInterface.cpp
@@ -15,17 +15,17 @@ namespace dom {
 bool
 CallbackInterface::GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
                                        JS::MutableHandle<JS::Value> aCallable)
 {
   if (!JS_GetPropertyById(cx, CallbackPreserveColor(), aPropId, aCallable)) {
     return false;
   }
   if (!aCallable.isObject() ||
-      !JS_ObjectIsCallable(cx, &aCallable.toObject())) {
+      !JS::IsCallable(&aCallable.toObject())) {
     char* propName =
       JS_EncodeString(cx, JS_FORGET_STRING_FLATNESS(JSID_TO_FLAT_STRING(aPropId)));
     nsPrintfCString description("Property '%s'", propName);
     JS_free(cx, propName);
     ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
     return false;
   }
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4906,17 +4906,17 @@ def getJSToNativeConversionInfo(type, de
         name = type.unroll().identifier.name
         if type.nullable():
             declType = CGGeneric("nsRefPtr<%s>" % name)
         else:
             declType = CGGeneric("OwningNonNull<%s>" % name)
         conversion = indent(CGCallbackTempRoot(name).define())
 
         if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
-            haveCallable = "JS_ObjectIsCallable(cx, &${val}.toObject())"
+            haveCallable = "JS::IsCallable(&${val}.toObject())"
             if not isDefinitelyObject:
                 haveCallable = "${val}.isObject() && " + haveCallable
             if defaultValue is not None:
                 assert(isinstance(defaultValue, IDLNullValue))
                 haveCallable = "${haveValue} && " + haveCallable
             template = (
                 ("if (%s) {\n" % haveCallable) +
                 conversion +
@@ -4931,17 +4931,17 @@ def getJSToNativeConversionInfo(type, de
                     haveObject = "${haveValue} && " + haveObject
                 template = CGIfElseWrapper(haveObject,
                                            CGGeneric(conversion),
                                            CGGeneric("${declName} = nullptr;\n")).define()
             else:
                 template = conversion
         else:
             template = wrapObjectTemplate(
-                "if (JS_ObjectIsCallable(cx, &${val}.toObject())) {\n" +
+                "if (JS::IsCallable(&${val}.toObject())) {\n" +
                 conversion +
                 "} else {\n" +
                 indent(onFailureNotCallable(failureCode).define()) +
                 "}\n",
                 type,
                 "${declName} = nullptr;\n",
                 failureCode)
         return JSToNativeConversionInfo(template, declType=declType,
@@ -13412,17 +13412,17 @@ class CGCallback(CGClass):
         CGClass.__init__(self, name,
                          bases=[ClassBase(baseName)],
                          constructors=self.getConstructors(),
                          methods=realMethods+getters+setters)
 
     def getConstructors(self):
         if (not self.idlObject.isInterface() and
             not self.idlObject._treatNonObjectAsNull):
-            body = "MOZ_ASSERT(JS_ObjectIsCallable(nullptr, mCallback));\n"
+            body = "MOZ_ASSERT(JS::IsCallable(mCallback));\n"
         else:
             # Not much we can assert about it, other than not being null, and
             # CallbackObject does that already.
             body = ""
         return [ClassConstructor(
             [Argument("JS::Handle<JSObject*>", "aCallback"),
              Argument("nsIGlobalObject*", "aIncumbentGlobal")],
             bodyInHeader=True,
@@ -13874,17 +13874,17 @@ class CallCallback(CallbackMethod):
     def getCallableDecl(self):
         return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
 
     def getPrettyName(self):
         return self.callback.identifier.name
 
     def getCallGuard(self):
         if self.callback._treatNonObjectAsNull:
-            return "JS_ObjectIsCallable(cx, mCallback) && "
+            return "JS::IsCallable(mCallback) && "
         return ""
 
 
 class CallbackOperationBase(CallbackMethod):
     """
     Common class for implementing various callback operations.
     """
     def __init__(self, signature, jsName, nativeName, descriptor,
@@ -13922,17 +13922,17 @@ class CallbackOperationBase(CallbackMeth
             """,
             methodAtomName=CGDictionary.makeIdName(self.methodName),
             atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
             errorReturn=self.getDefaultRetval())
         if not self.singleOperation:
             return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
         return fill(
             """
-            bool isCallable = JS_ObjectIsCallable(cx, mCallback);
+            bool isCallable = JS::IsCallable(mCallback);
             JS::Rooted<JS::Value> callable(cx);
             if (isCallable) {
               callable = JS::ObjectValue(*mCallback);
             } else {
               $*{getCallableFromProp}
             }
             """,
             getCallableFromProp=getCallableFromProp)
--- a/dom/bluetooth/BluetoothInterface.h
+++ b/dom/bluetooth/BluetoothInterface.h
@@ -49,16 +49,18 @@ public:
   virtual void Connect(const nsAString& aBdAddr,
                        BluetoothSocketType aType,
                        const uint8_t aUuid[16],
                        int aChannel, bool aEncrypt, bool aAuth,
                        BluetoothSocketResultHandler* aRes) = 0;
 
   virtual void Accept(int aFd, BluetoothSocketResultHandler* aRes) = 0;
 
+  virtual void Close(BluetoothSocketResultHandler* aRes) = 0;
+
 protected:
   virtual ~BluetoothSocketInterface();
 };
 
 //
 // Handsfree Interface
 //
 
--- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp
@@ -390,17 +390,20 @@ public:
   , mFd(aFd)
   { }
 
   NS_IMETHOD Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(sBluetoothSocketInterface);
 
-    sBluetoothSocketInterface->Accept(mFd, new AcceptResultHandler(GetIO()));
+    BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO());
+    GetIO()->mConsumer->SetCurrentResultHandler(res);
+
+    sBluetoothSocketInterface->Accept(mFd, res);
 
     return NS_OK;
   }
 
 private:
   int mFd;
 };
 
@@ -471,16 +474,17 @@ DroidSocketImpl::OnSocketCanConnectWitho
   }
 }
 
 BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
                                  BluetoothSocketType aType,
                                  bool aAuth,
                                  bool aEncrypt)
   : mObserver(aObserver)
+  , mCurrentRes(nullptr)
   , mImpl(nullptr)
   , mAuth(aAuth)
   , mEncrypt(aEncrypt)
 {
   MOZ_ASSERT(aObserver);
 
   EnsureBluetoothSocketHalLoad();
   mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
@@ -522,23 +526,25 @@ BluetoothSocket::ConnectSocket(const nsA
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_FALSE(mImpl, false);
 
   SetConnectionStatus(SOCKET_CONNECTING);
 
   mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
 
+  BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
+  SetCurrentResultHandler(res);
+
   // TODO: uuid as argument
   sBluetoothSocketInterface->Connect(
     aDeviceAddress,
     BluetoothSocketType::RFCOMM,
     UUID_OBEX_OBJECT_PUSH,
-    aChannel, mEncrypt, mAuth,
-    new ConnectSocketResultHandler(mImpl));
+    aChannel, mEncrypt, mAuth, res);
 
   return true;
 }
 
 class ListenResultHandler MOZ_FINAL : public BluetoothSocketResultHandler
 {
 public:
   ListenResultHandler(DroidSocketImpl* aImpl)
@@ -571,34 +577,42 @@ BluetoothSocket::ListenSocket(int aChann
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_FALSE(mImpl, false);
 
   SetConnectionStatus(SOCKET_LISTENING);
 
   mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
 
+  BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
+  SetCurrentResultHandler(res);
+
   sBluetoothSocketInterface->Listen(
     BluetoothSocketType::RFCOMM,
     NS_LITERAL_STRING("OBEX Object Push"),
     UUID_OBEX_OBJECT_PUSH,
-    aChannel, mEncrypt, mAuth,
-    new ListenResultHandler(mImpl));
+    aChannel, mEncrypt, mAuth, res);
 
   return true;
 }
 
 void
 BluetoothSocket::CloseSocket()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(sBluetoothSocketInterface);
   if (!mImpl) {
     return;
   }
 
+  // Stop any watching |SocketMessageWatcher|
+  if (mCurrentRes) {
+    sBluetoothSocketInterface->Close(mCurrentRes);
+  }
+
   // From this point on, we consider mImpl as being deleted.
   // We sever the relationship here so any future calls to listen or connect
   // will create a new implementation.
   mImpl->ShutdownOnMainThread();
   XRE_GetIOMessageLoop()->PostTask(
     FROM_HERE, new SocketIOShutdownTask<DroidSocketImpl>(mImpl));
 
   mImpl = nullptr;
@@ -628,24 +642,28 @@ BluetoothSocket::ReceiveSocketData(nsAut
   mObserver->ReceiveSocketData(this, aMessage);
 }
 
 void
 BluetoothSocket::OnConnectSuccess()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
+
+  SetCurrentResultHandler(nullptr);
   mObserver->OnSocketConnectSuccess(this);
 }
 
 void
 BluetoothSocket::OnConnectError()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
+
+  SetCurrentResultHandler(nullptr);
   mObserver->OnSocketConnectError(this);
 }
 
 void
 BluetoothSocket::OnDisconnect()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
--- a/dom/bluetooth/bluedroid/BluetoothSocket.h
+++ b/dom/bluetooth/bluedroid/BluetoothSocket.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_bluetooth_BluetoothSocket_h
 
 #include "BluetoothCommon.h"
 #include "mozilla/ipc/SocketBase.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSocketObserver;
+class BluetoothSocketResultHandler;
 class DroidSocketImpl;
 
 class BluetoothSocket : public mozilla::ipc::SocketConsumerBase
 {
 public:
   BluetoothSocket(BluetoothSocketObserver* aObserver,
                   BluetoothSocketType aType,
                   bool aAuth,
@@ -42,18 +43,24 @@ public:
     aDeviceAddress = mDeviceAddress;
   }
 
   inline void SetAddress(const nsAString& aDeviceAddress)
   {
     mDeviceAddress = aDeviceAddress;
   }
 
+  inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
+  {
+    mCurrentRes = aRes;
+  }
+
 private:
   BluetoothSocketObserver* mObserver;
+  BluetoothSocketResultHandler* mCurrentRes;
   DroidSocketImpl* mImpl;
   nsString mDeviceAddress;
   bool mAuth;
   bool mEncrypt;
 };
 
 END_BLUETOOTH_NAMESPACE
 
--- a/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp
@@ -4,34 +4,35 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothSocketHALInterface.h"
 #include <errno.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include "BluetoothHALHelpers.h"
+#include "nsClassHashtable.h"
 #include "nsXULAppAPI.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 typedef
   BluetoothHALInterfaceRunnable1<BluetoothSocketResultHandler, void,
-                                       int, int>
+                                 int, int>
   BluetoothSocketHALIntResultRunnable;
 
 typedef
   BluetoothHALInterfaceRunnable3<BluetoothSocketResultHandler, void,
-                                       int, const nsString, int,
-                                       int, const nsAString_internal&, int>
+                                 int, const nsString, int,
+                                 int, const nsAString_internal&, int>
   BluetoothSocketHALIntStringIntResultRunnable;
 
 typedef
   BluetoothHALInterfaceRunnable1<BluetoothSocketResultHandler, void,
-                                       BluetoothStatus, BluetoothStatus>
+                                 BluetoothStatus, BluetoothStatus>
   BluetoothSocketHALErrorRunnable;
 
 static nsresult
 DispatchBluetoothSocketHALResult(
   BluetoothSocketResultHandler* aRes,
   void (BluetoothSocketResultHandler::*aMethod)(int), int aArg,
   BluetoothStatus aStatus)
 {
@@ -73,21 +74,21 @@ DispatchBluetoothSocketHALResult(
   if (NS_FAILED(rv)) {
     BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
   }
   return rv;
 }
 
 void
 BluetoothSocketHALInterface::Listen(BluetoothSocketType aType,
-                                          const nsAString& aServiceName,
-                                          const uint8_t aServiceUuid[16],
-                                          int aChannel, bool aEncrypt,
-                                          bool aAuth,
-                                          BluetoothSocketResultHandler* aRes)
+                                    const nsAString& aServiceName,
+                                    const uint8_t aServiceUuid[16],
+                                    int aChannel, bool aEncrypt,
+                                    bool aAuth,
+                                    BluetoothSocketResultHandler* aRes)
 {
   int fd;
   bt_status_t status;
   btsock_type_t type = BTSOCK_RFCOMM; // silences compiler warning
 
   if (NS_SUCCEEDED(Convert(aType, type))) {
     status = mInterface->listen(type,
                                 NS_ConvertUTF16toUTF8(aServiceName).get(),
@@ -104,16 +105,44 @@ BluetoothSocketHALInterface::Listen(Blue
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 #define CMSGHDR_CONTAINS_FD(_cmsghdr) \
     ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \
       ((_cmsghdr)->cmsg_type == SCM_RIGHTS) )
 
+class SocketMessageWatcher;
+
+/* |SocketMessageWatcherWrapper| wraps SocketMessageWatcher to keep it from
+ * being released by hash table's Remove() method.
+ */
+class SocketMessageWatcherWrapper
+{
+public:
+  SocketMessageWatcherWrapper(SocketMessageWatcher* aSocketMessageWatcher)
+  : mSocketMessageWatcher(aSocketMessageWatcher)
+  {
+    MOZ_ASSERT(mSocketMessageWatcher);
+  }
+
+  SocketMessageWatcher* GetSocketMessageWatcher()
+  {
+    return mSocketMessageWatcher;
+  }
+
+private:
+  SocketMessageWatcher* mSocketMessageWatcher;
+};
+
+/* |sWatcherHashTable| maps result handlers to corresponding watchers */
+static nsClassHashtable<nsRefPtrHashKey<BluetoothSocketResultHandler>,
+                        SocketMessageWatcherWrapper>
+  sWatcherHashtable;
+
 /* |SocketMessageWatcher| receives Bluedroid's socket setup
  * messages on the I/O thread. You need to inherit from this
  * class to make use of it.
  *
  * Bluedroid sends two socket info messages (20 bytes) at
  * the beginning of a connection to both peers.
  *
  *   - 1st message: [channel:4]
@@ -130,21 +159,24 @@ public:
   static const unsigned char MSG2_SIZE = 16;
 
   static const unsigned char OFF_CHANNEL1 = 0;
   static const unsigned char OFF_SIZE = 4;
   static const unsigned char OFF_BDADDRESS = 6;
   static const unsigned char OFF_CHANNEL2 = 12;
   static const unsigned char OFF_STATUS = 16;
 
-  SocketMessageWatcher(int aFd)
+  SocketMessageWatcher(int aFd, BluetoothSocketResultHandler* aRes)
   : mFd(aFd)
   , mClientFd(-1)
   , mLen(0)
-  { }
+  , mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
 
   virtual ~SocketMessageWatcher()
   { }
 
   virtual void Proceed(BluetoothStatus aStatus) = 0;
 
   void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE
   {
@@ -159,34 +191,45 @@ public:
         break;
       default:
         /* message-size error */
         status = STATUS_FAIL;
         break;
     }
 
     if (IsComplete() || status != STATUS_SUCCESS) {
-      mWatcher.StopWatchingFileDescriptor();
+      StopWatching();
       Proceed(status);
     }
   }
 
   void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE
   { }
 
   void Watch()
   {
+    // add this watcher and its result handler to hash table
+    sWatcherHashtable.Put(mRes, new SocketMessageWatcherWrapper(this));
+
     MessageLoopForIO::current()->WatchFileDescriptor(
       mFd,
       true,
       MessageLoopForIO::WATCH_READ,
       &mWatcher,
       this);
   }
 
+  void StopWatching()
+  {
+    mWatcher.StopWatchingFileDescriptor();
+
+    // remove this watcher and its result handler from hash table
+    sWatcherHashtable.Remove(mRes);
+  }
+
   bool IsComplete() const
   {
     return mLen == (MSG1_SIZE + MSG2_SIZE);
   }
 
   int GetFd() const
   {
     return mFd;
@@ -219,16 +262,21 @@ public:
     return ReadInt32(OFF_STATUS);
   }
 
   int GetClientFd() const
   {
     return mClientFd;
   }
 
+  BluetoothSocketResultHandler* GetResultHandler() const
+  {
+    return mRes;
+  }
+
 private:
   BluetoothStatus RecvMsg1()
   {
     struct iovec iv;
     memset(&iv, 0, sizeof(iv));
     iv.iov_base = mBuf;
     iv.iov_len = MSG1_SIZE;
 
@@ -317,16 +365,17 @@ private:
     }
   }
 
   MessageLoopForIO::FileDescriptorWatcher mWatcher;
   int mFd;
   int mClientFd;
   unsigned char mLen;
   uint8_t mBuf[MSG1_SIZE + MSG2_SIZE];
+  nsRefPtr<BluetoothSocketResultHandler> mRes;
 };
 
 /* |SocketMessageWatcherTask| starts a SocketMessageWatcher
  * on the I/O task
  */
 class SocketMessageWatcherTask MOZ_FINAL : public Task
 {
 public:
@@ -368,42 +417,37 @@ private:
  * connect operations by reading the socket messages from
  * Bluedroid and forwarding the connected socket to the
  * resource handler.
  */
 class ConnectWatcher MOZ_FINAL : public SocketMessageWatcher
 {
 public:
   ConnectWatcher(int aFd, BluetoothSocketResultHandler* aRes)
-  : SocketMessageWatcher(aFd)
-  , mRes(aRes)
+  : SocketMessageWatcher(aFd, aRes)
   { }
 
   void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
-    if (mRes) {
-      DispatchBluetoothSocketHALResult(
-        mRes, &BluetoothSocketResultHandler::Connect, GetFd(),
-        GetBdAddress(), GetConnectionStatus(), aStatus);
-    }
+    DispatchBluetoothSocketHALResult(
+      GetResultHandler(), &BluetoothSocketResultHandler::Connect,
+      GetFd(), GetBdAddress(), GetConnectionStatus(), aStatus);
+
     MessageLoopForIO::current()->PostTask(
       FROM_HERE, new DeleteTask<ConnectWatcher>(this));
   }
-
-private:
-  nsRefPtr<BluetoothSocketResultHandler> mRes;
 };
 
 void
 BluetoothSocketHALInterface::Connect(const nsAString& aBdAddr,
-                                           BluetoothSocketType aType,
-                                           const uint8_t aUuid[16],
-                                           int aChannel, bool aEncrypt,
-                                           bool aAuth,
-                                           BluetoothSocketResultHandler* aRes)
+                                     BluetoothSocketType aType,
+                                     const uint8_t aUuid[16],
+                                     int aChannel, bool aEncrypt,
+                                     bool aAuth,
+                                     BluetoothSocketResultHandler* aRes)
 {
   int fd;
   bt_status_t status;
   bt_bdaddr_t bdAddr;
   btsock_type_t type = BTSOCK_RFCOMM; // silences compiler warning
 
   if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr)) &&
       NS_SUCCEEDED(Convert(aType, type))) {
@@ -420,58 +464,90 @@ BluetoothSocketHALInterface::Connect(con
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
   } else if (aRes) {
     DispatchBluetoothSocketHALResult(
       aRes, &BluetoothSocketResultHandler::Connect, -1, EmptyString(), 0,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
-/* Specializes SocketMessageWatcher for Accept operations by
- * reading the socket messages from Bluedroid and forwarding
- * the received client socket to the resource handler. The
- * first message is received immediately. When there's a new
+/* |AcceptWatcher| specializes SocketMessageWatcher for Accept
+ * operations by reading the socket messages from Bluedroid and
+ * forwarding the received client socket to the resource handler.
+ * The first message is received immediately. When there's a new
  * connection, Bluedroid sends the 2nd message with the socket
  * info and socket file descriptor.
  */
 class AcceptWatcher MOZ_FINAL : public SocketMessageWatcher
 {
 public:
   AcceptWatcher(int aFd, BluetoothSocketResultHandler* aRes)
-  : SocketMessageWatcher(aFd)
-  , mRes(aRes)
-  {
-    /* not supplying a result handler leaks received file descriptor */
-    MOZ_ASSERT(mRes);
-  }
+  : SocketMessageWatcher(aFd, aRes)
+  { }
 
   void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
-    if (mRes) {
-      DispatchBluetoothSocketHALResult(
-        mRes, &BluetoothSocketResultHandler::Accept, GetClientFd(),
-        GetBdAddress(), GetConnectionStatus(), aStatus);
-    }
+    DispatchBluetoothSocketHALResult(
+      GetResultHandler(), &BluetoothSocketResultHandler::Accept,
+      GetClientFd(), GetBdAddress(), GetConnectionStatus(), aStatus);
+
     MessageLoopForIO::current()->PostTask(
       FROM_HERE, new DeleteTask<AcceptWatcher>(this));
   }
-
-private:
-  nsRefPtr<BluetoothSocketResultHandler> mRes;
 };
 
 void
 BluetoothSocketHALInterface::Accept(int aFd,
-                                          BluetoothSocketResultHandler* aRes)
+                                    BluetoothSocketResultHandler* aRes)
 {
   /* receive Bluedroid's socket-setup messages and client fd */
   Task* t = new SocketMessageWatcherTask(new AcceptWatcher(aFd, aRes));
   XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
 }
 
+/* |DeleteSocketMessageWatcherTask| deletes a watching SocketMessageWatcher
+ * on the I/O task
+ */
+class DeleteSocketMessageWatcherTask MOZ_FINAL : public Task
+{
+public:
+  DeleteSocketMessageWatcherTask(BluetoothSocketResultHandler* aRes)
+  : mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  void Run() MOZ_OVERRIDE
+  {
+    // look up hash table for the watcher corresponding to |mRes|
+    SocketMessageWatcherWrapper* wrapper = sWatcherHashtable.Get(mRes);
+    if (!wrapper) {
+      return;
+    }
+
+    // stop the watcher if it exists
+    SocketMessageWatcher* watcher = wrapper->GetSocketMessageWatcher();
+    watcher->StopWatching();
+    watcher->Proceed(STATUS_DONE);
+  }
+
+private:
+  BluetoothSocketResultHandler* mRes;
+};
+
+void
+BluetoothSocketHALInterface::Close(BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(aRes);
+
+  /* stop the watcher corresponding to |aRes| */
+  Task* t = new DeleteSocketMessageWatcherTask(aRes);
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
+}
+
 BluetoothSocketHALInterface::BluetoothSocketHALInterface(
   const btsock_interface_t* aInterface)
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothSocketHALInterface::~BluetoothSocketHALInterface()
--- a/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.h
@@ -31,16 +31,18 @@ public:
   void Connect(const nsAString& aBdAddr,
                BluetoothSocketType aType,
                const uint8_t aUuid[16],
                int aChannel, bool aEncrypt, bool aAuth,
                BluetoothSocketResultHandler* aRes);
 
   void Accept(int aFd, BluetoothSocketResultHandler* aRes);
 
+  void Close(BluetoothSocketResultHandler* aRes);
+
 protected:
   BluetoothSocketHALInterface(const btsock_interface_t* aInterface);
   ~BluetoothSocketHALInterface();
 
 private:
   const btsock_interface_t* mInterface;
 };
 
--- a/dom/bluetooth2/BluetoothInterface.h
+++ b/dom/bluetooth2/BluetoothInterface.h
@@ -49,16 +49,18 @@ public:
   virtual void Connect(const nsAString& aBdAddr,
                        BluetoothSocketType aType,
                        const uint8_t aUuid[16],
                        int aChannel, bool aEncrypt, bool aAuth,
                        BluetoothSocketResultHandler* aRes) = 0;
 
   virtual void Accept(int aFd, BluetoothSocketResultHandler* aRes) = 0;
 
+  virtual void Close(BluetoothSocketResultHandler* aRes) = 0;
+
 protected:
   virtual ~BluetoothSocketInterface();
 };
 
 //
 // Handsfree Interface
 //
 
--- a/dom/bluetooth2/BluetoothRilListener.cpp
+++ b/dom/bluetooth2/BluetoothRilListener.cpp
@@ -177,17 +177,17 @@ MobileConnectionListener::NotifyNetworkS
 bool
 MobileConnectionListener::Listen(bool aStart)
 {
   nsCOMPtr<nsIMobileConnectionService> service =
     do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(service, false);
 
   nsCOMPtr<nsIMobileConnection> connection;
-  mcService->GetItemByServiceId(mClientId, getter_AddRefs(connection));
+  service->GetItemByServiceId(mClientId, getter_AddRefs(connection));
   NS_ENSURE_TRUE(connection, false);
 
   nsresult rv;
   if (aStart) {
     rv = connection->RegisterListener(this);
   } else {
     rv = connection->UnregisterListener(this);
   }
--- a/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
@@ -390,17 +390,20 @@ public:
   , mFd(aFd)
   { }
 
   NS_IMETHOD Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(sBluetoothSocketInterface);
 
-    sBluetoothSocketInterface->Accept(mFd, new AcceptResultHandler(GetIO()));
+    BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO());
+    GetIO()->mConsumer->SetCurrentResultHandler(res);
+
+    sBluetoothSocketInterface->Accept(mFd, res);
 
     return NS_OK;
   }
 
 private:
   int mFd;
 };
 
@@ -471,16 +474,17 @@ DroidSocketImpl::OnSocketCanConnectWitho
   }
 }
 
 BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
                                  BluetoothSocketType aType,
                                  bool aAuth,
                                  bool aEncrypt)
   : mObserver(aObserver)
+  , mCurrentRes(nullptr)
   , mImpl(nullptr)
   , mAuth(aAuth)
   , mEncrypt(aEncrypt)
 {
   MOZ_ASSERT(aObserver);
 
   EnsureBluetoothSocketHalLoad();
   mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
@@ -522,23 +526,25 @@ BluetoothSocket::ConnectSocket(const nsA
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_FALSE(mImpl, false);
 
   SetConnectionStatus(SOCKET_CONNECTING);
 
   mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
 
+  BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
+  SetCurrentResultHandler(res);
+
   // TODO: uuid as argument
   sBluetoothSocketInterface->Connect(
     aDeviceAddress,
     BluetoothSocketType::RFCOMM,
     UUID_OBEX_OBJECT_PUSH,
-    aChannel, mEncrypt, mAuth,
-    new ConnectSocketResultHandler(mImpl));
+    aChannel, mEncrypt, mAuth, res);
 
   return true;
 }
 
 class ListenResultHandler MOZ_FINAL : public BluetoothSocketResultHandler
 {
 public:
   ListenResultHandler(DroidSocketImpl* aImpl)
@@ -571,34 +577,42 @@ BluetoothSocket::ListenSocket(int aChann
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_FALSE(mImpl, false);
 
   SetConnectionStatus(SOCKET_LISTENING);
 
   mImpl = new DroidSocketImpl(XRE_GetIOMessageLoop(), this);
 
+  BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
+  SetCurrentResultHandler(res);
+
   sBluetoothSocketInterface->Listen(
     BluetoothSocketType::RFCOMM,
     NS_LITERAL_STRING("OBEX Object Push"),
     UUID_OBEX_OBJECT_PUSH,
-    aChannel, mEncrypt, mAuth,
-    new ListenResultHandler(mImpl));
+    aChannel, mEncrypt, mAuth, res);
 
   return true;
 }
 
 void
 BluetoothSocket::CloseSocket()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(sBluetoothSocketInterface);
   if (!mImpl) {
     return;
   }
 
+  // Stop any watching |SocketMessageWatcher|
+  if (mCurrentRes) {
+    sBluetoothSocketInterface->Close(mCurrentRes);
+  }
+
   // From this point on, we consider mImpl as being deleted.
   // We sever the relationship here so any future calls to listen or connect
   // will create a new implementation.
   mImpl->ShutdownOnMainThread();
   XRE_GetIOMessageLoop()->PostTask(
     FROM_HERE, new SocketIOShutdownTask<DroidSocketImpl>(mImpl));
 
   mImpl = nullptr;
@@ -628,24 +642,28 @@ BluetoothSocket::ReceiveSocketData(nsAut
   mObserver->ReceiveSocketData(this, aMessage);
 }
 
 void
 BluetoothSocket::OnConnectSuccess()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
+
+  SetCurrentResultHandler(nullptr);
   mObserver->OnSocketConnectSuccess(this);
 }
 
 void
 BluetoothSocket::OnConnectError()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
+
+  SetCurrentResultHandler(nullptr);
   mObserver->OnSocketConnectError(this);
 }
 
 void
 BluetoothSocket::OnDisconnect()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mObserver);
--- a/dom/bluetooth2/bluedroid/BluetoothSocket.h
+++ b/dom/bluetooth2/bluedroid/BluetoothSocket.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_bluetooth_BluetoothSocket_h
 
 #include "BluetoothCommon.h"
 #include "mozilla/ipc/SocketBase.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSocketObserver;
+class BluetoothSocketResultHandler;
 class DroidSocketImpl;
 
 class BluetoothSocket : public mozilla::ipc::SocketConsumerBase
 {
 public:
   BluetoothSocket(BluetoothSocketObserver* aObserver,
                   BluetoothSocketType aType,
                   bool aAuth,
@@ -42,18 +43,24 @@ public:
     aDeviceAddress = mDeviceAddress;
   }
 
   inline void SetAddress(const nsAString& aDeviceAddress)
   {
     mDeviceAddress = aDeviceAddress;
   }
 
+  inline void SetCurrentResultHandler(BluetoothSocketResultHandler* aRes)
+  {
+    mCurrentRes = aRes;
+  }
+
 private:
   BluetoothSocketObserver* mObserver;
+  BluetoothSocketResultHandler* mCurrentRes;
   DroidSocketImpl* mImpl;
   nsString mDeviceAddress;
   bool mAuth;
   bool mEncrypt;
 };
 
 END_BLUETOOTH_NAMESPACE
 
--- a/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothSocketHALInterface.h"
 #include <errno.h>
 #include <sys/socket.h>
 #include <unistd.h>
 #include "BluetoothHALHelpers.h"
+#include "nsClassHashtable.h"
 #include "nsXULAppAPI.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 typedef
   BluetoothHALInterfaceRunnable1<BluetoothSocketResultHandler, void,
                                  int, int>
   BluetoothSocketHALIntResultRunnable;
@@ -104,16 +105,44 @@ BluetoothSocketHALInterface::Listen(Blue
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 #define CMSGHDR_CONTAINS_FD(_cmsghdr) \
     ( ((_cmsghdr)->cmsg_level == SOL_SOCKET) && \
       ((_cmsghdr)->cmsg_type == SCM_RIGHTS) )
 
+class SocketMessageWatcher;
+
+/* |SocketMessageWatcherWrapper| wraps SocketMessageWatcher to keep it from
+ * being released by hash table's Remove() method.
+ */
+class SocketMessageWatcherWrapper
+{
+public:
+  SocketMessageWatcherWrapper(SocketMessageWatcher* aSocketMessageWatcher)
+  : mSocketMessageWatcher(aSocketMessageWatcher)
+  {
+    MOZ_ASSERT(mSocketMessageWatcher);
+  }
+
+  SocketMessageWatcher* GetSocketMessageWatcher()
+  {
+    return mSocketMessageWatcher;
+  }
+
+private:
+  SocketMessageWatcher* mSocketMessageWatcher;
+};
+
+/* |sWatcherHashTable| maps result handlers to corresponding watchers */
+static nsClassHashtable<nsRefPtrHashKey<BluetoothSocketResultHandler>,
+                        SocketMessageWatcherWrapper>
+  sWatcherHashtable;
+
 /* |SocketMessageWatcher| receives Bluedroid's socket setup
  * messages on the I/O thread. You need to inherit from this
  * class to make use of it.
  *
  * Bluedroid sends two socket info messages (20 bytes) at
  * the beginning of a connection to both peers.
  *
  *   - 1st message: [channel:4]
@@ -130,21 +159,24 @@ public:
   static const unsigned char MSG2_SIZE = 16;
 
   static const unsigned char OFF_CHANNEL1 = 0;
   static const unsigned char OFF_SIZE = 4;
   static const unsigned char OFF_BDADDRESS = 6;
   static const unsigned char OFF_CHANNEL2 = 12;
   static const unsigned char OFF_STATUS = 16;
 
-  SocketMessageWatcher(int aFd)
+  SocketMessageWatcher(int aFd, BluetoothSocketResultHandler* aRes)
   : mFd(aFd)
   , mClientFd(-1)
   , mLen(0)
-  { }
+  , mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
 
   virtual ~SocketMessageWatcher()
   { }
 
   virtual void Proceed(BluetoothStatus aStatus) = 0;
 
   void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE
   {
@@ -159,34 +191,45 @@ public:
         break;
       default:
         /* message-size error */
         status = STATUS_FAIL;
         break;
     }
 
     if (IsComplete() || status != STATUS_SUCCESS) {
-      mWatcher.StopWatchingFileDescriptor();
+      StopWatching();
       Proceed(status);
     }
   }
 
   void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE
   { }
 
   void Watch()
   {
+    // add this watcher and its result handler to hash table
+    sWatcherHashtable.Put(mRes, new SocketMessageWatcherWrapper(this));
+
     MessageLoopForIO::current()->WatchFileDescriptor(
       mFd,
       true,
       MessageLoopForIO::WATCH_READ,
       &mWatcher,
       this);
   }
 
+  void StopWatching()
+  {
+    mWatcher.StopWatchingFileDescriptor();
+
+    // remove this watcher and its result handler from hash table
+    sWatcherHashtable.Remove(mRes);
+  }
+
   bool IsComplete() const
   {
     return mLen == (MSG1_SIZE + MSG2_SIZE);
   }
 
   int GetFd() const
   {
     return mFd;
@@ -219,16 +262,21 @@ public:
     return ReadInt32(OFF_STATUS);
   }
 
   int GetClientFd() const
   {
     return mClientFd;
   }
 
+  BluetoothSocketResultHandler* GetResultHandler() const
+  {
+    return mRes;
+  }
+
 private:
   BluetoothStatus RecvMsg1()
   {
     struct iovec iv;
     memset(&iv, 0, sizeof(iv));
     iv.iov_base = mBuf;
     iv.iov_len = MSG1_SIZE;
 
@@ -317,16 +365,17 @@ private:
     }
   }
 
   MessageLoopForIO::FileDescriptorWatcher mWatcher;
   int mFd;
   int mClientFd;
   unsigned char mLen;
   uint8_t mBuf[MSG1_SIZE + MSG2_SIZE];
+  nsRefPtr<BluetoothSocketResultHandler> mRes;
 };
 
 /* |SocketMessageWatcherTask| starts a SocketMessageWatcher
  * on the I/O task
  */
 class SocketMessageWatcherTask MOZ_FINAL : public Task
 {
 public:
@@ -368,33 +417,28 @@ private:
  * connect operations by reading the socket messages from
  * Bluedroid and forwarding the connected socket to the
  * resource handler.
  */
 class ConnectWatcher MOZ_FINAL : public SocketMessageWatcher
 {
 public:
   ConnectWatcher(int aFd, BluetoothSocketResultHandler* aRes)
-  : SocketMessageWatcher(aFd)
-  , mRes(aRes)
+  : SocketMessageWatcher(aFd, aRes)
   { }
 
   void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
-    if (mRes) {
-      DispatchBluetoothSocketHALResult(
-        mRes, &BluetoothSocketResultHandler::Connect, GetFd(),
-        GetBdAddress(), GetConnectionStatus(), aStatus);
-    }
+    DispatchBluetoothSocketHALResult(
+      GetResultHandler(), &BluetoothSocketResultHandler::Connect,
+      GetFd(), GetBdAddress(), GetConnectionStatus(), aStatus);
+
     MessageLoopForIO::current()->PostTask(
       FROM_HERE, new DeleteTask<ConnectWatcher>(this));
   }
-
-private:
-  nsRefPtr<BluetoothSocketResultHandler> mRes;
 };
 
 void
 BluetoothSocketHALInterface::Connect(const nsAString& aBdAddr,
                                      BluetoothSocketType aType,
                                      const uint8_t aUuid[16],
                                      int aChannel, bool aEncrypt,
                                      bool aAuth,
@@ -431,47 +475,79 @@ BluetoothSocketHALInterface::Connect(con
  * The first message is received immediately. When there's a new
  * connection, Bluedroid sends the 2nd message with the socket
  * info and socket file descriptor.
  */
 class AcceptWatcher MOZ_FINAL : public SocketMessageWatcher
 {
 public:
   AcceptWatcher(int aFd, BluetoothSocketResultHandler* aRes)
-  : SocketMessageWatcher(aFd)
-  , mRes(aRes)
-  {
-    /* not supplying a result handler leaks received file descriptor */
-    MOZ_ASSERT(mRes);
-  }
+  : SocketMessageWatcher(aFd, aRes)
+  { }
 
   void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
-    if (mRes) {
-      DispatchBluetoothSocketHALResult(
-        mRes, &BluetoothSocketResultHandler::Accept, GetClientFd(),
-        GetBdAddress(), GetConnectionStatus(), aStatus);
-    }
+    DispatchBluetoothSocketHALResult(
+      GetResultHandler(), &BluetoothSocketResultHandler::Accept,
+      GetClientFd(), GetBdAddress(), GetConnectionStatus(), aStatus);
+
     MessageLoopForIO::current()->PostTask(
       FROM_HERE, new DeleteTask<AcceptWatcher>(this));
   }
-
-private:
-  nsRefPtr<BluetoothSocketResultHandler> mRes;
 };
 
 void
 BluetoothSocketHALInterface::Accept(int aFd,
                                     BluetoothSocketResultHandler* aRes)
 {
   /* receive Bluedroid's socket-setup messages and client fd */
   Task* t = new SocketMessageWatcherTask(new AcceptWatcher(aFd, aRes));
   XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
 }
 
+/* |DeleteSocketMessageWatcherTask| deletes a watching SocketMessageWatcher
+ * on the I/O task
+ */
+class DeleteSocketMessageWatcherTask MOZ_FINAL : public Task
+{
+public:
+  DeleteSocketMessageWatcherTask(BluetoothSocketResultHandler* aRes)
+  : mRes(aRes)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  void Run() MOZ_OVERRIDE
+  {
+    // look up hash table for the watcher corresponding to |mRes|
+    SocketMessageWatcherWrapper* wrapper = sWatcherHashtable.Get(mRes);
+    if (!wrapper) {
+      return;
+    }
+
+    // stop the watcher if it exists
+    SocketMessageWatcher* watcher = wrapper->GetSocketMessageWatcher();
+    watcher->StopWatching();
+    watcher->Proceed(STATUS_DONE);
+  }
+
+private:
+  BluetoothSocketResultHandler* mRes;
+};
+
+void
+BluetoothSocketHALInterface::Close(BluetoothSocketResultHandler* aRes)
+{
+  MOZ_ASSERT(aRes);
+
+  /* stop the watcher corresponding to |aRes| */
+  Task* t = new DeleteSocketMessageWatcherTask(aRes);
+  XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
+}
+
 BluetoothSocketHALInterface::BluetoothSocketHALInterface(
   const btsock_interface_t* aInterface)
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothSocketHALInterface::~BluetoothSocketHALInterface()
--- a/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.h
+++ b/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.h
@@ -31,16 +31,18 @@ public:
   void Connect(const nsAString& aBdAddr,
                BluetoothSocketType aType,
                const uint8_t aUuid[16],
                int aChannel, bool aEncrypt, bool aAuth,
                BluetoothSocketResultHandler* aRes);
 
   void Accept(int aFd, BluetoothSocketResultHandler* aRes);
 
+  void Close(BluetoothSocketResultHandler* aRes);
+
 protected:
   BluetoothSocketHALInterface(const btsock_interface_t* aInterface);
   ~BluetoothSocketHALInterface();
 
 private:
   const btsock_interface_t* mInterface;
 };
 
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1426,17 +1426,17 @@ WebGLContext::PresentScreenBuffer()
     mShouldPresent = false;
 
     return true;
 }
 
 void
 WebGLContext::DummyFramebufferOperation(const char *info)
 {
-    GLenum status = CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    FBStatus status = CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
         ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
 }
 
 static bool
 CheckContextLost(GLContext* gl, bool* out_isGuilty)
 {
     MOZ_ASSERT(gl);
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -350,16 +350,20 @@ public:
     void DrawBuffers(const dom::Sequence<GLenum>& buffers);
     void Flush();
     void Finish();
     void FramebufferRenderbuffer(GLenum target, GLenum attachment,
                                  GLenum rbtarget, WebGLRenderbuffer *wrb);
     void FramebufferTexture2D(GLenum target, GLenum attachment,
                               GLenum textarget, WebGLTexture *tobj,
                               GLint level);
+
+    // Framebuffer validation
+    bool ValidateFramebufferAttachment(GLenum attachment, const char* funcName);
+
     void FrontFace(GLenum mode);
     void GenerateMipmap(GLenum target);
     already_AddRefed<WebGLActiveInfo> GetActiveAttrib(WebGLProgram *prog,
                                                       GLuint index);
     already_AddRefed<WebGLActiveInfo> GetActiveUniform(WebGLProgram *prog,
                                                        GLuint index);
     void GetAttachedShaders(WebGLProgram* prog,
                             dom::Nullable<nsTArray<nsRefPtr<WebGLShader>>>& retval);
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -59,17 +59,17 @@ static bool BaseTypeAndSizeFromUniformTy
 const WebGLRectangleObject*
 WebGLContext::CurValidFBRectObject() const
 {
     const WebGLRectangleObject* rect = nullptr;
 
     if (mBoundFramebuffer) {
         // We don't really need to ask the driver.
         // Use 'precheck' to just check that our internal state looks good.
-        GLenum precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus();
+        FBStatus precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus();
         if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
             rect = &mBoundFramebuffer->RectangleObject();
     } else {
         rect = static_cast<const WebGLRectangleObject*>(this);
     }
 
     return rect;
 }
@@ -343,17 +343,17 @@ WebGLContext::CheckFramebufferStatus(GLe
     if (target != LOCAL_GL_FRAMEBUFFER) {
         ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
         return 0;
     }
 
     if (!mBoundFramebuffer)
         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
 
-    return mBoundFramebuffer->CheckFramebufferStatus();
+    return mBoundFramebuffer->CheckFramebufferStatus().get();
 }
 
 void
 WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
                                      GLint level,
                                      GLenum internalformat,
                                      GLint xoffset,
                                      GLint yoffset,
@@ -790,40 +790,55 @@ void
 WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, WebGLRenderbuffer *wrb)
 {
     if (IsContextLost())
         return;
 
     if (!mBoundFramebuffer)
         return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
 
-    return mBoundFramebuffer->FramebufferRenderbuffer(target, attachment, rbtarget, wrb);
+    if (target != LOCAL_GL_FRAMEBUFFER)
+        return ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
+
+    if (rbtarget != LOCAL_GL_RENDERBUFFER)
+        return ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
+
+    if (!ValidateFramebufferAttachment(attachment, "framebufferRenderbuffer"))
+        return;
+
+    return mBoundFramebuffer->FramebufferRenderbuffer(attachment, rbtarget, wrb);
 }
 
 void
 WebGLContext::FramebufferTexture2D(GLenum target,
                                    GLenum attachment,
                                    GLenum textarget,
                                    WebGLTexture *tobj,
                                    GLint level)
 {
     if (IsContextLost())
         return;
 
     if (!mBoundFramebuffer)
         return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
 
+    if (target != LOCAL_GL_FRAMEBUFFER)
+        return ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
+
     if (textarget != LOCAL_GL_TEXTURE_2D &&
         (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
          textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
     {
         return ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
     }
 
-    return mBoundFramebuffer->FramebufferTexture2D(target, attachment, TexImageTarget(textarget), tobj, level);
+    if (!ValidateFramebufferAttachment(attachment, "framebufferTexture2D"))
+        return;
+
+    return mBoundFramebuffer->FramebufferTexture2D(attachment, textarget, tobj, level);
 }
 
 void
 WebGLContext::FrontFace(GLenum mode)
 {
     if (IsContextLost())
         return;
 
@@ -1079,37 +1094,21 @@ WebGLContext::GetFramebufferAttachmentPa
         return JS::NullValue();
     }
 
     if (!mBoundFramebuffer) {
         ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query framebuffer 0");
         return JS::NullValue();
     }
 
-    if (attachment != LOCAL_GL_DEPTH_ATTACHMENT &&
-        attachment != LOCAL_GL_STENCIL_ATTACHMENT &&
-        attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
-    {
-        if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
-        {
-            if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
-                attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments))
-            {
-                ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment);
-                return JS::NullValue();
-            }
-
-            mBoundFramebuffer->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
-        }
-        else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
-        {
-            ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment);
-            return JS::NullValue();
-        }
-    }
+    if (!ValidateFramebufferAttachment(attachment, "getFramebufferAttachmentParameter"))
+        return JS::NullValue();
+
+    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
+        mBoundFramebuffer->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
 
     MakeContextCurrent();
 
     const WebGLFramebuffer::Attachment& fba = mBoundFramebuffer->GetAttachment(attachment);
 
     if (fba.Renderbuffer()) {
         switch (pname) {
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -516,16 +516,44 @@ bool WebGLContext::ValidateGLSLString(co
              return false;
         }
     }
 
     return true;
 }
 
 /**
+ * Return true if the framebuffer attachment is valid. Attachment must
+ * be one of depth/stencil/depth_stencil/color attachment.
+ */
+bool
+WebGLContext::ValidateFramebufferAttachment(GLenum attachment, const char* funcName)
+{
+    if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
+        attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
+        attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+    {
+        return true;
+    }
+
+    GLenum colorAttachCount = 1;
+    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
+        colorAttachCount = mGLMaxColorAttachments;
+
+    if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+        attachment < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + colorAttachCount))
+    {
+        return true;
+    }
+
+    ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName, attachment);
+    return false;
+}
+
+/**
  * Return true if format is a valid texture image format for source,
  * taking into account enabled WebGL extensions.
  */
 bool
 WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
 {
     /* Core WebGL texture formats */
     if (format == LOCAL_GL_ALPHA ||
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -19,33 +19,33 @@ using namespace mozilla::gl;
 
 JSObject*
 WebGLFramebuffer::WrapObject(JSContext* cx)
 {
     return dom::WebGLFramebufferBinding::Wrap(cx, this);
 }
 
 WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
-    : WebGLBindableName<GLenum>()
+    : WebGLBindableName<FBTarget>()
     , WebGLContextBoundObject(context)
     , mStatus(0)
     , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
     , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
     , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
 {
     SetIsDOMBinding();
     mContext->MakeContextCurrent();
     mContext->gl->fGenFramebuffers(1, &mGLName);
     mContext->mFramebuffers.insertBack(this);
 
     mColorAttachments.SetLength(1);
     mColorAttachments[0].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0;
 }
 
-WebGLFramebuffer::Attachment::Attachment(GLenum aAttachmentPoint)
+WebGLFramebuffer::Attachment::Attachment(FBAttachment aAttachmentPoint)
     : mAttachmentPoint(aAttachmentPoint)
     , mTexImageTarget(LOCAL_GL_NONE)
     , mNeedsFinalize(false)
 {}
 
 WebGLFramebuffer::Attachment::~Attachment()
 {}
 
@@ -336,18 +336,18 @@ WebGLFramebuffer::Attachment::IsComplete
         if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
             return false; // Textures can't have the correct format for stencil buffers
 
         if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
             return IsValidFBOTextureDepthStencilFormat(webGLFormat);
         }
 
         if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
-            mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
-                                      WebGLContext::kMaxColorAttachments))
+            mAttachmentPoint <= FBAttachment(LOCAL_GL_COLOR_ATTACHMENT0 - 1 +
+                                             WebGLContext::kMaxColorAttachments))
         {
             return IsValidFBOTextureColorFormat(webGLFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     if (Renderbuffer()) {
@@ -358,45 +358,45 @@ WebGLFramebuffer::Attachment::IsComplete
 
         if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
             return IsValidFBORenderbufferStencilFormat(internalFormat);
 
         if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
             return IsValidFBORenderbufferDepthStencilFormat(internalFormat);
 
         if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
-            mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
-                                      WebGLContext::kMaxColorAttachments))
+            mAttachmentPoint <= FBAttachment(LOCAL_GL_COLOR_ATTACHMENT0 - 1 +
+                                             WebGLContext::kMaxColorAttachments))
         {
             return IsValidFBORenderbufferColorFormat(internalFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     MOZ_ASSERT(false, "Should not get here.");
     return false;
 }
 
 void
-WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext* gl, GLenum attachmentLoc) const
+WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext* gl, FBAttachment attachmentLoc) const
 {
     if (!mNeedsFinalize)
         return;
 
     mNeedsFinalize = false;
 
     if (!HasImage()) {
         if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
             gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
                                          LOCAL_GL_RENDERBUFFER, 0);
             gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
                                          LOCAL_GL_RENDERBUFFER, 0);
         } else {
-            gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachmentLoc,
+            gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
                                          LOCAL_GL_RENDERBUFFER, 0);
         }
 
         return;
     }
     MOZ_ASSERT(HasImage());
 
     if (Texture()) {
@@ -407,17 +407,17 @@ WebGLFramebuffer::Attachment::FinalizeAt
         const GLuint glName = Texture()->GLName();
 
         if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
             gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
                                       imageTarget, glName, mipLevel);
             gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
                                       imageTarget, glName, mipLevel);
         } else {
-            gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc,
+            gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
                                       imageTarget, glName, mipLevel);
         }
         return;
     }
 
     if (Renderbuffer()) {
         Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
         return;
@@ -459,32 +459,25 @@ WebGLFramebuffer::DetachAllAttachments()
     }
 
     DetachAttachment(mDepthAttachment);
     DetachAttachment(mStencilAttachment);
     DetachAttachment(mDepthStencilAttachment);
 }
 
 void
-WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
-                                          GLenum attachment,
-                                          GLenum rbtarget,
+WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachment,
+                                          RBTarget rbtarget,
                                           WebGLRenderbuffer* wrb)
 {
     MOZ_ASSERT(mContext->mBoundFramebuffer == this);
 
     if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb))
         return;
 
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
-
-    if (rbtarget != LOCAL_GL_RENDERBUFFER)
-        return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
-
     /* Get the requested attachment. If result is NULL, attachment is
      * invalid and an error is generated.
      *
      * Don't use GetAttachment(...) here because it opt builds it
      * returns mColorAttachment[0] for invalid attachment, which we
      * really don't want to mess with.
      */
     Attachment* a = GetAttachmentOrNull(attachment);
@@ -504,30 +497,26 @@ WebGLFramebuffer::FramebufferRenderbuffe
     // Attach new
     if (wrb)
         wrb->AttachTo(this, attachment);
 
     a->SetRenderbuffer(wrb);
 }
 
 void
-WebGLFramebuffer::FramebufferTexture2D(GLenum target,
-                                       GLenum attachment,
+WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachment,
                                        TexImageTarget texImageTarget,
                                        WebGLTexture* wtex,
                                        GLint level)
 {
     MOZ_ASSERT(mContext->mBoundFramebuffer == this);
 
     if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex))
         return;
 
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
-
     if (wtex) {
         bool isTexture2D = wtex->Target() == LOCAL_GL_TEXTURE_2D;
         bool isTexTarget2D = texImageTarget == LOCAL_GL_TEXTURE_2D;
         if (isTexture2D != isTexTarget2D) {
             return mContext->ErrorInvalidOperation("framebufferTexture2D: mismatched texture and texture target");
         }
     }
 
@@ -558,96 +547,96 @@ WebGLFramebuffer::FramebufferTexture2D(G
     // Attach new
     if (wtex)
         wtex->AttachTo(this, attachment);
 
     a->SetTexImage(wtex, texImageTarget, level);
 }
 
 WebGLFramebuffer::Attachment*
-WebGLFramebuffer::GetAttachmentOrNull(GLenum attachment)
+WebGLFramebuffer::GetAttachmentOrNull(FBAttachment attachment)
 {
     if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
         return &mDepthStencilAttachment;
 
     if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
         return &mDepthAttachment;
 
     if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
         return &mStencilAttachment;
 
-    if (!CheckColorAttachmentNumber(attachment, "getAttachmentOrNull"))
+    if (!mContext->ValidateFramebufferAttachment(attachment.get(), "getAttachmentOrNull"))
         return nullptr;
 
-    size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
+    size_t colorAttachmentId = attachment.get() - LOCAL_GL_COLOR_ATTACHMENT0;
     EnsureColorAttachments(colorAttachmentId);
 
     return &mColorAttachments[colorAttachmentId];
 }
 
 const WebGLFramebuffer::Attachment&
-WebGLFramebuffer::GetAttachment(GLenum attachment) const
+WebGLFramebuffer::GetAttachment(FBAttachment attachment) const
 {
     if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
         return mDepthStencilAttachment;
     if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
         return mDepthAttachment;
     if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
         return mStencilAttachment;
 
-    if (!CheckColorAttachmentNumber(attachment, "getAttachment")) {
+    if (!mContext->ValidateFramebufferAttachment(attachment.get(), "getAttachment")) {
         MOZ_ASSERT(false);
         return mColorAttachments[0];
     }
 
-    size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
+    size_t colorAttachmentId = attachment.get() - LOCAL_GL_COLOR_ATTACHMENT0;
     if (colorAttachmentId >= mColorAttachments.Length()) {
         MOZ_ASSERT(false);
         return mColorAttachments[0];
     }
 
     return mColorAttachments[colorAttachmentId];
 }
 
 void
 WebGLFramebuffer::DetachTexture(const WebGLTexture* tex)
 {
     size_t count = mColorAttachments.Length();
     for (size_t i = 0; i < count; i++) {
         if (mColorAttachments[i].Texture() == tex) {
-            FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_TEXTURE_2D, nullptr, 0);
+            FramebufferTexture2D(LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_TEXTURE_2D, nullptr, 0);
             // a texture might be attached more that once while editing the framebuffer
         }
     }
 
     if (mDepthAttachment.Texture() == tex)
-        FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
+        FramebufferTexture2D(LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
     if (mStencilAttachment.Texture() == tex)
-        FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
+        FramebufferTexture2D(LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
     if (mDepthStencilAttachment.Texture() == tex)
-        FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
+        FramebufferTexture2D(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
 }
 
 void
 WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb)
 {
     size_t count = mColorAttachments.Length();
     for (size_t i = 0; i < count; i++) {
         if (mColorAttachments[i].Renderbuffer() == rb) {
-            FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_RENDERBUFFER, nullptr);
+            FramebufferRenderbuffer(LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_RENDERBUFFER, nullptr);
             // a renderbuffer might be attached more that once while editing the framebuffer
         }
     }
 
     if (mDepthAttachment.Renderbuffer() == rb)
-        FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
+        FramebufferRenderbuffer(LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
     if (mStencilAttachment.Renderbuffer() == rb)
-        FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
+        FramebufferRenderbuffer(LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
     if (mDepthStencilAttachment.Renderbuffer() == rb)
-        FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
+        FramebufferRenderbuffer(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
 }
 
 bool
 WebGLFramebuffer::HasDefinedAttachments() const
 {
     bool hasAttachments = false;
 
     size_t count = mColorAttachments.Length();
@@ -752,17 +741,17 @@ const WebGLRectangleObject&
 WebGLFramebuffer::RectangleObject() const
 {
     // If we're using this as the RectObj of an FB, we need to be sure the FB
     // has a consistent rect.
     MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?");
     return GetAnyRectObject();
 }
 
-GLenum
+FBStatus
 WebGLFramebuffer::PrecheckFramebufferStatus() const
 {
     MOZ_ASSERT(mContext->mBoundFramebuffer == this);
 
     if (!HasDefinedAttachments())
         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
 
     if (HasIncompleteAttachments())
@@ -772,23 +761,23 @@ WebGLFramebuffer::PrecheckFramebufferSta
         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // Inconsistent sizes
 
     if (HasDepthStencilConflict())
         return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
 
     return LOCAL_GL_FRAMEBUFFER_COMPLETE;
 }
 
-GLenum
+FBStatus
 WebGLFramebuffer::CheckFramebufferStatus() const
 {
     if (mStatus != 0)
         return mStatus;
 
-    mStatus = PrecheckFramebufferStatus();
+    mStatus = PrecheckFramebufferStatus().get();
     if (mStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
         return mStatus;
 
     // Looks good on our end. Let's ask the driver.
     mContext->MakeContextCurrent();
 
     // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
     FinalizeAttachments();
@@ -892,43 +881,16 @@ WebGLFramebuffer::CheckAndInitializeAtta
     if (mStencilAttachment.HasUninitializedImageData())
         mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
     if (mDepthStencilAttachment.HasUninitializedImageData())
         mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
 
     return true;
 }
 
-bool WebGLFramebuffer::CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const
-{
-    const char* const errorFormating = "%s: attachment: invalid enum value 0x%x";
-
-    if (mContext->IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
-        if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
-            attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments))
-        {
-            mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
-            return false;
-        }
-    } else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0) {
-        if (attachment > LOCAL_GL_COLOR_ATTACHMENT0 &&
-            attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
-        {
-            mContext->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x. "
-                                       "Try the WEBGL_draw_buffers extension if supported.", functionName, attachment);
-            return false;
-        } else {
-            mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
-            return false;
-        }
-    }
-
-    return true;
-}
-
 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
 {
     MOZ_ASSERT(colorAttachmentId < WebGLContext::kMaxColorAttachments);
 
     size_t currentAttachmentCount = mColorAttachments.Length();
     if (colorAttachmentId < currentAttachmentCount)
         return;
 
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -20,38 +20,38 @@ class WebGLFramebufferAttachable;
 class WebGLTexture;
 class WebGLRenderbuffer;
 namespace gl {
     class GLContext;
 }
 
 class WebGLFramebuffer MOZ_FINAL
     : public nsWrapperCache
-    , public WebGLBindableName<GLenum>
+    , public WebGLBindableName<FBTarget>
     , public WebGLRefCountedObject<WebGLFramebuffer>
     , public LinkedListElement<WebGLFramebuffer>
     , public WebGLContextBoundObject
     , public SupportsWeakPtr<WebGLFramebuffer>
 {
 public:
     MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLFramebuffer)
 
     explicit WebGLFramebuffer(WebGLContext* context);
 
     struct Attachment
     {
         // deleting a texture or renderbuffer immediately detaches it
         WebGLRefPtr<WebGLTexture> mTexturePtr;
         WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
-        GLenum mAttachmentPoint;
+        FBAttachment mAttachmentPoint;
         TexImageTarget mTexImageTarget;
         GLint mTexImageLevel;
         mutable bool mNeedsFinalize;
 
-        explicit Attachment(GLenum aAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0);
+        explicit Attachment(FBAttachment aAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0);
         ~Attachment();
 
         bool IsDefined() const;
 
         bool IsDeleteRequested() const;
 
         bool HasAlpha() const;
         bool IsReadableFloat() const;
@@ -83,44 +83,42 @@ public:
 
         void Reset();
 
         const WebGLRectangleObject& RectangleObject() const;
 
         bool HasImage() const;
         bool IsComplete() const;
 
-        void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
+        void FinalizeAttachment(gl::GLContext* gl, FBAttachment attachmentLoc) const;
     };
 
     void Delete();
 
-    void FramebufferRenderbuffer(GLenum target,
-                                 GLenum attachment,
-                                 GLenum rbtarget,
+    void FramebufferRenderbuffer(FBAttachment attachment,
+                                 RBTarget rbtarget,
                                  WebGLRenderbuffer* wrb);
 
-    void FramebufferTexture2D(GLenum target,
-                              GLenum attachment,
+    void FramebufferTexture2D(FBAttachment attachment,
                               TexImageTarget texImageTarget,
                               WebGLTexture* wtex,
                               GLint level);
 
 private:
     void DetachAttachment(WebGLFramebuffer::Attachment& attachment);
     void DetachAllAttachments();
     const WebGLRectangleObject& GetAnyRectObject() const;
-    Attachment* GetAttachmentOrNull(GLenum attachment);
+    Attachment* GetAttachmentOrNull(FBAttachment attachment);
 
 public:
     bool HasDefinedAttachments() const;
     bool HasIncompleteAttachments() const;
     bool AllImageRectsMatch() const;
-    GLenum PrecheckFramebufferStatus() const;
-    GLenum CheckFramebufferStatus() const;
+    FBStatus PrecheckFramebufferStatus() const;
+    FBStatus CheckFramebufferStatus() const;
     GLenum GetFormatForAttachment(const WebGLFramebuffer::Attachment& attachment) const;
 
     bool HasDepthStencilConflict() const {
         return int(mDepthAttachment.IsDefined()) +
                int(mStencilAttachment.IsDefined()) +
                int(mDepthStencilAttachment.IsDefined()) >= 2;
     }
 
@@ -138,17 +136,17 @@ public:
     const Attachment& StencilAttachment() const {
         return mStencilAttachment;
     }
 
     const Attachment& DepthStencilAttachment() const {
         return mDepthStencilAttachment;
     }
 
-    const Attachment& GetAttachment(GLenum attachment) const;
+    const Attachment& GetAttachment(FBAttachment attachment) const;
 
     void DetachTexture(const WebGLTexture* tex);
 
     void DetachRenderbuffer(const WebGLRenderbuffer* rb);
 
     const WebGLRectangleObject& RectangleObject() const;
 
     WebGLContext* GetParentObject() const {
@@ -162,21 +160,20 @@ public:
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
 
     // mask mirrors glClear.
     bool HasCompletePlanes(GLbitfield mask);
 
     bool CheckAndInitializeAttachments();
 
-    bool CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const;
+    bool CheckColorAttachmentNumber(FBAttachment attachment, const char* functionName) const;
 
     void EnsureColorAttachments(size_t colorAttachmentId);
 
-    Attachment* AttachmentFor(GLenum attachment);
     void NotifyAttachableChanged() const;
 
 private:
     ~WebGLFramebuffer() {
         DeleteOnce();
     }
 
     mutable GLenum mStatus;
--- a/dom/canvas/WebGLFramebufferAttachable.cpp
+++ b/dom/canvas/WebGLFramebufferAttachable.cpp
@@ -7,30 +7,30 @@
 #include "WebGLFramebufferAttachable.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLTexture.h"
 
 using namespace mozilla;
 
 void
-WebGLFramebufferAttachable::AttachTo(WebGLFramebuffer* fb, GLenum attachment)
+WebGLFramebufferAttachable::AttachTo(WebGLFramebuffer* fb, FBAttachment attachment)
 {
     MOZ_ASSERT(fb);
     if (!fb)
         return;
 
     if (mAttachmentPoints.Contains(AttachmentPoint(fb, attachment)))
         return; // Already attached. Ignore.
 
     mAttachmentPoints.AppendElement(AttachmentPoint(fb, attachment));
 }
 
 void
-WebGLFramebufferAttachable::DetachFrom(WebGLFramebuffer* fb, GLenum attachment)
+WebGLFramebufferAttachable::DetachFrom(WebGLFramebuffer* fb, FBAttachment attachment)
 {
     MOZ_ASSERT(fb);
     if (!fb)
         return;
 
     const size_t i = mAttachmentPoints.IndexOf(AttachmentPoint(fb, attachment));
     if (i == mAttachmentPoints.NoIndex) {
         MOZ_ASSERT(false, "Is not attached to FB");
--- a/dom/canvas/WebGLFramebufferAttachable.h
+++ b/dom/canvas/WebGLFramebufferAttachable.h
@@ -5,41 +5,42 @@
 
 #ifndef WEBGLFRAMEBUFFERATTACHABLE_H_
 #define WEBGLFRAMEBUFFERATTACHABLE_H_
 
 #include "GLDefs.h"
 #include "nsTArray.h"
 #include "mozilla/WeakPtr.h"
 #include "WebGLFramebuffer.h"
+#include "WebGLStrongTypes.h"
 
 namespace mozilla {
 
 class WebGLFramebufferAttachable
 {
     struct AttachmentPoint
     {
-        AttachmentPoint(const WebGLFramebuffer* fb, GLenum attachment)
+        AttachmentPoint(const WebGLFramebuffer* fb, FBAttachment attachment)
             : mFB(fb)
             , mAttachment(attachment)
         {}
 
         WeakPtr<const WebGLFramebuffer> mFB;
-        GLenum mAttachment;
+        FBAttachment mAttachment;
 
         bool operator==(const AttachmentPoint& o) const {
           return mFB == o.mFB && mAttachment == o.mAttachment;
         }
     };
 
     nsTArray<AttachmentPoint> mAttachmentPoints;
 
 public:
 
     // Track FBO/Attachment combinations
-    void AttachTo(WebGLFramebuffer* fb, GLenum attachment);
-    void DetachFrom(WebGLFramebuffer* fb, GLenum attachment);
+    void AttachTo(WebGLFramebuffer* fb, FBAttachment attachment);
+    void DetachFrom(WebGLFramebuffer* fb, FBAttachment attachment);
     void NotifyFBsStatusChanged();
 };
 
 } // namespace mozilla
 
 #endif // !WEBGLFRAMEBUFFERATTACHABLE_H_
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -38,17 +38,17 @@ NeedsDepthStencilEmu(GLContext* gl, GLen
 }
 
 JSObject*
 WebGLRenderbuffer::WrapObject(JSContext *cx) {
     return dom::WebGLRenderbufferBinding::Wrap(cx, this);
 }
 
 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
-    : WebGLBindableName<GLenum>()
+    : WebGLBindableName<RBTarget>()
     , WebGLContextBoundObject(context)
     , mPrimaryRB(0)
     , mSecondaryRB(0)
     , mInternalFormat(0)
     , mInternalFormatForGL(0)
     , mImageDataStatus(WebGLImageDataStatus::NoImageData)
 {
     SetIsDOMBinding();
@@ -177,63 +177,63 @@ WebGLRenderbuffer::RenderbufferStorage(G
     if (secondaryFormat) {
         gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, secondaryFormat, width, height);
     } else {
         gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA4, 1, 1);
     }
 }
 
 void
-WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment) const {
+WebGLRenderbuffer::FramebufferRenderbuffer(FBAttachment attachment) const {
     GLContext* gl = mContext->gl;
     if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
-        gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment, LOCAL_GL_RENDERBUFFER, mPrimaryRB);
+        gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment.get(), LOCAL_GL_RENDERBUFFER, mPrimaryRB);
         return;
     }
 
     GLuint stencilRB = mPrimaryRB;
     if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
         printf_stderr("DEV-ONLY: Using secondary buffer to emulate DepthStencil.\n");
         MOZ_ASSERT(mSecondaryRB);
         stencilRB = mSecondaryRB;
     }
     gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,   LOCAL_GL_RENDERBUFFER, mPrimaryRB);
     gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, stencilRB);
 }
 
 GLint
-WebGLRenderbuffer::GetRenderbufferParameter(GLenum target, GLenum pname) const {
+WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target, RBParam pname) const {
     GLContext* gl = mContext->gl;
 
-    switch (pname) {
+    switch (pname.get()) {
         case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE: {
             if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
                 if (gl->WorkAroundDriverBugs() &&
                     gl->Renderer() == GLRenderer::Tegra)
                 {
                     return 8;
                 }
 
                 ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
 
                 GLint i = 0;
-                gl->fGetRenderbufferParameteriv(target, pname, &i);
+                gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
                 return i;
             }
             // Fall through otherwise.
         }
         case LOCAL_GL_RENDERBUFFER_WIDTH:
         case LOCAL_GL_RENDERBUFFER_HEIGHT:
         case LOCAL_GL_RENDERBUFFER_RED_SIZE:
         case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
         case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
         case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
         case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE: {
             GLint i = 0;
-            gl->fGetRenderbufferParameteriv(target, pname, &i);
+            gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
             return i;
         }
     }
 
     MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
     return 0;
 }
 
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -13,17 +13,17 @@
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLRenderbuffer MOZ_FINAL
     : public nsWrapperCache
-    , public WebGLBindableName<GLenum>
+    , public WebGLBindableName<RBTarget>
     , public WebGLRefCountedObject<WebGLRenderbuffer>
     , public LinkedListElement<WebGLRenderbuffer>
     , public WebGLRectangleObject
     , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
 public:
     explicit WebGLRenderbuffer(WebGLContext* context);
@@ -47,19 +47,19 @@ public:
     int64_t MemoryUsage() const;
 
     WebGLContext *GetParentObject() const {
         return Context();
     }
 
     void BindRenderbuffer() const;
     void RenderbufferStorage(GLenum internalFormat, GLsizei width, GLsizei height) const;
-    void FramebufferRenderbuffer(GLenum attachment) const;
+    void FramebufferRenderbuffer(FBAttachment attachment) const;
     // Only handles a subset of `pname`s.
-    GLint GetRenderbufferParameter(GLenum target, GLenum pname) const;
+    GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
 
 protected:
     ~WebGLRenderbuffer() {
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -148,16 +148,24 @@ public:
     bool operator==(const StrongGLenum& other) const {
         return get() == other.get();
     }
 
     bool operator!=(const StrongGLenum& other) const {
         return get() != other.get();
     }
 
+    bool operator<=(const StrongGLenum& other) const {
+        return get() <= other.get();
+    }
+
+    bool operator>=(const StrongGLenum& other) const {
+        return get() >= other.get();
+    }
+
     static bool IsValueLegal(GLenum value) {
         if (value > UINT16_MAX) {
             return false;
         }
         return std::binary_search(Details::values(),
                                   Details::values() + Details::valuesCount(),
                                   uint16_t(value));
     }
@@ -337,9 +345,64 @@ STRONG_GLENUM_BEGIN(TexInternalFormat)
     STRONG_GLENUM_VALUE(RGB8I),
     STRONG_GLENUM_VALUE(R8_SNORM),
     STRONG_GLENUM_VALUE(RG8_SNORM),
     STRONG_GLENUM_VALUE(RGB8_SNORM),
     STRONG_GLENUM_VALUE(RGBA8_SNORM),
     STRONG_GLENUM_VALUE(RGB10_A2UI),
 STRONG_GLENUM_END(TexInternalFormat)
 
+STRONG_GLENUM_BEGIN(FBTarget)
+    STRONG_GLENUM_VALUE(NONE),
+    STRONG_GLENUM_VALUE(READ_FRAMEBUFFER),
+    STRONG_GLENUM_VALUE(DRAW_FRAMEBUFFER),
+    STRONG_GLENUM_VALUE(FRAMEBUFFER),
+STRONG_GLENUM_END(FBTarget)
+
+STRONG_GLENUM_BEGIN(RBTarget)
+    STRONG_GLENUM_VALUE(NONE),
+    STRONG_GLENUM_VALUE(RENDERBUFFER),
+STRONG_GLENUM_END(RBTarget)
+
+STRONG_GLENUM_BEGIN(FBAttachment)
+    STRONG_GLENUM_VALUE(DEPTH_STENCIL_ATTACHMENT),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT0),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT1),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT2),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT3),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT4),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT5),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT6),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT7),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT8),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT9),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT10),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT11),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT12),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT13),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT14),
+    STRONG_GLENUM_VALUE(COLOR_ATTACHMENT15),
+    STRONG_GLENUM_VALUE(DEPTH_ATTACHMENT),
+    STRONG_GLENUM_VALUE(STENCIL_ATTACHMENT),
+STRONG_GLENUM_END(FBAttachment)
+
+STRONG_GLENUM_BEGIN(FBStatus)
+    STRONG_GLENUM_VALUE(FRAMEBUFFER_COMPLETE),
+    STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+    STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+    STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_DIMENSIONS),
+    STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER),
+    STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_READ_BUFFER),
+    STRONG_GLENUM_VALUE(FRAMEBUFFER_UNSUPPORTED),
+STRONG_GLENUM_END(FBStatus)
+
+STRONG_GLENUM_BEGIN(RBParam)
+    STRONG_GLENUM_VALUE(RENDERBUFFER_WIDTH),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_HEIGHT),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_RED_SIZE),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_GREEN_SIZE),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_BLUE_SIZE),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_ALPHA_SIZE),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_DEPTH_SIZE),
+    STRONG_GLENUM_VALUE(RENDERBUFFER_STENCIL_SIZE),
+STRONG_GLENUM_END(RBParam)
+
 #endif
--- a/dom/datastore/moz.build
+++ b/dom/datastore/moz.build
@@ -12,17 +12,17 @@ XPIDL_SOURCES += [
 XPIDL_MODULE = 'dom_datastore'
 
 EXPORTS.mozilla.dom += [
     'DataStore.h',
     'DataStoreCursor.h',
     'DataStoreService.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'DataStore.cpp',
     'DataStoreCursor.cpp',
     'DataStoreDB.cpp',
     'DataStoreRevision.cpp',
     'DataStoreService.cpp',
 ]
 
 LOCAL_INCLUDES += [
--- a/dom/events/DOMEventTargetHelper.cpp
+++ b/dom/events/DOMEventTargetHelper.cpp
@@ -273,18 +273,17 @@ DOMEventTargetHelper::DispatchTrustedEve
 
 nsresult
 DOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
                                       JSContext* aCx,
                                       const JS::Value& aValue)
 {
   nsRefPtr<EventHandlerNonNull> handler;
   JS::Rooted<JSObject*> callable(aCx);
-  if (aValue.isObject() &&
-      JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
+  if (aValue.isObject() && JS::IsCallable(callable = &aValue.toObject())) {
     handler = new EventHandlerNonNull(callable, dom::GetIncumbentGlobal());
   }
   SetEventHandler(aType, EmptyString(), handler);
   return NS_OK;
 }
 
 void
 DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
--- a/dom/filesystem/moz.build
+++ b/dom/filesystem/moz.build
@@ -8,17 +8,17 @@ EXPORTS.mozilla.dom += [
     'DeviceStorageFileSystem.h',
     'Directory.h',
     'FileSystemBase.h',
     'FileSystemRequestParent.h',
     'FileSystemTaskBase.h',
     'FileSystemUtils.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'CreateDirectoryTask.cpp',
     'CreateFileTask.cpp',
     'DeviceStorageFileSystem.cpp',
     'Directory.cpp',
     'FileSystemBase.cpp',
     'FileSystemPermissionRequest.cpp',
     'FileSystemRequestParent.cpp',
     'FileSystemTaskBase.cpp',
--- a/dom/fmradio/ipc/moz.build
+++ b/dom/fmradio/ipc/moz.build
@@ -6,17 +6,17 @@
 
 EXPORTS.mozilla.dom += [
     'FMRadioChild.h',
     'FMRadioParent.h',
     'FMRadioRequestChild.h',
     'FMRadioRequestParent.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'FMRadioChild.cpp',
     'FMRadioParent.cpp',
     'FMRadioRequestChild.cpp',
     'FMRadioRequestParent.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
--- a/dom/fmradio/moz.build
+++ b/dom/fmradio/moz.build
@@ -10,17 +10,17 @@ if CONFIG['MOZ_B2G_FM']:
     ]
 
     EXPORTS.mozilla.dom += [
         'FMRadio.h',
         'FMRadioCommon.h',
         'FMRadioService.h',
     ]
 
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'FMRadio.cpp',
         'FMRadioService.cpp',
     ]
 
     FINAL_LIBRARY = 'xul'
 
 IPDL_SOURCES += [
     'ipc/PFMRadio.ipdl',
--- a/dom/icc/moz.build
+++ b/dom/icc/moz.build
@@ -6,17 +6,17 @@
 
 DIRS += ['interfaces']
 
 EXPORTS.mozilla.dom += [
     'Icc.h',
     'IccManager.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'Icc.cpp',
     'IccListener.cpp',
     'IccManager.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/json/nsJSON.cpp
+++ b/dom/json/nsJSON.cpp
@@ -212,18 +212,17 @@ nsJSON::EncodeInternal(JSContext* cx, co
    * Manually call toJSON if implemented by the object and check that
    * the result is still an object
    * Note: It is perfectly fine to not implement toJSON, so it is
    * perfectly fine for GetMethod to fail
    */
   JS::Rooted<JS::Value> val(cx, aValue);
   JS::Rooted<JS::Value> toJSON(cx);
   if (JS_GetProperty(cx, obj, "toJSON", &toJSON) &&
-      toJSON.isObject() &&
-      JS_ObjectIsCallable(cx, &toJSON.toObject())) {
+      toJSON.isObject() && JS::IsCallable(&toJSON.toObject())) {
     // If toJSON is implemented, it must not throw
     if (!JS_CallFunctionValue(cx, obj, toJSON, JS::HandleValueArray::empty(), &val)) {
       if (JS_IsExceptionPending(cx))
         // passing NS_OK will throw the pending exception
         return NS_OK;
 
       // No exception, but still failed
       return NS_ERROR_FAILURE;
--- a/dom/mobileconnection/MobileConnection.cpp
+++ b/dom/mobileconnection/MobileConnection.cpp
@@ -16,16 +16,19 @@
 #include "mozilla/Services.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsIPermissionManager.h"
 #include "nsIVariant.h"
 #include "nsJSON.h"
 #include "nsJSUtils.h"
 #include "nsServiceManagerUtils.h"
 
+#ifdef CONVERT_STRING_TO_NULLABLE_ENUM
+#undef CONVERT_STRING_TO_NULLABLE_ENUM
+#endif
 #define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum)      \
 {                                                                       \
   uint32_t i = 0;                                                       \
   for (const EnumEntry* entry = _enumType##Values::strings;             \
        entry->value;                                                    \
        ++entry, ++i) {                                                  \
     if (_string.EqualsASCII(entry->value)) {                            \
       _enum.SetValue(static_cast<_enumType>(i));                        \
--- a/dom/mobileconnection/MobileConnectionInfo.cpp
+++ b/dom/mobileconnection/MobileConnectionInfo.cpp
@@ -5,16 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MobileConnectionInfo.h"
 
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "jsapi.h"
 
+#ifdef CONVERT_STRING_TO_NULLABLE_ENUM
+#undef CONVERT_STRING_TO_NULLABLE_ENUM
+#endif
 #define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum)      \
 {                                                                       \
   _enum.SetNull();                                                      \
                                                                         \
   uint32_t i = 0;                                                       \
   for (const EnumEntry* entry = _enumType##Values::strings;             \
        entry->value;                                                    \
        ++entry, ++i) {                                                  \
--- a/dom/mobileconnection/moz.build
+++ b/dom/mobileconnection/moz.build
@@ -25,17 +25,17 @@ XPIDL_SOURCES += [
     'interfaces/nsICellInfo.idl',
     'interfaces/nsIMobileCellInfo.idl',
     'interfaces/nsIMobileConnectionInfo.idl',
     'interfaces/nsIMobileConnectionService.idl',
     'interfaces/nsIMobileNetworkInfo.idl',
     'interfaces/nsINeighboringCellInfo.idl',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'DOMMMIError.cpp',
     'ipc/MobileConnectionChild.cpp',
     'ipc/MobileConnectionIPCService.cpp',
     'ipc/MobileConnectionParent.cpp',
     'MobileCellInfo.cpp',
     'MobileConnection.cpp',
     'MobileConnectionArray.cpp',
     'MobileConnectionCallback.cpp',
--- a/dom/mobilemessage/gonk/SmsService.cpp
+++ b/dom/mobilemessage/gonk/SmsService.cpp
@@ -5,26 +5,22 @@
 
 #include "SmsMessage.h"
 #include "SmsService.h"
 #include "mozilla/Preferences.h"
 #include "nsServiceManagerUtils.h"
 
 namespace {
 
-const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
 #define kPrefDefaultServiceId "dom.sms.defaultServiceId"
-const char* kObservedPrefs[] = {
-  kPrefDefaultServiceId,
-  nullptr
-};
 
 uint32_t
 getDefaultServiceId()
 {
+  static const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
   int32_t id = mozilla::Preferences::GetInt(kPrefDefaultServiceId, 0);
   int32_t numRil = mozilla::Preferences::GetInt(kPrefRilNumRadioInterfaces, 1);
 
   if (id >= numRil || id < 0) {
     id = 0;
   }
 
   return id;
@@ -41,16 +37,20 @@ NS_IMPL_ISUPPORTS(SmsService,
                   nsIObserver)
 
 SmsService::SmsService()
 {
   mRil = do_GetService("@mozilla.org/ril;1");
   NS_WARN_IF_FALSE(mRil, "This shouldn't fail!");
 
   // Initialize observer.
+  static const char* kObservedPrefs[] = {
+    kPrefDefaultServiceId,
+    nullptr
+  };
   Preferences::AddStrongObservers(this, kObservedPrefs);
   mDefaultServiceId = getDefaultServiceId();
 }
 
 /*
  * Implementation of nsIObserver.
  */
 
--- a/dom/mobilemessage/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/ipc/SmsIPCService.cpp
@@ -14,24 +14,18 @@
 #include "mozilla/Preferences.h"
 #include "nsString.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 
 namespace {
 
-const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
 #define kPrefMmsDefaultServiceId "dom.mms.defaultServiceId"
 #define kPrefSmsDefaultServiceId "dom.sms.defaultServiceId"
-const char* kObservedPrefs[] = {
-  kPrefMmsDefaultServiceId,
-  kPrefSmsDefaultServiceId,
-  nullptr
-};
 
 // TODO: Bug 767082 - WebSMS: sSmsChild leaks at shutdown
 PSmsChild* gSmsChild;
 
 // SmsIPCService is owned by nsLayoutModule.
 SmsIPCService* sSingleton = nullptr;
 
 PSmsChild*
@@ -81,16 +75,17 @@ SendCursorRequest(const IPCMobileMessage
 
   actor.forget(aResult);
   return NS_OK;
 }
 
 uint32_t
 getDefaultServiceId(const char* aPrefKey)
 {
+  static const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
   int32_t id = mozilla::Preferences::GetInt(aPrefKey, 0);
   int32_t numRil = mozilla::Preferences::GetInt(kPrefRilNumRadioInterfaces, 1);
 
   if (id >= numRil || id < 0) {
     id = 0;
   }
 
   return id;
@@ -114,16 +109,21 @@ SmsIPCService::GetSingleton()
   }
 
   nsRefPtr<SmsIPCService> service = sSingleton;
   return service.forget();
 }
 
 SmsIPCService::SmsIPCService()
 {
+  static const char* kObservedPrefs[] = {
+    kPrefMmsDefaultServiceId,
+    kPrefSmsDefaultServiceId,
+    nullptr
+  };
   Preferences::AddStrongObservers(this, kObservedPrefs);
   mMmsDefaultServiceId = getDefaultServiceId(kPrefMmsDefaultServiceId);
   mSmsDefaultServiceId = getDefaultServiceId(kPrefSmsDefaultServiceId);
 }
 
 SmsIPCService::~SmsIPCService()
 {
   sSingleton = nullptr;
--- a/dom/mobilemessage/moz.build
+++ b/dom/mobilemessage/moz.build
@@ -30,17 +30,17 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'go
         'gonk/WspPduHelper.jsm',
     ]
     EXTRA_COMPONENTS += [
         'gonk/MmsService.js',
         'gonk/MmsService.manifest',
         'gonk/MobileMessageDatabaseService.js',
         'gonk/MobileMessageDatabaseService.manifest',
     ]
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'gonk/SmsService.cpp',
     ]
 
 EXPORTS.mozilla.dom += [
     'DOMMobileMessageError.h',
     'MmsMessage.h',
     'MobileMessageManager.h',
     'SmsMessage.h',
--- a/dom/nfc/moz.build
+++ b/dom/nfc/moz.build
@@ -9,27 +9,27 @@ XPIDL_MODULE = 'dom_nfc'
 
 if CONFIG['MOZ_NFC']:
     XPIDL_SOURCES += [
         'nsINfcContentHelper.idl',
     ]
     EXPORTS.mozilla.dom += [
         'MozNDEFRecord.h',
     ]
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'MozNDEFRecord.cpp',
     ]
     EXTRA_COMPONENTS += [
         'NfcContentHelper.js',
         'nsNfc.js',
         'nsNfc.manifest',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_NFC']:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'gonk/NfcMessageHandler.cpp',
         'gonk/NfcService.cpp',
     ]
     XPIDL_SOURCES += [
         'gonk/nsINfcService.idl',
     ]
     EXTRA_COMPONENTS += [
         'gonk/Nfc.js',
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1604,17 +1604,17 @@ NPObjWrapper_Convert(JSContext *cx, JS::
   // specifically java.lang.Integer.  The Integer class has static valueOf
   // methods, none of which are nullary, so the JS-reflected method will behave
   // poorly when called with no arguments.  We work around this problem by
   // giving plugins a [[DefaultValue]] which uses only toString and not valueOf.
 
   JS::Rooted<JS::Value> v(cx, JSVAL_VOID);
   if (!JS_GetProperty(cx, obj, "toString", &v))
     return false;
-  if (!v.isPrimitive() && JS_ObjectIsCallable(cx, v.toObjectOrNull())) {
+  if (!v.isPrimitive() && JS::IsCallable(v.toObjectOrNull())) {
     if (!JS_CallFunctionValue(cx, obj, v, JS::HandleValueArray::empty(), vp))
       return false;
     if (vp.isPrimitive())
       return true;
   }
 
   JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
                        JS_GetClass(obj)->name,
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -1087,17 +1087,17 @@ Promise::ResolveInternal(JSContext* aCx,
 
     // Thenables.
     JS::Rooted<JS::Value> then(aCx);
     if (!JS_GetProperty(aCx, valueObj, "then", &then)) {
       HandleException(aCx);
       return;
     }
 
-    if (then.isObject() && JS_ObjectIsCallable(aCx, &then.toObject())) {
+    if (then.isObject() && JS::IsCallable(&then.toObject())) {
       // This is the then() function of the thenable aValueObj.
       JS::Rooted<JSObject*> thenObj(aCx, &then.toObject());
       nsRefPtr<PromiseInit> thenCallback =
         new PromiseInit(thenObj, mozilla::dom::GetIncumbentGlobal());
       nsRefPtr<ThenableResolverTask> task =
         new ThenableResolverTask(this, valueObj, thenCallback);
       DispatchToMainOrWorkerThread(task);
       return;
--- a/dom/speakermanager/moz.build
+++ b/dom/speakermanager/moz.build
@@ -7,17 +7,17 @@
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
 EXPORTS += [
     'SpeakerManager.h',
     'SpeakerManagerService.h',
     'SpeakerManagerServiceChild.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'SpeakerManager.cpp',
     'SpeakerManagerService.cpp',
     'SpeakerManagerServiceChild.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/system/gonk/Volume.cpp
+++ b/dom/system/gonk/Volume.cpp
@@ -373,17 +373,17 @@ void
 Volume::HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   // The volume name will have already been parsed, and the tokenizer will point
   // to the token after the volume name
   switch (aResponseCode) {
-    case ResponseCode::VolumeListResult: {
+    case ::ResponseCode::VolumeListResult: {
       // Each line will look something like:
       //
       //  sdcard /mnt/sdcard 1
       //
       nsDependentCSubstring mntPoint(aTokenizer.nextToken());
       SetMountPoint(mntPoint);
       nsresult errCode;
       nsCString state(aTokenizer.nextToken());
@@ -392,17 +392,17 @@ Volume::HandleVoldResponse(int aResponse
         mCanBeShared = false;
         SetState(nsIVolume::STATE_MOUNTED);
       } else {
         SetState((STATE)state.ToInteger(&errCode));
       }
       break;
     }
 
-    case ResponseCode::VolumeStateChange: {
+    case ::ResponseCode::VolumeStateChange: {
       // Format of the line looks something like:
       //
       //  Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted)
       //
       // So we parse out the state after the string " to "
       while (aTokenizer.hasMoreTokens()) {
         nsAutoCString token(aTokenizer.nextToken());
         if (token.EqualsLiteral("to")) {
@@ -410,22 +410,22 @@ Volume::HandleVoldResponse(int aResponse
           token = aTokenizer.nextToken();
           SetState((STATE)token.ToInteger(&errCode));
           break;
         }
       }
       break;
     }
 
-    case ResponseCode::VolumeDiskInserted:
+    case ::ResponseCode::VolumeDiskInserted:
       SetMediaPresent(true);
       break;
 
-    case ResponseCode::VolumeDiskRemoved: // fall-thru
-    case ResponseCode::VolumeBadRemoval:
+    case ::ResponseCode::VolumeDiskRemoved: // fall-thru
+    case ::ResponseCode::VolumeBadRemoval:
       SetMediaPresent(false);
       break;
 
     default:
       LOG("Volume: %s unrecognized reponse code (ignored)", NameStr());
       break;
   }
 }
--- a/dom/system/gonk/VolumeManager.cpp
+++ b/dom/system/gonk/VolumeManager.cpp
@@ -138,31 +138,31 @@ VolumeManager::FindAddVolumeByName(const
   return vol;
 }
 
 class VolumeListCallback : public VolumeResponseCallback
 {
   virtual void ResponseReceived(const VolumeCommand* aCommand)
   {
     switch (ResponseCode()) {
-      case ResponseCode::VolumeListResult: {
+      case ::ResponseCode::VolumeListResult: {
         // Each line will look something like:
         //
         //  sdcard /mnt/sdcard 1
         //
         // So for each volume that we get back, we update any volumes that
         // we have of the same name, or add new ones if they don't exist.
         nsCWhitespaceTokenizer tokenizer(ResponseStr());
         nsDependentCSubstring volName(tokenizer.nextToken());
         RefPtr<Volume> vol = VolumeManager::FindAddVolumeByName(volName);
         vol->HandleVoldResponse(ResponseCode(), tokenizer);
         break;
       }
 
-      case ResponseCode::CommandOkay: {
+      case ::ResponseCode::CommandOkay: {
         // We've received the list of volumes. Tell anybody who
         // is listening that we're open for business.
         VolumeManager::SetState(VolumeManager::VOLUMES_READY);
         break;
       }
     }
   }
 };
@@ -280,26 +280,26 @@ VolumeManager::OnLineRead(int aFd, nsDep
   if (*endPtr == ' ') {
     endPtr++;
   }
 
   // Now fish out the rest of the line after the response code
   nsDependentCString  responseLine(endPtr, aMessage.Length() - (endPtr - aMessage.Data()));
   DBG("Rcvd: %d '%s'", responseCode, responseLine.Data());
 
-  if (responseCode >= ResponseCode::UnsolicitedInformational) {
+  if (responseCode >= ::ResponseCode::UnsolicitedInformational) {
     // These are unsolicited broadcasts. We intercept these and process
     // them ourselves
     HandleBroadcast(responseCode, responseLine);
   } else {
     // Everything else is considered to be part of the command response.
     if (mCommands.size() > 0) {
       VolumeCommand* cmd = mCommands.front();
       cmd->HandleResponse(responseCode, responseLine);
-      if (responseCode >= ResponseCode::CommandOkay) {
+      if (responseCode >= ::ResponseCode::CommandOkay) {
         // That's a terminating response. We can remove the command.
         mCommands.pop();
         mCommandPending = false;
         // Start the next command, if there is one.
         WriteCommandData();
       }
     } else {
       ERR("Response with no command");
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -30,17 +30,17 @@ XPIDL_SOURCES += [
 
 XPIDL_MODULE = 'dom_system_gonk'
 
 EXPORTS += [
     'GonkGPSGeolocationProvider.h',
     'nsVolume.h',
     'nsVolumeService.h',
 ]
-SOURCES += [
+UNIFIED_SOURCES += [
     'AudioChannelManager.cpp',
     'AudioManager.cpp',
     'AutoMounter.cpp',
     'AutoMounterSetting.cpp',
     'GonkGPSGeolocationProvider.cpp',
     'MozMtpDatabase.cpp',
     'MozMtpServer.cpp',
     'MozMtpStorage.cpp',
--- a/dom/tests/mochitest/bugs/test_onerror_message.html
+++ b/dom/tests/mochitest/bugs/test_onerror_message.html
@@ -26,17 +26,17 @@ var expected = [
 { name: "Error", message: "foo", filename: "bar", lineNumber: 123 },
 { name: "", message: "uncaught exception: [object Object]" },
 { name: "DuckError", message: "foo", filename: "bar", lineNumber: 123 },
 { name: "", message: "uncaught exception: [object Object]" },
 { name: "", message: "foo", filename: "baz", lineNumber: 123 },
 { name: "", message: "uncaught exception: [object Object]" },
 { name: "InvalidStateError", message: "An attempt was made to use an object that is not, or is no longer, usable", filename: location, lineNumber: 60 },
 { name: "ReferenceError", message: "xxx is not defined", filename: location, lineNumber: 64 },
-{ name: "ReferenceError", message: "xxx is not defined, did you mean 'x'?", filename: location, lineNumber: 66 }
+{ name: "ReferenceError", message: "xxx is not defined", filename: location, lineNumber: 66 }
 ];
 
 var counter = 0;
 var origin = location.protocol + "//" + location.host;
 postMessage(counter, origin);
 window.onmessage = function(e) {
 	if (e.origin !== origin)
 		return;
--- a/dom/wifi/moz.build
+++ b/dom/wifi/moz.build
@@ -25,16 +25,16 @@ EXTRA_JS_MODULES += [
     'StateMachine.jsm',
     'WifiCommand.jsm',
     'WifiNetUtil.jsm',
     'WifiP2pManager.jsm',
     'WifiP2pWorkerObserver.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    SOURCES = [
+    UNIFIED_SOURCES = [
         'WifiCertService.cpp',
         'WifiHotspotUtils.cpp',
         'WifiProxyService.cpp',
         'WifiUtils.cpp',
     ]
 
 FINAL_LIBRARY = 'xul'
--- a/dom/workers/MessagePort.cpp
+++ b/dom/workers/MessagePort.cpp
@@ -22,23 +22,23 @@ using mozilla::dom::AutoNoJSAPI;
 using namespace mozilla;
 
 USING_WORKERS_NAMESPACE
 
 namespace {
 
 class DelayedEventRunnable MOZ_FINAL : public WorkerRunnable
 {
-  nsRefPtr<MessagePort> mMessagePort;
+  nsRefPtr<mozilla::dom::workers::MessagePort> mMessagePort;
   nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents;
 
 public:
   DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
                        TargetAndBusyBehavior aBehavior,
-                       MessagePort* aMessagePort,
+                       mozilla::dom::workers::MessagePort* aMessagePort,
                        nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
   : WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aMessagePort);
     MOZ_ASSERT(aEvents.Length());
 
     mEvents.SwapElements(aEvents);
@@ -67,16 +67,18 @@ public:
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
 };
 
 } // anonymous namespace
 
+BEGIN_WORKERS_NAMESPACE
+
 MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
                          uint64_t aSerial)
 : MessagePortBase(aWindow), mSharedWorker(aSharedWorker),
   mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aSharedWorker);
   SetIsDOMBinding();
@@ -293,16 +295,18 @@ MessagePort::PreHandleEvent(EventChainPr
       aVisitor.mParentTarget = nullptr;
       return NS_OK;
     }
   }
 
   return DOMEventTargetHelper::PreHandleEvent(aVisitor);
 }
 
+END_WORKERS_NAMESPACE
+
 bool
 DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
 {
   MOZ_ASSERT(mMessagePort);
   mMessagePort->AssertCorrectThread();
   MOZ_ASSERT(mEvents.Length());
 
   AutoNoJSAPI nojsapi;
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -473,79 +473,16 @@ public:
     // for the same registration) are aborted. Update() sets a new
     // UpdatePromise on the registration.
     registration->mUpdatePromise->AddPromise(mPromise);
 
     return rv;
   }
 };
 
-/*
- * Implements the async aspects of the unregister algorithm.
- */
-class UnregisterRunnable : public nsRunnable
-{
-  nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
-  nsCOMPtr<nsIURI> mScopeURI;
-
-public:
-  UnregisterRunnable(nsIServiceWorkerUnregisterCallback* aCallback,
-                     nsIURI* aScopeURI)
-    : mCallback(aCallback), mScopeURI(aScopeURI)
-  {
-    AssertIsOnMainThread();
-  }
-
-  NS_IMETHODIMP
-  Run()
-  {
-    AssertIsOnMainThread();
-
-    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
-    nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
-      swm->GetDomainInfo(mScopeURI);
-    MOZ_ASSERT(domainInfo);
-
-    nsCString spec;
-    nsresult rv = mScopeURI->GetSpecIgnoringRef(spec);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return mCallback->UnregisterFailed();
-    }
-
-    nsRefPtr<ServiceWorkerRegistrationInfo> registration;
-    if (!domainInfo->mServiceWorkerRegistrationInfos.Get(spec,
-                                                         getter_AddRefs(registration))) {
-      return mCallback->UnregisterSucceeded(false);
-    }
-
-    MOZ_ASSERT(registration);
-
-    registration->mPendingUninstall = true;
-    rv = mCallback->UnregisterSucceeded(true);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    // The "Wait until no document is using registration" can actually be
-    // handled by [[HandleDocumentUnload]] in Bug 1041340, so we simply check
-    // if the document is currently in use here.
-    if (!registration->IsControllingDocuments()) {
-      if (!registration->mPendingUninstall) {
-        return NS_OK;
-      }
-
-      registration->Clear();
-      domainInfo->RemoveRegistration(registration);
-    }
-
-    return NS_OK;
-  }
-};
-
 // If we return an error code here, the ServiceWorkerContainer will
 // automatically reject the Promise.
 NS_IMETHODIMP
 ServiceWorkerManager::Register(const nsAString& aScope,
                                const nsAString& aScriptURL,
                                nsISupports** aPromise)
 {
   AssertIsOnMainThread();
@@ -1052,16 +989,79 @@ ServiceWorkerManager::Unregister(nsIServ
   MOZ_ASSERT(aCallback);
 
   nsCOMPtr<nsIURI> scopeURI;
   nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
+  /*
+   * Implements the async aspects of the unregister algorithm.
+   */
+  class UnregisterRunnable : public nsRunnable
+  {
+    nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
+    nsCOMPtr<nsIURI> mScopeURI;
+
+  public:
+    UnregisterRunnable(nsIServiceWorkerUnregisterCallback* aCallback,
+                       nsIURI* aScopeURI)
+      : mCallback(aCallback), mScopeURI(aScopeURI)
+    {
+      AssertIsOnMainThread();
+    }
+
+    NS_IMETHODIMP
+    Run()
+    {
+      AssertIsOnMainThread();
+
+      nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+      nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
+        swm->GetDomainInfo(mScopeURI);
+      MOZ_ASSERT(domainInfo);
+
+      nsCString spec;
+      nsresult rv = mScopeURI->GetSpecIgnoringRef(spec);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return mCallback->UnregisterFailed();
+      }
+
+      nsRefPtr<ServiceWorkerRegistrationInfo> registration;
+      if (!domainInfo->mServiceWorkerRegistrationInfos.Get(spec,
+                                                           getter_AddRefs(registration))) {
+        return mCallback->UnregisterSucceeded(false);
+      }
+
+      MOZ_ASSERT(registration);
+
+      registration->mPendingUninstall = true;
+      rv = mCallback->UnregisterSucceeded(true);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      // The "Wait until no document is using registration" can actually be
+      // handled by [[HandleDocumentUnload]] in Bug 1041340, so we simply check
+      // if the document is currently in use here.
+      if (!registration->IsControllingDocuments()) {
+        if (!registration->mPendingUninstall) {
+          return NS_OK;
+        }
+
+        registration->Clear();
+        domainInfo->RemoveRegistration(registration);
+      }
+
+      return NS_OK;
+    }
+  };
+
   nsRefPtr<nsIRunnable> unregisterRunnable =
     new UnregisterRunnable(aCallback, scopeURI);
   return NS_DispatchToCurrentThread(unregisterRunnable);
 }
 
 /* static */
 already_AddRefed<ServiceWorkerManager>
 ServiceWorkerManager::GetInstance()
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -198,17 +198,16 @@ class ServiceWorkerManager MOZ_FINAL : p
   friend class RegisterRunnable;
   friend class CallInstallRunnable;
   friend class CancelServiceWorkerInstallationRunnable;
   friend class ServiceWorkerRegistrationInfo;
   friend class ServiceWorkerUpdateInstance;
   friend class GetReadyPromiseRunnable;
   friend class GetRegistrationsRunnable;
   friend class GetRegistrationRunnable;
-  friend class UnregisterRunnable;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERMANAGER
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_SERVICEWORKERMANAGER_IMPL_IID)
 
   static ServiceWorkerManager* FactoryCreate()
   {
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -70,17 +70,17 @@ SharedWorker::Constructor(const GlobalOb
   if (NS_FAILED(rv)) {
     aRv = rv;
     return nullptr;
   }
 
   return sharedWorker.forget();
 }
 
-already_AddRefed<MessagePort>
+already_AddRefed<mozilla::dom::workers::MessagePort>
 SharedWorker::Port()
 {
   AssertIsOnMainThread();
 
   nsRefPtr<MessagePort> messagePort = mMessagePort;
   return messagePort.forget();
 }
 
--- a/dom/workers/SharedWorker.h
+++ b/dom/workers/SharedWorker.h
@@ -40,17 +40,17 @@ class SharedWorker MOZ_FINAL : public DO
   bool mSuspended;
 
 public:
   static already_AddRefed<SharedWorker>
   Constructor(const GlobalObject& aGlobal, JSContext* aCx,
               const nsAString& aScriptURL, const Optional<nsAString>& aName,
               ErrorResult& aRv);
 
-  already_AddRefed<MessagePort>
+  already_AddRefed<mozilla::dom::workers::MessagePort>
   Port();
 
   uint64_t
   Serial() const
   {
     return mSerial;
   }
 
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -1207,18 +1207,18 @@ EventRunnable::PreDispatch(JSContext* aC
             }
           }
         }
 
         if (doClone) {
           // Anything subject to GC must be cloned.
           JSStructuredCloneCallbacks* callbacks =
             aWorkerPrivate->IsChromeWorker() ?
-            ChromeWorkerStructuredCloneCallbacks(true) :
-            WorkerStructuredCloneCallbacks(true);
+            workers::ChromeWorkerStructuredCloneCallbacks(true) :
+            workers::WorkerStructuredCloneCallbacks(true);
 
           nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
 
           if (mResponseBuffer.write(aCx, response, transferable, callbacks,
                                     &clonedObjects)) {
             mClonedObjects.SwapElements(clonedObjects);
           } else {
             NS_WARNING("Failed to clone response!");
@@ -1315,18 +1315,18 @@ EventRunnable::WorkerRun(JSContext* aCx,
     if (NS_SUCCEEDED(mResponseResult)) {
       if (mResponseBuffer.data()) {
         MOZ_ASSERT(mResponse.isUndefined());
 
         JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer));
 
         JSStructuredCloneCallbacks* callbacks =
           aWorkerPrivate->IsChromeWorker() ?
-          ChromeWorkerStructuredCloneCallbacks(false) :
-          WorkerStructuredCloneCallbacks(false);
+          workers::ChromeWorkerStructuredCloneCallbacks(false) :
+          workers::WorkerStructuredCloneCallbacks(false);
 
         nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
         clonedObjects.SwapElements(mClonedObjects);
 
         JS::Rooted<JS::Value> response(aCx);
         if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) {
           return false;
         }
@@ -1499,18 +1499,18 @@ SendRunnable::MainThreadRun()
 
     nsIXPConnect* xpc = nsContentUtils::XPConnect();
     MOZ_ASSERT(xpc);
 
     nsresult rv = NS_OK;
 
     JSStructuredCloneCallbacks* callbacks =
       mWorkerPrivate->IsChromeWorker() ?
-      ChromeWorkerStructuredCloneCallbacks(true) :
-      WorkerStructuredCloneCallbacks(true);
+      workers::ChromeWorkerStructuredCloneCallbacks(true) :
+      workers::WorkerStructuredCloneCallbacks(true);
 
     JS::Rooted<JS::Value> body(cx);
     if (mBody.read(cx, &body, callbacks, &mClonedObjects)) {
       if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) {
         rv = NS_ERROR_DOM_INVALID_STATE_ERR;
       }
     }
     else {
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -31,17 +31,17 @@ EXPORTS.mozilla.dom.workers.bindings += 
     'ServiceWorker.h',
     'SharedWorker.h',
     'URL.h',
     'WorkerFeature.h',
     'XMLHttpRequest.h',
     'XMLHttpRequestUpload.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'ChromeWorkerScope.cpp',
     'DataStore.cpp',
     'DataStoreCursor.cpp',
     'File.cpp',
     'FileReaderSync.cpp',
     'Location.cpp',
     'MessagePort.cpp',
     'Navigator.cpp',
--- a/dom/workers/test/test_simpleThread.html
+++ b/dom/workers/test/test_simpleThread.html
@@ -47,17 +47,17 @@ Tests of DOM Worker Threads (Bug 437152)
   worker.onerror = function(event) {
     event.preventDefault();
     is(event.target, worker);
     is(event.message, "InternalError: uncaught exception: Bad message: asdf");
 
     worker.onerror = function(otherEvent) {
       otherEvent.preventDefault();
       is(otherEvent.target, worker);
-      ok(otherEvent.message.contains("ReferenceError: Components is not defined"));
+      is(otherEvent.message, "ReferenceError: Components is not defined");
       gotErrors = true;
 
       worker.onerror = function(oneMoreEvent) {
         ok(false, "Worker had an error:" + oneMoreEvent.message);
         SimpleTest.finish();
       };
     };
   };
--- a/gfx/2d/Tools.h
+++ b/gfx/2d/Tools.h
@@ -128,38 +128,40 @@ struct AlignedArray
       // Since we used the placement |operator new| function to construct the
       // elements of this array we need to invoke their destructors manually.
       // For types where the destructor does nothing the compiler's dead code
       // elimination step should optimize this loop away.
       mPtr[i].~T();
     }
 #endif
 
-    delete [] mStorage;
+    moz_free(mStorage);
     mStorage = nullptr;
     mPtr = nullptr;
   }
 
   MOZ_ALWAYS_INLINE void Realloc(size_t aCount, bool aZero = false)
   {
-    delete [] mStorage;
+    moz_free(mStorage);
     CheckedInt32 storageByteCount =
       CheckedInt32(sizeof(T)) * aCount + (alignment - 1);
     if (!storageByteCount.isValid()) {
       mStorage = nullptr;
       mPtr = nullptr;
       mCount = 0;
       return;
     }
     // We don't create an array of T here, since we don't want ctors to be
     // invoked at the wrong places if we realign below.
     if (aZero) {
-      mStorage = static_cast<uint8_t *>(calloc(1, storageByteCount.value()));
+      // calloc can be more efficient than new[] for large chunks,
+      // so we use calloc/malloc/free for everything.
+      mStorage = static_cast<uint8_t *>(moz_calloc(1, storageByteCount.value()));
     } else {
-      mStorage = new (std::nothrow) uint8_t[storageByteCount.value()];
+      mStorage = static_cast<uint8_t *>(moz_malloc(storageByteCount.value()));
     }
     if (!mStorage) {
       mStorage = nullptr;
       mPtr = nullptr;
       mCount = 0;
       return;
     }
     if (uintptr_t(mStorage) % alignment) {
deleted file mode 100644
--- a/gfx/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp.orig
+++ /dev/null
@@ -1,490 +0,0 @@
-//
-// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#include "angle_gl.h"
-#include "compiler/translator/BuiltInFunctionEmulator.h"
-#include "compiler/translator/SymbolTable.h"
-
-namespace {
-
-// we use macros here instead of function definitions to work around more GLSL
-// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
-// problematic because if the argument has side-effects they will be repeatedly
-// evaluated. This is unlikely to show up in real shaders, but is something to
-// consider.
-const char* kFunctionEmulationVertexSource[] = {
-    "#error no emulation for cos(float)",
-    "#error no emulation for cos(vec2)",
-    "#error no emulation for cos(vec3)",
-    "#error no emulation for cos(vec4)",
-
-    "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
-    "#error no emulation for distance(vec2, vec2)",
-    "#error no emulation for distance(vec3, vec3)",
-    "#error no emulation for distance(vec4, vec4)",
-
-    "#define webgl_dot_emu(x, y) ((x) * (y))",
-    "#error no emulation for dot(vec2, vec2)",
-    "#error no emulation for dot(vec3, vec3)",
-    "#error no emulation for dot(vec4, vec4)",
-
-    "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
-    "#error no emulation for length(vec2)",
-    "#error no emulation for length(vec3)",
-    "#error no emulation for length(vec4)",
-
-    "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
-    "#error no emulation for normalize(vec2)",
-    "#error no emulation for normalize(vec3)",
-    "#error no emulation for normalize(vec4)",
-
-    "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
-    "#error no emulation for reflect(vec2, vec2)",
-    "#error no emulation for reflect(vec3, vec3)",
-    "#error no emulation for reflect(vec4, vec4)",
-
-    // |faceforward(N, I, Nref)| is |dot(NRef, I) < 0 ? N : -N|
-    "#define webgl_faceforward_emu(N, I, Nref) (((Nref) * (I) < 0.0) ? (N) : -(N))",
-    "#error no emulation for faceforward(vec2, vec2, vec2)",
-    "#error no emulation for faceforward(vec3, vec3, vec3)",
-    "#error no emulation for faceforward(vec4, vec4, vec4)"
-};
-
-const char* kFunctionEmulationFragmentSource[] = {
-    "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
-    "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
-    "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
-    "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
-
-    "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
-    "#error no emulation for distance(vec2, vec2)",
-    "#error no emulation for distance(vec3, vec3)",
-    "#error no emulation for distance(vec4, vec4)",
-
-    "#define webgl_dot_emu(x, y) ((x) * (y))",
-    "#error no emulation for dot(vec2, vec2)",
-    "#error no emulation for dot(vec3, vec3)",
-    "#error no emulation for dot(vec4, vec4)",
-
-    "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
-    "#error no emulation for length(vec2)",
-    "#error no emulation for length(vec3)",
-    "#error no emulation for length(vec4)",
-
-    "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
-    "#error no emulation for normalize(vec2)",
-    "#error no emulation for normalize(vec3)",
-    "#error no emulation for normalize(vec4)",
-
-    "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
-    "#error no emulation for reflect(vec2, vec2)",
-    "#error no emulation for reflect(vec3, vec3)",
-    "#error no emulation for reflect(vec4, vec4)",
-
-    // |faceforward(N, I, Nref)| is |dot(NRef, I) < 0 ? N : -N|
-    "#define webgl_faceforward_emu(N, I, Nref) (((Nref) * (I) < 0.0) ? (N) : -(N))",
-    "#error no emulation for faceforward(vec2, vec2, vec2)",
-    "#error no emulation for faceforward(vec3, vec3, vec3)",
-    "#error no emulation for faceforward(vec4, vec4, vec4)"
-};
-
-const bool kFunctionEmulationVertexMask[] = {
-#if defined(__APPLE__)
-    // Work around ATI driver bugs in Mac.
-    false, // TFunctionCos1
-    false, // TFunctionCos2
-    false, // TFunctionCos3
-    false, // TFunctionCos4
-    true,  // TFunctionDistance1_1
-    false, // TFunctionDistance2_2
-    false, // TFunctionDistance3_3
-    false, // TFunctionDistance4_4
-    true,  // TFunctionDot1_1
-    false, // TFunctionDot2_2
-    false, // TFunctionDot3_3
-    false, // TFunctionDot4_4
-    true,  // TFunctionLength1
-    false, // TFunctionLength2
-    false, // TFunctionLength3
-    false, // TFunctionLength4
-    true,  // TFunctionNormalize1
-    false, // TFunctionNormalize2
-    false, // TFunctionNormalize3
-    false, // TFunctionNormalize4
-    true,  // TFunctionReflect1_1
-    false, // TFunctionReflect2_2
-    false, // TFunctionReflect3_3
-    false, // TFunctionReflect4_4
-    true,  // TFunctionFaceForward1_1_1
-    false, // TFunctionFaceForward2_2_2
-    false, // TFunctionFaceForward3_3_3
-    false, // TFunctionFaceForward4_4_4
-#else
-    // Work around D3D driver bug in Win.
-    false, // TFunctionCos1
-    false, // TFunctionCos2
-    false, // TFunctionCos3
-    false, // TFunctionCos4
-    false, // TFunctionDistance1_1
-    false, // TFunctionDistance2_2
-    false, // TFunctionDistance3_3
-    false, // TFunctionDistance4_4
-    false, // TFunctionDot1_1
-    false, // TFunctionDot2_2
-    false, // TFunctionDot3_3
-    false, // TFunctionDot4_4
-    false, // TFunctionLength1
-    false, // TFunctionLength2
-    false, // TFunctionLength3
-    false, // TFunctionLength4
-    false, // TFunctionNormalize1
-    false, // TFunctionNormalize2
-    false, // TFunctionNormalize3
-    false, // TFunctionNormalize4
-    false, // TFunctionReflect1_1
-    false, // TFunctionReflect2_2
-    false, // TFunctionReflect3_3
-    false, // TFunctionReflect4_4
-    false, // TFunctionFaceForward1_1_1
-    false, // TFunctionFaceForward2_2_2
-    false, // TFunctionFaceForward3_3_3
-    false, // TFunctionFaceForward4_4_4
-#endif
-    false  // TFunctionUnknown
-};
-
-const bool kFunctionEmulationFragmentMask[] = {
-#if defined(__APPLE__)
-    // Work around ATI driver bugs in Mac.
-    true,  // TFunctionCos1
-    true,  // TFunctionCos2
-    true,  // TFunctionCos3
-    true,  // TFunctionCos4
-    true,  // TFunctionDistance1_1
-    false, // TFunctionDistance2_2
-    false, // TFunctionDistance3_3
-    false, // TFunctionDistance4_4
-    true,  // TFunctionDot1_1
-    false, // TFunctionDot2_2
-    false, // TFunctionDot3_3
-    false, // TFunctionDot4_4
-    true,  // TFunctionLength1
-    false, // TFunctionLength2
-    false, // TFunctionLength3
-    false, // TFunctionLength4
-    true,  // TFunctionNormalize1
-    false, // TFunctionNormalize2
-    false, // TFunctionNormalize3
-    false, // TFunctionNormalize4
-    true,  // TFunctionReflect1_1
-    false, // TFunctionReflect2_2
-    false, // TFunctionReflect3_3
-    false, // TFunctionReflect4_4
-    true,  // TFunctionFaceForward1_1_1
-    false, // TFunctionFaceForward2_2_2
-    false, // TFunctionFaceForward3_3_3
-    false, // TFunctionFaceForward4_4_4
-#else
-    // Work around D3D driver bug in Win.
-    false, // TFunctionCos1
-    false, // TFunctionCos2
-    false, // TFunctionCos3
-    false, // TFunctionCos4
-    false, // TFunctionDistance1_1
-    false, // TFunctionDistance2_2
-    false, // TFunctionDistance3_3
-    false, // TFunctionDistance4_4
-    false, // TFunctionDot1_1
-    false, // TFunctionDot2_2
-    false, // TFunctionDot3_3
-    false, // TFunctionDot4_4
-    false, // TFunctionLength1
-    false, // TFunctionLength2
-    false, // TFunctionLength3
-    false, // TFunctionLength4
-    false, // TFunctionNormalize1
-    false, // TFunctionNormalize2
-    false, // TFunctionNormalize3
-    false, // TFunctionNormalize4
-    false, // TFunctionReflect1_1
-    false, // TFunctionReflect2_2
-    false, // TFunctionReflect3_3
-    false, // TFunctionReflect4_4
-    false, // TFunctionFaceForward1_1_1
-    false, // TFunctionFaceForward2_2_2
-    false, // TFunctionFaceForward3_3_3
-    false, // TFunctionFaceForward4_4_4
-#endif
-    false  // TFunctionUnknown
-};
-
-class BuiltInFunctionEmulationMarker : public TIntermTraverser {
-public:
-    BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
-        : mEmulator(emulator)
-    {
-    }
-
-    virtual bool visitUnary(Visit visit, TIntermUnary* node)
-    {
-        if (visit == PreVisit) {
-            bool needToEmulate = mEmulator.SetFunctionCalled(
-                node->getOp(), node->getOperand()->getType());
-            if (needToEmulate)
-                node->setUseEmulatedFunction();
-        }
-        return true;
-    }
-
-    virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
-    {
-        if (visit == PreVisit) {
-            // Here we handle all the built-in functions instead of the ones we
-            // currently identified as problematic.
-            switch (node->getOp()) {
-                case EOpLessThan:
-                case EOpGreaterThan:
-                case EOpLessThanEqual:
-                case EOpGreaterThanEqual:
-                case EOpVectorEqual:
-                case EOpVectorNotEqual:
-                case EOpMod:
-                case EOpPow:
-                case EOpAtan:
-                case EOpMin:
-                case EOpMax:
-                case EOpClamp:
-                case EOpMix:
-                case EOpStep:
-                case EOpSmoothStep:
-                case EOpDistance:
-                case EOpDot:
-                case EOpCross:
-                case EOpFaceForward:
-                case EOpReflect:
-                case EOpRefract:
-                case EOpMul:
-                    break;
-                default:
-                    return true;
-            };
-<<<<<<< HEAD
-            const TIntermSequence& sequence = *(node->getSequence());
-            // Right now we only handle built-in functions with two parameters.
-            if (sequence.size() != 2)
-                return true;
-            TIntermTyped* param1 = sequence[0]->getAsTyped();
-            TIntermTyped* param2 = sequence[1]->getAsTyped();
-            if (!param1 || !param2)
-=======
-            const TIntermSequence& sequence = node->getSequence();
-            bool needToEmulate = false;
-
-            if (sequence.size() == 2) {
-                TIntermTyped* param1 = sequence[0]->getAsTyped();
-                TIntermTyped* param2 = sequence[1]->getAsTyped();
-                if (!param1 || !param2)
-                    return true;
-                needToEmulate = mEmulator.SetFunctionCalled(
-                    node->getOp(), param1->getType(), param2->getType());
-            } else if (sequence.size() == 3) {
-                TIntermTyped* param1 = sequence[0]->getAsTyped();
-                TIntermTyped* param2 = sequence[1]->getAsTyped();
-                TIntermTyped* param3 = sequence[2]->getAsTyped();
-                if (!param1 || !param2 || !param3)
-                    return true;
-                needToEmulate = mEmulator.SetFunctionCalled(
-                    node->getOp(), param1->getType(), param2->getType(), param3->getType());
-            } else {
->>>>>>> 700b9c6... Emulate faceforward(float, float, float) when function emulation is enabled
-                return true;
-            }
-            if (needToEmulate)
-                node->setUseEmulatedFunction();
-        }
-        return true;
-    }
-
-private:
-    BuiltInFunctionEmulator& mEmulator;
-};
-
-}  // anonymous namepsace
-
-BuiltInFunctionEmulator::BuiltInFunctionEmulator(sh::GLenum shaderType)
-{
-    if (shaderType == GL_FRAGMENT_SHADER) {
-        mFunctionMask = kFunctionEmulationFragmentMask;
-        mFunctionSource = kFunctionEmulationFragmentSource;
-    } else {
-        mFunctionMask = kFunctionEmulationVertexMask;
-        mFunctionSource = kFunctionEmulationVertexSource;
-    }
-}
-
-bool BuiltInFunctionEmulator::SetFunctionCalled(
-    TOperator op, const TType& param)
-{
-    TBuiltInFunction function = IdentifyFunction(op, param);
-    return SetFunctionCalled(function);
-}
-
-bool BuiltInFunctionEmulator::SetFunctionCalled(
-    TOperator op, const TType& param1, const TType& param2)
-{
-    TBuiltInFunction function = IdentifyFunction(op, param1, param2);
-    return SetFunctionCalled(function);
-}
-
-bool BuiltInFunctionEmulator::SetFunctionCalled(
-    TOperator op, const TType& param1, const TType& param2, const TType& param3)
-{
-    TBuiltInFunction function = IdentifyFunction(op, param1, param2, param3);
-    return SetFunctionCalled(function);
-}
-
-bool BuiltInFunctionEmulator::SetFunctionCalled(
-    BuiltInFunctionEmulator::TBuiltInFunction function) {
-    if (function == TFunctionUnknown || mFunctionMask[function] == false)
-        return false;
-    for (size_t i = 0; i < mFunctions.size(); ++i) {
-        if (mFunctions[i] == function)
-            return true;
-    }
-    mFunctions.push_back(function);
-    return true;
-}
-
-void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
-    TInfoSinkBase& out, bool withPrecision) const
-{
-    if (mFunctions.size() == 0)
-        return;
-    out << "// BEGIN: Generated code for built-in function emulation\n\n";
-    if (withPrecision) {
-        out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
-            << "#define webgl_emu_precision highp\n"
-            << "#else\n"
-            << "#define webgl_emu_precision mediump\n"
-            << "#endif\n\n";
-    } else {
-        out << "#define webgl_emu_precision\n\n";
-    }
-    for (size_t i = 0; i < mFunctions.size(); ++i) {
-        out << mFunctionSource[mFunctions[i]] << "\n\n";
-    }
-    out << "// END: Generated code for built-in function emulation\n\n";
-}
-
-BuiltInFunctionEmulator::TBuiltInFunction
-BuiltInFunctionEmulator::IdentifyFunction(
-    TOperator op, const TType& param)
-{
-    if (param.getNominalSize() > 4 || param.getSecondarySize() > 4)
-        return TFunctionUnknown;
-    unsigned int function = TFunctionUnknown;
-    switch (op) {
-        case EOpCos:
-            function = TFunctionCos1;
-            break;
-        case EOpLength:
-            function = TFunctionLength1;
-            break;
-        case EOpNormalize:
-            function = TFunctionNormalize1;
-            break;
-        default:
-            break;
-    }
-    if (function == TFunctionUnknown)
-        return TFunctionUnknown;
-    if (param.isVector())
-        function += param.getNominalSize() - 1;
-    return static_cast<TBuiltInFunction>(function);
-}
-
-BuiltInFunctionEmulator::TBuiltInFunction
-BuiltInFunctionEmulator::IdentifyFunction(
-    TOperator op, const TType& param1, const TType& param2)
-{
-    // Right now for all the emulated functions with two parameters, the two
-    // parameters have the same type.
-    if (param1.getNominalSize()     != param2.getNominalSize()   ||
-        param1.getSecondarySize()   != param2.getSecondarySize() ||
-        param1.getNominalSize() > 4 || param1.getSecondarySize() > 4)
-        return TFunctionUnknown;
-
-    unsigned int function = TFunctionUnknown;
-    switch (op) {
-        case EOpDistance:
-            function = TFunctionDistance1_1;
-            break;
-        case EOpDot:
-            function = TFunctionDot1_1;
-            break;
-        case EOpReflect:
-            function = TFunctionReflect1_1;
-            break;
-        default:
-            break;
-    }
-    if (function == TFunctionUnknown)
-        return TFunctionUnknown;
-    if (param1.isVector())
-        function += param1.getNominalSize() - 1;
-    return static_cast<TBuiltInFunction>(function);
-}
-
-BuiltInFunctionEmulator::TBuiltInFunction
-BuiltInFunctionEmulator::IdentifyFunction(
-    TOperator op, const TType& param1, const TType& param2, const TType& param3)
-{
-    // Check that all params have the same type, length,
-    // and that they're not too large.
-    if (param1.isVector() != param2.isVector() ||
-        param2.isVector() != param3.isVector() ||
-        param1.getNominalSize() != param2.getNominalSize() ||
-        param2.getNominalSize() != param3.getNominalSize() ||
-        param1.getNominalSize() > 4)
-        return TFunctionUnknown;
-
-    unsigned int function = TFunctionUnknown;
-    switch (op) {
-        case EOpFaceForward:
-            function = TFunctionFaceForward1_1_1;
-            break;
-        default:
-            break;
-    }
-    if (function == TFunctionUnknown)
-        return TFunctionUnknown;
-    if (param1.isVector())
-        function += param1.getNominalSize() - 1;
-    return static_cast<TBuiltInFunction>(function);
-}
-
-void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
-    TIntermNode* root)
-{
-    ASSERT(root);
-
-    BuiltInFunctionEmulationMarker marker(*this);
-    root->traverse(&marker);
-}
-
-void BuiltInFunctionEmulator::Cleanup()
-{
-    mFunctions.clear();
-}
-
-//static
-TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
-    const TString& name)
-{
-    ASSERT(name[name.length() - 1] == '(');
-    return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
-}
-
deleted file mode 100644
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp.orig
+++ /dev/null
@@ -1,629 +0,0 @@
-//
-// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// formatutils9.cpp: Queries for GL image formats and their translations to D3D9
-// formats.
-
-#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h"
-#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h"
-#include "libGLESv2/renderer/generatemip.h"
-#include "libGLESv2/renderer/loadimage.h"
-#include "libGLESv2/renderer/copyimage.h"
-#include "libGLESv2/renderer/vertexconversion.h"
-
-namespace rx
-{
-
-namespace d3d9
-{
-
-const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z')));
-const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L')));
-
-struct D3D9FastCopyFormat
-{
-    GLenum destFormat;
-    GLenum destType;
-    ColorCopyFunction copyFunction;
-
-    D3D9FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction)
-        : destFormat(destFormat), destType(destType), copyFunction(copyFunction)
-    { }
-
-    bool operator<(const D3D9FastCopyFormat& other) const
-    {
-        return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0;
-    }
-};
-
-typedef std::multimap<D3DFORMAT, D3D9FastCopyFormat> D3D9FastCopyMap;
-
-static D3D9FastCopyMap BuildFastCopyMap()
-{
-    D3D9FastCopyMap map;
-
-<<<<<<< HEAD
-    map.insert(std::make_pair(D3DFMT_A8R8G8B8, D3D9FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8)));
-=======
-    //                       | Internal format                                   | Texture format      | Render format        | Load function                           |
-    map.insert(D3D9FormatPair(GL_NONE,                             D3D9FormatInfo(D3DFMT_NULL,          D3DFMT_NULL,           UnreachableLoad                          )));
-
-    map.insert(D3D9FormatPair(GL_DEPTH_COMPONENT16,                D3D9FormatInfo(D3DFMT_INTZ,          D3DFMT_D24S8,          UnreachableLoad                          )));
-    map.insert(D3D9FormatPair(GL_DEPTH_COMPONENT32_OES,            D3D9FormatInfo(D3DFMT_INTZ,          D3DFMT_D32,            UnreachableLoad                          )));
-    map.insert(D3D9FormatPair(GL_DEPTH24_STENCIL8_OES,             D3D9FormatInfo(D3DFMT_INTZ,          D3DFMT_D24S8,          UnreachableLoad                          )));
-    map.insert(D3D9FormatPair(GL_STENCIL_INDEX8,                   D3D9FormatInfo(D3DFMT_UNKNOWN,       D3DFMT_D24S8,          UnreachableLoad                          ))); // TODO: What's the texture format?
-
-    map.insert(D3D9FormatPair(GL_RGBA32F_EXT,                      D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F,  loadToNative<GLfloat, 4>                 )));
-    map.insert(D3D9FormatPair(GL_RGB32F_EXT,                       D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F,  loadToNative3To4<GLfloat, gl::Float32One>)));
-    map.insert(D3D9FormatPair(GL_RG32F_EXT,                        D3D9FormatInfo(D3DFMT_G32R32F,       D3DFMT_G32R32F,        loadToNative<GLfloat, 2>                 )));
-    map.insert(D3D9FormatPair(GL_R32F_EXT,                         D3D9FormatInfo(D3DFMT_R32F,          D3DFMT_R32F,           loadToNative<GLfloat, 1>                 )));
-    map.insert(D3D9FormatPair(GL_ALPHA32F_EXT,                     D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN,        loadAlphaFloatDataToRGBA                 )));
-    map.insert(D3D9FormatPair(GL_LUMINANCE32F_EXT,                 D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN,        loadLuminanceFloatDataToRGBA             )));
-    map.insert(D3D9FormatPair(GL_LUMINANCE_ALPHA32F_EXT,           D3D9FormatInfo(D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN,        loadLuminanceAlphaFloatDataToRGBA        )));
-
-    map.insert(D3D9FormatPair(GL_RGBA16F_EXT,                      D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F,  loadToNative<GLhalf, 4>                  )));
-    map.insert(D3D9FormatPair(GL_RGB16F_EXT,                       D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F,  loadToNative3To4<GLhalf, gl::Float16One> )));
-    map.insert(D3D9FormatPair(GL_RG16F_EXT,                        D3D9FormatInfo(D3DFMT_G16R16F,       D3DFMT_G16R16F,        loadToNative<GLhalf, 2>                  )));
-    map.insert(D3D9FormatPair(GL_R16F_EXT,                         D3D9FormatInfo(D3DFMT_R16F,          D3DFMT_R16F,           loadToNative<GLhalf, 1>                  )));
-    map.insert(D3D9FormatPair(GL_ALPHA16F_EXT,                     D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN,        loadAlphaHalfFloatDataToRGBA             )));
-    map.insert(D3D9FormatPair(GL_LUMINANCE16F_EXT,                 D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN,        loadLuminanceHalfFloatDataToRGBA         )));
-    map.insert(D3D9FormatPair(GL_LUMINANCE_ALPHA16F_EXT,           D3D9FormatInfo(D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN,        loadLuminanceAlphaHalfFloatDataToRGBA    )));
-
-    map.insert(D3D9FormatPair(GL_ALPHA8_EXT,                       D3D9FormatInfo(D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       FallbackLoad<gl::supportsSSE2, loadAlphaDataToBGRASSE2, loadAlphaDataToBGRA>)));
-
-    map.insert(D3D9FormatPair(GL_RGB8_OES,                         D3D9FormatInfo(D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       loadRGBUByteDataToBGRX                    )));
-    map.insert(D3D9FormatPair(GL_RGB565,                           D3D9FormatInfo(D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       loadRGB565DataToBGRA                      )));
-    map.insert(D3D9FormatPair(GL_RGBA8_OES,                        D3D9FormatInfo(D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       FallbackLoad<gl::supportsSSE2, loadRGBAUByteDataToBGRASSE2, loadRGBAUByteDataToBGRA>)));
-    map.insert(D3D9FormatPair(GL_RGBA4,                            D3D9FormatInfo(D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       loadRGBA4444DataToBGRA                    )));
-    map.insert(D3D9FormatPair(GL_RGB5_A1,                          D3D9FormatInfo(D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       loadRGBA5551DataToBGRA                    )));
-    map.insert(D3D9FormatPair(GL_R8_EXT,                           D3D9FormatInfo(D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       loadRUByteDataToBGRX                      )));
-    map.insert(D3D9FormatPair(GL_RG8_EXT,                          D3D9FormatInfo(D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       loadRGUByteDataToBGRX                     )));
-
-    map.insert(D3D9FormatPair(GL_BGRA8_EXT,                        D3D9FormatInfo(D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       loadToNative<GLubyte, 4>                  )));
-    map.insert(D3D9FormatPair(GL_BGRA4_ANGLEX,                     D3D9FormatInfo(D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       loadRGBA4444DataToRGBA                    )));
-    map.insert(D3D9FormatPair(GL_BGR5_A1_ANGLEX,                   D3D9FormatInfo(D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       loadRGBA5551DataToRGBA                    )));
-
-    map.insert(D3D9FormatPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT,     D3D9FormatInfo(D3DFMT_DXT1,          D3DFMT_UNKNOWN,        loadCompressedBlockDataToNative<4, 4,  8> )));
-    map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,    D3D9FormatInfo(D3DFMT_DXT1,          D3DFMT_UNKNOWN,        loadCompressedBlockDataToNative<4, 4,  8> )));
-    map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,  D3D9FormatInfo(D3DFMT_DXT3,          D3DFMT_UNKNOWN,        loadCompressedBlockDataToNative<4, 4, 16> )));
-    map.insert(D3D9FormatPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,  D3D9FormatInfo(D3DFMT_DXT5,          D3DFMT_UNKNOWN,        loadCompressedBlockDataToNative<4, 4, 16> )));
-
-    // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and
-    // then changing the format and loading function appropriately.
-    map.insert(D3D9FormatPair(GL_LUMINANCE8_EXT,                   D3D9FormatInfo(D3DFMT_L8,            D3DFMT_L8,             loadToNative<GLubyte, 1>                  )));
-    map.insert(D3D9FormatPair(GL_LUMINANCE8_ALPHA8_EXT,            D3D9FormatInfo(D3DFMT_A8L8,          D3DFMT_A8L8,           loadToNative<GLubyte, 2>                  )));
->>>>>>> 20c20e0... Fix for Windows XP conformance crash
-
-    return map;
-}
-
-// A map to determine the pixel size and mip generation function of a given D3D format
-typedef std::map<D3DFORMAT, D3DFormat> D3D9FormatInfoMap;
-
-D3DFormat::D3DFormat()
-    : pixelBytes(0),
-      blockWidth(0),
-      blockHeight(0),
-      internalFormat(GL_NONE),
-      mipGenerationFunction(NULL),
-      colorReadFunction(NULL),
-      fastCopyFunctions()
-{
-}
-
-ColorCopyFunction D3DFormat::getFastCopyFunction(GLenum format, GLenum type) const
-{
-    FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type));
-    return (iter != fastCopyFunctions.end()) ? iter->second : NULL;
-}
-
-static inline void InsertD3DFormatInfo(D3D9FormatInfoMap *map, D3DFORMAT format, GLuint bits, GLuint blockWidth,
-                                       GLuint blockHeight, GLenum internalFormat, MipGenerationFunction mipFunc,
-                                       ColorReadFunction colorReadFunc)
-{
-    D3DFormat info;
-    info.pixelBytes = bits / 8;
-    info.blockWidth = blockWidth;
-    info.blockHeight = blockHeight;
-    info.internalFormat = internalFormat;
-    info.mipGenerationFunction = mipFunc;
-    info.colorReadFunction = colorReadFunc;
-
-    static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap();
-    std::pair<D3D9FastCopyMap::const_iterator, D3D9FastCopyMap::const_iterator> fastCopyIter = fastCopyMap.equal_range(format);
-    for (D3D9FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++)
-    {
-        info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction));
-    }
-
-    map->insert(std::make_pair(format, info));
-}
-
-static D3D9FormatInfoMap BuildD3D9FormatInfoMap()
-{
-    D3D9FormatInfoMap map;
-
-    //                       | D3DFORMAT           | S  |W |H | Internal format                   | Mip generation function   | Color read function             |
-    InsertD3DFormatInfo(&map, D3DFMT_NULL,            0, 0, 0, GL_NONE,                            NULL,                       NULL                             );
-    InsertD3DFormatInfo(&map, D3DFMT_UNKNOWN,         0, 0, 0, GL_NONE,                            NULL,                       NULL                             );
-
-    InsertD3DFormatInfo(&map, D3DFMT_L8,              8, 1, 1, GL_LUMINANCE8_EXT,                  GenerateMip<L8>,            ReadColor<L8, GLfloat>           );
-    InsertD3DFormatInfo(&map, D3DFMT_A8,              8, 1, 1, GL_ALPHA8_EXT,                      GenerateMip<A8>,            ReadColor<A8, GLfloat>           );
-    InsertD3DFormatInfo(&map, D3DFMT_A8L8,           16, 1, 1, GL_LUMINANCE8_ALPHA8_EXT,           GenerateMip<A8L8>,          ReadColor<A8L8, GLfloat>         );
-    InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4,       16, 1, 1, GL_BGRA4_ANGLEX,                    GenerateMip<B4G4R4A4>,      ReadColor<B4G4R4A4, GLfloat>     );
-    InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5,       16, 1, 1, GL_BGR5_A1_ANGLEX,                  GenerateMip<B5G5R5A1>,      ReadColor<B5G5R5A1, GLfloat>     );
-    InsertD3DFormatInfo(&map, D3DFMT_R5G6B5,         16, 1, 1, GL_RGB565,                          GenerateMip<R5G6B5>,        ReadColor<R5G6B5, GLfloat>       );
-    InsertD3DFormatInfo(&map, D3DFMT_X8R8G8B8,       32, 1, 1, GL_BGRA8_EXT,                       GenerateMip<B8G8R8X8>,      ReadColor<B8G8R8X8, GLfloat>     );
-    InsertD3DFormatInfo(&map, D3DFMT_A8R8G8B8,       32, 1, 1, GL_BGRA8_EXT,                       GenerateMip<B8G8R8A8>,      ReadColor<B8G8R8A8, GLfloat>     );
-    InsertD3DFormatInfo(&map, D3DFMT_R16F,           16, 1, 1, GL_R16F_EXT,                        GenerateMip<R16F>,          ReadColor<R16F, GLfloat>         );
-    InsertD3DFormatInfo(&map, D3DFMT_G16R16F,        32, 1, 1, GL_RG16F_EXT,                       GenerateMip<R16G16F>,       ReadColor<R16G16F, GLfloat>      );
-    InsertD3DFormatInfo(&map, D3DFMT_A16B16G16R16F,  64, 1, 1, GL_RGBA16F_EXT,                     GenerateMip<R16G16B16A16F>, ReadColor<R16G16B16A16F, GLfloat>);
-    InsertD3DFormatInfo(&map, D3DFMT_R32F,           32, 1, 1, GL_R32F_EXT,                        GenerateMip<R32F>,          ReadColor<R32F, GLfloat>         );
-    InsertD3DFormatInfo(&map, D3DFMT_G32R32F,        64, 1, 1, GL_RG32F_EXT,                       GenerateMip<R32G32F>,       ReadColor<R32G32F, GLfloat>      );
-    InsertD3DFormatInfo(&map, D3DFMT_A32B32G32R32F, 128, 1, 1, GL_RGBA32F_EXT,                     GenerateMip<R32G32B32A32F>, ReadColor<R32G32B32A32F, GLfloat>);
-
-    InsertD3DFormatInfo(&map, D3DFMT_D16,            16, 1, 1, GL_DEPTH_COMPONENT16,               NULL,                       NULL                             );
-    InsertD3DFormatInfo(&map, D3DFMT_D24S8,          32, 1, 1, GL_DEPTH24_STENCIL8_OES,            NULL,                       NULL                             );
-    InsertD3DFormatInfo(&map, D3DFMT_D24X8,          32, 1, 1, GL_DEPTH_COMPONENT16,               NULL,                       NULL                             );
-    InsertD3DFormatInfo(&map, D3DFMT_D32,            32, 1, 1, GL_DEPTH_COMPONENT32_OES,           NULL,                       NULL                             );
-
-    InsertD3DFormatInfo(&map, D3DFMT_INTZ,           32, 1, 1, GL_DEPTH24_STENCIL8_OES,            NULL,                       NULL                             );
-
-    InsertD3DFormatInfo(&map, D3DFMT_DXT1,           64, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,   NULL,                       NULL                             );
-    InsertD3DFormatInfo(&map, D3DFMT_DXT3,          128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL,                       NULL                             );
-    InsertD3DFormatInfo(&map, D3DFMT_DXT5,          128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL,                       NULL                             );
-
-    return map;
-}
-
-const D3DFormat &GetD3DFormatInfo(D3DFORMAT format)
-{
-    static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap();
-    D3D9FormatInfoMap::const_iterator iter = infoMap.find(format);
-    if (iter != infoMap.end())
-    {
-        return iter->second;
-    }
-    else
-    {
-        static const D3DFormat defaultInfo;
-        return defaultInfo;
-    }
-}
-
-
-
-typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitialzerPair;
-typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitialzerMap;
-
-static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap()
-{
-    InternalFormatInitialzerMap map;
-
-    map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData<GLhalf,   0x0000,     0x0000,     0x0000,     gl::Float16One>));
-    map.insert(InternalFormatInitialzerPair(GL_RGB32F, Initialize4ComponentData<GLfloat,  0x00000000, 0x00000000, 0x00000000, gl::Float32One>));
-
-    return map;
-}
-
-// Each GL internal format corresponds to one D3D format and data loading function.
-// Due to not all formats being available all the time, some of the function/format types are wrapped
-// in templates that perform format support queries on a Renderer9 object which is supplied
-// when requesting the function or format.
-
-typedef bool(*FallbackPredicateFunction)();
-
-template <FallbackPredicateFunction pred, LoadImageFunction prefered, LoadImageFunction fallback>
-static void FallbackLoad(size_t width, size_t height, size_t depth,
-                         const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
-                         uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
-{
-    if (pred())
-    {
-        prefered(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch);
-    }
-    else
-    {
-        fallback(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch);
-    }
-}
-
-static void UnreachableLoad(size_t width, size_t height, size_t depth,
-                            const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
-                            uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
-{
-    UNREACHABLE();
-}
-
-typedef std::pair<GLenum, TextureFormat> D3D9FormatPair;
-typedef std::map<GLenum, TextureFormat> D3D9FormatMap;
-
-TextureFormat::TextureFormat()
-    : texFormat(D3DFMT_NULL),
-      renderFormat(D3DFMT_NULL),
-      dataInitializerFunction(NULL),
-      loadFunction(UnreachableLoad)
-{
-}
-
-static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalFormat, D3DFORMAT texFormat,
-                                        D3DFORMAT renderFormat, LoadImageFunction loadFunction)
-{
-    TextureFormat info;
-    info.texFormat = texFormat;
-    info.renderFormat = renderFormat;
-
-    static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap();
-    InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat);
-    info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL;
-
-    info.loadFunction = loadFunction;
-
-    map->insert(std::make_pair(internalFormat, info));
-}
-
-static D3D9FormatMap BuildD3D9FormatMap()
-{
-    D3D9FormatMap map;
-
-    //                       | Internal format                     | Texture format      | Render format        | Load function                           |
-    InsertD3D9FormatInfo(&map, GL_NONE,                             D3DFMT_NULL,          D3DFMT_NULL,           UnreachableLoad                          );
-
-    InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16,                D3DFMT_INTZ,          D3DFMT_D24S8,          UnreachableLoad                          );
-    InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES,            D3DFMT_INTZ,          D3DFMT_D32,            UnreachableLoad                          );
-    InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES,             D3DFMT_INTZ,          D3DFMT_D24S8,          UnreachableLoad                          );
-    InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8,                   D3DFMT_UNKNOWN,       D3DFMT_D24S8,          UnreachableLoad                          ); // TODO: What's the texture format?
-
-    InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT,                      D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F,  LoadToNative<GLfloat, 4>                 );
-    InsertD3D9FormatInfo(&map, GL_RGB32F_EXT,                       D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F,  LoadToNative3To4<GLfloat, gl::Float32One>);
-    InsertD3D9FormatInfo(&map, GL_RG32F_EXT,                        D3DFMT_G32R32F,       D3DFMT_G32R32F,        LoadToNative<GLfloat, 2>                 );
-    InsertD3D9FormatInfo(&map, GL_R32F_EXT,                         D3DFMT_R32F,          D3DFMT_R32F,           LoadToNative<GLfloat, 1>                 );
-    InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT,                     D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN,        LoadA32FToRGBA32F                        );
-    InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT,                 D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN,        LoadL32FToRGBA32F                        );
-    InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT,           D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN,        LoadLA32FToRGBA32F                       );
-
-    InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT,                      D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F,  LoadToNative<GLhalf, 4>                  );
-    InsertD3D9FormatInfo(&map, GL_RGB16F_EXT,                       D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F,  LoadToNative3To4<GLhalf, gl::Float16One> );
-    InsertD3D9FormatInfo(&map, GL_RG16F_EXT,                        D3DFMT_G16R16F,       D3DFMT_G16R16F,        LoadToNative<GLhalf, 2>                  );
-    InsertD3D9FormatInfo(&map, GL_R16F_EXT,                         D3DFMT_R16F,          D3DFMT_R16F,           LoadToNative<GLhalf, 1>                  );
-    InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT,                     D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN,        LoadA16FToRGBA16F                        );
-    InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT,                 D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN,        LoadL16FToRGBA16F                        );
-    InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT,           D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN,        LoadLA16FToRGBA16F                       );
-
-    InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT,                       D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       FallbackLoad<gl::supportsSSE2, LoadA8ToBGRA8_SSE2, LoadA8ToBGRA8>);
-
-    InsertD3D9FormatInfo(&map, GL_RGB8_OES,                         D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       LoadRGB8ToBGRX8                           );
-    InsertD3D9FormatInfo(&map, GL_RGB565,                           D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       LoadR5G6B5ToBGRA8                         );
-    InsertD3D9FormatInfo(&map, GL_RGBA8_OES,                        D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       FallbackLoad<gl::supportsSSE2, LoadRGBA8ToBGRA8_SSE2, LoadRGBA8ToBGRA8>);
-    InsertD3D9FormatInfo(&map, GL_RGBA4,                            D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       LoadRGBA4ToBGRA8                          );
-    InsertD3D9FormatInfo(&map, GL_RGB5_A1,                          D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       LoadRGB5A1ToBGRA8                         );
-    InsertD3D9FormatInfo(&map, GL_R8_EXT,                           D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       LoadR8ToBGRX8                             );
-    InsertD3D9FormatInfo(&map, GL_RG8_EXT,                          D3DFMT_X8R8G8B8,      D3DFMT_X8R8G8B8,       LoadRG8ToBGRX8                            );
-
-    InsertD3D9FormatInfo(&map, GL_BGRA8_EXT,                        D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       LoadToNative<GLubyte, 4>                  );
-    InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX,                     D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       LoadBGRA4ToBGRA8                          );
-    InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX,                   D3DFMT_A8R8G8B8,      D3DFMT_A8R8G8B8,       LoadBGR5A1ToBGRA8                         );
-
-    InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,     D3DFMT_DXT1,          D3DFMT_UNKNOWN,        LoadCompressedToNative<4, 4,  8>          );
-    InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,    D3DFMT_DXT1,          D3DFMT_UNKNOWN,        LoadCompressedToNative<4, 4,  8>          );
-    InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE,  D3DFMT_DXT3,          D3DFMT_UNKNOWN,        LoadCompressedToNative<4, 4, 16>          );
-    InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE,  D3DFMT_DXT5,          D3DFMT_UNKNOWN,        LoadCompressedToNative<4, 4, 16>          );
-
-    // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and
-    // then changing the format and loading function appropriately.
-    InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT,                   D3DFMT_L8,            D3DFMT_UNKNOWN,        LoadToNative<GLubyte, 1>                  );
-    InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT,            D3DFMT_A8L8,          D3DFMT_UNKNOWN,        LoadToNative<GLubyte, 2>                  );
-
-    return map;
-}
-
-const TextureFormat &GetTextureFormatInfo(GLenum internalFormat)
-{
-    static const D3D9FormatMap formatMap = BuildD3D9FormatMap();
-    D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat);
-    if (iter != formatMap.end())
-    {
-        return iter->second;
-    }
-    else
-    {
-        static const TextureFormat defaultInfo;
-        return defaultInfo;
-    }
-}
-
-static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType)
-{
-    switch (declType)
-    {
-      case D3DDECLTYPE_FLOAT1:   return GL_FLOAT;
-      case D3DDECLTYPE_FLOAT2:   return GL_FLOAT;
-      case D3DDECLTYPE_FLOAT3:   return GL_FLOAT;
-      case D3DDECLTYPE_FLOAT4:   return GL_FLOAT;
-      case D3DDECLTYPE_UBYTE4:   return GL_UNSIGNED_INT;
-      case D3DDECLTYPE_SHORT2:   return GL_INT;
-      case D3DDECLTYPE_SHORT4:   return GL_INT;
-      case D3DDECLTYPE_UBYTE4N:  return GL_UNSIGNED_NORMALIZED;
-      case D3DDECLTYPE_SHORT4N:  return GL_SIGNED_NORMALIZED;
-      case D3DDECLTYPE_USHORT4N: return GL_UNSIGNED_NORMALIZED;
-      case D3DDECLTYPE_SHORT2N:  return GL_SIGNED_NORMALIZED;
-      case D3DDECLTYPE_USHORT2N: return GL_UNSIGNED_NORMALIZED;
-      default: UNREACHABLE();    return GL_NONE;
-    }
-}
-
-// Attribute format conversion
-enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
-
-struct TranslationDescription
-{
-    DWORD capsFlag;
-    VertexFormat preferredConversion;
-    VertexFormat fallbackConversion;
-};
-
-// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
-//
-// BYTE                 SHORT (Cast)
-// BYTE-norm            FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
-// UNSIGNED_BYTE        UBYTE4 (Identity) or SHORT (Cast)
-// UNSIGNED_BYTE-norm   UBYTE4N (Identity) or FLOAT (Normalize)
-// SHORT                SHORT (Identity)
-// SHORT-norm           SHORT-norm (Identity) or FLOAT (Normalize)
-// UNSIGNED_SHORT       FLOAT (Cast)
-// UNSIGNED_SHORT-norm  USHORT-norm (Identity) or FLOAT (Normalize)
-// FIXED (not in WebGL) FLOAT (FixedToFloat)
-// FLOAT                FLOAT (Identity)
-
-// GLToCType maps from GL type (as GLenum) to the C typedef.
-template <GLenum GLType> struct GLToCType { };
-
-template <> struct GLToCType<GL_BYTE>           { typedef GLbyte type;      };
-template <> struct GLToCType<GL_UNSIGNED_BYTE>  { typedef GLubyte type;     };
-template <> struct GLToCType<GL_SHORT>          { typedef GLshort type;     };
-template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type;    };
-template <> struct GLToCType<GL_FIXED>          { typedef GLuint type;      };
-template <> struct GLToCType<GL_FLOAT>          { typedef GLfloat type;     };
-
-// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
-enum D3DVertexType
-{
-    D3DVT_FLOAT,
-    D3DVT_SHORT,
-    D3DVT_SHORT_NORM,
-    D3DVT_UBYTE,
-    D3DVT_UBYTE_NORM,
-    D3DVT_USHORT_NORM
-};
-
-// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
-template <unsigned int D3DType> struct D3DToCType { };
-
-template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
-template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
-template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
-template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
-template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
-template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
-
-// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
-template <unsigned int type, int size> struct WidenRule { };
-
-template <int size> struct WidenRule<D3DVT_FLOAT, size>          : NoWiden<size> { };
-template <int size> struct WidenRule<D3DVT_SHORT, size>          : WidenToEven<size> { };
-template <int size> struct WidenRule<D3DVT_SHORT_NORM, size>     : WidenToEven<size> { };
-template <int size> struct WidenRule<D3DVT_UBYTE, size>          : WidenToFour<size> { };
-template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size>     : WidenToFour<size> { };
-template <int size> struct WidenRule<D3DVT_USHORT_NORM, size>    : WidenToEven<size> { };
-
-// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
-template <unsigned int d3dtype, int size> struct VertexTypeFlags { };
-
-template <unsigned int _capflag, unsigned int _declflag>
-struct VertexTypeFlagsHelper
-{
-    enum { capflag = _capflag };
-    enum { declflag = _declflag };
-};
-
-template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
-template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
-template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
-template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
-template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
-template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
-template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
-template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
-template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
-template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
-template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
-template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
-
-
-// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
-template <GLenum GLtype, bool normalized> struct VertexTypeMapping { };
-
-template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
-struct VertexTypeMappingBase
-{
-    enum { preferred = Preferred };
-    enum { fallback = Fallback };
-};
-
-template <> struct VertexTypeMapping<GL_BYTE, false>                        : VertexTypeMappingBase<D3DVT_SHORT> { };                       // Cast
-template <> struct VertexTypeMapping<GL_BYTE, true>                         : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Normalize
-template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false>               : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { };          // Identity, Cast
-template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true>                : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { };     // Identity, Normalize
-template <> struct VertexTypeMapping<GL_SHORT, false>                       : VertexTypeMappingBase<D3DVT_SHORT> { };                       // Identity
-template <> struct VertexTypeMapping<GL_SHORT, true>                        : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { };     // Cast, Normalize
-template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false>              : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Cast
-template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true>               : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { };    // Cast, Normalize
-template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized>   : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // FixedToFloat
-template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized>   : VertexTypeMappingBase<D3DVT_FLOAT> { };                       // Identity
-
-
-// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
-// The conversion rules themselves are defined in vertexconversion.h.
-
-// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
-template <GLenum fromType, bool normalized, unsigned int toType>
-struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> { };
-
-// All conversions from normalized types to float use the Normalize operator.
-template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> { };
-
-// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules.
-template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT>  : FixedToFloat<GLint, 16> { };
-template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { };
-
-// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
-// whether it is normalized or not.
-template <class T, bool normalized> struct DefaultVertexValuesStage2 { };
-
-template <class T> struct DefaultVertexValuesStage2<T, true>  : NormalizedDefaultValues<T> { };
-template <class T> struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> { };
-
-// Work out the default value rule for a D3D type (expressed as the C type) and
-template <class T, bool normalized> struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> { };
-template <bool normalized> struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> { };
-
-// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
-// The fallback conversion produces an output that all D3D9 devices must support.
-template <class T> struct UsePreferred { enum { type = T::preferred }; };
-template <class T> struct UseFallback { enum { type = T::fallback }; };
-
-// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
-// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
-// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
-template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
-struct Converter
-    : VertexDataConverter<typename GLToCType<fromType>::type,
-                          WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
-                          ConversionRule<fromType,
-                                         normalized,
-                                         PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
-                          DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
-{
-private:
-    enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
-    enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
-
-public:
-    enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
-    enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
-};
-
-VertexFormat::VertexFormat()
-    : conversionType(VERTEX_CONVERT_NONE),
-      outputElementSize(0),
-      copyFunction(NULL),
-      nativeFormat(D3DDECLTYPE_UNUSED),
-      componentType(GL_NONE)
-{
-}
-
-// Initialize a TranslationInfo
-VertexFormat CreateVertexFormatInfo(bool identity, size_t elementSize, VertexCopyFunction copyFunc, D3DDECLTYPE nativeFormat)
-{
-    VertexFormat formatInfo;
-    formatInfo.conversionType = identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU;
-    formatInfo.outputElementSize = elementSize;
-    formatInfo.copyFunction = copyFunc;
-    formatInfo.nativeFormat = nativeFormat;
-    formatInfo.componentType = GetDeclTypeComponentType(nativeFormat);
-    return formatInfo;
-}
-
-#define TRANSLATION(type, norm, size, preferred)                                    \
-    CreateVertexFormatInfo                                                          \
-    (                                                                               \
-        Converter<type, norm, size, preferred>::identity,                           \
-        Converter<type, norm, size, preferred>::finalSize,                          \
-        Converter<type, norm, size, preferred>::convertArray,                       \
-        static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag)  \
-    )
-
-#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size)    \
-    {                                                       \
-        Converter<type, norm, size, UsePreferred>::capflag, \
-        TRANSLATION(type, norm, size, UsePreferred),        \
-        TRANSLATION(type, norm, size, UseFallback)          \
-    }
-
-#define TRANSLATIONS_FOR_TYPE(type)                                                                                                                                                                         \
-    {                                                                                                                                                                                                       \
-        { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
-        { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) },     \
-    }
-
-#define TRANSLATIONS_FOR_TYPE_NO_NORM(type)                                                                                                                                                                 \
-    {                                                                                                                                                                                                       \
-        { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
-        { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
-    }
-
-static inline unsigned int ComputeTypeIndex(GLenum type)
-{
-    switch (type)
-    {
-      case GL_BYTE:           return 0;
-      case GL_UNSIGNED_BYTE:  return 1;
-      case GL_SHORT:          return 2;
-      case GL_UNSIGNED_SHORT: return 3;
-      case GL_FIXED:          return 4;
-      case GL_FLOAT:          return 5;
-
-      default: UNREACHABLE(); return 5;
-    }
-}
-
-const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat)
-{
-    static bool initialized = false;
-    static DWORD intializedDeclTypes = 0;
-    static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
-    if (!initialized)
-    {
-        const TranslationDescription translations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
-        {
-            TRANSLATIONS_FOR_TYPE(GL_BYTE),
-            TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
-            TRANSLATIONS_FOR_TYPE(GL_SHORT),
-            TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
-            TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED),
-            TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT)
-        };
-        for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
-        {
-            for (unsigned int j = 0; j < 2; j++)
-            {
-                for (unsigned int k = 0; k < 4; k++)
-                {
-                    if (translations[i][j][k].capsFlag == 0 || (supportedDeclTypes & translations[i][j][k].capsFlag) != 0)
-                    {
-                        formatConverters[i][j][k] = translations[i][j][k].preferredConversion;
-                    }
-                    else
-                    {
-                        formatConverters[i][j][k] = translations[i][j][k].fallbackConversion;
-                    }
-                }
-            }
-        }
-        initialized = true;
-        intializedDeclTypes = supportedDeclTypes;
-    }
-
-    ASSERT(intializedDeclTypes == supportedDeclTypes);
-
-    // Pure integer attributes only supported in ES3.0
-    ASSERT(!vertexFormat.mPureInteger);
-    return formatConverters[ComputeTypeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1];
-}
-
-}
-
-}
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -583,16 +583,30 @@ already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
                                         bool* aOutInOverscrolledApzc)
 {
   nsRefPtr<AsyncPanZoomController> apzc;
   if (aEvent.mTouches.Length() == 0) {
     return apzc.forget();
   }
 
+  { // In this block we flush repaint requests for the entire APZ tree. We need to do this
+    // at the start of an input block for a number of reasons. One of the reasons is so that
+    // after we untransform the event into gecko space, it doesn't end up under something
+    // else. Another reason is that if we hit-test this event and end up on a layer's
+    // dispatch-to-content region we cannot be sure we actually got the correct layer. We
+    // have to fall back to the gecko hit-test to handle this case, but we can't untransform
+    // the event we send to gecko because we don't know the layer to untransform with
+    // respect to.
+    MonitorAutoLock lock(mTreeLock);
+    for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
+      FlushRepaintsRecursively(apzc);
+    }
+  }
+
   apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutInOverscrolledApzc);
   for (size_t i = 1; i < aEvent.mTouches.Length(); i++) {
     nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutInOverscrolledApzc);
     apzc = CommonAncestor(apzc.get(), apzc2.get());
     APZCTM_LOG("Using APZC %p as the common ancestor\n", apzc.get());
     // For now, we only ever want to do pinching on the root APZC for a given layers id. So
     // when we find the common ancestor of multiple points, also walk up to the root APZC.
     apzc = RootAPZCForLayersId(apzc);
@@ -832,16 +846,27 @@ APZCTreeManager::UpdateZoomConstraintsRe
     // We can have subtrees with their own layers id - leave those alone.
     if (!child->IsRootForLayersId()) {
       UpdateZoomConstraintsRecursively(child, aConstraints);
     }
   }
 }
 
 void
+APZCTreeManager::FlushRepaintsRecursively(AsyncPanZoomController* aApzc)
+{
+  mTreeLock.AssertCurrentThreadOwns();
+
+  aApzc->FlushRepaintForNewInputBlock();
+  for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
+    FlushRepaintsRecursively(child);
+  }
+}
+
+void
 APZCTreeManager::CancelAnimation(const ScrollableLayerGuid &aGuid)
 {
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
   if (apzc) {
     apzc->CancelAnimation();
   }
 }
 
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -375,16 +375,17 @@ private:
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
                                                                   bool* aOutInOverscrolledApzc);
   nsEventStatus ProcessTouchInput(MultiTouchInput& aInput,
                                   ScrollableLayerGuid* aOutTargetGuid);
   nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent,
                              ScrollableLayerGuid* aOutTargetGuid);
   void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
                                         const ZoomConstraints& aConstraints);
+  void FlushRepaintsRecursively(AsyncPanZoomController* aApzc);
 
   AsyncPanZoomController* PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
                                               const FrameMetrics& aMetrics,
                                               uint64_t aLayersId,
                                               const gfx::Matrix4x4& aAncestorTransform,
                                               const nsIntRegion& aObscured,
                                               AsyncPanZoomController* aParent,
                                               AsyncPanZoomController* aNextSibling,
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -70,17 +70,17 @@
 
 #if ENABLE_APZC_LOGGING
 #  include "LayersLogging.h"
 #  define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
 #  define APZC_LOG_FM(fm, prefix, ...) \
     { std::stringstream ss; \
       ss << nsPrintfCString(prefix, __VA_ARGS__).get(); \
       AppendToString(ss, fm, ":", "", true); \
-      APZC_LOG("%s", ss.str().c_str()); \
+      APZC_LOG("%s\n", ss.str().c_str()); \
     }
 #else
 #  define APZC_LOG(...)
 #  define APZC_LOG_FM(fm, prefix, ...)
 #endif
 
 // Static helper functions
 namespace {
@@ -2294,16 +2294,32 @@ void AsyncPanZoomController::ScheduleCom
 }
 
 void AsyncPanZoomController::FlushRepaintForOverscrollHandoff() {
   ReentrantMonitorAutoEnter lock(mMonitor);
   RequestContentRepaint();
   UpdateSharedCompositorFrameMetrics();
 }
 
+void AsyncPanZoomController::FlushRepaintForNewInputBlock() {
+  APZC_LOG("%p flushing repaint for new input block\n", this);
+
+  ReentrantMonitorAutoEnter lock(mMonitor);
+  // We need to send a new repaint request unthrottled, but that
+  // will obsolete any pending repaint request in the paint throttler.
+  // Therefore we should clear out the pending task and restore the
+  // state of mLastPaintRequestMetrics to what it was before the
+  // pending task was queued.
+  mPaintThrottler.CancelPendingTask();
+  mLastPaintRequestMetrics = mLastDispatchedPaintMetrics;
+
+  RequestContentRepaint(mFrameMetrics, false /* not throttled */);
+  UpdateSharedCompositorFrameMetrics();
+}
+
 bool AsyncPanZoomController::SnapBackIfOverscrolled() {
   ReentrantMonitorAutoEnter lock(mMonitor);
   if (IsOverscrolled()) {
     APZC_LOG("%p is overscrolled, starting snap-back\n", this);
     StartSnapBack();
     return true;
   }
   return false;
@@ -2318,17 +2334,17 @@ int32_t AsyncPanZoomController::GetLastT
   nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
   return listener ? listener->GetLastTouchIdentifier() : -1;
 }
 
 void AsyncPanZoomController::RequestContentRepaint() {
   RequestContentRepaint(mFrameMetrics);
 }
 
-void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) {
+void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics, bool aThrottled) {
   aFrameMetrics.SetDisplayPortMargins(
     CalculatePendingDisplayPort(aFrameMetrics,
                                 GetVelocityVector(),
                                 mPaintThrottler.AverageDuration().ToSeconds()));
   aFrameMetrics.SetUseDisplayPortMargins();
 
   // If we're trying to paint what we already think is painted, discard this
   // request since it's a pointless paint.
@@ -2344,22 +2360,26 @@ void AsyncPanZoomController::RequestCont
             aFrameMetrics.GetScrollOffset().y) < EPSILON &&
       aFrameMetrics.GetZoom() == mLastPaintRequestMetrics.GetZoom() &&
       fabsf(aFrameMetrics.GetViewport().width - mLastPaintRequestMetrics.GetViewport().width) < EPSILON &&
       fabsf(aFrameMetrics.GetViewport().height - mLastPaintRequestMetrics.GetViewport().height) < EPSILON) {
     return;
   }
 
   SendAsyncScrollEvent();
-  mPaintThrottler.PostTask(
-    FROM_HERE,
-    UniquePtr<CancelableTask>(NewRunnableMethod(this,
-                      &AsyncPanZoomController::DispatchRepaintRequest,
-                      aFrameMetrics)),
-    GetFrameTime());
+  if (aThrottled) {
+    mPaintThrottler.PostTask(
+      FROM_HERE,
+      UniquePtr<CancelableTask>(NewRunnableMethod(this,
+                        &AsyncPanZoomController::DispatchRepaintRequest,
+                        aFrameMetrics)),
+      GetFrameTime());
+  } else {
+    DispatchRepaintRequest(aFrameMetrics);
+  }
 
   aFrameMetrics.SetPresShellId(mLastContentPaintMetrics.GetPresShellId());
   mLastPaintRequestMetrics = aFrameMetrics;
 }
 
 /*static*/ CSSRect
 GetDisplayPortRect(const FrameMetrics& aFrameMetrics)
 {
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -540,19 +540,22 @@ protected:
    * request is made while a paint is currently happening, it gets queued up. If
    * a new paint request arrives before a paint is completed, the old request
    * gets discarded.
    */
   void RequestContentRepaint();
 
   /**
    * Tell the paint throttler to request a content repaint with the given
-   * metrics.  (Helper function used by RequestContentRepaint.)
+   * metrics.  (Helper function used by RequestContentRepaint.) If aThrottled
+   * is set to false, the repaint request is sent directly without going through
+   * the paint throttler. In particular, the GeckoContentController::RequestContentRepaint
+   * function will be invoked before this function returns.
    */
-  void RequestContentRepaint(FrameMetrics& aFrameMetrics);
+  void RequestContentRepaint(FrameMetrics& aFrameMetrics, bool aThrottled = true);
 
   /**
    * Actually send the next pending paint request to gecko.
    */
   void DispatchRepaintRequest(const FrameMetrics& aFrameMetrics);
 
   /**
    * Gets the current frame metrics. This is *not* the Gecko copy stored in the
@@ -791,16 +794,22 @@ public:
    * Sets allowed touch behavior for current touch session.
    * This method is invoked by the APZCTreeManager which in its turn invoked by
    * the widget after performing touch-action values retrieving.
    * Must be called after receiving the TOUCH_START even that started the
    * touch session.
    */
   void SetAllowedTouchBehavior(const nsTArray<TouchBehaviorFlags>& aBehaviors);
 
+  /**
+   * Flush a repaint request if one is needed, without throttling it with the
+   * paint throttler.
+   */
+  void FlushRepaintForNewInputBlock();
+
 private:
   void ScheduleContentResponseTimeout();
   void ContentResponseTimeout();
   /**
    * Processes any pending input blocks that are ready for processing. There
    * must be at least one input block in the queue when this function is called.
    */
   void ProcessPendingInputBlocks();
--- a/gfx/layers/apz/src/TaskThrottler.cpp
+++ b/gfx/layers/apz/src/TaskThrottler.cpp
@@ -54,16 +54,25 @@ TaskThrottler::TaskComplete(const TimeSt
     mStartTime = aTimeStamp;
     mQueuedTask->Run();
     mQueuedTask = nullptr;
   } else {
     mOutstanding = false;
   }
 }
 
+void
+TaskThrottler::CancelPendingTask()
+{
+  if (mQueuedTask) {
+    mQueuedTask->Cancel();
+    mQueuedTask = nullptr;
+  }
+}
+
 TimeDuration
 TaskThrottler::TimeSinceLastRequest(const TimeStamp& aTimeStamp)
 {
   return aTimeStamp - mStartTime;
 }
 
 }
 }
--- a/gfx/layers/apz/src/TaskThrottler.h
+++ b/gfx/layers/apz/src/TaskThrottler.h
@@ -71,16 +71,21 @@ public:
   }
 
   /**
    * return true if Throttler has an outstanding task
    */
   bool IsOutstanding() { return mOutstanding; }
 
   /**
+   * Cancel the queued task if there is one.
+   */
+  void CancelPendingTask();
+
+  /**
    * Return the time elapsed since the last request was processed
    */
   TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp);
 
   /**
    * Clear average history.
    */
   void ClearHistory() { mMean.clear(); }
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -1267,17 +1267,19 @@ CompositorOGL::DrawQuad(const Rect& aRec
 #ifdef XP_MACOSX
       if (gl()->WorkAroundDriverBugs() &&
           gl()->Vendor() == GLVendor::NVIDIA &&
           !nsCocoaFeatures::OnMavericksOrLater()) {
         // Bug 987497: With some GPUs the nvidia driver on 10.8 and below
         // won't pick up the TexturePass2 uniform change below if we don't do
         // something to force it. Re-activating the shader seems to be one way
         // of achieving that.
-        program->Activate();
+        GLint program;
+        mGLContext->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &program);
+        mGLContext->fUseProgram(program);
       }
 #endif
 
       program->SetTexturePass2(true);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
                                      effectComponentAlpha->mTextureCoords,
                                      effectComponentAlpha->mOnBlack);
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -1483,26 +1483,26 @@ class APZCTreeManagerTester : public ::t
 protected:
   virtual void SetUp() {
     gfxPrefs::GetSingleton();
     AsyncPanZoomController::SetThreadAssertionsEnabled(false);
 
     testStartTime = TimeStamp::Now();
     AsyncPanZoomController::SetFrameTime(testStartTime);
 
-    mcc = new NiceMock<MockContentController>();
+    mcc = new NiceMock<MockContentControllerDelayed>();
     manager = new TestAPZCTreeManager();
   }
 
   virtual void TearDown() {
     manager->ClearTree();
   }
 
   TimeStamp testStartTime;
-  nsRefPtr<MockContentController> mcc;
+  nsRefPtr<MockContentControllerDelayed> mcc;
 
   nsTArray<nsRefPtr<Layer> > layers;
   nsRefPtr<LayerManager> lm;
   nsRefPtr<Layer> root;
 
   nsRefPtr<TestAPZCTreeManager> manager;
 
 protected:
@@ -1520,16 +1520,25 @@ protected:
     aLayer->SetFrameMetrics(metrics);
   }
 
   static TestAsyncPanZoomController* ApzcOf(Layer* aLayer) {
     EXPECT_EQ(1u, aLayer->GetFrameMetricsCount());
     return (TestAsyncPanZoomController*)aLayer->GetAsyncPanZoomController(0);
   }
 
+  void CreateSimpleScrollingLayer() {
+    const char* layerTreeSyntax = "t";
+    nsIntRegion layerVisibleRegion[] = {
+      nsIntRegion(nsIntRect(0,0,200,200)),
+    };
+    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, nullptr, lm, layers);
+    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 500, 500));
+  }
+
   void CreateSimpleMultiLayerTree() {
     const char* layerTreeSyntax = "c(tt)";
     // LayerID                     0 12
     nsIntRegion layerVisibleRegion[] = {
       nsIntRegion(nsIntRect(0,0,100,100)),
       nsIntRegion(nsIntRect(0,0,100,50)),
       nsIntRegion(nsIntRect(0,50,100,50)),
     };
@@ -1746,19 +1755,16 @@ TEST_F(APZHitTestingTester, HitTesting2)
   EXPECT_EQ(Point(37.5, 75), transformToApzc * Point(75, 75));
   // and transformToGecko should reapply it
   EXPECT_EQ(Point(75, 75), transformToGecko * Point(37.5, 75));
 
   // Pan the root layer upward by 50 pixels.
   // This causes layers[1] to scroll out of view, and an async transform
   // of -50 to be set on the root layer.
   int time = 0;
-  // Silence GMock warnings about "uninteresting mock function calls".
-  EXPECT_CALL(*mcc, PostDelayedTask(_,_)).Times(AtLeast(1));
-  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   // This first pan will move the APZC by 50 pixels, and dispatch a paint request.
   // Since this paint request is in the queue to Gecko, transformToGecko will
   // take it into account.
   ApzcPanNoFling(apzcroot, time, 100, 50);
 
   // Hit where layers[3] used to be. It should now hit the root.
@@ -1897,16 +1903,86 @@ TEST_F(APZHitTestingTester, ComplexMulti
   nsRefPtr<AsyncPanZoomController> hit = GetTargetAPZC(ScreenPoint(25, 25));
   EXPECT_EQ(ApzcOf(layers[1]), hit.get());
   hit = GetTargetAPZC(ScreenPoint(275, 375));
   EXPECT_EQ(ApzcOf(layers[9]), hit.get());
   hit = GetTargetAPZC(ScreenPoint(250, 100));
   EXPECT_EQ(ApzcOf(layers[7]), hit.get());
 }
 
+TEST_F(APZHitTestingTester, TestRepaintFlushOnNewInputBlock) {
+  // The main purpose of this test is to verify that touch-start events (or anything
+  // that starts a new input block) don't ever get untransformed. This should always
+  // hold because the APZ code should flush repaints when we start a new input block
+  // and the transform to gecko space should be empty.
+
+  CreateSimpleScrollingLayer();
+  ScopedLayerTreeRegistration registration(0, root, mcc);
+  manager->UpdatePanZoomControllerTree(nullptr, root, false, 0, 0);
+  AsyncPanZoomController* apzcroot = ApzcOf(root);
+
+  // At this point, the following holds (all coordinates in screen pixels):
+  // layers[0] has content from (0,0)-(500,500), clipped by composition bounds (0,0)-(200,200)
+
+  MockFunction<void(std::string checkPointName)> check;
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
+    EXPECT_CALL(check, Call("post-first-touch-start"));
+    EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
+    EXPECT_CALL(check, Call("post-second-fling"));
+    EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(AtLeast(1));
+    EXPECT_CALL(check, Call("post-second-touch-start"));
+  }
+
+  int time = 0;
+  // This first pan will move the APZC by 50 pixels, and dispatch a paint request.
+  ApzcPanNoFling(apzcroot, time, 100, 50);
+
+  // Verify that a touch start doesn't get untransformed
+  ScreenIntPoint touchPoint(50, 50);
+  MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, time, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(0, touchPoint, ScreenSize(0, 0), 0, 0));
+
+  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr));
+  EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
+  check.Call("post-first-touch-start");
+
+  // Send a touchend to clear state
+  mti.mType = MultiTouchInput::MULTITOUCH_END;
+  manager->ReceiveInputEvent(mti, nullptr);
+
+  AsyncPanZoomController::SetFrameTime(testStartTime + TimeDuration::FromMilliseconds(1000));
+
+  // Now do two pans. The first of these will dispatch a repaint request, as above.
+  // The second will get stuck in the paint throttler because the first one doesn't
+  // get marked as "completed", so this will result in a non-empty LD transform.
+  // (Note that any outstanding repaint requests from the first half of this test
+  // don't impact this half because we advance the time by 1 second, which will trigger
+  // the max-wait-exceeded codepath in the paint throttler).
+  ApzcPanNoFling(apzcroot, time, 100, 50);
+  check.Call("post-second-fling");
+  ApzcPanNoFling(apzcroot, time, 100, 50);
+
+  // Ensure that a touch start again doesn't get untransformed by flushing
+  // a repaint
+  mti.mType = MultiTouchInput::MULTITOUCH_START;
+  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr));
+  EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
+  check.Call("post-second-touch-start");
+
+  mti.mType = MultiTouchInput::MULTITOUCH_END;
+  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, manager->ReceiveInputEvent(mti, nullptr));
+  EXPECT_EQ(touchPoint, mti.mTouches[0].mScreenPoint);
+
+  mcc->RunThroughDelayedTasks();
+}
+
 class APZOverscrollHandoffTester : public APZCTreeManagerTester {
 protected:
   UniquePtr<ScopedLayerTreeRegistration> registration;
   TestAsyncPanZoomController* rootApzc;
 
   void SetScrollHandoff(Layer* aChild, Layer* aParent) {
     FrameMetrics metrics = aChild->GetFrameMetrics(0);
     metrics.SetScrollParentId(aParent->GetFrameMetrics(0).GetScrollId());
--- a/ipc/chromium/src/base/message_pump_win.cc
+++ b/ipc/chromium/src/base/message_pump_win.cc
@@ -4,16 +4,17 @@
 
 #include "base/message_pump_win.h"
 
 #include <math.h>
 
 #include "base/message_loop.h"
 #include "base/histogram.h"
 #include "base/win_util.h"
+#include "WinUtils.h"
 
 using base::Time;
 
 namespace base {
 
 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow";
 
 // Message sent to get an additional time slice for pumping (processing) another
@@ -258,41 +259,17 @@ void MessagePumpForUI::InitMessageWnd() 
 
 void MessagePumpForUI::WaitForWork() {
   // Wait until a message is available, up to the time needed by the timer
   // manager to fire the next set of timers.
   int delay = GetCurrentDelay();
   if (delay < 0)  // Negative value means no timers waiting.
     delay = INFINITE;
 
-  DWORD result;
-  result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
-                                       MWMO_INPUTAVAILABLE);
-
-  if (WAIT_OBJECT_0 == result) {
-    // A WM_* message is available.
-    // If a parent child relationship exists between windows across threads
-    // then their thread inputs are implicitly attached.
-    // This causes the MsgWaitForMultipleObjectsEx API to return indicating
-    // that messages are ready for processing (specifically mouse messages
-    // intended for the child window. Occurs if the child window has capture)
-    // The subsequent PeekMessages call fails to return any messages thus
-    // causing us to enter a tight loop at times.
-    // The WaitMessage call below is a workaround to give the child window
-    // sometime to process its input messages.
-    MSG msg = {0};
-    DWORD queue_status = GetQueueStatus(QS_MOUSE);
-    if (HIWORD(queue_status) & QS_MOUSE &&
-       !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
-      WaitMessage();
-    }
-    return;
-  }
-
-  DCHECK_NE(WAIT_FAILED, result) << GetLastError();
+  mozilla::widget::WinUtils::WaitForMessage(delay);
 }
 
 void MessagePumpForUI::HandleWorkMessage() {
   // If we are being called outside of the context of Run, then don't try to do
   // any work.  This could correspond to a MessageBox call or something of that
   // sort.
   if (!state_) {
     // Since we handled a kMsgHaveWork message, we must still update this flag.
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -30,175 +30,191 @@ class JavaScriptBase : public WrapperOwn
     virtual ~JavaScriptBase() {}
 
     virtual void ActorDestroy(WrapperOwner::ActorDestroyReason why) {
         WrapperOwner::ActorDestroy(why);
     }
 
     /*** IPC handlers ***/
 
-    bool AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
-        return Answer::AnswerPreventExtensions(objId, rs);
+    bool AnswerPreventExtensions(const uint64_t &objId, ReturnStatus *rs) {
+        return Answer::AnswerPreventExtensions(ObjectId::deserialize(objId), rs);
     }
-    bool AnswerGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
+    bool AnswerGetPropertyDescriptor(const uint64_t &objId, const nsString &id,
                                      ReturnStatus *rs,
                                      PPropertyDescriptor *out) {
-        return Answer::AnswerGetPropertyDescriptor(objId, id, rs, out);
+        return Answer::AnswerGetPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
     }
-    bool AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
+    bool AnswerGetOwnPropertyDescriptor(const uint64_t &objId,
                                         const nsString &id,
                                         ReturnStatus *rs,
                                         PPropertyDescriptor *out) {
-        return Answer::AnswerGetOwnPropertyDescriptor(objId, id, rs, out);
+        return Answer::AnswerGetOwnPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
     }
-    bool AnswerDefineProperty(const ObjectId &objId, const nsString &id,
+    bool AnswerDefineProperty(const uint64_t &objId, const nsString &id,
                               const PPropertyDescriptor &flags,
                               ReturnStatus *rs) {
-        return Answer::AnswerDefineProperty(objId, id, flags, rs);
+        return Answer::AnswerDefineProperty(ObjectId::deserialize(objId), id, flags, rs);
     }
-    bool AnswerDelete(const ObjectId &objId, const nsString &id,
+    bool AnswerDelete(const uint64_t &objId, const nsString &id,
                       ReturnStatus *rs, bool *success) {
-        return Answer::AnswerDelete(objId, id, rs, success);
+        return Answer::AnswerDelete(ObjectId::deserialize(objId), id, rs, success);
     }
 
-    bool AnswerHas(const ObjectId &objId, const nsString &id,
+    bool AnswerHas(const uint64_t &objId, const nsString &id,
                    ReturnStatus *rs, bool *bp) {
-        return Answer::AnswerHas(objId, id, rs, bp);
+        return Answer::AnswerHas(ObjectId::deserialize(objId), id, rs, bp);
     }
-    bool AnswerHasOwn(const ObjectId &objId, const nsString &id,
+    bool AnswerHasOwn(const uint64_t &objId, const nsString &id,
                       ReturnStatus *rs, bool *bp) {
-        return Answer::AnswerHasOwn(objId, id, rs, bp);
+        return Answer::AnswerHasOwn(ObjectId::deserialize(objId), id, rs, bp);
     }
-    bool AnswerGet(const ObjectId &objId, const ObjectVariant &receiverVar,
+    bool AnswerGet(const uint64_t &objId, const ObjectVariant &receiverVar,
                    const nsString &id,
                    ReturnStatus *rs, JSVariant *result) {
-        return Answer::AnswerGet(objId, receiverVar, id, rs, result);
+        return Answer::AnswerGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
     }
-    bool AnswerSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+    bool AnswerSet(const uint64_t &objId, const ObjectVariant &receiverVar,
                    const nsString &id, const bool &strict,
                    const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
-        return Answer::AnswerSet(objId, receiverVar, id, strict, value, rs, result);
+        return Answer::AnswerSet(ObjectId::deserialize(objId), receiverVar, id, strict, value, rs, result);
     }
 
-    bool AnswerIsExtensible(const ObjectId &objId, ReturnStatus *rs,
+    bool AnswerIsExtensible(const uint64_t &objId, ReturnStatus *rs,
                             bool *result) {
-        return Answer::AnswerIsExtensible(objId, rs, result);
+        return Answer::AnswerIsExtensible(ObjectId::deserialize(objId), rs, result);
     }
-    bool AnswerCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
+    bool AnswerCallOrConstruct(const uint64_t &objId, const nsTArray<JSParam> &argv,
                                const bool &construct, ReturnStatus *rs, JSVariant *result,
                                nsTArray<JSParam> *outparams) {
-        return Answer::AnswerCallOrConstruct(objId, argv, construct, rs, result, outparams);
+        return Answer::AnswerCallOrConstruct(ObjectId::deserialize(objId), argv, construct, rs, result, outparams);
     }
-    bool AnswerHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
-        return Answer::AnswerHasInstance(objId, v, rs, bp);
+    bool AnswerHasInstance(const uint64_t &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
+        return Answer::AnswerHasInstance(ObjectId::deserialize(objId), v, rs, bp);
     }
-    bool AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
+    bool AnswerObjectClassIs(const uint64_t &objId, const uint32_t &classValue,
                              bool *result) {
-        return Answer::AnswerObjectClassIs(objId, classValue, result);
+        return Answer::AnswerObjectClassIs(ObjectId::deserialize(objId), classValue, result);
     }
-    bool AnswerClassName(const ObjectId &objId, nsString *result) {
-        return Answer::AnswerClassName(objId, result);
+    bool AnswerClassName(const uint64_t &objId, nsString *result) {
+        return Answer::AnswerClassName(ObjectId::deserialize(objId), result);
     }
 
-    bool AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+    bool AnswerGetPropertyNames(const uint64_t &objId, const uint32_t &flags,
                                 ReturnStatus *rs, nsTArray<nsString> *names) {
-        return Answer::AnswerGetPropertyNames(objId, flags, rs, names);
+        return Answer::AnswerGetPropertyNames(ObjectId::deserialize(objId), flags, rs, names);
     }
-    bool AnswerInstanceOf(const ObjectId &objId, const JSIID &iid,
+    bool AnswerInstanceOf(const uint64_t &objId, const JSIID &iid,
                           ReturnStatus *rs, bool *instanceof) {
-        return Answer::AnswerInstanceOf(objId, iid, rs, instanceof);
+        return Answer::AnswerInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
     }
-    bool AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
+    bool AnswerDOMInstanceOf(const uint64_t &objId, const int &prototypeID, const int &depth,
                              ReturnStatus *rs, bool *instanceof) {
-        return Answer::AnswerDOMInstanceOf(objId, prototypeID, depth, rs, instanceof);
+        return Answer::AnswerDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
     }
 
-    bool RecvDropObject(const ObjectId &objId) {
-        return Answer::RecvDropObject(objId);
+    bool AnswerIsCallable(const uint64_t &objId, bool *result) {
+        return Answer::AnswerIsCallable(ObjectId::deserialize(objId), result);
+    }
+
+    bool AnswerIsConstructor(const uint64_t &objId, bool *result) {
+        return Answer::AnswerIsConstructor(ObjectId::deserialize(objId), result);
+    }
+
+    bool RecvDropObject(const uint64_t &objId) {
+        return Answer::RecvDropObject(ObjectId::deserialize(objId));
     }
 
     /*** Dummy call handlers ***/
 
     bool SendDropObject(const ObjectId &objId) {
-        return Base::SendDropObject(objId);
+        return Base::SendDropObject(objId.serialize());
     }
     bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
-        return Base::CallPreventExtensions(objId, rs);
+        return Base::CallPreventExtensions(objId.serialize(), rs);
     }
     bool CallGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
                                      ReturnStatus *rs,
                                      PPropertyDescriptor *out) {
-        return Base::CallGetPropertyDescriptor(objId, id, rs, out);
+        return Base::CallGetPropertyDescriptor(objId.serialize(), id, rs, out);
     }
     bool CallGetOwnPropertyDescriptor(const ObjectId &objId,
                                       const nsString &id,
                                       ReturnStatus *rs,
                                       PPropertyDescriptor *out) {
-        return Base::CallGetOwnPropertyDescriptor(objId, id, rs, out);
+        return Base::CallGetOwnPropertyDescriptor(objId.serialize(), id, rs, out);
     }
     bool CallDefineProperty(const ObjectId &objId, const nsString &id,
                             const PPropertyDescriptor &flags,
                               ReturnStatus *rs) {
-        return Base::CallDefineProperty(objId, id, flags, rs);
+        return Base::CallDefineProperty(objId.serialize(), id, flags, rs);
     }
     bool CallDelete(const ObjectId &objId, const nsString &id,
                     ReturnStatus *rs, bool *success) {
-        return Base::CallDelete(objId, id, rs, success);
+        return Base::CallDelete(objId.serialize(), id, rs, success);
     }
 
     bool CallHas(const ObjectId &objId, const nsString &id,
                    ReturnStatus *rs, bool *bp) {
-        return Base::CallHas(objId, id, rs, bp);
+        return Base::CallHas(objId.serialize(), id, rs, bp);
     }
     bool CallHasOwn(const ObjectId &objId, const nsString &id,
                     ReturnStatus *rs, bool *bp) {
-        return Base::CallHasOwn(objId, id, rs, bp);
+        return Base::CallHasOwn(objId.serialize(), id, rs, bp);
     }
     bool CallGet(const ObjectId &objId, const ObjectVariant &receiverVar,
                  const nsString &id,
                  ReturnStatus *rs, JSVariant *result) {
-        return Base::CallGet(objId, receiverVar, id, rs, result);
+        return Base::CallGet(objId.serialize(), receiverVar, id, rs, result);
     }
     bool CallSet(const ObjectId &objId, const ObjectVariant &receiverVar,
                  const nsString &id, const bool &strict,
                  const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
-        return Base::CallSet(objId, receiverVar, id, strict, value, rs, result);
+        return Base::CallSet(objId.serialize(), receiverVar, id, strict, value, rs, result);
     }
 
     bool CallIsExtensible(const ObjectId &objId, ReturnStatus *rs,
                           bool *result) {
-        return Base::CallIsExtensible(objId, rs, result);
+        return Base::CallIsExtensible(objId.serialize(), rs, result);
     }
     bool CallCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
                              const bool &construct, ReturnStatus *rs, JSVariant *result,
                              nsTArray<JSParam> *outparams) {
-        return Base::CallCallOrConstruct(objId, argv, construct, rs, result, outparams);
+        return Base::CallCallOrConstruct(objId.serialize(), argv, construct, rs, result, outparams);
     }
     bool CallHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
-        return Base::CallHasInstance(objId, v, rs, bp);
+        return Base::CallHasInstance(objId.serialize(), v, rs, bp);
     }
     bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
                            bool *result) {
-        return Base::CallObjectClassIs(objId, classValue, result);
+        return Base::CallObjectClassIs(objId.serialize(), classValue, result);
     }
     bool CallClassName(const ObjectId &objId, nsString *result) {
-        return Base::CallClassName(objId, result);
+        return Base::CallClassName(objId.serialize(), result);
     }
 
     bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
                               ReturnStatus *rs, nsTArray<nsString> *names) {
-        return Base::CallGetPropertyNames(objId, flags, rs, names);
+        return Base::CallGetPropertyNames(objId.serialize(), flags, rs, names);
     }
     bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
                         ReturnStatus *rs, bool *instanceof) {
-        return Base::CallInstanceOf(objId, iid, rs, instanceof);
+        return Base::CallInstanceOf(objId.serialize(), iid, rs, instanceof);
     }
     bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
                            ReturnStatus *rs, bool *instanceof) {
-        return Base::CallDOMInstanceOf(objId, prototypeID, depth, rs, instanceof);
+        return Base::CallDOMInstanceOf(objId.serialize(), prototypeID, depth, rs, instanceof);
+    }
+
+    bool CallIsCallable(const ObjectId &objId, bool *result) {
+        return Base::CallIsCallable(objId.serialize(), result);
+    }
+
+    bool CallIsConstructor(const ObjectId &objId, bool *result) {
+        return Base::CallIsConstructor(objId.serialize(), result);
     }
 
     /* The following code is needed to suppress a bogus MSVC warning (C4250). */
 
     virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp) {
         return WrapperOwner::toObjectVariant(cx, obj, objVarp);
     }
     virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar) {
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -48,17 +48,18 @@ JavaScriptChild::init()
     JS_AddWeakPointerCallback(rt_, UpdateChildWeakPointersAfterGC, this);
     return true;
 }
 
 void
 JavaScriptChild::updateWeakPointers()
 {
     objects_.sweep();
-    objectIds_.sweep();
+    unwaivedObjectIds_.sweep();
+    waivedObjectIds_.sweep();
 }
 
 JSObject *
 JavaScriptChild::scopeForTargetObjects()
 {
     // CPOWs from the parent need to point into the child's privileged junk
     // scope so that they can benefit from XrayWrappers in the child.
     return xpc::PrivilegedJunkScope();
--- a/js/ipc/JavaScriptLogging.h
+++ b/js/ipc/JavaScriptLogging.h
@@ -91,17 +91,17 @@ class Logging
         out = NS_ConvertUTF16toUTF8(str);
     }
 
     void formatObject(bool incoming, bool local, ObjectId id, nsCString &out) {
         const char *side, *objDesc;
 
         if (local == incoming) {
             JS::RootedObject obj(cx);
-            obj = shared->findObjectById(id);
+            obj = shared->objects_.find(id);
             if (obj) {
                 JSAutoCompartment ac(cx, obj);
                 objDesc = js_ObjectClassName(cx, obj);
             } else {
                 objDesc = "<dead object>";
             }
 
             side = shared->isParent() ? "parent" : "child";
@@ -155,19 +155,19 @@ class Logging
               nsAutoCString tmp;
               format(value.get_nsString(), tmp);
               out = nsPrintfCString("\"%s\"", tmp.get());
               break;
           }
           case JSVariant::TObjectVariant: {
               const ObjectVariant &ovar = value.get_ObjectVariant();
               if (ovar.type() == ObjectVariant::TLocalObject)
-                  formatObject(incoming, true, ovar.get_LocalObject().id(), out);
+                  formatObject(incoming, true, ObjectId::deserialize(ovar.get_LocalObject().serializedId()), out);
               else
-                  formatObject(incoming, false, ovar.get_RemoteObject().id(), out);
+                  formatObject(incoming, false, ObjectId::deserialize(ovar.get_RemoteObject().serializedId()), out);
               break;
           }
           case JSVariant::Tdouble: {
               out = nsPrintfCString("%.0f", value.get_double());
               break;
           }
           case JSVariant::Tbool: {
               out = value.get_bool() ? "true" : "false";
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -48,17 +48,18 @@ JavaScriptParent::init()
     return true;
 }
 
 void
 JavaScriptParent::trace(JSTracer *trc)
 {
     if (active()) {
         objects_.trace(trc);
-        objectIds_.trace(trc);
+        unwaivedObjectIds_.trace(trc);
+        waivedObjectIds_.trace(trc);
     }
 }
 
 JSObject *
 JavaScriptParent::scopeForTargetObjects()
 {
     // CPWOWs from the child need to point into the parent's unprivileged junk
     // scope so that a compromised child cannot compromise the parent. In
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -5,16 +5,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "JavaScriptShared.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TabChild.h"
 #include "jsfriendapi.h"
 #include "xpcprivate.h"
+#include "WrapperFactory.h"
 #include "mozilla/Preferences.h"
 
 using namespace js;
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::jsipc;
 
 IdToObjectMap::IdToObjectMap()
@@ -118,17 +119,17 @@ ObjectToIdMap::sweep()
     }
 }
 
 ObjectId
 ObjectToIdMap::find(JSObject *obj)
 {
     Table::Ptr p = table_->lookup(obj);
     if (!p)
-        return 0;
+        return ObjectId::nullId();
     return p->value();
 }
 
 bool
 ObjectToIdMap::add(JSContext *cx, JSObject *obj, ObjectId id)
 {
     if (!table_->put(obj, id))
         return false;
@@ -157,17 +158,17 @@ ObjectToIdMap::remove(JSObject *obj)
 
 bool JavaScriptShared::sLoggingInitialized;
 bool JavaScriptShared::sLoggingEnabled;
 bool JavaScriptShared::sStackLoggingEnabled;
 
 JavaScriptShared::JavaScriptShared(JSRuntime *rt)
   : rt_(rt),
     refcount_(1),
-    lastId_(0)
+    nextSerialNumber_(1)
 {
     if (!sLoggingInitialized) {
         sLoggingInitialized = true;
 
         if (PR_GetEnv("MOZ_CPOW_LOG")) {
             sLoggingEnabled = true;
             sStackLoggingEnabled = true;
         } else {
@@ -181,17 +182,19 @@ JavaScriptShared::JavaScriptShared(JSRun
 
 bool
 JavaScriptShared::init()
 {
     if (!objects_.init())
         return false;
     if (!cpows_.init())
         return false;
-    if (!objectIds_.init())
+    if (!unwaivedObjectIds_.init())
+        return false;
+    if (!waivedObjectIds_.init())
         return false;
 
     return true;
 }
 
 void
 JavaScriptShared::decref()
 {
@@ -376,31 +379,36 @@ JavaScriptShared::ConvertID(const JSIID 
     to->m3[3] = from.m3_3();
     to->m3[4] = from.m3_4();
     to->m3[5] = from.m3_5();
     to->m3[6] = from.m3_6();
     to->m3[7] = from.m3_7();
 }
 
 JSObject *
-JavaScriptShared::findObjectById(JSContext *cx, uint32_t objId)
+JavaScriptShared::findObjectById(JSContext *cx, const ObjectId &objId)
 {
-    RootedObject obj(cx, findObjectById(objId));
+    RootedObject obj(cx, objects_.find(objId));
     if (!obj) {
         JS_ReportError(cx, "operation not possible on dead CPOW");
         return nullptr;
     }
 
     // Each process has a dedicated compartment for CPOW targets. All CPOWs
     // from the other process point to objects in this scope. From there, they
     // can access objects in other compartments using cross-compartment
     // wrappers.
     JSAutoCompartment ac(cx, scopeForTargetObjects());
-    if (!JS_WrapObject(cx, &obj))
-        return nullptr;
+    if (objId.hasXrayWaiver()) {
+        if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, &obj))
+            return nullptr;
+    } else {
+        if (!JS_WrapObject(cx, &obj))
+            return nullptr;
+    }
     return obj;
 }
 
 static const uint64_t DefaultPropertyOp = 1;
 static const uint64_t UnknownPropertyOp = 2;
 
 bool
 JavaScriptShared::fromDescriptor(JSContext *cx, Handle<JSPropertyDescriptor> desc,
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -11,17 +11,57 @@
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/jsipc/PJavaScript.h"
 #include "nsJSUtils.h"
 #include "nsFrameMessageManager.h"
 
 namespace mozilla {
 namespace jsipc {
 
-typedef uint64_t ObjectId;
+class ObjectId {
+  public:
+    // Use 47 bits at most, to be safe, since jsval privates are encoded as
+    // doubles. See bug 1065811 comment 12 for an explanation.
+    static const size_t SERIAL_NUMBER_BITS = 47;
+    static const size_t FLAG_BITS = 1;
+    static const uint64_t SERIAL_NUMBER_MAX = (uint64_t(1) << SERIAL_NUMBER_BITS) - 1;
+
+    explicit ObjectId(uint64_t serialNumber, bool hasXrayWaiver)
+      : serialNumber_(serialNumber), hasXrayWaiver_(hasXrayWaiver)
+    {
+        if (MOZ_UNLIKELY(serialNumber == 0 || serialNumber > SERIAL_NUMBER_MAX))
+            MOZ_CRASH("Bad CPOW Id");
+    }
+
+    bool operator==(const ObjectId &other) const {
+        bool equal = serialNumber() == other.serialNumber();
+        MOZ_ASSERT_IF(equal, hasXrayWaiver() == other.hasXrayWaiver());
+        return equal;
+    }
+
+    bool isNull() { return !serialNumber_; }
+
+    uint64_t serialNumber() const { return serialNumber_; }
+    bool hasXrayWaiver() const { return hasXrayWaiver_; }
+    uint64_t serialize() const {
+        MOZ_ASSERT(serialNumber(), "Don't send a null ObjectId over IPC");
+        return uint64_t((serialNumber() << FLAG_BITS) | ((hasXrayWaiver() ? 1 : 0) << 0));
+    }
+
+    static ObjectId nullId() { return ObjectId(); }
+    static ObjectId deserialize(uint64_t data) {
+        return ObjectId(data >> FLAG_BITS, data & 1);
+    }
+
+  private:
+    ObjectId() : serialNumber_(0), hasXrayWaiver_(false) {}
+
+    uint64_t serialNumber_ : SERIAL_NUMBER_BITS;
+    bool hasXrayWaiver_ : 1;
+};
 
 class JavaScriptShared;
 
 class CpowIdHolder : public CpowHolder
 {
   public:
     CpowIdHolder(JavaScriptShared *js, const InfallibleTArray<CpowEntry> &cpows)
       : js_(js),
@@ -31,22 +71,37 @@ class CpowIdHolder : public CpowHolder
 
     bool ToObject(JSContext *cx, JS::MutableHandleObject objp);
 
   private:
     JavaScriptShared *js_;
     const InfallibleTArray<CpowEntry> &cpows_;
 };
 
+// DefaultHasher<T> requires that T coerce to an integral type. We could make
+// ObjectId do that, but doing so would weaken our type invariants, so we just
+// reimplement it manually.
+struct ObjectIdHasher
+{
+    typedef ObjectId Lookup;
+    static js::HashNumber hash(const Lookup &l) {
+        return l.serialize();
+    }
+    static bool match(const ObjectId &k, const ObjectId &l) {
+        return k == l;
+    }
+    static void rekey(ObjectId &k, const ObjectId& newKey) {
+        k = newKey;
+    }
+};
+
 // Map ids -> JSObjects
 class IdToObjectMap
 {
-    typedef js::DefaultHasher<ObjectId> TableKeyHasher;
-
-    typedef js::HashMap<ObjectId, JS::Heap<JSObject *>, TableKeyHasher, js::SystemAllocPolicy> Table;
+    typedef js::HashMap<ObjectId, JS::Heap<JSObject *>, ObjectIdHasher, js::SystemAllocPolicy> Table;
 
   public:
     IdToObjectMap();
 
     bool init();
     void trace(JSTracer *trc);
     void sweep();
 
@@ -90,19 +145,16 @@ class JavaScriptShared
     explicit JavaScriptShared(JSRuntime *rt);
     virtual ~JavaScriptShared() {}
 
     bool init();
 
     void decref();
     void incref();
 
-    static const uint32_t OBJECT_EXTRA_BITS  = 1;
-    static const uint32_t OBJECT_IS_CALLABLE = (1 << 0);
-
     bool Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JS::MutableHandleObject objp);
     bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
 
   protected:
     bool toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to);
     bool fromVariant(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
 
     bool fromDescriptor(JSContext *cx, JS::Handle<JSPropertyDescriptor> desc,
@@ -114,23 +166,20 @@ class JavaScriptShared
     bool convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId id);
 
     virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp) = 0;
     virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar) = 0;
 
     static void ConvertID(const nsID &from, JSIID *to);
     static void ConvertID(const JSIID &from, nsID *to);
 
-    JSObject *findCPOWById(uint32_t objId) {
+    JSObject *findCPOWById(const ObjectId &objId) {
         return cpows_.find(objId);
     }
-    JSObject *findObjectById(uint32_t objId) {
-        return objects_.find(objId);
-    }
-    JSObject *findObjectById(JSContext *cx, uint32_t objId);
+    JSObject *findObjectById(JSContext *cx, const ObjectId &objId);
 
     static bool LoggingEnabled() { return sLoggingEnabled; }
     static bool StackLoggingEnabled() { return sStackLoggingEnabled; }
 
     friend class Logging;
 
     virtual bool isParent() = 0;
 
@@ -138,23 +187,40 @@ class JavaScriptShared
 
   protected:
     JSRuntime *rt_;
     uintptr_t refcount_;
 
     IdToObjectMap objects_;
     IdToObjectMap cpows_;
 
-    ObjectId lastId_;
-    ObjectToIdMap objectIds_;
+    uint64_t nextSerialNumber_;
+
+    // CPOW references can be weak, and any object we store in a map may be
+    // GCed (at which point the CPOW will report itself "dead" to the owner).
+    // This means that we don't want to store any js::Wrappers in the CPOW map,
+    // because CPOW will die if the wrapper is GCed, even if the underlying
+    // object is still alive.
+    //
+    // This presents a tricky situation for Xray waivers, since they're normally
+    // represented as a special same-compartment wrapper. We have to strip them
+    // off before putting them in the id-to-object and object-to-id maps, so we
+    // need a way of distinguishing them at lookup-time.
+    //
+    // For the id-to-object map, we encode waiver-or-not information into the id
+    // itself, which lets us do the right thing when accessing the object.
+    //
+    // For the object-to-id map, we just keep two maps, one for each type.
+    ObjectToIdMap unwaivedObjectIds_;
+    ObjectToIdMap waivedObjectIds_;
+    ObjectToIdMap &objectIdMap(bool waiver) {
+        return waiver ? waivedObjectIds_ : unwaivedObjectIds_;
+    }
 
     static bool sLoggingInitialized;
     static bool sLoggingEnabled;
     static bool sStackLoggingEnabled;
 };
 
-// Use 47 at most, to be safe, since jsval privates are encoded as doubles.
-static const uint64_t MAX_CPOW_IDS = (uint64_t(1) << 47) - 1;
-
 } // namespace jsipc
 } // namespace mozilla
 
 #endif
--- a/js/ipc/JavaScriptTypes.ipdlh
+++ b/js/ipc/JavaScriptTypes.ipdlh
@@ -24,22 +24,22 @@ struct JSIID
     uint8_t m3_4;
     uint8_t m3_5;
     uint8_t m3_6;
     uint8_t m3_7;
 };
 
 struct LocalObject
 {
-    uint64_t id;
+    uint64_t serializedId;
 };
 
 struct RemoteObject
 {
-    uint64_t id;
+    uint64_t serializedId;
 };
 
 union ObjectVariant
 {
     LocalObject;
     RemoteObject;
 };
 
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -40,14 +40,17 @@ both:
     rpc HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
     rpc ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
     rpc ClassName(uint64_t objId) returns (nsString name);
 
     rpc GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
     rpc InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
     rpc DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
 
+    rpc IsCallable(uint64_t objId) returns (bool result);
+    rpc IsConstructor(uint64_t objId) returns (bool result);
+
 parent:
     async __delete__();
 };
 
 }
 }
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -631,17 +631,58 @@ WrapperAnswer::AnswerDOMInstanceOf(const
     if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
         return fail(cx, rs);
     *instanceof = tmp;
 
     return ok(rs);
 }
 
 bool
+WrapperAnswer::AnswerIsCallable(const ObjectId &objId, bool *result)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObjectById(cx, objId));
+    if (!obj) {
+        // This is very unfortunate, but we have no choice.
+        *result = false;
+        return true;
+    }
+    JSAutoCompartment ac(cx, obj); // Not really necessary here, but be safe.
+
+    LOG("%s.isCallable()", ReceiverObj(objId));
+
+    *result = JS::IsCallable(obj);
+    return true;
+}
+
+bool
+WrapperAnswer::AnswerIsConstructor(const ObjectId &objId, bool *result)
+{
+    AutoSafeJSContext cx;
+    JSAutoRequest request(cx);
+
+    RootedObject obj(cx, findObjectById(cx, objId));
+    if (!obj) {
+        // This is very unfortunate, but we have no choice.
+        *result = false;
+        return true;
+    }
+    JSAutoCompartment ac(cx, obj); // Not really necessary here, but be safe.
+
+    LOG("%s.isConstructor()", ReceiverObj(objId));
+
+    *result = JS::IsConstructor(obj);
+    return true;
+}
+
+
+bool
 WrapperAnswer::RecvDropObject(const ObjectId &objId)
 {
-    JSObject *obj = findObjectById(objId);
+    JSObject *obj = objects_.find(objId);
     if (obj) {
-        objectIds_.remove(obj);
+        objectIdMap(objId.hasXrayWaiver()).remove(obj);
         objects_.remove(objId);
     }
     return true;
 }
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -55,16 +55,19 @@ class WrapperAnswer : public virtual Jav
 
     bool AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
                                 ReturnStatus *rs, nsTArray<nsString> *names);
     bool AnswerInstanceOf(const ObjectId &objId, const JSIID &iid,
                           ReturnStatus *rs, bool *instanceof);
     bool AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
                              ReturnStatus *rs, bool *instanceof);
 
+    bool AnswerIsCallable(const ObjectId &objId, bool *result);
+    bool AnswerIsConstructor(const ObjectId &objId, bool *result);
+
     bool RecvDropObject(const ObjectId &objId);
 
   private:
     bool fail(JSContext *cx, ReturnStatus *rs);
     bool ok(ReturnStatus *rs);
 };
 
 } // mozilla
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -6,16 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WrapperOwner.h"
 #include "JavaScriptLogging.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "jsfriendapi.h"
 #include "xpcprivate.h"
+#include "WrapperFactory.h"
 
 using namespace js;
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::jsipc;
 
 WrapperOwner::WrapperOwner(JSRuntime *rt)
   : JavaScriptShared(rt),
@@ -33,18 +34,18 @@ OwnerOf(JSObject *obj)
 ObjectId
 WrapperOwner::idOfUnchecked(JSObject *obj)
 {
     MOZ_ASSERT(IsCPOW(obj));
 
     Value v = GetProxyExtra(obj, 1);
     MOZ_ASSERT(v.isDouble());
 
-    ObjectId objId = BitwiseCast<uint64_t>(v.toDouble());
-    MOZ_ASSERT(objId);
+    ObjectId objId = ObjectId::deserialize(BitwiseCast<uint64_t>(v.toDouble()));
+    MOZ_ASSERT(!objId.isNull());
 
     return objId;
 }
 
 ObjectId
 WrapperOwner::idOf(JSObject *obj)
 {
     ObjectId objId = idOfUnchecked(obj);
@@ -658,32 +659,59 @@ CPOWProxyHandler::finalize(JSFreeOp *fop
 
 void
 CPOWProxyHandler::objectMoved(JSObject *proxy, const JSObject *old) const
 {
     OwnerOf(proxy)->updatePointer(proxy, old);
 }
 
 bool
-CPOWProxyHandler::isCallable(JSObject *obj) const
+CPOWProxyHandler::isCallable(JSObject *proxy) const
 {
-    return OwnerOf(obj)->isCallable(obj);
-}
-
-bool
-CPOWProxyHandler::isConstructor(JSObject *obj) const
-{
-    return isCallable(obj);
+    WrapperOwner *parent = OwnerOf(proxy);
+    if (!parent->active())
+        return false;
+    return parent->isCallable(proxy);
 }
 
 bool
 WrapperOwner::isCallable(JSObject *obj)
 {
     ObjectId objId = idOf(obj);
-    return !!(objId & OBJECT_IS_CALLABLE);
+
+    bool callable = false;
+    if (!CallIsCallable(objId, &callable)) {
+        NS_WARNING("IPC isCallable() failed");
+        return false;
+    }
+
+    return callable;
+}
+
+bool
+CPOWProxyHandler::isConstructor(JSObject *proxy) const
+{
+    WrapperOwner *parent = OwnerOf(proxy);
+    if (!parent->active())
+        return false;
+    return parent->isConstructor(proxy);
+}
+
+bool
+WrapperOwner::isConstructor(JSObject *obj)
+{
+    ObjectId objId = idOf(obj);
+
+    bool constructor = false;
+    if (!CallIsConstructor(objId, &constructor)) {
+        NS_WARNING("IPC isConstructor() failed");
+        return false;
+    }
+
+    return constructor;
 }
 
 void
 WrapperOwner::drop(JSObject *obj)
 {
     ObjectId objId = idOf(obj);
 
     cpows_.remove(objId);
@@ -838,73 +866,62 @@ WrapperOwner::toObjectVariant(JSContext 
 {
     RootedObject obj(cx, objArg);
     JS_ASSERT(obj);
 
     // We always save objects unwrapped in the CPOW table. If we stored
     // wrappers, then the wrapper might be GCed while the target remained alive.
     // Whenever operating on an object that comes from the table, we wrap it
     // in findObjectById.
-    obj = js::UncheckedUnwrap(obj, false);
+    unsigned wrapperFlags = 0;
+    obj = js::UncheckedUnwrap(obj, false, &wrapperFlags);
     if (obj && IsCPOW(obj) && OwnerOf(obj) == this) {
-        *objVarp = LocalObject(idOf(obj));
+        *objVarp = LocalObject(idOf(obj).serialize());
         return true;
     }
+    bool waiveXray = wrapperFlags & xpc::WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG;
 
-    ObjectId id = objectIds_.find(obj);
-    if (id) {
-        *objVarp = RemoteObject(id);
+    ObjectId id = objectIdMap(waiveXray).find(obj);
+    if (!id.isNull()) {
+        MOZ_ASSERT(id.hasXrayWaiver() == waiveXray);
+        *objVarp = RemoteObject(id.serialize());
         return true;
     }
 
     // Need to call PreserveWrapper on |obj| in case it's a reflector.
     // FIXME: What if it's an XPCWrappedNative?
     if (mozilla::dom::IsDOMObject(obj))
         mozilla::dom::TryPreserveWrapper(obj);
 
-    id = ++lastId_;
-    if (id > MAX_CPOW_IDS) {
-        JS_ReportError(cx, "CPOW id limit reached");
-        return false;
-    }
-
-    id <<= OBJECT_EXTRA_BITS;
-    if (JS_ObjectIsCallable(cx, obj))
-        id |= OBJECT_IS_CALLABLE;
-
+    id = ObjectId(nextSerialNumber_++, waiveXray);
     if (!objects_.add(id, obj))
         return false;
-    if (!objectIds_.add(cx, obj, id))
+    if (!objectIdMap(waiveXray).add(cx, obj, id))
         return false;
 
-    *objVarp = RemoteObject(id);
+    *objVarp = RemoteObject(id.serialize());
     return true;
 }
 
 JSObject *
 WrapperOwner::fromObjectVariant(JSContext *cx, ObjectVariant objVar)
 {
     if (objVar.type() == ObjectVariant::TRemoteObject) {
         return fromRemoteObjectVariant(cx, objVar.get_RemoteObject());
     } else {
         return fromLocalObjectVariant(cx, objVar.get_LocalObject());
     }
 }
 
 JSObject *
 WrapperOwner::fromRemoteObjectVariant(JSContext *cx, RemoteObject objVar)
 {
-    ObjectId objId = objVar.id();
+    ObjectId objId = ObjectId::deserialize(objVar.serializedId());
     RootedObject obj(cx, findCPOWById(objId));
     if (!obj) {
-        // If we didn't find an existing CPOW, we need to create one.
-        if (objId > MAX_CPOW_IDS) {
-            JS_ReportError(cx, "unusable CPOW id");
-            return nullptr;
-        }
 
         // All CPOWs live in the privileged junk scope.
         RootedObject junkScope(cx, xpc::PrivilegedJunkScope());
         JSAutoCompartment ac(cx, junkScope);
         RootedValue v(cx, UndefinedValue());
         obj = NewProxyObject(cx,
                              &CPOWProxyHandler::singleton,
                              v,
@@ -915,27 +932,27 @@ WrapperOwner::fromRemoteObjectVariant(JS
 
         if (!cpows_.add(objId, obj))
             return nullptr;
 
         // Incref once we know the decref will be called.
         incref();
 
         SetProxyExtra(obj, 0, PrivateValue(this));
-        SetProxyExtra(obj, 1, DoubleValue(BitwiseCast<double>(objId)));
+        SetProxyExtra(obj, 1, DoubleValue(BitwiseCast<double>(objId.serialize())));
     }
 
     if (!JS_WrapObject(cx, &obj))
         return nullptr;
     return obj;
 }
 
 JSObject *
 WrapperOwner::fromLocalObjectVariant(JSContext *cx, LocalObject objVar)
 {
-    ObjectId id = objVar.id();
+    ObjectId id = ObjectId::deserialize(objVar.serializedId());
     Rooted<JSObject*> obj(cx, findObjectById(cx, id));
     if (!obj)
         return nullptr;
     if (!JS_WrapObject(cx, &obj))
         return nullptr;
     return obj;
 }
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -56,17 +56,17 @@ class WrapperOwner : public virtual Java
     // SpiderMonkey Extensions.
     bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
     bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
                          bool construct);
     bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp);
     bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
     const char* className(JSContext *cx, JS::HandleObject proxy);
     bool isCallable(JSObject *obj);
-    // isConstructable is implemented here as isCallable.
+    bool isConstructor(JSObject *obj);
 
     nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
 
     bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
 
     /*
      * Check that |obj| is a DOM wrapper whose prototype chain contains
      * |prototypeID| at depth |depth|.
@@ -142,16 +142,19 @@ class WrapperOwner : public virtual Java
     virtual bool CallClassName(const ObjectId &objId, nsString *result) = 0;
 
     virtual bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
                                       ReturnStatus *rs, nsTArray<nsString> *names) = 0;
     virtual bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
                                 ReturnStatus *rs, bool *instanceof) = 0;
     virtual bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
                                    ReturnStatus *rs, bool *instanceof) = 0;
+
+    virtual bool CallIsCallable(const ObjectId &objId, bool *result) = 0;
+    virtual bool CallIsConstructor(const ObjectId &objId, bool *result) = 0;
 };
 
 bool
 IsCPOW(JSObject *obj);
 
 bool
 IsWrappedCPOW(JSObject *obj);
 
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -359,23 +359,27 @@ ValidateSimdOperation(JSContext *cx, Asm
           case AsmJSSimdOperation_or: native = simd_int32x4_or; break;
           case AsmJSSimdOperation_xor: native = simd_int32x4_xor; break;
           case AsmJSSimdOperation_select: native = simd_int32x4_select; break;
           case AsmJSSimdOperation_splat: native = simd_int32x4_splat; break;
           case AsmJSSimdOperation_withX: native = simd_int32x4_withX; break;
           case AsmJSSimdOperation_withY: native = simd_int32x4_withY; break;
           case AsmJSSimdOperation_withZ: native = simd_int32x4_withZ; break;
           case AsmJSSimdOperation_withW: native = simd_int32x4_withW; break;
+          case AsmJSSimdOperation_fromFloat32x4: native = simd_int32x4_fromFloat32x4; break;
+          case AsmJSSimdOperation_fromFloat32x4Bits: native = simd_int32x4_fromFloat32x4Bits; break;
           case AsmJSSimdOperation_lessThanOrEqual:
           case AsmJSSimdOperation_greaterThanOrEqual:
           case AsmJSSimdOperation_notEqual:
           case AsmJSSimdOperation_mul:
           case AsmJSSimdOperation_div:
           case AsmJSSimdOperation_max:
           case AsmJSSimdOperation_min:
+          case AsmJSSimdOperation_fromInt32x4:
+          case AsmJSSimdOperation_fromInt32x4Bits:
             MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("shouldn't have been validated in the first "
                                                     "place");
         }
         break;
       case AsmJSSimdType_float32x4:
         switch (global.simdOperation()) {
           case AsmJSSimdOperation_add: native = simd_float32x4_add; break;
           case AsmJSSimdOperation_sub: native = simd_float32x4_sub; break;
@@ -393,16 +397,22 @@ ValidateSimdOperation(JSContext *cx, Asm
           case AsmJSSimdOperation_or: native = simd_float32x4_or; break;
           case AsmJSSimdOperation_xor: native = simd_float32x4_xor; break;
           case AsmJSSimdOperation_select: native = simd_float32x4_select; break;
           case AsmJSSimdOperation_splat: native = simd_float32x4_splat; break;
           case AsmJSSimdOperation_withX: native = simd_float32x4_withX; break;
           case AsmJSSimdOperation_withY: native = simd_float32x4_withY; break;
           case AsmJSSimdOperation_withZ: native = simd_float32x4_withZ; break;
           case AsmJSSimdOperation_withW: native = simd_float32x4_withW; break;
+          case AsmJSSimdOperation_fromInt32x4: native = simd_float32x4_fromInt32x4; break;
+          case AsmJSSimdOperation_fromInt32x4Bits: native = simd_float32x4_fromInt32x4Bits; break;
+          case AsmJSSimdOperation_fromFloat32x4:
+          case AsmJSSimdOperation_fromFloat32x4Bits:
+             MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("shouldn't have been validated in the first "
+                                                     "place");
         }
         break;
     }
     if (!native || !IsNativeFunction(v, native))
         return LinkFail(cx, "bad SIMD.type.* operation");
     return true;
 }
 
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -91,17 +91,21 @@ enum AsmJSSimdOperation
     AsmJSSimdOperation_and,
     AsmJSSimdOperation_or,
     AsmJSSimdOperation_xor,
     AsmJSSimdOperation_select,
     AsmJSSimdOperation_splat,
     AsmJSSimdOperation_withX,
     AsmJSSimdOperation_withY,
     AsmJSSimdOperation_withZ,
-    AsmJSSimdOperation_withW
+    AsmJSSimdOperation_withW,
+    AsmJSSimdOperation_fromInt32x4,
+    AsmJSSimdOperation_fromFloat32x4,
+    AsmJSSimdOperation_fromInt32x4Bits,
+    AsmJSSimdOperation_fromFloat32x4Bits
 };
 
 // These labels describe positions in the prologue/epilogue of functions while
 // compiling an AsmJSModule.
 struct AsmJSFunctionLabels
 {
     AsmJSFunctionLabels(jit::Label &entry, jit::Label &overflowExit)
       : entry(entry), overflowExit(overflowExit) {}
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -1422,17 +1422,21 @@ class MOZ_STACK_CLASS ModuleCompiler
             !addStandardLibrarySimdOpName("xor", AsmJSSimdOperation_xor) ||
             !addStandardLibrarySimdOpName("select", AsmJSSimdOperation_select) ||
             !addStandardLibrarySimdOpName("splat", AsmJSSimdOperation_splat) ||
             !addStandardLibrarySimdOpName("max", AsmJSSimdOperation_max) ||
             !addStandardLibrarySimdOpName("min", AsmJSSimdOperation_min) ||
             !addStandardLibrarySimdOpName("withX", AsmJSSimdOperation_withX) ||
             !addStandardLibrarySimdOpName("withY", AsmJSSimdOperation_withY) ||
             !addStandardLibrarySimdOpName("withZ", AsmJSSimdOperation_withZ) ||
-            !addStandardLibrarySimdOpName("withW", AsmJSSimdOperation_withW))
+            !addStandardLibrarySimdOpName("withW", AsmJSSimdOperation_withW) ||
+            !addStandardLibrarySimdOpName("fromFloat32x4", AsmJSSimdOperation_fromFloat32x4) ||
+            !addStandardLibrarySimdOpName("fromInt32x4", AsmJSSimdOperation_fromInt32x4) ||
+            !addStandardLibrarySimdOpName("fromFloat32x4Bits", AsmJSSimdOperation_fromFloat32x4Bits) ||
+            !addStandardLibrarySimdOpName("fromInt32x4Bits", AsmJSSimdOperation_fromInt32x4Bits))
         {
             return false;
         }
 
         uint32_t srcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin;
         uint32_t srcBodyStart = tokenStream().currentToken().pos.end;
 
         // "use strict" should be added to the source if we are in an implicit
@@ -2504,16 +2508,28 @@ class FunctionCompiler
         MOZ_ASSERT(mask->type() == MIRType_Int32x4);
         MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
         MOZ_ASSERT(lhs->type() == type);
         MSimdTernaryBitwise *ins = MSimdTernaryBitwise::NewAsmJS(alloc(), mask, lhs, rhs, op, type);
         curBlock_->add(ins);
         return ins;
     }
 
+    template<class T>
+    MDefinition *convertSimd(MDefinition *vec, MIRType from, MIRType to)
+    {
+        if (inDeadCode())
+            return nullptr;
+
+        MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to);
+        T *ins = T::NewAsmJS(alloc(), vec, from, to);
+        curBlock_->add(ins);
+        return ins;
+    }
+
     MDefinition *splatSimd(MDefinition *v, MIRType type)
     {
         if (inDeadCode())
             return nullptr;
 
         JS_ASSERT(IsSimdType(type));
         MSimdSplatX4 *ins = MSimdSplatX4::New(alloc(), type, v);
         curBlock_->add(ins);
@@ -3583,23 +3599,28 @@ IsSimdValidOperationType(AsmJSSimdType t
       case AsmJSSimdOperation_xor:
       case AsmJSSimdOperation_select:
       case AsmJSSimdOperation_splat:
       case AsmJSSimdOperation_withX:
       case AsmJSSimdOperation_withY:
       case AsmJSSimdOperation_withZ:
       case AsmJSSimdOperation_withW:
         return true;
+      case AsmJSSimdOperation_fromFloat32x4:
+      case AsmJSSimdOperation_fromFloat32x4Bits:
+        return type == AsmJSSimdType_int32x4;
       case AsmJSSimdOperation_mul:
       case AsmJSSimdOperation_div:
       case AsmJSSimdOperation_max:
       case AsmJSSimdOperation_min:
       case AsmJSSimdOperation_lessThanOrEqual:
       case AsmJSSimdOperation_notEqual:
       case AsmJSSimdOperation_greaterThanOrEqual:
+      case AsmJSSimdOperation_fromInt32x4:
+      case AsmJSSimdOperation_fromInt32x4Bits:
         return type == AsmJSSimdType_float32x4;
     }
     return false;
 }
 
 static bool
 CheckGlobalMathImport(ModuleCompiler &m, ParseNode *initNode, PropertyName *varName,
                       PropertyName *field)
@@ -4959,16 +4980,49 @@ CheckSimdOperationCall(FunctionCompiler 
         return CheckSimdWith(f, call, retType, SimdLane::LaneX, def, type);
       case AsmJSSimdOperation_withY:
         return CheckSimdWith(f, call, retType, SimdLane::LaneY, def, type);
       case AsmJSSimdOperation_withZ:
         return CheckSimdWith(f, call, retType, SimdLane::LaneZ, def, type);
       case AsmJSSimdOperation_withW:
         return CheckSimdWith(f, call, retType, SimdLane::LaneW, def, type);
 
+      case AsmJSSimdOperation_fromInt32x4: {
+        DefinitionVector defs;
+        if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Int32x4), &defs))
+            return false;
+        *def = f.convertSimd<MSimdConvert>(defs[0], MIRType_Int32x4, retType.toMIRType());
+        *type = retType;
+        return true;
+      }
+      case AsmJSSimdOperation_fromInt32x4Bits: {
+        DefinitionVector defs;
+        if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Int32x4), &defs))
+            return false;
+        *def = f.convertSimd<MSimdReinterpretCast>(defs[0], MIRType_Int32x4, retType.toMIRType());
+        *type = retType;
+        return true;
+      }
+      case AsmJSSimdOperation_fromFloat32x4: {
+        DefinitionVector defs;
+        if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Float32x4), &defs))
+            return false;
+        *def = f.convertSimd<MSimdConvert>(defs[0], MIRType_Float32x4, retType.toMIRType());
+        *type = retType;
+        return true;
+      }
+      case AsmJSSimdOperation_fromFloat32x4Bits: {
+        DefinitionVector defs;
+        if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Float32x4), &defs))
+            return false;
+        *def = f.convertSimd<MSimdReinterpretCast>(defs[0], MIRType_Float32x4, retType.toMIRType());
+        *type = retType;
+        return true;
+      }
+
       case AsmJSSimdOperation_splat: {
         DefinitionVector defs;
         Type formalType = retType.simdToCoercedScalarType();
         if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(formalType), &defs))
             return false;
         *def = f.splatSimd(defs[0], retType.toMIRType());
         *type = retType;
         return true;
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -1061,27 +1061,31 @@ obj_freeze(JSContext *cx, unsigned argc,
     if (!GetFirstArgumentAsObject(cx, args, "Object.freeze", &obj))
         return false;
 
     args.rval().setObject(*obj);
 
     return JSObject::freeze(cx, obj);
 }
 
+// ES6 draft rev27 (2014/08/24) 19.1.2.12 Object.isFrozen(O)
 static bool
 obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, args, "Object.preventExtensions", &obj))
-        return false;
+
+    // step 1
+    bool frozen = true;
 
-    bool frozen;
-    if (!JSObject::isFrozen(cx, obj, &frozen))
-        return false;
+    // step 2
+    if (args.get(0).isObject()) {
+        RootedObject obj(cx, &args.get(0).toObject());
+        if (!JSObject::isFrozen(cx, obj, &frozen))
+            return false;
+    }
     args.rval().setBoolean(frozen);
     return true;
 }
 
 static bool
 obj_seal(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -4018,18 +4018,17 @@ PointerType::ConstructData(JSContext* cx
   // Case 1 - Null pointer
   //
   if (args.length() == 0)
     return true;
 
   // Analyze the arguments a bit to decide what to do next.
   RootedObject baseObj(cx, PointerType::GetBaseType(obj));
   bool looksLikeClosure = CType::GetTypeCode(baseObj) == TYPE_function &&
-                          args[0].isObject() &&
-                          JS_ObjectIsCallable(cx, &args[0].toObject());
+                          args[0].isObject() && JS::IsCallable(&args[0].toObject());
 
   //
   // Case 2 - Initialized pointer
   //
   if (!looksLikeClosure) {
     if (args.length() != 1) {
       JS_ReportError(cx, "first argument must be a function");
       return false;
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -609,16 +609,22 @@ CompileFunctionBody(JSContext *cx, Mutab
         }
 
         parser.tokenStream.seek(start);
     }
 
     if (!NameFunctions(cx, fn))
         return false;
 
+    if (!SetDisplayURL(cx, parser.tokenStream, ss))
+        return false;
+
+    if (!SetSourceMap(cx, parser.tokenStream, ss))
+        return false;
+
     if (fn->pn_funbox->function()->isInterpreted()) {
         JS_ASSERT(fun == fn->pn_funbox->function());
 
         Rooted<JSScript*> script(cx, JSScript::Create(cx, js::NullPtr(), false, options,
                                                       /* staticLevel = */ 0, sourceObject,
                                                       /* sourceStart = */ 0, srcBuf.length()));
         if (!script)
             return false;
@@ -642,22 +648,16 @@ CompileFunctionBody(JSContext *cx, Mutab
 
         if (!EmitFunctionScript(cx, &funbce, fn->pn_body))
             return false;
     } else {
         fun.set(fn->pn_funbox->function());
         JS_ASSERT(IsAsmJSModuleNative(fun->native()));
     }
 
-    if (!SetDisplayURL(cx, parser.tokenStream, ss))
-        return false;
-
-    if (!SetSourceMap(cx, parser.tokenStream, ss))
-        return false;
-
     if (!sct.complete())
         return false;
 
     return true;
 }
 
 bool
 frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun,
--- a/js/src/jit-test/tests/asm.js/testSIMD.js
+++ b/js/src/jit-test/tests/asm.js/testSIMD.js
@@ -559,16 +559,83 @@ CheckF4Comp(NEF32, 'var y=f4(1,0,3,4);  
 CheckF4Comp(GTF32, 'var y=f4(1,2,3,4);  var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=gt(y,z)', [T, T, T, T]);
 CheckF4Comp(GTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4);  var x=i4(0,0,0,0); x=gt(y,z)', [F, F, F, F]);
 CheckF4Comp(GTF32, 'var y=f4(1,0,3,4);  var z=f4(1,1,7,0);  var x=i4(0,0,0,0); x=gt(y,z)', [F, F, F, T]);
 
 CheckF4Comp(GEF32, 'var y=f4(1,2,3,4);  var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=ge(y,z)', [T, T, T, T]);
 CheckF4Comp(GEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4);  var x=i4(0,0,0,0); x=ge(y,z)', [F, F, F, F]);
 CheckF4Comp(GEF32, 'var y=f4(1,0,3,4);  var z=f4(1,1,7,0);  var x=i4(0,0,0,0); x=ge(y,z)', [T, F, F, T]);
 
+// Conversions operators
+const CVTIF = 'var cvt=f4.fromInt32x4;';
+const CVTFI = 'var cvt=i4.fromFloat32x4;';
+
+assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromInt32x4; return {}");
+assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f");
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIF + 'function f(x){x=i4(x); var y=f4(0,0,0,0); y=cvt(x); return f4(y);} return f'), this);
+assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4]);
+assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MIN), Math.fround(INT32_MAX), -1]);
+
+// TODO amend tests once int32x4.fromFloat32x4 is fully specified, when float
+// values can't be converted into an int32 without overflowing.  In these
+// tests, we assume x86/x64, so a conversion which failed will return the
+// undefined int32 value. See also bug 1068028.
+const UNDEFINED_INT32 = 0x80000000 | 0;
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTFI + 'function f(x){x=f4(x); var y=i4(0,0,0,0); y=cvt(x); return i4(y);} return f'), this);
+assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4]);
+assertEqX4(f(SIMD.float32x4(NaN,Infinity,-Infinity,-0)), [UNDEFINED_INT32, UNDEFINED_INT32, UNDEFINED_INT32, 0]);
+
+// Cast operators
+const CVTIFB = 'var cvt=f4.fromInt32x4Bits;';
+const CVTFIB = 'var cvt=i4.fromFloat32x4Bits;';
+
+var cast = (function() {
+    var i32 = new Int32Array(1);
+    var f32 = new Float32Array(i32.buffer);
+
+    function fromInt32Bits(x) {
+        i32[0] = x;
+        return f32[0];
+    }
+
+    function fromFloat32Bits(x) {
+        f32[0] = x;
+        return i32[0];
+    }
+
+    return {
+        fromInt32Bits,
+        fromFloat32Bits
+    }
+})();
+
+assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromInt32x4; return {}");
+assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f");
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIFB + 'function f(x){x=i4(x); var y=f4(0,0,0,0); y=cvt(x); return f4(y);} return f'), this);
+assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits));
+assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits));
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32A + CVTIFB + 'function f(x){x=i4(x); var y=f4(0,0,0,0); var z=f4(1,1,1,1); y=cvt(x); y=f4a(y, z); return f4(y)} return f'), this);
+assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits).map((x) => x+1));
+assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits).map((x) => x+1));
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTFIB + 'function f(x){x=f4(x); var y=i4(0,0,0,0); y=cvt(x); return i4(y);} return f'), this);
+assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits));
+assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits));
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + I32A + CVTFIB + 'function f(x){x=f4(x); var y=i4(0,0,0,0); var z=i4(1,1,1,1); y=cvt(x); y=i4a(y,z); return i4(y);} return f'), this);
+assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits).map((x) => x+1));
+assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits).map((x) => x+1));
+
 // Bitwise ops
 const ANDI32 = 'var andd=i4.and;';
 const ORI32 = 'var orr=i4.or;';
 const XORI32 = 'var xorr=i4.xor;';
 
 CheckI4(ANDI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=andd(x,y)', [42 & 2, 1337 & 4, -1 & 7, 13 & 15]);
 CheckI4(ORI32, ' var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=orr(x,y)',  [42 | 2, 1337 | 4, -1 | 7, 13 | 15]);
 CheckI4(XORI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=xorr(x,y)', [42 ^ 2, 1337 ^ 4, -1 ^ 7, 13 ^ 15]);
--- a/js/src/jit-test/tests/basic/testErrorInFinalizerCalledWhileUnwinding.js
+++ b/js/src/jit-test/tests/basic/testErrorInFinalizerCalledWhileUnwinding.js
@@ -20,13 +20,13 @@ function test() {
     "this won't work"();
   }
 }
 
 try {
     test();
 } catch(e) {
     caught = true;
-    assertEq(e.toString().contains("ReferenceError: not_defined is not defined"), true);
+    assertEq(''+e, "ReferenceError: not_defined is not defined");
 }
 
 assertEq(finalizerRun, true);
 assertEq(caught, true);
deleted file mode 100644
--- a/js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-01.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Test that we get a suggestion in a ReferenceError's message.
-
-function levenshteinDistance() {}
-
-let e;
-try {
-  // Note "ie" instead of "ei" in "levenshtein".
-  levenshtienDistance()
-} catch (ee) {
-  e = ee;
-}
-
-assertEq(e !== undefined, true);
-assertEq(e.name, "ReferenceError");
-assertEq(e.message.contains("did you mean 'levenshteinDistance'?"), true);
deleted file mode 100644
--- a/js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-02.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Test that we don't waste cycles on edit distance when names are too long.
-
-const name = "a".repeat(10000);
-this[name] = () => {};
-
-let e;
-try {
-  eval(name + "a()");
-} catch (ee) {
-  e = ee;
-}
-
-assertEq(e !== undefined, true);
-assertEq(e.name, "ReferenceError");
-// Name was too long, shouldn't have provided a suggestion.
-assertEq(e.message.contains("did you mean"), false);
deleted file mode 100644
--- a/js/src/jit-test/tests/basic/testReferenceErrorNameSuggestion-03.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Test that we actually suggest the most similar name.
-
-function rza() {}
-function gza() {}
-function odb() {}
-function methodMan() {}
-function inspectahDeck() {}
-function raekwonTheChef() {}
-function ghostfaceKillah() {}
-function uGod() {}
-function mastaKillah() {}
-
-let e;
-try {
-  // Missing "d".
-  methoMan();
-} catch (ee) {
-  e = ee;
-}
-
-assertEq(e !== undefined, true);
-assertEq(e.name, "ReferenceError");
-assertEq(e.message.contains("did you mean 'methodMan'?"), true);
--- a/js/src/jit-test/tests/debug/Source-displayURL.js
+++ b/js/src/jit-test/tests/debug/Source-displayURL.js
@@ -64,8 +64,28 @@ g.evaluate('function f() {}\n' +
 assertEq(getDisplayURL(), 'http://example.com/bar.js');
 
 // With both a comment and the evaluate option.
 g.evaluate('function f() {}\n' +
            '//# sourceURL=http://example.com/foo.js',
            {displayURL: 'http://example.com/bar.js'});
 assertEq(getDisplayURL(), 'http://example.com/foo.js');
 
+
+// Bug 981987 reported that we hadn't set sourceURL yet when firing onNewScript
+// from the Function constructor.
+var capturedScript;
+var capturedDisplayURL;
+var capturedSourceMapURL;
+dbg.onNewScript = function (script) {
+  capturedScript = script;
+  capturedDisplayURL = script.source.displayURL;
+  capturedSourceMapURL = script.sourceMapURL;
+  dbg.onNewScript = undefined;
+};
+var fun = gw.makeDebuggeeValue(g.Function('//# sourceURL=munge.js\n//# sourceMappingURL=grunge.map\n'));
+assertEq(capturedScript, fun.script);
+
+assertEq(capturedDisplayURL, fun.script.source.displayURL);
+assertEq(capturedDisplayURL, 'munge.js');
+
+assertEq(capturedSourceMapURL, fun.script.sourceMapURL);
+assertEq(capturedSourceMapURL, 'grunge.map');
--- a/js/src/jit-test/tests/ion/recover-objects.js
+++ b/js/src/jit-test/tests/ion/recover-objects.js
@@ -1,10 +1,10 @@
 setJitCompilerOption("baseline.warmup.trigger", 10);
-setJitCompilerOption("ion.warmup.trigger", 20);
+setJitCompilerOption("ion.warmup.trigger", 30);
 
 var uceFault = function (i) {
     if (i > 98)
         uceFault = function (i) { return true; };
     return false;
 };
 
 // Without "use script" in the inner function, the arguments might be
@@ -107,18 +107,33 @@ function dynamicSlots(i) {
     };
     // Add a function call to capture a resumepoint at the end of the call or
     // inside the inlined block, such as the bailout does not rewind to the
     // beginning of the function.
     resumeHere(); bailout();
     assertEq(obj.p0 + obj.p10 + obj.p20 + obj.p30 + obj.p40, 5 * i + 100);
 }
 
+// Check that we can correctly recover allocations of new objects.
+function Point(x, y)
+{
+    this.x = x;
+    this.y = y;
+}
+
+function createThisWithTemplate(i)
+{
+    var p = new Point(i - 1, i + 1);
+    bailout();
+    assertEq(p.y - p.x, 2);
+}
+
 
 for (var i = 0; i < 100; i++) {
     notSoEmpty1(i);
     notSoEmpty2(i);
     observeArg(i);
     complexPhi(i);
     withinIf(i);
     unknownLoad(i);
     dynamicSlots(i);
+    createThisWithTemplate(i);
 }
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -5828,17 +5828,17 @@ DoGetNameFallback(JSContext *cx, Baselin
     JS_ASSERT(op == JSOP_NAME || op == JSOP_GETGNAME);
 
     RootedPropertyName name(cx, script->getName(pc));
 
     if (JSOp(pc[JSOP_GETGNAME_LENGTH]) == JSOP_TYPEOF) {
         if (!GetScopeNameForTypeOf(cx, scopeChain, name, res))
             return false;
     } else {
-        if (!GetScopeName(cx, script, pc, scopeChain, name, res))
+        if (!GetScopeName(cx, scopeChain, name, res))
             return false;
     }
 
     types::TypeScript::Monitor(cx, script, pc, res);
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
@@ -6500,17 +6500,17 @@ TryAttachNativeDoesNotExistStub(JSContex
 }
 
 static bool
 ComputeGetPropResult(JSContext *cx, BaselineFrame *frame, JSOp op, HandlePropertyName name,
                      MutableHandleValue val, MutableHandleValue res)
 {
     // Handle arguments.length and arguments.callee on optimized arguments, as
     // it is not an object.
-    if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && IsOptimizedArguments(frame, val.address())) {
+    if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && IsOptimizedArguments(frame, val)) {
         if (op == JSOP_LENGTH) {
             res.setInt32(frame->numActualArgs());
         } else {
             MOZ_ASSERT(name == cx->names().callee);
             MOZ_ASSERT(!frame->script()->strict());
             res.setObject(*frame->callee());
         }
     } else {
@@ -8507,17 +8507,18 @@ DoCallFallback(JSContext *cx, BaselineFr
 
     RootedValue callee(cx, vp[0]);
     RootedValue thisv(cx, vp[1]);
 
     Value *args = vp + 2;
 
     // Handle funapply with JSOP_ARGUMENTS
     if (op == JSOP_FUNAPPLY && argc == 2 && args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
-        if (!GuardFunApplyArgumentsOptimization(cx, frame, callee, args, argc))
+        CallArgs callArgs = CallArgsFromVp(argc, vp);
+        if (!GuardFunApplyArgumentsOptimization(cx, frame, callArgs))
             return false;
     }
 
     // Compute construcing and useNewType flags.
     bool constructing = (op == JSOP_NEW);
     bool newType = types::UseNewType(cx, script, pc);
 
     // Try attaching a call stub.
@@ -8527,17 +8528,17 @@ DoCallFallback(JSContext *cx, BaselineFr
     // Maybe update PC in profiler entry before leaving this script by call.
     if (cx->runtime()->spsProfiler.enabled() && frame->hasPushedSPSFrame())
         cx->runtime()->spsProfiler.updatePC(script, pc);
 
     if (!MaybeCloneFunctionAtCallsite(cx, &callee, script, pc))
         return false;
 
     if (op == JSOP_NEW) {
-        if (!InvokeConstructor(cx, callee, argc, args, res.address()))
+        if (!InvokeConstructor(cx, callee, argc, args, res))
             return false;
     } else if (op == JSOP_EVAL && frame->scopeChain()->global().valueIsEval(callee)) {
         if (!DirectEval(cx, CallArgsFromVp(argc, vp)))
             return false;
         res.set(vp[0]);
     } else {
         JS_ASSERT(op == JSOP_CALL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY || op == JSOP_EVAL);
         if (!Invoke(cx, thisv, callee, argc, args, res))
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -485,16 +485,26 @@ class CompileInfo
 
         return false;
     }
 
     // Returns true if a slot can be recovered before or during a bailout.  A
     // definition which can be observed and recovered, implies that this
     // definition can be optimized away as long as we can compute its values.
     bool isRecoverableOperand(uint32_t slot) const {
+        // If this script is not a function, then none of the slots are
+        // obserbavle.  If it this |slot| is not observable, thus we can always
+        // recover it.
+        if (!funMaybeLazy())
+            return true;
+
+        // The |this| can be recovered.
+        if (slot == thisSlot())
+            return true;
+
         if (isObservableFrameSlot(slot))
             return false;
 
         if (needsArgsObj() && isObservableArgumentSlot(slot))
             return false;
 
         return true;
     }
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5166,19 +5166,21 @@ IonBuilder::createThisScriptedSingleton(
 
     if (!target->nonLazyScript()->types)
         return nullptr;
     if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
         return nullptr;
 
     // Generate an inline path to create a new |this| object with
     // the given singleton prototype.
+    MConstant *templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
     MCreateThisWithTemplate *createThis =
-        MCreateThisWithTemplate::New(alloc(), constraints(), templateObject,
+        MCreateThisWithTemplate::New(alloc(), constraints(), templateConst,
                                      templateObject->type()->initialHeap(constraints()));
+    current->add(templateConst);
     current->add(createThis);
 
     return createThis;
 }
 
 MDefinition *
 IonBuilder::createThis(JSFunction *target, MDefinition *callee)
 {
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1719,17 +1719,17 @@ GetPropertyIC::update(JSContext *cx, siz
     void *returnAddr;
     RootedScript outerScript(cx, GetTopIonJSScript(cx, &returnAddr));
     IonScript *ion = outerScript->ionScript();
 
     GetPropertyIC &cache = ion->getCache(cacheIndex).toGetProperty();
     RootedPropertyName name(cx, cache.name());
 
     // Override the return value if we are invalidated (bug 728188).
-    AutoDetectInvalidation adi(cx, vp.address(), ion);
+    AutoDetectInvalidation adi(cx, vp, ion);
 
     // If the cache is idempotent, we will redo the op in the interpreter.
     if (cache.idempotent())
         adi.disable();
 
     // For now, just stop generating new stubs once we hit the stub count
     // limit. Once we can make calls from within generated stubs, a new call
     // stub will be generated instead and the previous stubs unlinked.
@@ -3456,17 +3456,17 @@ GetElementIC::update(JSContext *cx, size
     RootedScript outerScript(cx, GetTopIonJSScript(cx, &returnAddr));
     IonScript *ion = outerScript->ionScript();
     GetElementIC &cache = ion->getCache(cacheIndex).toGetElement();
     RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
 
     // Override the return value when the script is invalidated (bug 728188).
-    AutoDetectInvalidation adi(cx, res.address(), ion);
+    AutoDetectInvalidation adi(cx, res, ion);
 
     if (cache.isDisabled()) {
         if (!GetObjectElementOperation(cx, JSOp(*pc), obj, /* wasObject = */true, idval, res))
             return false;
         if (!cache.monitoredResult())
             types::TypeScript::Monitor(cx, script, pc, res);
         return true;
     }
@@ -4369,20 +4369,20 @@ NameIC::update(JSContext *cx, size_t cac
                 return false;
         } else if (IsCacheableNameCallGetter(scopeChain, obj, holder, shape)) {
             if (!cache.attachCallGetter(cx, outerScript, ion, scopeChain, obj, holder, shape, returnAddr))
                 return false;
         }
     }
 
     if (cache.isTypeOf()) {
-        if (!FetchName<true>(cx, script, pc, obj, holder, name, shape, vp))
+        if (!FetchName<true>(cx, obj, holder, name, shape, vp))
             return false;
     } else {
-        if (!FetchName<false>(cx, script, pc, obj, holder, name, shape, vp))
+        if (!FetchName<false>(cx, obj, holder, name, shape, vp))
             return false;
     }
 
     // Monitor changes to cache entry.
     types::TypeScript::Monitor(cx, script, pc, vp);
 
     return true;
 }
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -520,17 +520,17 @@ class SnapshotIterator
                 if (v.isObject())
                     *argsObj = &v.toObject().as<ArgumentsObject>();
             } else {
                 skip();
             }
         }
 
         if (thisv)
-            *thisv = read();
+            *thisv = maybeRead(fallback);
         else
             skip();
 
         unsigned i = 0;
         if (end < start)
             i = start;
 
         for (; i < start; i++)
@@ -713,39 +713,31 @@ class InlineFrameIterator
     JSObject *scopeChain() const {
         SnapshotIterator s(si_);
 
         // scopeChain
         Value v = s.read();
         return computeScopeChain(v);
     }
 
-    JSObject *thisObject() const {
-        // In strict modes, |this| may not be an object and thus may not be
-        // readable which can either segv in read or trigger the assertion.
-        Value v = thisValue();
-        JS_ASSERT(v.isObject());
-        return &v.toObject();
-    }
-
-    Value thisValue() const {
+    Value thisValue(MaybeReadFallback &fallback) const {
         // JS_ASSERT(isConstructing(...));
         SnapshotIterator s(si_);
 
         // scopeChain
         s.skip();
 
         // return value
         s.skip();
 
         // Arguments object.
         if (script()->argumentsHasVarBinding())
             s.skip();
 
-        return s.read();
+        return s.maybeRead(fallback);
     }
 
     InlineFrameIterator &operator++() {
         findNextFrame();
         return *this;
     }
 
     void dump() const;
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -3540,16 +3540,34 @@ class LValueToString : public LInstructi
         return mir_->toToString();
     }
 
     const LDefinition *tempToUnbox() {
         return getTemp(0);
     }
 };
 
+class LInt32x4ToFloat32x4 : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(Int32x4ToFloat32x4);
+    explicit LInt32x4ToFloat32x4(const LAllocation &input) {
+        setOperand(0, input);
+    }
+};
+
+class LFloat32x4ToInt32x4 : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(Float32x4ToInt32x4);
+    explicit LFloat32x4ToInt32x4(const LAllocation &input) {
+        setOperand(0, input);
+    }
+};
+
 // No-op instruction that is used to hold the entry snapshot. This simplifies
 // register allocation as it doesn't need to sniff the snapshot out of the
 // LIRGraph.
 class LStart : public LInstructionHelper<0, 0, 0>
 {
   public:
     LIR_HEADER(Start)
 };
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -161,16 +161,18 @@
     _(DoubleToInt32)                \
     _(Float32ToInt32)               \
     _(TruncateDToInt32)             \
     _(TruncateFToInt32)             \
     _(BooleanToString)              \
     _(IntToString)                  \
     _(DoubleToString)               \
     _(ValueToString)                \
+    _(Int32x4ToFloat32x4)           \
+    _(Float32x4ToInt32x4)           \
     _(Start)                        \
     _(OsrEntry)                     \
     _(OsrValue)                     \
     _(OsrScopeChain)                \
     _(OsrReturnValue)               \
     _(OsrArgumentsObject)           \
     _(RegExp)                       \
     _(RegExpExec)                   \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3702,16 +3702,43 @@ LIRGenerator::visitSimdConstant(MSimdCon
         return define(new(alloc()) LInt32x4(), ins);
     if (ins->type() == MIRType_Float32x4)
         return define(new(alloc()) LFloat32x4(), ins);
 
     MOZ_CRASH("Unknown SIMD kind when generating constant");
 }
 
 bool
+LIRGenerator::visitSimdConvert(MSimdConvert *ins)
+{
+    MOZ_ASSERT(IsSimdType(ins->type()));
+    MDefinition *input = ins->input();
+    LUse use = useRegisterAtStart(input);
+
+    if (ins->type() == MIRType_Int32x4) {
+        MOZ_ASSERT(input->type() == MIRType_Float32x4);
+        return define(new(alloc()) LFloat32x4ToInt32x4(use), ins);
+    }
+
+    if (ins->type() == MIRType_Float32x4) {
+        MOZ_ASSERT(input->type() == MIRType_Int32x4);
+        return define(new(alloc()) LInt32x4ToFloat32x4(use), ins);
+    }
+
+    MOZ_CRASH("Unknown SIMD kind when generating constant");
+}
+
+bool
+LIRGenerator::visitSimdReinterpretCast(MSimdReinterpretCast *ins)
+{
+    MOZ_ASSERT(IsSimdType(ins->type()) && IsSimdType(ins->input()->type()));
+    return redefine(ins, ins->input());
+}
+
+bool
 LIRGenerator::visitSimdExtractElement(MSimdExtractElement *ins)
 {
     JS_ASSERT(IsSimdType(ins->input()->type()));
     JS_ASSERT(!IsSimdType(ins->type()));
 
     if (ins->input()->type() == MIRType_Int32x4) {
         // Note: there could be int16x8 in the future, which doesn't use the
         // same instruction. We either need to pass the arity or create new LIns.
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -270,16 +270,18 @@ class LIRGenerator : public LIRGenerator
     bool visitRecompileCheck(MRecompileCheck *ins);
     bool visitSimdExtractElement(MSimdExtractElement *ins);
     bool visitSimdInsertElement(MSimdInsertElement *ins);
     bool visitSimdSignMask(MSimdSignMask *ins);
     bool visitSimdBinaryComp(MSimdBinaryComp *ins);
     bool visitSimdBinaryArith(MSimdBinaryArith *ins);
     bool visitSimdBinaryBitwise(MSimdBinaryBitwise *ins);
     bool visitSimdConstant(MSimdConstant *ins);
+    bool visitSimdConvert(MSimdConvert *ins);
+    bool visitSimdReinterpretCast(MSimdReinterpretCast *ins);
     bool visitPhi(MPhi *ins);
     bool visitBeta(MBeta *ins);
     bool visitObjectState(MObjectState *ins);
     bool visitArrayState(MArrayState *ins);
     bool visitUnknownValue(MUnknownValue *ins);
     bool visitLexicalCheck(MLexicalCheck *ins);
     bool visitThrowUninitializedLexical(MThrowUninitializedLexical *ins);
 };
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3162,21 +3162,33 @@ MBeta::printOpcode(FILE *fp) const
 
 bool
 MNewObject::shouldUseVM() const
 {
     JSObject *obj = templateObject();
     return obj->hasSingletonType() || obj->hasDynamicSlots();
 }
 
+bool
+MCreateThisWithTemplate::canRecoverOnBailout() const
+{
+    MOZ_ASSERT(!templateObject()->denseElementsAreCopyOnWrite());
+    MOZ_ASSERT(!templateObject()->is<ArrayObject>());
+    return true;
+}
+
 MObjectState::MObjectState(MDefinition *obj)
 {
     // This instruction is only used as a summary for bailout paths.
     setRecoveredOnBailout();
-    JSObject *templateObject = obj->toNewObject()->templateObject();
+    JSObject *templateObject = nullptr;
+    if (obj->isNewObject())
+        templateObject = obj->toNewObject()->templateObject();
+    else
+        templateObject = obj->toCreateThisWithTemplate()->templateObject();
     numSlots_ = templateObject->slotSpan();
     numFixedSlots_ = templateObject->numFixedSlots();
 }
 
 bool
 MObjectState::init(TempAllocator &alloc, MDefinition *obj)
 {
     if (!MVariadicInstruction::init(alloc, numSlots() + 1))
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1356,16 +1356,72 @@ class MSimdConstant : public MNullaryIns
         return value_;
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
+// Converts all lanes of a given vector into the type of another vector
+class MSimdConvert : public MUnaryInstruction
+{
+    MSimdConvert(MDefinition *obj, MIRType fromType, MIRType toType)
+      : MUnaryInstruction(obj)
+    {
+        MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
+        MOZ_ASSERT(IsSimdType(toType));
+        setResultType(toType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdConvert);
+    static MSimdConvert *NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
+                                  MIRType toType)
+    {
+        return new(alloc) MSimdConvert(obj, fromType, toType);
+    }
+
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition *ins) const {
+        return congruentIfOperandsEqual(ins);
+    }
+    ALLOW_CLONE(MSimdConvert)
+};
+
+// Casts bits of a vector input to another SIMD type (doesn't generate code).
+class MSimdReinterpretCast : public MUnaryInstruction
+{
+    MSimdReinterpretCast(MDefinition *obj, MIRType fromType, MIRType toType)
+      : MUnaryInstruction(obj)
+    {
+        MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
+        MOZ_ASSERT(IsSimdType(toType));
+        setResultType(toType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdReinterpretCast);
+    static MSimdReinterpretCast* NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
+                                          MIRType toType)
+    {
+        return new(alloc) MSimdReinterpretCast(obj, fromType, toType);
+    }
+
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition *ins) const {
+        return congruentIfOperandsEqual(ins);
+    }
+    ALLOW_CLONE(MSimdReinterpretCast)
+};
+
 // Extracts a lane element from a given vector type, given by its lane symbol.
 class MSimdExtractElement : public MUnaryInstruction
 {
   protected:
     SimdLane lane_;
 
     MSimdExtractElement(MDefinition *obj, MIRType type, SimdLane lane)
       : MUnaryInstruction(obj), lane_(lane)
@@ -3568,51 +3624,53 @@ class MAssertRange
     }
 
     void printOpcode(FILE *fp) const;
 };
 
 // Caller-side allocation of |this| for |new|:
 // Given a templateobject, construct |this| for JSOP_NEW
 class MCreateThisWithTemplate
-  : public MNullaryInstruction
-{
-    // Template for |this|, provided by TI
-    AlwaysTenuredObject templateObject_;
+  : public MUnaryInstruction
+{
     gc::InitialHeap initialHeap_;
 
-    MCreateThisWithTemplate(types::CompilerConstraintList *constraints, JSObject *templateObject,
+    MCreateThisWithTemplate(types::CompilerConstraintList *constraints, MConstant *templateConst,
                             gc::InitialHeap initialHeap)
-      : templateObject_(templateObject),
+      : MUnaryInstruction(templateConst),
         initialHeap_(initialHeap)
     {
         setResultType(MIRType_Object);
-        setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
+        setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
     }
 
   public:
     INSTRUCTION_HEADER(CreateThisWithTemplate);
     static MCreateThisWithTemplate *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
-                                        JSObject *templateObject, gc::InitialHeap initialHeap)
-    {
-        return new(alloc) MCreateThisWithTemplate(constraints, templateObject, initialHeap);
-    }
-
+                                        MConstant *templateConst, gc::InitialHeap initialHeap)
+    {
+        return new(alloc) MCreateThisWithTemplate(constraints, templateConst, initialHeap);
+    }
+
+    // Template for |this|, provided by TI.
     JSObject *templateObject() const {
-        return templateObject_;
+        return &getOperand(0)->toConstant()->value().toObject();
     }
 
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
     }
 
     // Although creation of |this| modifies global state, it is safely repeatable.
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
+
+    bool writeRecoverData(CompactBufferWriter &writer) const;
+    bool canRecoverOnBailout() const;
 };
 
 // Caller-side allocation of |this| for |new|:
 // Given a prototype operand, construct |this| for JSOP_NEW.
 class MCreateThisWithProto
   : public MBinaryInstruction,
     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
 {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -10,16 +10,18 @@
 namespace js {
 namespace jit {
 
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
     _(SimdValueX4)                                                          \
     _(SimdSplatX4)                                                          \
     _(SimdConstant)                                                         \
+    _(SimdConvert)                                                          \
+    _(SimdReinterpretCast)                                                  \
     _(SimdExtractElement)                                                   \
     _(SimdInsertElement)                                                    \
     _(SimdSignMask)                                                         \
     _(SimdBinaryComp)                                                       \
     _(SimdBinaryArith)                                                      \
     _(SimdBinaryBitwise)                                                    \
     _(SimdTernaryBitwise)                                                   \
     _(CloneLiteral)                                                         \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -109,16 +109,18 @@ class ParallelSafetyVisitor : public MDe
 
     // I am taking the policy of blacklisting everything that's not
     // obviously safe for now.  We can loosen as we need.
 
     SAFE_OP(Constant)
     SAFE_OP(SimdValueX4)
     SAFE_OP(SimdSplatX4)
     SAFE_OP(SimdConstant)
+    SAFE_OP(SimdConvert)
+    SAFE_OP(SimdReinterpretCast)
     SAFE_OP(SimdExtractElement)
     SAFE_OP(SimdInsertElement)
     SAFE_OP(SimdSignMask)
     SAFE_OP(SimdBinaryComp)
     SAFE_OP(SimdBinaryArith)
     SAFE_OP(SimdBinaryBitwise)
     SAFE_OP(SimdTernaryBitwise)
     UNSAFE_OP(CloneLiteral)
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -9,16 +9,18 @@
 #include "jscntxt.h"
 #include "jsmath.h"
 #include "jsobj.h"
 #include "jsstr.h"
 
 #include "builtin/RegExp.h"
 #include "builtin/TypedObject.h"
 
+#include "gc/Heap.h"
+
 #include "jit/JitFrameIterator.h"
 #include "jit/JitSpewer.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "jit/VMFunctions.h"
 
 #include "vm/Interpreter.h"
 #include "vm/Interpreter-inl.h"
@@ -1090,16 +1092,52 @@ RNewDerivedTypedObject::recover(JSContex
         return false;
 
     RootedValue result(cx, ObjectValue(*obj));
     iter.storeInstructionResult(result);
     return true;
 }
 
 bool
+MCreateThisWithTemplate::writeRecoverData(CompactBufferWriter &writer) const
+{
+    MOZ_ASSERT(canRecoverOnBailout());
+    writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateThisWithTemplate));
+    writer.writeByte(bool(initialHeap() == gc::TenuredHeap));
+    return true;
+}
+
+RCreateThisWithTemplate::RCreateThisWithTemplate(CompactBufferReader &reader)
+{
+    tenuredHeap_ = reader.readByte();
+}
+
+bool
+RCreateThisWithTemplate::recover(JSContext *cx, SnapshotIterator &iter) const
+{
+    RootedObject templateObject(cx, &iter.read().toObject());
+
+    // Use AutoEnterAnalysis to avoid invoking the object metadata callback
+    // while bailing out, which could try to walk the stack.
+    types::AutoEnterAnalysis enter(cx);
+
+    // See CodeGenerator::visitCreateThisWithTemplate
+    gc::AllocKind allocKind = templateObject->asTenured()->getAllocKind();
+    gc::InitialHeap initialHeap = tenuredHeap_ ? gc::TenuredHeap : gc::DefaultHeap;
+    JSObject *resultObject = JSObject::copy(cx, allocKind, initialHeap, templateObject);
+    if (!resultObject)
+        return false;
+
+    RootedValue result(cx);
+    result.setObject(*resultObject);
+    iter.storeInstructionResult(result);
+    return true;
+}
+
+bool
 MObjectState::writeRecoverData(CompactBufferWriter &writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
     writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState));
     writer.writeUnsigned(numSlots());
     return true;
 }
 
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -49,16 +49,17 @@ namespace jit {
     _(StringSplit)                              \
     _(RegExpExec)                               \
     _(RegExpTest)                               \
     _(RegExpReplace)                            \
     _(TypeOf)                                   \
     _(NewObject)                                \
     _(NewArray)                                 \
     _(NewDerivedTypedObject)                    \
+    _(CreateThisWithTemplate)                   \
     _(ObjectState)                              \
     _(ArrayState)
 
 class RResumePoint;
 class SnapshotIterator;
 
 class RInstruction
 {
@@ -552,16 +553,31 @@ class RNewDerivedTypedObject MOZ_FINAL :
 
     virtual uint32_t numOperands() const {
         return 3;
     }
 
     bool recover(JSContext *cx, SnapshotIterator &iter) const;
 };
 
+class RCreateThisWithTemplate MOZ_FINAL : public RInstruction
+{
+  private:
+    bool tenuredHeap_;
+
+  public:
+    RINSTRUCTION_HEADER_(CreateThisWithTemplate)
+
+    virtual uint32_t numOperands() const {
+        return 1;
+    }
+
+    bool recover(JSContext *cx, SnapshotIterator &iter) const;
+};
+
 class RObjectState MOZ_FINAL : public RInstruction
 {
   private:
     uint32_t numSlots_;        // Number of slots.
 
   public:
     RINSTRUCTION_HEADER_(ObjectState)
 
--- a/js/src/jit/ScalarReplacement.cpp
+++ b/js/src/jit/ScalarReplacement.cpp
@@ -132,17 +132,17 @@ EmulateStateOf<MemoryView>::run(MemoryVi
 // ScalarReplacementOfObject.
 //
 // For the moment, this code is dumb as it only supports objects which are not
 // changing shape, and which are known by TI at the object creation.
 static bool
 IsObjectEscaped(MInstruction *ins)
 {
     MOZ_ASSERT(ins->type() == MIRType_Object);
-    MOZ_ASSERT(ins->isNewObject() || ins->isGuardShape());
+    MOZ_ASSERT(ins->isNewObject() || ins->isGuardShape() || ins->isCreateThisWithTemplate());
 
     // Check if the object is escaped. If the object is not the first argument
     // of either a known Store / Load, then we consider it as escaped. This is a
     // cheap and conservative escape analysis.
     for (MUseIterator i(ins->usesBegin()); i != ins->usesEnd(); i++) {
         MNode *consumer = (*i)->consumer();
         if (!consumer->isDefinition()) {
             // Cannot optimize if it is observable from fun.arguments or others.
@@ -947,17 +947,17 @@ ScalarReplacement(MIRGenerator *mir, MIR
     EmulateStateOf<ArrayMemoryView> replaceArray(mir, graph);
     bool addedPhi = false;
 
     for (ReversePostorderIterator block = graph.rpoBegin(); block != graph.rpoEnd(); block++) {
         if (mir->shouldCancel("Scalar Replacement (main loop)"))
             return false;
 
         for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
-            if (ins->isNewObject() && !IsObjectEscaped(*ins)) {
+            if ((ins->isNewObject() || ins->isCreateThisWithTemplate()) && !IsObjectEscaped(*ins)) {
                 ObjectMemoryView view(graph.alloc(), *ins);
                 if (!replaceObject.run(view))
                     return false;
                 view.assertSuccess();
                 addedPhi = true;
                 continue;
             }
 
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -30,17 +30,18 @@ using namespace js::jit;
 
 namespace js {
 namespace jit {
 
 // Don't explicitly initialize, it's not guaranteed that this initializer will
 // run before the constructors for static VMFunctions.
 /* static */ VMFunction *VMFunction::functions;
 
-AutoDetectInvalidation::AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript)
+AutoDetectInvalidation::AutoDetectInvalidation(JSContext *cx, MutableHandleValue rval,
+                                               IonScript *ionScript)
   : cx_(cx),
     ionScript_(ionScript ? ionScript : GetTopIonJSScript(cx)->ionScript()),
     rval_(rval),
     disabled_(false)
 { }
 
 void
 VMFunction::addToFunctions()
@@ -79,17 +80,17 @@ InvokeFunction(JSContext *cx, HandleObje
     Value thisv = argv[0];
     Value *argvWithoutThis = argv + 1;
 
     // For constructing functions, |this| is constructed at caller side and we can just call Invoke.
     // When creating this failed / is impossible at caller site, i.e. MagicValue(JS_IS_CONSTRUCTING),
     // we use InvokeConstructor that creates it at the callee side.
     RootedValue rv(cx);
     if (thisv.isMagic(JS_IS_CONSTRUCTING)) {
-        if (!InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, rv.address()))
+        if (!InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, &rv))
             return false;
     } else {
         if (!Invoke(cx, thisv, ObjectValue(*obj), argc, argvWithoutThis, &rv))
             return false;
     }
 
     if (obj->is<JSFunction>()) {
         jsbytecode *pc;
@@ -343,17 +344,17 @@ ArraySpliceDense(JSContext *cx, HandleOb
     return js::array_splice_impl(cx, 2, argv.begin(), false);
 }
 
 bool
 ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
 {
     JS_ASSERT(obj->is<ArrayObject>());
 
-    AutoDetectInvalidation adi(cx, rval.address());
+    AutoDetectInvalidation adi(cx, rval);
 
     JS::AutoValueArray<2> argv(cx);
     argv[0].setUndefined();
     argv[1].setObject(*obj);
     if (!js::array_pop(cx, 0, argv.begin()))
         return false;
 
     // If the result is |undefined|, the array was probably empty and we
@@ -395,17 +396,17 @@ ArrayPushDense(JSContext *cx, HandleObje
     return true;
 }
 
 bool
 ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval)
 {
     JS_ASSERT(obj->is<ArrayObject>());
 
-    AutoDetectInvalidation adi(cx, rval.address());
+    AutoDetectInvalidation adi(cx, rval);
 
     JS::AutoValueArray<2> argv(cx);
     argv[0].setUndefined();
     argv[1].setObject(*obj);
     if (!js::array_shift(cx, 0, argv.begin()))
         return false;
 
     // If the result is |undefined|, the array was probably empty and we
@@ -1109,17 +1110,17 @@ SetDenseElement(JSContext *cx, HandleObj
 
     RootedValue indexVal(cx, Int32Value(index));
     return SetObjectElement(cx, obj, indexVal, value, strict);
 }
 
 void
 AutoDetectInvalidation::setReturnOverride()
 {
-    cx_->runtime()->jitRuntime()->setIonReturnOverride(*rval_);
+    cx_->runtime()->jitRuntime()->setIonReturnOverride(rval_.get());
 }
 
 #ifdef DEBUG
 void
 AssertValidObjectPtr(JSContext *cx, JSObject *obj)
 {
     // Check what we can, so that we'll hopefully assert/crash if we get a
     // bogus object (pointer).
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -582,23 +582,23 @@ template <class R, class Context, class 
 #undef COMPUTE_ARG_FLOAT
 #undef SEP_OR
 #undef NOTHING
 
 class AutoDetectInvalidation
 {
     JSContext *cx_;
     IonScript *ionScript_;
-    Value *rval_;
+    MutableHandleValue rval_;
     bool disabled_;
 
     void setReturnOverride();
 
   public:
-    AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript = nullptr);
+    AutoDetectInvalidation(JSContext *cx, MutableHandleValue rval, IonScript *ionScript = nullptr);
 
     void disable() {
         JS_ASSERT(!disabled_);
         disabled_ = true;
     }
 
     ~AutoDetectInvalidation() {
         if (!disabled_ && ionScript_->invalidated())
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -2485,66 +2485,66 @@ Simulator::decodeType01(SimInstruction *
                     set_register(rd_hi, hi_res);
                     if (instr->hasS())
                         MOZ_CRASH();
                 }
             } else {
                 if (instr->bit(23)) {
                     // Load-exclusive / store-exclusive.
                     //
-                    // Bare-bones simulation: the store always succeeds, and we do not
-                    // execute any fences.  Also, we allow readDW and writeDW to split
-                    // the memory transaction.
+                    // Bare-bones simulation: the store always succeeds, and we
+                    // do not execute any fences.  Also, we allow readDW and
+                    // writeDW to split the memory transaction.
                     //
-                    // The next step up would involve remembering the value that was
-                    // read with load-exclusive so that we could use compareExchange
-                    // for the store-exclusive, and to implement atomic doubleword
-                    // read and write.
+                    // The next step up would involve remembering the value
+                    // that was read with load-exclusive so that we could use
+                    // compareExchange for the store-exclusive, and to
+                    // implement atomic doubleword read and write.
                     //
                     // Also see DMB/DSB/ISB below.
                     if (instr->bit(20)) {
                         // Load-exclusive.
                         int rn = instr->rnValue();
                         int rt = instr->rtValue();
                         int32_t address = get_register(rn);
                         switch (instr->bits(22,21)) {
-                        case 0:
+                          case 0:
                             set_register(rt, readW(address, instr));
                             break;
-                        case 1:
+                          case 1:
                             set_dw_register(rt, readDW(address));
                             break;
-                        case 2:
+                          case 2:
                             set_register(rt, readBU(address));
                             break;
-                        case 3:
+                          case 3:
                             set_register(rt, readHU(address, instr));
                             break;
                         }
                     } else {
                         // Store-exclusive.
                         int rn = instr->rnValue();
                         int rd = instr->rdValue();
                         int rt = instr->bits(3,0);
                         int32_t address = get_register(rn);
                         int32_t value = get_register(rt);
                         switch (instr->bits(22,21)) {
-                        case 0:
+                          case 0:
                             writeW(address, value, instr);
                             break;
-                        case 1: {
-                            MOZ_ASSERT((rt % 2) == 0);
-                            int32_t value2 = get_register(rt+1);
-                            writeDW(address, value, value2);
-                            break;
-                        }
-                        case 2:
+                          case 1: {
+                              MOZ_ASSERT((rt % 2) == 0);
+                              int32_t value2 = get_register(rt+1);
+                              writeDW(address, value, value2);
+                              break;
+                          }
+                          case 2:
                             writeB(address, (uint8_t)value);
                             break;
-                        case 3:
+                          case 3:
                             writeH(address, (uint16_t)value, instr);
                             break;
                         }
                         set_register(rd, 0);
                     }
                 } else {
                     MOZ_CRASH(); // Not used atm
                 }
@@ -2945,23 +2945,23 @@ Simulator::decodeType2(SimInstruction *i
             writeW(addr, get_register(rd), instr);
     }
 }
 
 static uint32_t
 rotateBytes(uint32_t val, int32_t rotate)
 {
     switch (rotate) {
-    default:
+      default:
         return val;
-    case 1:
+      case 1:
         return (val >> 8) | (val << 24);
-    case 2:
+      case 2:
         return (val >> 16) | (val << 16);
-    case 3:
+      case 3:
         return (val >> 24) | (val << 8);
     }
 }
 
 void
 Simulator::decodeType3(SimInstruction *instr)
 {
     int rd = instr->rdValue();
@@ -3035,48 +3035,56 @@ Simulator::decodeType3(SimInstruction *i
                 }
             } else {
                 switch (instr->bits(22, 21)) {
                   case 0:
                     MOZ_CRASH();
                     break;
                   case 1:
                     if (instr->bits(7,4) == 7 && instr->bits(19,16) == 15) {
-                        uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), instr->bits(11, 10));
-                        if (instr->bit(20))
-                            set_register(rd, (int32_t)(int16_t)(rm_val & 0xFFFF)); // SXTH
-                        else
-                            set_register(rd, (int32_t)(int8_t)(rm_val & 0xFF));    // SXTB
+                        uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
+                                                      instr->bits(11, 10));
+                        if (instr->bit(20)) {
+                            // Sxth.
+                            set_register(rd, (int32_t)(int16_t)(rm_val & 0xFFFF));
+                        }
+                        else {
+                            // Sxtb.
+                            set_register(rd, (int32_t)(int8_t)(rm_val & 0xFF));
+                        }
                     } else {
                         MOZ_CRASH();
                     }
                     break;
                   case 2:
                     if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
                         if (instr->bits(19, 16) == 0xF) {
                             // Uxtb16.
-                            uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), instr->bits(11, 10));
+                            uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
+                                                          instr->bits(11, 10));
                             set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
                         } else {
                             MOZ_CRASH();
                         }
                     } else {
                         MOZ_CRASH();
                     }
                     break;
                   case 3:
                     if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
                         if (instr->bits(19, 16) == 0xF) {
                             // Uxtb.
-                            uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), instr->bits(11, 10));
+                            uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
+                                                          instr->bits(11, 10));
                             set_register(rd, (rm_val & 0xFF));
                         } else {
                             // Uxtab.
                             uint32_t rn_val = get_register(rn);
-                            uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), instr->bits(11, 10));
+                            uint32_t rm_val = rotateBytes(get_register(instr->rmValue()),
+                                                          instr->bits(11, 10));
                             set_register(rd, rn_val + (rm_val & 0xFF));
                         }
                     } else {
                         MOZ_CRASH();
                     }
                     break;
                 }
             }
@@ -4032,24 +4040,25 @@ Simulator::decodeSpecialCondition(SimIns
         } else {
             MOZ_CRASH();
         }
         break;
       case 0xA:
         if (instr->bits(31,20) == 0xf57) {
             // Minimal simulation: do nothing.
             //
-            // If/when we upgrade load-exclusive and store-exclusive (above) to do something
-            // useful concurrency-wise, we should also upgrade these instructions.
+            // If/when we upgrade load-exclusive and store-exclusive (above) to
+            // do something useful concurrency-wise, we should also upgrade
+            // these instructions.
             switch (instr->bits(7,4)) {
-            case 5: // DMB
-            case 4: // DSB
-            case 6: // ISB
+              case 5: // DMB
+              case 4: // DSB
+              case 6: // ISB
                 break;
-            default:
+              default:
                 MOZ_CRASH();
             }
         } else {
             MOZ_CRASH();
         }
         break;
       case 0xB:
         if (instr->bits(22, 20) == 5 && instr->bits(15, 12) == 0xf) {
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -1491,16 +1491,24 @@ class AssemblerX86Shared : public Assemb
     void cvtsi2ss(Register src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.cvtsi2ss_rr(src.code(), dest.code());
     }
     void cvtsi2sd(Register src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.cvtsi2sd_rr(src.code(), dest.code());
     }
+    void cvttps2dq(FloatRegister src, FloatRegister dest) {
+        MOZ_ASSERT(HasSSE2());
+        masm.cvttps2dq_rr(src.code(), dest.code());
+    }
+    void cvtdq2ps(FloatRegister src, FloatRegister dest) {
+        MOZ_ASSERT(HasSSE2());
+        masm.cvtdq2ps_rr(src.code(), dest.code());
+    }
     void movmskpd(FloatRegister src, Register dest) {
         JS_ASSERT(HasSSE2());
         masm.movmskpd_rr(src.code(), dest.code());
     }
     void movmskps(FloatRegister src, Register dest) {
         JS_ASSERT(HasSSE2());
         masm.movmskps_rr(src.code(), dest.code());
     }
--- a/js/src/jit/shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/shared/BaseAssembler-x86-shared.h
@@ -300,16 +300,18 @@ private:
         OP2_ORPS_VpsWps     = 0x56,
         OP2_XORPS_VpsWps    = 0x57,
         OP2_ADDSD_VsdWsd    = 0x58,
         OP2_ADDPS_VpsWps    = 0x58,
         OP2_MULSD_VsdWsd    = 0x59,
         OP2_MULPS_VpsWps    = 0x59,
         OP2_CVTSS2SD_VsdEd  = 0x5A,
         OP2_CVTSD2SS_VsdEd  = 0x5A,
+        OP2_CVTTPS2DQ_VdqWps = 0x5B,
+        OP2_CVTDQ2PS_VpsWdq = 0x5B,
         OP2_SUBSD_VsdWsd    = 0x5C,
         OP2_SUBPS_VpsWps    = 0x5C,
         OP2_MINSD_VsdWsd    = 0x5D,
         OP2_MINSS_VssWss    = 0x5D,
         OP2_MINPS_VpsWps    = 0x5D,
         OP2_DIVSD_VsdWsd    = 0x5E,
         OP2_DIVPS_VpsWps    = 0x5E,
         OP2_MAXSD_VsdWsd    = 0x5F,
@@ -2730,16 +2732,31 @@ public:
     void cvtsi2sd_rr(RegisterID src, XMMRegisterID dst)
     {
         spew("cvtsi2sd   %s, %s",
              nameIReg(src), nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src);
     }
 
+    void cvttps2dq_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        spew("cvttps2dq   %s, %s",
+             nameFPReg(src), nameFPReg(dst));
+        m_formatter.prefix(PRE_SSE_F3);
+        m_formatter.twoByteOp(OP2_CVTTPS2DQ_VdqWps, (RegisterID)dst, (RegisterID)src);
+    }
+
+    void cvtdq2ps_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        spew("cvtdq2ps   %s, %s",
+             nameFPReg(src), nameFPReg(dst));
+        m_formatter.twoByteOp(OP2_CVTDQ2PS_VpsWdq, (RegisterID)dst, (RegisterID)src);
+    }
+
 #ifdef JS_CODEGEN_X64
     void cvtsq2sd_rr(RegisterID src, XMMRegisterID dst)
     {
         spew("cvtsq2sd   %s, %s",
              nameIReg(src), nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteOp64(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src);
     }
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -2166,16 +2166,34 @@ bool
 CodeGeneratorX86Shared::visitFloat32x4(LFloat32x4 *ins)
 {
     const LDefinition *out = ins->getDef(0);
     masm.loadConstantFloat32x4(ins->getValue(), ToFloatRegister(out));
     return true;
 }
 
 bool
+CodeGeneratorX86Shared::visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4 *ins)
+{
+    FloatRegister in = ToFloatRegister(ins->input());
+    FloatRegister out = ToFloatRegister(ins->output());
+    masm.convertInt32x4ToFloat32x4(in, out);
+    return true;
+}
+
+bool
+CodeGeneratorX86Shared::visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4 *ins)
+{
+    FloatRegister in = ToFloatRegister(ins->input());
+    FloatRegister out = ToFloatRegister(ins->output());
+    masm.convertFloat32x4ToInt32x4(in, out);
+    return true;
+}
+
+bool
 CodeGeneratorX86Shared::visitSimdValueInt32x4(LSimdValueInt32x4 *ins)
 {
     MSimdValueX4 *mir = ins->mir();
     MOZ_ASSERT(mir->type() == MIRType_Int32x4);
 
     FloatRegister output = ToFloatRegister(ins->output());
     if (AssemblerX86Shared::HasSSE41()) {
         masm.movd(ToRegister(ins->getOperand(0)), output);
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -207,16 +207,18 @@ class CodeGeneratorX86Shared : public Co
     bool visitNegF(LNegF *lir);
 
     // SIMD operators
     bool visitSimdValueInt32x4(LSimdValueInt32x4 *lir);
     bool visitSimdValueFloat32x4(LSimdValueFloat32x4 *lir);
     bool visitSimdSplatX4(LSimdSplatX4 *lir);
     bool visitInt32x4(LInt32x4 *ins);
     bool visitFloat32x4(LFloat32x4 *ins);
+    bool visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4 *ins);
+    bool visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4 *ins);
     bool visitSimdExtractElementI(LSimdExtractElementI *lir);
     bool visitSimdExtractElementF(LSimdExtractElementF *lir);
     bool visitSimdInsertElementI(LSimdInsertElementI *lir);
     bool visitSimdInsertElementF(LSimdInsertElementF *lir);
     bool visitSimdSignMaskX4(LSimdSignMaskX4 *ins);
     bool visitSimdBinaryCompIx4(LSimdBinaryCompIx4 *lir);
     bool visitSimdBinaryCompFx4(LSimdBinaryCompFx4 *lir);
     bool visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *lir);
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -187,16 +187,19 @@ static inline bool
 IsCompatibleLIRCoercion(MIRType to, MIRType from)
 {
     if (to == from)
         return true;
     if ((to == MIRType_Int32 || to == MIRType_Boolean) &&
         (from == MIRType_Int32 || from == MIRType_Boolean)) {
         return true;
     }
+    // SIMD types can be coerced with from*Bits operators.
+    if (IsSimdType(to) && IsSimdType(from))
+        return true;
     return false;
 }
 
 bool
 LIRGeneratorShared::redefine(MDefinition *def, MDefinition *as)
 {
     JS_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type()));
 
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -462,16 +462,28 @@ class MacroAssemblerX86Shared : public A
     }
     void convertFloat32ToDouble(FloatRegister src, FloatRegister dest) {
         cvtss2sd(src, dest);
     }
     void convertDoubleToFloat32(FloatRegister src, FloatRegister dest) {
         cvtsd2ss(src, dest);
     }
 
+    void convertFloat32x4ToInt32x4(FloatRegister src, FloatRegister dest) {
+        // TODO: Note that if the conversion failed (because the converted
+        // result is larger than the maximum signed int32, or less than the
+        // least signed int32, or NaN), this will return the undefined integer
+        // value (0x8000000). Spec should define what to do in such cases. See
+        // also bug 1068020.
+        cvttps2dq(src, dest);
+    }
+    void convertInt32x4ToFloat32x4(FloatRegister src, FloatRegister dest) {
+        cvtdq2ps(src, dest);
+    }
+
     void bitwiseAndX4(const Operand &src, FloatRegister dest) {
         // TODO Using the "ps" variant for all types incurs a domain crossing
         // penalty for integer types and double.
         andps(src, dest);
     }
     void bitwiseAndNotX4(const Operand &src, FloatRegister dest) {
         andnps(src, dest);
     }
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -38,17 +38,16 @@
  *
  * to report:
  *
  * "Rhino is not a member of the Monkey family"
  */
 
 MSG_DEF(JSMSG_NOT_AN_ERROR,            0, JSEXN_NONE, "<Error #0 is reserved>")
 MSG_DEF(JSMSG_NOT_DEFINED,             1, JSEXN_REFERENCEERR, "{0} is not defined")
-MSG_DEF(JSMSG_NOT_DEFINED_DID_YOU_MEAN, 2, JSEXN_REFERENCEERR, "{0} is not defined, did you mean '{1}'?")
 MSG_DEF(JSMSG_MORE_ARGS_NEEDED,        3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}")
 MSG_DEF(JSMSG_INCOMPATIBLE_PROTO,      3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
 MSG_DEF(JSMSG_NO_CONSTRUCTOR,          1, JSEXN_TYPEERR, "{0} has no constructor")
 MSG_DEF(JSMSG_BAD_SORT_ARG,            0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
 MSG_DEF(JSMSG_CANT_WATCH,              1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}")
 MSG_DEF(JSMSG_READ_ONLY,               1, JSEXN_TYPEERR, "{0} is read-only")
 MSG_DEF(JSMSG_CANT_DELETE,             1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
 MSG_DEF(JSMSG_NOT_FUNCTION,            1, JSEXN_TYPEERR, "{0} is not a function")
--- a/js/src/jsapi-tests/testXDR.cpp
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -27,17 +27,17 @@ CompileScriptForPrincipalsVersionOrigin(
         return nullptr;
     JS_ALWAYS_TRUE(JS_DecodeBytes(cx, bytes, nbytes, chars, &nchars));
     JS::CompileOptions options(cx);
     options.setOriginPrincipals(originPrincipals)
            .setFileAndLine(filename, lineno)
            .setVersion(version);
     JS::RootedScript script(cx);
     JS::Compile(cx, obj, options, chars, nchars, &script);
-    free(chars);
+    JS_free(cx, chars);
     return script;
 }
 
 static JSScript *
 FreezeThaw(JSContext *cx, JS::HandleScript script)
 {
     // freeze
     uint32_t nbytes;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3992,29 +3992,39 @@ JS_GetFunctionDisplayId(JSFunction *fun)
 }
 
 JS_PUBLIC_API(uint16_t)
 JS_GetFunctionArity(JSFunction *fun)
 {
     return fun->nargs();
 }
 
+namespace JS {
+
+JS_PUBLIC_API(bool)
+IsCallable(JSObject *obj)
+{
+    return obj->isCallable();
+}
+
+JS_PUBLIC_API(bool)
+IsConstructor(JSObject *obj)
+{
+    return obj->isConstructor();
+}
+
+} /* namespace JS */
+
 JS_PUBLIC_API(bool)
 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
 {
     return obj->is<JSFunction>();
 }
 
 JS_PUBLIC_API(bool)
-JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
-{
-    return obj->isCallable();
-}
-
-JS_PUBLIC_API(bool)
 JS_IsNativeFunction(JSObject *funobj, JSNative call)
 {
     if (!funobj->is<JSFunction>())
         return false;
     JSFunction *fun = &funobj->as<JSFunction>();
     return fun->isNative() && fun->native() == call;
 }
 
@@ -4461,25 +4471,25 @@ JS::Compile(JSContext *cx, HandleObject 
     SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
     return Compile(cx, obj, options, srcBuf, script);
 }
 
 bool
 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
             const char *bytes, size_t length, MutableHandleScript script)
 {
-    mozilla::ScopedFreePtr<char16_t> chars;
+    mozilla::UniquePtr<char16_t, JS::FreePolicy> chars;
     if (options.utf8)
-        chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
+        chars.reset(UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get());
     else
-        chars = InflateString(cx, bytes, &length);
+        chars.reset(InflateString(cx, bytes, &length));
     if (!chars)
         return false;
 
-    return Compile(cx, obj, options, chars, length, script);
+    return Compile(cx, obj, options, chars.get(), length, script);
 }
 
 bool
 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, FILE *fp,
             MutableHandleScript script)
 {
     FileContents buffer(cx);
     if (!ReadCompleteFile(cx, fp, buffer))
@@ -4661,25 +4671,25 @@ JS::CompileFunction(JSContext *cx, Handl
     return JS::CompileFunction(cx, obj, options, name, nargs, argnames, srcBuf, fun);
 }
 
 JS_PUBLIC_API(bool)
 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
                     const char *name, unsigned nargs, const char *const *argnames,
                     const char *bytes, size_t length, MutableHandleFunction fun)
 {
-    mozilla::ScopedFreePtr<char16_t> chars;
+    mozilla::UniquePtr<char16_t, JS::FreePolicy> chars;
     if (options.utf8)
-        chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
+        chars.reset(UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get());
     else
-        chars = InflateString(cx, bytes, &length);
+        chars.reset(InflateString(cx, bytes, &length));
     if (!chars)
         return false;
 
-    return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length, fun);
+    return CompileFunction(cx, obj, options, name, nargs, argnames, chars.get(), length, fun);
 }
 
 JS_PUBLIC_API(bool)
 JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
                      unsigned nargs, const char *const *argnames,
                      const char16_t *chars, size_t length,
                      const CompileOptions &options, MutableHandleFunction fun)
 {
@@ -5028,17 +5038,17 @@ JS_PUBLIC_API(bool)
 JS::Construct(JSContext *cx, HandleValue fval, const JS::HandleValueArray& args,
               MutableHandleValue rval)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, fval, args);
     AutoLastFrameCheck lfc(cx);
 
-    return InvokeConstructor(cx, fval, args.length(), args.begin(), rval.address());
+    return InvokeConstructor(cx, fval, args.length(), args.begin(), rval);
 }
 
 static JSObject *
 JS_NewHelper(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, ctor, inputArgs);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3376,28 +3376,39 @@ JS_GetFunctionDisplayId(JSFunction *fun)
 
 /*
  * Return the arity (length) of fun.
  */
 extern JS_PUBLIC_API(uint16_t)
 JS_GetFunctionArity(JSFunction *fun);
 
 /*
+ * API for determining callability and constructability. This does the right
+ * thing for proxies.
+ */
+namespace JS {
+
+extern JS_PUBLIC_API(bool)
+IsCallable(JSObject *obj);
+
+extern JS_PUBLIC_API(bool)
+IsConstructor(JSObject *obj);
+
+} /* namespace JS */
+
+/*
  * Infallible predicate to test whether obj is a function object (faster than
  * comparing obj's class name to "Function", but equivalent unless someone has
  * overwritten the "Function" identifier with a different constructor and then
  * created instances using that constructor that might be passed in as obj).
  */
 extern JS_PUBLIC_API(bool)
 JS_ObjectIsFunction(JSContext *cx, JSObject *obj);
 
 extern JS_PUBLIC_API(bool)
-JS_ObjectIsCallable(JSContext *cx, JSObject *obj);
-
-extern JS_PUBLIC_API(bool)
 JS_IsNativeFunction(JSObject *funobj, JSNative call);
 
 /* Return whether the given function is a valid constructor. */
 extern JS_PUBLIC_API(bool)
 JS_IsConstructor(JSFunction *fun);
 
 /*
  * Bind the given callable to use the given object as "this".
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2943,17 +2943,17 @@ array_of(JSContext *cx, unsigned argc, V
         return ArrayFromCallArgs(cx, type, args);
     }
 
     // Step 4.
     RootedObject obj(cx);
     {
         RootedValue v(cx);
         Value argv[1] = {NumberValue(args.length())};
-        if (!InvokeConstructor(cx, args.thisv(), 1, argv, v.address()))
+        if (!InvokeConstructor(cx, args.thisv(), 1, argv, &v))
             return false;
         obj = ToObject(cx, v);
         if (!obj)
             return false;
     }
 
     // Step 8.
     for (unsigned k = 0; k < args.length(); k++) {
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -9,17 +9,16 @@
  */
 
 #include "jscntxtinlines.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 
-#include <algorithm>
 #include <ctype.h>
 #include <stdarg.h>
 #include <string.h>
 #ifdef ANDROID
 # include <android/log.h>
 # include <fstream>
 # include <string>
 #endif  // ANDROID
@@ -45,17 +44,16 @@
 #include "js/OldDebugAPI.h"
 #include "vm/Debugger.h"
 #include "vm/HelperThreads.h"
 #include "vm/Shape.h"
 
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
-#include "vm/ScopeObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::DebugOnly;
 using mozilla::PodArrayZero;
 using mozilla::PodZero;
@@ -876,188 +874,20 @@ js::CallErrorReporter(JSContext *cx, con
 {
     JS_ASSERT(message);
     JS_ASSERT(reportp);
 
     if (JSErrorReporter onError = cx->runtime()->errorReporter)
         onError(cx, message, reportp);
 }
 
-static const size_t MAX_NAME_LENGTH_FOR_EDIT_DISTANCE = 1000;
-static const size_t MAX_REFERENCE_ERROR_NAMES_TO_CHECK = 1000;
-
-/*
- * The edit distance between two strings is defined as the Levenshtein distance,
- * which is described here: (http://en.wikipedia.org/wiki/Levenshtein_distance).
- * Intuitively, this is the number of insert, delete, and/or substitution
- * operations required to get from one string to the other.
- *
- * Given two atoms, this function computes their edit distance using dynamic
- * programming. The resulting algorithm has O(m * n) complexity, but since it is
- * only used for ReferenceError reporting, and the given atoms are expected to
- * be small, its performance should be good enough. Despite that, we will only
- * compute the edit distance for names whose length are shorter than
- * MAX_NAME_LENGTH_FOR_EDIT_DISTANCE. We shouldn't ever find a pair with an edit
- * distance of 0 (or else there wouldn't have been a ReferenceError), so we set
- * the value presult points to to 0 and return true when a name is too long.
- */
-static bool ComputeEditDistance(JSContext *cx, HandleAtom atom1,
-                                HandleAtom atom2, size_t *presult)
+void
+js_ReportIsNotDefined(JSContext *cx, const char *name)
 {
-    *presult = 0;
-
-    const size_t m = atom1->length();
-    if (m >= MAX_NAME_LENGTH_FOR_EDIT_DISTANCE)
-        return true;
-    const size_t n = atom2->length();
-    if (m >= MAX_NAME_LENGTH_FOR_EDIT_DISTANCE)
-        return true;
-
-    Vector<size_t> d(cx);
-    if (!d.growBy((m + 1) * (n + 1)))
-        return false;
-
-    AutoStableStringChars aChars(cx);
-    AutoStableStringChars bChars(cx);
-    if (!aChars.initTwoByte(cx, atom1) || !bChars.initTwoByte(cx, atom2))
-        return false;
-
-    const char16_t *a = aChars.twoByteRange().start().get();
-    const char16_t *b = bChars.twoByteRange().start().get();
-
-    /*
-     * D(i, j) is defined as the edit distance between the i-length prefix
-     * of a and the m-length prefix of b.
-     */
-#define D(i, j) (d[(i) * ((n) + 1) + (j)])
-
-    /*
-     * Given the i-length prefix of a, the 0-length prefix of b can be
-     * obtained by deleting i characters.
-     */
-    for (size_t i = 0; i <= m; ++i)
-        D(i, 0) = i;
-
-    /*
-     * Given the j-length prefix of b, the 0-length prefix of a can be
-     * obtained by inserting i characters.
-     */
-    for (size_t j = 0; j <= n; ++j)
-        D(0, j) = j;
-
-    for (size_t i = 1; i <= m; ++i) {
-        for (size_t j = 1; j <= n; ++j) {
-            /*
-             * If the i-length prefix of a and the j-length prefix of b are
-             * equal in their last character, their edit distance equals
-             * that of the i-1-length and j-1-length prefix of a and b,
-             * respectively.
-             */
-            if (a[i - 1] == b[j - 1])
-                D(i, j) = D(i - 1, j - 1); // No operation required
-            else {
-                D(i, j) = std::min(
-                                   D(i - 1, j) + 1, // Deletion
-                                   std::min(
-                                            D(i, j - 1) + 1, // Insertion
-                                            D(i - 1, j - 1) + 1 // Substitution
-                                            )
-                                   );
-            }
-        }
-    }
-
-    *presult = D(m, n);
-
-#undef D
-
-    return true;
-}
-
-void
-js_ReportIsNotDefined(JSContext *cx, HandleScript script, jsbytecode *pc, HandleAtom atom)
-{
-    /*
-     * Walk the static scope chain and the global object to find the name that
-     * most closely matches the one we are looking for, so we can provide it as
-     * a hint to the user.
-     *
-     * To quantify how closely one name matches another, we define a metric on
-     * strings known as the edit distance (see ComputeEditDistance for details).
-     * We then pick the name with the shortest edit distance from the name we
-     * were trying to find.
-     */
-    AutoIdVector ids(cx);
-    for (StaticScopeIter<CanGC> ssi(cx, InnermostStaticScope(script, pc)); !ssi.done(); ssi++) {
-        switch (ssi.type()) {
-          case StaticScopeIter<NoGC>::BLOCK:
-            if (!GetPropertyNames(cx, &ssi.block(), JSITER_OWNONLY, &ids)) {
-                /*
-                 * If GetPropertyNames fails (due to overrecursion), we still
-                 * want to act as if we had never called it, and report the
-                 * reference error instead. Otherwise, we would break
-                 * tests/gc/bug-886560.js.
-                 */
-                js_ReportIsNotDefined(cx, atom);
-                return;
-            }
-            break;
-
-          case StaticScopeIter<NoGC>::FUNCTION:
-          {
-            RootedScript script(cx, ssi.funScript());
-            for (BindingIter bi(script); !bi.done(); bi++)
-                ids.append(NameToId(bi->name()));
-            break;
-          }
-
-          case StaticScopeIter<CanGC>::NAMED_LAMBDA:
-            ids.append(NameToId(ssi.lambdaName()));
-            break;
-        }
-    }
-    if (!GetPropertyNames(cx, cx->glo