Merge inbound to m-c
authorWes Kocher <wkocher@mozilla.com>
Tue, 15 Oct 2013 20:15:17 -0700
changeset 150829 1990042c0ae6cb896c03d637edb2159bb1c7c90f
parent 150788 71909c62bc14f4eb4ad0c535207ad8d92a6066e6 (current diff)
parent 150828 a2e78dec2ccf750bc511d0b53d059bc35fcfdc06 (diff)
child 150838 9f63bbc005279333095be0000696dcf12629b16d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone27.0a1
Merge inbound to m-c
testing/marionette/client/marionette/venv_mochitest.sh
toolkit/library/Makefile.in
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -308,17 +308,17 @@ var gPluginHandler = {
         break;
 
       case "PluginInstantiated":
       case "PluginRemoved":
         shouldShowNotification = true;
         break;
     }
 
-    // Hide the in-content UI if it's too big. The crashed plugin handler already did this.
+    // Show the in-content UI if it's not too big. The crashed plugin handler already did this.
     if (eventType != "PluginCrashed" && eventType != "PluginRemoved") {
       let overlay = this.getPluginUI(plugin, "main");
       if (overlay != null) {
         if (!this.isTooSmall(plugin, overlay))
           overlay.style.visibility = "visible";
 
         plugin.addEventListener("overflow", function(event) {
           overlay.style.visibility = "hidden";
@@ -984,22 +984,22 @@ var gPluginHandler = {
     // Is the <object>'s size too small to hold what we want to show?
     if (this.isTooSmall(plugin, overlay)) {
       // First try hiding the crash report submission UI.
       statusDiv.removeAttribute("status");
 
       if (this.isTooSmall(plugin, overlay)) {
         // Hide the overlay's contents. Use visibility style, so that it doesn't
         // collapse down to 0x0.
-        overlay.style.visibility = "hidden";
         isShowing = false;
       }
     }
 
     if (isShowing) {
+      overlay.style.visibility = "visible";
       // If a previous plugin on the page was too small and resulted in adding a
       // notification bar, then remove it because this plugin instance it big
       // enough to serve as in-content notification.
       hideNotificationBar();
       doc.mozNoPluginCrashedNotification = true;
     } else {
       // If another plugin on the page was large enough to show our UI, we don't
       // want to show a notification bar.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -919,16 +919,17 @@ nsContentUtils::GetParserService()
  * @return              the set of flags
  */
 uint32_t
 nsContentUtils::ParseSandboxAttributeToFlags(const nsAString& aSandboxAttrValue)
 {
   // If there's a sandbox attribute at all (and there is if this is being
   // called), start off by setting all the restriction flags.
   uint32_t out = SANDBOXED_NAVIGATION |
+                 SANDBOXED_AUXILIARY_NAVIGATION |
                  SANDBOXED_TOPLEVEL_NAVIGATION |
                  SANDBOXED_PLUGINS |
                  SANDBOXED_ORIGIN |
                  SANDBOXED_FORMS |
                  SANDBOXED_SCRIPTS |
                  SANDBOXED_AUTOMATIC_FEATURES |
                  SANDBOXED_POINTER_LOCK |
                  SANDBOXED_DOMAIN;
@@ -949,16 +950,18 @@ nsContentUtils::ParseSandboxAttributeToF
         // allow-scripts removes both SANDBOXED_SCRIPTS and
         // SANDBOXED_AUTOMATIC_FEATURES.
         out &= ~SANDBOXED_SCRIPTS;
         out &= ~SANDBOXED_AUTOMATIC_FEATURES;
       } else if (token.LowerCaseEqualsLiteral("allow-top-navigation")) {
         out &= ~SANDBOXED_TOPLEVEL_NAVIGATION;
       } else if (token.LowerCaseEqualsLiteral("allow-pointer-lock")) {
         out &= ~SANDBOXED_POINTER_LOCK;
+      } else if (token.LowerCaseEqualsLiteral("allow-popups")) {
+        out &= ~SANDBOXED_AUXILIARY_NAVIGATION;
       }
     }
   }
 
   return out;
 }
 
 #ifdef IBMBIDI
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5214,17 +5214,17 @@ nsDocument::Register(JSContext* aCx, con
     if (!protoObject) {
       rv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
   } else {
     // If a prototype is provided, we must check to ensure that it inherits
     // from HTMLElement.
     protoObject = aOptions.mPrototype;
-    if (!JS_WrapObject(aCx, protoObject.address())) {
+    if (!JS_WrapObject(aCx, &protoObject)) {
       rv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
 
     // Check the proto chain for HTMLElement prototype.
     JS::Rooted<JSObject*> protoProto(aCx);
     if (!JS_GetPrototype(aCx, protoObject, &protoProto)) {
       rv.Throw(NS_ERROR_UNEXPECTED);
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -225,24 +225,23 @@ mozilla::dom::ipc::UnpackClonedMessageDa
 
 StructuredCloneData
 mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aData)
 {
   return UnpackClonedMessageData<Child>(aData);
 }
 
 bool
-SameProcessCpowHolder::ToObject(JSContext* aCx, JSObject** aObjp)
+SameProcessCpowHolder::ToObject(JSContext* aCx, JS::MutableHandleObject aObjp)
 {
-  *aObjp = mObj;
-
   if (!mObj) {
     return true;
   }
 
+  aObjp.set(mObj);
   return JS_WrapObject(aCx, aObjp);
 }
 
 // nsIMessageListenerManager
 
 NS_IMETHODIMP
 nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
                                           nsIMessageListener* aListener)
@@ -833,17 +832,17 @@ nsFrameMessageManager::ReceiveMessage(ns
 
         JS::Rooted<JS::Value> targetv(ctx);
         JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
         nsContentUtils::WrapNative(ctx, global, aTarget, targetv.address(),
                                    nullptr, true);
 
         JS::RootedObject cpows(ctx);
         if (aCpows) {
-          if (!aCpows->ToObject(ctx, cpows.address())) {
+          if (!aCpows->ToObject(ctx, &cpows)) {
             return NS_ERROR_UNEXPECTED;
           }
         }
 
         if (!cpows) {
           cpows = JS_NewObject(ctx, nullptr, nullptr, nullptr);
           if (!cpows) {
             return NS_ERROR_UNEXPECTED;
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -117,28 +117,28 @@ struct nsMessageListenerInfo
   nsCOMPtr<nsIMessageListener> mStrongListener;
   nsWeakPtr mWeakListener;
   nsCOMPtr<nsIAtom> mMessage;
 };
 
 class CpowHolder
 {
   public:
-    virtual bool ToObject(JSContext* cx, JSObject** objp) = 0;
+    virtual bool ToObject(JSContext* cx, JS::MutableHandleObject objp) = 0;
 };
 
 class MOZ_STACK_CLASS SameProcessCpowHolder : public CpowHolder
 {
   public:
     SameProcessCpowHolder(JSRuntime *aRuntime, JS::Handle<JSObject *> aObj)
       : mObj(aRuntime, aObj)
     {
     }
 
-    bool ToObject(JSContext* aCx, JSObject** aObjp);
+    bool ToObject(JSContext* aCx, JS::MutableHandleObject aObjp);
 
   private:
     JS::Rooted<JSObject*> mObj;
 };
 
 class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
                                         public nsIMessageBroadcaster,
                                         public nsIFrameScriptLoader,
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -67,22 +67,18 @@ GK_ATOM(actuate, "actuate")
 GK_ATOM(address, "address")
 GK_ATOM(after, "after")
 GK_ATOM(after_end, "after_end")
 GK_ATOM(after_start, "after_start")
 GK_ATOM(align, "align")
 GK_ATOM(alink, "alink")
 GK_ATOM(all, "all")
 GK_ATOM(allowevents, "allowevents")
-GK_ATOM(allowforms, "allow-forms")
 GK_ATOM(allownegativeassertions, "allownegativeassertions")
 GK_ATOM(allowfullscreen, "allowfullscreen")
-GK_ATOM(allowsameorigin, "allow-same-origin")
-GK_ATOM(allowscripts, "allow-scripts")
-GK_ATOM(allowtopnavigation, "allow-top-navigation")
 GK_ATOM(allowuntrusted, "allowuntrusted")
 GK_ATOM(alt, "alt")
 GK_ATOM(alternate, "alternate")
 GK_ATOM(always, "always")
 GK_ATOM(ancestor, "ancestor")
 GK_ATOM(ancestorOrSelf, "ancestor-or-self")
 GK_ATOM(_and, "and")
 GK_ATOM(any, "any")
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -3120,17 +3120,17 @@ nsObjectLoadingContent::LegacyCall(JSCon
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   JS::Rooted<JSObject*> obj(aCx, thisContent->GetWrapper());
   MOZ_ASSERT(obj, "How did we get called?");
 
   // Make sure we're not dealing with an Xray.  Our DoCall code can't handle
   // random cross-compartment wrappers, so we're going to have to wrap
   // everything up into our compartment, but that means we need to check that
   // this is not an Xray situation by hand.
-  if (!JS_WrapObject(aCx, obj.address())) {
+  if (!JS_WrapObject(aCx, &obj)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return JS::UndefinedValue();
   }
 
   if (nsDOMClassInfo::ObjectIsNativeWrapper(aCx, obj)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return JS::UndefinedValue();
   }
--- a/content/base/src/nsSandboxFlags.h
+++ b/content/base/src/nsSandboxFlags.h
@@ -8,18 +8,21 @@
  * HTML5 spec.
  */
 
 #ifndef nsSandboxFlags_h___
 #define nsSandboxFlags_h___
 
 /**
  * This flag prevents content from navigating browsing contexts other than
- * the sandboxed browsing context itself (or browsing contexts further
- * nested inside it), and the top-level browsing context.
+ * itself, browsing contexts nested inside it, the top-level browsing context
+ * and browsing contexts that it has opened.
+ * As it is always on for sandboxed browsing contexts, it is used implicitly
+ * within the code by checking that the overall flags are non-zero.
+ * It is only uesd directly when the sandbox flags are initially set up.
  */
 const unsigned long SANDBOXED_NAVIGATION  = 0x1;
 
 /**
  * This flag prevents content from navigating their top-level browsing
  * context.
  */
 const unsigned long SANDBOXED_TOPLEVEL_NAVIGATION = 0x2;
@@ -60,9 +63,16 @@ const unsigned long SANDBOXED_AUTOMATIC_
  * This flag blocks the document from acquiring pointerlock.
  */
 const unsigned long SANDBOXED_POINTER_LOCK = 0x80;
 
 /**
  * This flag blocks the document from changing document.domain.
  */
 const unsigned long SANDBOXED_DOMAIN = 0x100;
+
+/**
+ * This flag prevents content from creating new auxiliary browsing contexts,
+ * e.g. using the target attribute, the window.open() method, or the
+ * showModalDialog() method.
+ */
+const unsigned long SANDBOXED_AUXILIARY_NAVIGATION = 0x200;
 #endif
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -2367,16 +2367,18 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
       RefPtr<ScaledFont> scaledFont =
         gfxPlatform::GetPlatform()->GetScaledFontForFont(mCtx->mTarget, font);
 
       if (!scaledFont) {
         // This can occur when something switched DirectWrite off.
         return;
       }
 
+      RefPtr<GlyphRenderingOptions> renderingOptions = font->GetGlyphRenderingOptions();
+
       GlyphBuffer buffer;
 
       std::vector<Glyph> glyphBuf;
 
       for (uint32_t i = runs[c].mCharacterOffset; i < endRun; i++) {
         Glyph newGlyph;
         if (glyphs[i].IsSimpleGlyph()) {
           newGlyph.mIndex = glyphs[i].GetSimpleGlyph();
@@ -2438,17 +2440,18 @@ struct MOZ_STACK_CLASS CanvasBidiProcess
       Rect bounds = mCtx->mTarget->GetTransform().
         TransformBounds(Rect(mBoundingBox.x, mBoundingBox.y,
                              mBoundingBox.width, mBoundingBox.height));
       if (mOp == CanvasRenderingContext2D::TEXT_DRAW_OPERATION_FILL) {
         AdjustedTarget(mCtx, &bounds)->
           FillGlyphs(scaledFont, buffer,
                      CanvasGeneralPattern().
                        ForStyle(mCtx, CanvasRenderingContext2D::STYLE_FILL, mCtx->mTarget),
-                     DrawOptions(mState->globalAlpha, mCtx->UsedOperation()));
+                     DrawOptions(mState->globalAlpha, mCtx->UsedOperation()),
+                     renderingOptions);
       } else if (mOp == CanvasRenderingContext2D::TEXT_DRAW_OPERATION_STROKE) {
         // stroke glyphs one at a time to avoid poor CoreGraphics performance
         // when stroking a path with a very large number of points
         buffer.mGlyphs = &glyphBuf.front();
         buffer.mNumGlyphs = 1;
         const ContextState& state = *mState;
         AdjustedTarget target(mCtx, &bounds);
         const StrokeOptions strokeOpts(state.lineWidth, state.lineJoin,
--- a/content/html/content/src/HTMLUnknownElement.cpp
+++ b/content/html/content/src/HTMLUnknownElement.cpp
@@ -19,17 +19,17 @@ HTMLUnknownElement::WrapNode(JSContext *
     HTMLUnknownElementBinding::Wrap(aCx, aScope, this));
   if (obj && Substring(NodeName(), 0, 2).LowerCaseEqualsLiteral("x-")) {
     // If we have a registered x-tag then we fix the prototype.
     JSAutoCompartment ac(aCx, obj);
     nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
     JS::Rooted<JSObject*> prototype(aCx);
     document->GetCustomPrototype(LocalName(), &prototype);
     if (prototype) {
-      NS_ENSURE_TRUE(JS_WrapObject(aCx, prototype.address()), nullptr);
+      NS_ENSURE_TRUE(JS_WrapObject(aCx, &prototype), nullptr);
       NS_ENSURE_TRUE(JS_SetPrototype(aCx, obj, prototype), nullptr);
     }
   }
   return obj;
 }
 
 NS_IMPL_ELEMENT_CLONE(HTMLUnknownElement)
 
--- a/content/html/content/test/file_iframe_sandbox_a_if4.html
+++ b/content/html/content/test/file_iframe_sandbox_a_if4.html
@@ -7,21 +7,23 @@
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 
 <script type="text/javascript">
 function doStuff() {
   try {
     window.parent.ok_wrapper(false, "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with its parent");
   } catch(e) {
+    window.parent.parent.postMessage({type: "ok", ok: true, desc: "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with its parent"}, "*");
   }
 
   try {
     window.parent.parent.ok_wrapper(false, "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with the top level");
   } catch(e) {
+    window.parent.parent.postMessage({type: "ok", ok: true, desc: "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with the top level"}, "*");
   }
 }
 </script>
 
 <body onLoad="doStuff()">
   I am not sandboxed but contained within a sandboxed document with 'allow-scripts'
 </body>
 </html>
--- a/content/html/content/test/file_iframe_sandbox_b_if3.html
+++ b/content/html/content/test/file_iframe_sandbox_b_if3.html
@@ -8,17 +8,17 @@
 <script>
   function ok(result, message) {
     window.parent.postMessage({ok: result, desc: message}, "*");
   }
 
   function testXHR() {
   var xhr = new XMLHttpRequest();
 
-  xhr.open("GET", "file_iframe_sandbox_if1.html");
+  xhr.open("GET", "file_iframe_sandbox_b_if1.html");
 
   xhr.onreadystatechange = function (oEvent) {
     var result = false;
     if (xhr.readyState == 4) {
       if (xhr.status == 0) {
         result = true;
       }
       ok(result, "XHR should be blocked in an iframe sandboxed WITHOUT 'allow-same-origin'");
--- a/content/html/content/test/file_iframe_sandbox_c_if4.html
+++ b/content/html/content/test/file_iframe_sandbox_c_if4.html
@@ -1,44 +1,45 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 341604</title>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
 </head>
 <script type="text/javascript">
   function ok(result, desc) {
     window.parent.ok_wrapper(result, desc);
   }
 
   function doStuff() {
-    // try to open a new window via target="_blank", window.open(), and showModalDialog()
+    // try to open a new window via target="_blank", target="BC341604", window.open(), and showModalDialog()
     // the window we try to open closes itself once it opens
     sendMouseEvent({type:'click'}, 'target_blank');
+    sendMouseEvent({type:'click'}, 'target_BC341604');
 
     var threw = false;
     try {
       window.open("about:blank");
     } catch (error) {
       threw = true;
     }
-    
+
     ok(threw, "window.open threw a JS exception and was not allowed");
 
     threw = false;
     try {
       window.showModalDialog("about:blank");
     } catch(error) {
       threw = true;
     }
-    
+
     ok(threw, "window.showModalDialog threw a JS exception and was not allowed");
   }
 </script>
 <body onLoad="doStuff()">
   I am sandboxed but with "allow-scripts allow-same-origin"
 
   <a href="file_iframe_sandbox_open_window_fail.html" target="_blank" id="target_blank">open window</a>
+  <a href="file_iframe_sandbox_open_window_fail.html" target="BC341604" id="target_BC341604">open window</a>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_close.html
@@ -0,0 +1,3 @@
+<script>
+  self.close();
+</script>
--- a/content/html/content/test/file_iframe_sandbox_d_if10.html
+++ b/content/html/content/test/file_iframe_sandbox_d_if10.html
@@ -3,15 +3,15 @@
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 341604</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <script type="application/javascript">
 function doTest() {
-  window.parent.postMessage({test:'if_10'}, "*");
+  window.parent.postMessage({type: "if_10"}, "*");
 }
 </script>
 <body onload='doTest()'>
   I am sandboxed with 'allow-scripts'
 </body>
 </html>
--- a/content/html/content/test/file_iframe_sandbox_d_if14.html
+++ b/content/html/content/test/file_iframe_sandbox_d_if14.html
@@ -9,23 +9,23 @@
 
 <script type="text/javascript">
   var test20Context = "Test 20: Navigate another window (not opened by us): ";
 
   function doTest() {
     // Try to navigate auxiliary browsing context (window) not opened by us.
     // We should not be able to do this as we are sandboxed.
     sendMouseEvent({type:'click'}, 'navigate_window');
-    window.parent.postMessage("test attempted", "*");
+    window.parent.postMessage({type: "attempted"}, "*");
 
     // Try to navigate auxiliary browsing context (window) not opened by us, using window.open().
     // We should not be able to do this as we are sandboxed.
     try {
       window.open("file_iframe_sandbox_window_navigation_fail.html?" + escape(test20Context), "window_to_navigate2");
-      window.parent.postMessage("test attempted", "*");
+      window.parent.postMessage({type: "attempted"}, "*");
     } catch(error) {
       window.parent.postMessage({ok: true, desc: test20Context + "as expected, error thrown during window.open(..., \"window_to_navigate2\")"}, "*");
     }
   }
 </script>
 
 <body onload="doTest()">
   I am sandboxed but with "allow-scripts allow-same-origin allow-top-navigation".
--- a/content/html/content/test/file_iframe_sandbox_d_if16.html
+++ b/content/html/content/test/file_iframe_sandbox_d_if16.html
@@ -4,17 +4,17 @@
   <meta charset="utf-8">
   <title>Test for Bug 838692</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 
 <script type="application/javascript">
 function doTest() {
-  window.parent.parent.postMessage("test attempted", "*");
+  window.parent.parent.postMessage({type: "attempted"}, "*");
   sendMouseEvent({type:'click'}, 'anchor');
 }
 </script>
 
 <body onload="doTest()">
   I am sandboxed with 'allow-same-origin allow-scripts'
 
   <a href="file_iframe_sandbox_navigation_fail.html?Test 16: Navigate parent/ancestor by name:%20" target='if_parent' id='anchor'>
--- a/content/html/content/test/file_iframe_sandbox_d_if20.html
+++ b/content/html/content/test/file_iframe_sandbox_d_if20.html
@@ -7,17 +7,17 @@
 </head>
 
 <script type="application/javascript">
   var testContext = "Test 19: navigate _parent with window.open(): ";
 
   function doTest() {
     try {
       window.open("file_iframe_sandbox_navigation_fail.html?" + escape(testContext), "_parent");
-      window.parent.parent.postMessage("test attempted", "*");
+      window.parent.parent.postMessage({type: "attempted"}, "*");
     } catch(error) {
       window.parent.parent.postMessage({ok: true, desc: testContext + "as expected, error thrown during window.open(..., \"_parent\")"}, "*");
     }
   }
 </script>
 
 <body onload="doTest()">
   I am sandboxed with 'allow-scripts'
--- a/content/html/content/test/file_iframe_sandbox_d_if22.html
+++ b/content/html/content/test/file_iframe_sandbox_d_if22.html
@@ -7,17 +7,17 @@
 </head>
 
 <script type="application/javascript">
   var testContext = "Test 21: navigate parent by name with window.open(): ";
 
   function doTest() {
     try {
       window.open("file_iframe_sandbox_navigation_fail.html?" + escape(testContext), "if_parent2");
-      window.parent.parent.postMessage("test attempted", "*");
+      window.parent.parent.postMessage({type: "attempted"}, "*");
     } catch(error) {
       window.parent.parent.postMessage({ok: true, desc: testContext + "as expected, error thrown during window.open(..., \"if_parent2\")"}, "*");
     }
   }
 </script>
 
 <body onload="doTest()">
   I am sandboxed with 'allow-same-origin allow-scripts'
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_d_if23.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 838692</title>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="application/javascript">
+  var test27Context = "Test 27: navigate opened window by name with anchor: ";
+  var test28Context = "Test 28: navigate opened window by name with window.open(): ";
+
+  var windowsToClose = new Array();
+
+  function closeWindows() {
+    for (var i = 0; i < windowsToClose.length; i++) {
+      windowsToClose[i].close();
+    }
+  }
+
+  // Add message listener to forward messages on to parent
+  window.addEventListener("message", receiveMessage, false);
+
+  function receiveMessage(event) {
+    switch (event.data.type) {
+      case "closeWindows":
+        closeWindows();
+        break;
+      default:
+        window.parent.postMessage(event.data, "*");
+    }
+  }
+
+  function doTest() {
+    try {
+      windowsToClose.push(window.open("about:blank", "test27window"));
+      var test27Anchor = document.getElementById("test27Anchor");
+      test27Anchor.href = "file_iframe_sandbox_window_navigation_pass.html?" + escape(test27Context);
+      sendMouseEvent({type:"click"}, "test27Anchor");
+      window.parent.postMessage({type: "attempted"}, "*");
+    } catch(error) {
+      window.parent.postMessage({ok: false, desc: test27Context + "error thrown during window.open(): " + error}, "*");
+    }
+
+    try {
+      windowsToClose.push(window.open("about:blank", "test28window"));
+      window.open("file_iframe_sandbox_window_navigation_pass.html?" + escape(test28Context), "test28window");
+      window.parent.postMessage({type: "attempted"}, "*");
+    } catch(error) {
+      window.parent.postMessage({ok: false, desc: test28Context + "error thrown during window.open(): " + error}, "*");
+    }
+  }
+</script>
+
+<body onload="doTest()">
+  I am sandboxed with 'allow-scripts allow-popups'
+
+  <a id="test27Anchor" target="test27window">Test 27 anchor</a>
+</body>
+</html>
--- a/content/html/content/test/file_iframe_sandbox_d_if4.html
+++ b/content/html/content/test/file_iframe_sandbox_d_if4.html
@@ -3,17 +3,17 @@
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 341604</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <script type="application/javascript">
 function doTest() {
-  window.parent.parent.postMessage("test attempted", "*");
+  window.parent.parent.postMessage({type: "attempted"}, "*");
   sendMouseEvent({type:'click'}, 'anchor');
 }
 </script>
 <body onload="doTest()">
   I am sandboxed with 'allow-scripts'
 
   <a href="file_iframe_sandbox_navigation_fail.html" target='_parent' id='anchor'>
 </body>
--- a/content/html/content/test/file_iframe_sandbox_d_if5.html
+++ b/content/html/content/test/file_iframe_sandbox_d_if5.html
@@ -4,17 +4,17 @@
   <meta charset="utf-8">
   <title>Test for Bug 341604</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <script type="application/javascript">
 function doTest() {
   sendMouseEvent({type:'click'}, 'anchor');
-  window.parent.postMessage("test attempted", "*");
+  window.parent.postMessage({type: "attempted"}, "*");
 }
 </script>
 <body onload="doTest()">
   I am sandboxed with 'allow-scripts allow-same-origin'
 
   <a href="file_iframe_sandbox_navigation_fail.html?Test 4: Navigate sibling iframe by name:%20" target='if_sibling' id='anchor'>
 </body>
 </html>
--- a/content/html/content/test/file_iframe_sandbox_e_if6.html
+++ b/content/html/content/test/file_iframe_sandbox_e_if6.html
@@ -5,17 +5,17 @@
   <title>Test for Bug 341604</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 </head>
 <script type="application/javascript">
 function doTest() {
   document.getElementById('anchor').href = "file_iframe_sandbox_top_navigation_fail.html" + location.search;
-  window.top.opener.postMessage("test attempted", "*");
+  window.top.opener.postMessage({type: "attempted"}, "*");
   sendMouseEvent({type:'click'}, 'anchor');
 }
 </script>
 <body onload="doTest()">
   I am sandboxed with 'allow-scripts'
 
   <a target='_top' id='anchor'>
 </body>
--- a/content/html/content/test/file_iframe_sandbox_e_if8.html
+++ b/content/html/content/test/file_iframe_sandbox_e_if8.html
@@ -5,17 +5,17 @@
   <title>Tests for Bug 838692</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 
 <script>
   function doTest() {
     // Try to navigate top using its name (e_if7).  We should not be able to do this as allow-top-navigation is not specified.
-    window.top.opener.postMessage("test attempted", "*");
+    window.top.opener.postMessage({type: "attempted"}, "*");
     sendMouseEvent({type:'click'}, 'navigate_top');
   }
 </script>
 
 <body onload="doTest()">
   I am sandboxed but with "allow-scripts"
 
   <a href="file_iframe_sandbox_top_navigation_fail.html?Test 15: Navigate top by name:%20" target="e_if7" id="navigate_top">navigate top</a>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_h_if1.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Tests for Bug 766282</title>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+</head>
+<script type="text/javascript">
+  function ok(result, desc) {
+    window.parent.ok_wrapper(result, desc);
+  }
+
+  function doStuff() {
+    // Try to open a new window via target="_blank", target="BC766282" and window.open().
+    // The window we try to open closes itself once it opens.
+    sendMouseEvent({type:'click'}, 'target_blank');
+    sendMouseEvent({type:'click'}, 'target_BC766282');
+
+    try {
+      window.open("file_iframe_sandbox_open_window_pass.html");
+    } catch(e) {
+      ok(false, "Test 3: iframes sandboxed with allow-popups, should be able to open windows");
+    }
+  }
+</script>
+<body onLoad="doStuff()">
+  I am sandboxed but with "allow-popups allow-scripts allow-same-origin"
+
+  <a href="file_iframe_sandbox_open_window_pass.html" target="_blank" id="target_blank">open window</a>
+  <a href="file_iframe_sandbox_open_window_pass.html?BC766282" target="BC766282" id="target_BC766282">open window</a>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_j_if1.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="text/javascript">
+  function doStuff() {
+    // Open a new window via showModalDialog().
+    try {
+      window.showModalDialog("file_iframe_sandbox_k_if5.html");
+    } catch(e) {
+      window.parent.ok_wrapper(false, "iframes sandboxed with allow-popups should be able to open a modal dialog");
+    }
+
+    // Open a new window via showModalDialog().
+    try {
+      window.showModalDialog("file_iframe_sandbox_k_if7.html");
+    } catch(e) {
+      window.parent.ok_wrapper(false, "iframes sandboxed with allow-popups should be able to open a modal dialog");
+    }
+  }
+</script>
+
+<body onLoad="doStuff()">
+  I am sandboxed with "allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation".
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_j_if2.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="text/javascript">
+  function doSubOpens() {
+    // Open a new window showModalDialog().
+    try {
+      window.showModalDialog("file_iframe_sandbox_k_if9.html");
+    } catch(e) {
+      window.parent.ok_wrapper(false, "iframes sandboxed with allow-popups should be able to open a modal dialog");
+    }
+  }
+
+  window.doSubOpens = doSubOpens;
+</script>
+
+<body>
+  I am sandboxed but with "allow-scripts allow-popups allow-same-origin".
+  After my initial load, "allow-same-origin" is removed and then I open file_iframe_sandbox_k_if9.html,
+  which attemps to call a function in my parent.
+  This should succeed since the new sandbox flags shouldn't have taken affect on me until I'm reloaded.
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_j_if3.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Tests for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+</head>
+<script type="text/javascript">
+  function ok(result, desc) {
+    window.parent.ok_wrapper(result, desc);
+  }
+
+  function doStuff() {
+    // Try to open a new window via showModalDialog().
+    // The window we try to open closes itself once it opens.
+    try {
+      window.showModalDialog("file_iframe_sandbox_open_window_pass.html");
+    } catch(e) {
+      ok(false, "iframes sandboxed with allow-popups should be able to open a modal dialog");
+    }
+  }
+</script>
+<body onLoad="doStuff()">
+  I am sandboxed but with "allow-popups allow-scripts allow-same-origin"
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if1.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="text/javascript">
+  var windowsToClose = new Array();
+
+  function closeWindows() {
+    for (var i = 0; i < windowsToClose.length; i++) {
+      windowsToClose[i].close();
+    }
+    window.open("file_iframe_sandbox_close.html", "blank_if2");
+    window.open("file_iframe_sandbox_close.html", "BC766282_if2");
+  }
+
+  // Add message listener to forward messages on to parent
+  window.addEventListener("message", receiveMessage, false);
+
+  function receiveMessage(event) {
+    switch (event.data.type) {
+      case "closeWindows":
+        closeWindows();
+        break;
+    }
+  }
+
+  function doStuff() {
+    // Open a new window via target="_blank", target="BC766282_if2" and window.open().
+    sendMouseEvent({type:'click'}, 'target_blank_if2');
+    sendMouseEvent({type:'click'}, 'target_BC766282_if2');
+
+    windowsToClose.push(window.open("file_iframe_sandbox_k_if2.html"));
+  }
+</script>
+<body onLoad="doStuff()">
+  I am navigated to from file_iframe_sandbox_k_if8.html.
+  This was opened in an iframe with "allow-scripts allow-popups allow-same-origin".
+  However allow-same-origin was removed from the iframe before navigating to me,
+  so I should only have "allow-scripts allow-popups" in force.
+  <a href="file_iframe_sandbox_k_if2.html" target="_blank" id="target_blank_if2">open window</a>
+  <a href="file_iframe_sandbox_k_if2.html" target="BC766282_if2" id="target_BC766282_if2">open window</a>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if2.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="text/javascript">
+  if (window.name == "") {
+    window.name = "blank_if2";
+  }
+
+  function ok(result, message) {
+    window.opener.parent.postMessage({type: "ok", ok: result, desc: message}, "*");
+  }
+
+  function doStuff() {
+    // Check that sandboxed forms browsing context flag copied by attempting to submit a form.
+    document.getElementById('a_form').submit();
+    window.opener.parent.postMessage({type: "attempted"}, "*");
+
+    // Check that sandboxed origin browsing context flag copied by attempting to access cookies.
+    try {
+      var foo = document.cookie;
+      ok(false, "Sandboxed origin browsing context flag NOT copied to new auxiliary browsing context.");
+    } catch(error) {
+      ok(true, "Sandboxed origin browsing context flag copied to new auxiliary browsing context.");
+    }
+
+    // Check that sandboxed top-level navigation browsing context flag copied.
+    // if_3 tries to navigate this document.
+    var if_3 = document.getElementById('if_3');
+    if_3.src = "file_iframe_sandbox_k_if3.html";
+  }
+</script>
+
+<body onLoad="doStuff()">
+  I am not sandboxed directly, but opened from a sandboxed document with 'allow-scripts allow-popups'
+
+  <form method="get" action="file_iframe_sandbox_window_form_fail.html" id="a_form">
+    First name: <input type="text" name="firstname">
+    Last name: <input type="text" name="lastname">
+    <input type="submit" id="a_button">
+  </form>
+
+  <iframe id="if_3" src="about:blank" height="10" width="10"></iframe>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+</head>
+<script type="application/javascript">
+  function doTest() {
+    sendMouseEvent({type:'click'}, 'anchor');
+    window.parent.opener.parent.postMessage({type: "attempted"}, "*");
+  }
+</script>
+<body onload="doTest()">
+  I am sandboxed with 'allow-scripts allow-popups'
+
+  <a href="file_iframe_sandbox_window_top_navigation_fail.html" target='_top' id='anchor'>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if4.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="text/javascript">
+  function doStuff() {
+    // Open a new window via target="_blank", target="BC766282_if5" and window.open().
+    sendMouseEvent({type:'click'}, 'target_blank_if5');
+    sendMouseEvent({type:'click'}, 'target_BC766282_if5');
+
+    window.open("file_iframe_sandbox_k_if5.html");
+
+    // Open a new window via target="_blank", target="BC766282_if7" and window.open().
+    sendMouseEvent({type:'click'}, 'target_blank_if7');
+    sendMouseEvent({type:'click'}, 'target_BC766282_if7');
+
+    window.open("file_iframe_sandbox_k_if7.html");
+  }
+</script>
+
+<body onLoad="doStuff()">
+  I am sandboxed with "allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation".
+  <a href="file_iframe_sandbox_k_if5.html" target="_blank" id="target_blank_if5">open window</a>
+  <a href="file_iframe_sandbox_k_if5.html" target="BC766282_if5" id="target_BC766282_if5">open window</a>
+
+  <a href="file_iframe_sandbox_k_if7.html" target="_blank" id="target_blank_if7">open window</a>
+  <a href="file_iframe_sandbox_k_if7.html" target="BC766282_if7" id="target_BC766282_if7">open window</a>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if5.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="text/javascript">
+  function doStuff() {
+    // Check that sandboxed origin browsing context flag NOT set by attempting to access cookies.
+    try {
+      var foo = document.cookie;
+      window.opener.parent.ok_wrapper(true, "Sandboxed origin browsing context flag NOT set on new auxiliary browsing context.");
+    } catch(error) {
+      window.opener.parent.ok_wrapper(false, "Sandboxed origin browsing context flag set on new auxiliary browsing context.");
+    }
+
+    // Check that sandboxed top-level navigation browsing context flag NOT set.
+    // if_6 tries to navigate this document.
+    var if_6 = document.getElementById('if_6');
+    if_6.src = "file_iframe_sandbox_k_if6.html";
+  }
+</script>
+
+<body onLoad="doStuff()">
+  I am not sandboxed directly, but opened from a sandboxed document with at least
+  'allow-scripts allow-popups allow-same-origin allow-top-navigation'
+
+  <iframe id="if_6" src="about:blank" height="10" width="10"></iframe>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if6.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+</head>
+
+<script type="application/javascript">
+  function doTest() {
+    sendMouseEvent({type:'click'}, 'anchor');
+  }
+</script>
+
+<body onload="doTest()">
+  I am sandboxed with at least 'allow-scripts allow-popups allow-top-navigation'
+
+  <a href="file_iframe_sandbox_window_top_navigation_pass.html" target='_top' id='anchor'>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if7.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="text/javascript">
+  function doStuff() {
+    // Check that sandboxed forms browsing context flag NOT set by attempting to submit a form.
+    document.getElementById('a_form').submit();
+  }
+</script>
+
+<body onLoad="doStuff()">
+  I am not sandboxed directly, but opened from a sandboxed document with at least
+  'allow-scripts allow-popups allow-forms allow-same-origin'
+
+  <form method="get" action="file_iframe_sandbox_window_form_pass.html" id="a_form">
+    First name: <input type="text" name="firstname">
+    Last name: <input type="text" name="lastname">
+    <input type="submit" id="a_button">
+  </form>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if8.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="text/javascript">
+  function doSubOpens() {
+    // Open a new window via target="_blank", target="BC766282_if9" and window.open().
+    sendMouseEvent({type:'click'}, 'target_blank_if9');
+    sendMouseEvent({type:'click'}, 'target_BC766282_if9');
+
+    window.open("file_iframe_sandbox_k_if9.html");
+
+    sendMouseEvent({type:'click'}, 'target_if1');
+  }
+
+  window.doSubOpens = doSubOpens;
+</script>
+
+<body>
+  I am sandboxed but with "allow-scripts allow-popups allow-same-origin".
+  After my initial load, "allow-same-origin" is removed and then I open file_iframe_sandbox_k_if9.html
+  in 3 different ways, which attemps to call a function in my parent.
+  This should succeed since the new sandbox flags shouldn't have taken affect on me until I'm reloaded.
+  <a href="file_iframe_sandbox_k_if9.html" target="_blank" id="target_blank_if9">open window</a>
+  <a href="file_iframe_sandbox_k_if9.html" target="BC766282_if9" id="target_BC766282_if9">open window</a>
+
+  Now navigate to file_iframe_sandbox_k_if1.html to do tests for a sandbox opening a window
+  when only "allow-scripts allow-popups" are specified.
+  <a href="file_iframe_sandbox_k_if1.html" id="target_if1">navigate to if1</a>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_k_if9.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script>
+  function doStuff() {
+    window.opener.parent.ok_wrapper(true, "A window opened from within a sandboxed document should inherit the flags of the document, not of the docshell/sandbox attribute.");
+    self.close();
+  }
+</script>
+
+<body onload='doStuff()'>
+  I'm a window opened from the sandboxed document of file_iframe_sandbox_k_if8.html.
+  I should be able to call ok_wrapper in main test page directly because I should be same-origin with it.
+</body>
+</html>
--- a/content/html/content/test/file_iframe_sandbox_open_window_fail.html
+++ b/content/html/content/test/file_iframe_sandbox_open_window_fail.html
@@ -1,21 +1,19 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 341604</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 
 <body onLoad="doStuff()">
   I should NOT be opened by a sandboxed iframe via any method
 </body>
 </html>
 
 <script>
   function doStuff() {
-    console.log("file_iframe_sandbox_window_open_fail.html");
     window.opener.ok(false, "sandboxed documents should NOT be able to open windows");
     self.close();
   }
-</script>
\ No newline at end of file
+</script>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_open_window_pass.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<body onLoad="doStuff()">
+  I should be opened by a sandboxed iframe via any method when "allow-popups" is specified.
+</body>
+</html>
+
+<script>
+  function doStuff() {
+    // Check that the browsing context's (window's) name is as expected.
+    var expectedName = location.search.substring(1);
+    if (expectedName == window.name) {
+      window.opener.ok(true, "sandboxed documents should be able to open windows when \"allow-popups\" is specified");
+    } else {
+      window.opener.ok(false, "window opened with \"allow-popups\", but expected name was " + expectedName + " and actual was " + window.name);
+    }
+    self.close();
+  }
+</script>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_window_form_fail.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<body onLoad="doStuff()">
+  I should NOT be loaded by a form submit from a window opened from a sandbox without 'allow-forms'.
+</body>
+</html>
+
+<script>
+  function doStuff() {
+    window.opener.parent.postMessage({ok: false, desc: "documents sandboxed without allow-forms should NOT be able to submit forms"}, "*");
+
+    self.close();
+  }
+</script>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_window_form_pass.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script>
+  function doStuff() {
+    window.opener.parent.ok_wrapper(true, "Sandboxed forms browsing context flag NOT set on new auxiliary browsing context.");
+
+    self.close();
+  }
+</script>
+
+<body onLoad="doStuff()">
+  I should be loaded by a form submit from a window opened from a sandbox with 'allow-forms allow-same-origin'.
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_window_navigation_pass.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script>
+function doStuff() {
+  var testContext = unescape(location.search.substring(1));
+  window.opener.postMessage({type: "ok", ok: true, desc: testContext + "a permitted sandboxed document should be able to navigate a window it has opened.", addToAttempted: false}, "*");
+  window.close();
+}
+</script>
+
+<body onLoad="doStuff()">
+PASS
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_window_top_navigation_fail.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script>
+  function doStuff() {
+    window.opener.parent.postMessage({ok: false, desc:  "Sandboxed top-level navigation browsing context flag NOT copied to new auxiliary browsing context."}, "*");
+
+    // Check that when no browsing context returned by "target='_top'", a new browsing context isn't opened by mistake.
+    try {
+      window.opener.parent.opener.parent.postMessage({ok: false, desc:  "An attempt at top navigation without 'allow-top-navigation' should not have opened a new browsing context."}, "*");
+    } catch (error) {
+    }
+
+    self.close();
+  }
+</script>
+<body onLoad="doStuff()">
+FAIL
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_iframe_sandbox_window_top_navigation_pass.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 766282</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script>
+  function doStuff() {
+    window.opener.parent.ok_wrapper(true, "Sandboxed top-level navigation browsing context flag NOT copied to new auxiliary browsing context.");
+
+    self.close();
+  }
+</script>
+
+<body onLoad="doStuff()">
+  I am navigated to from a window opened from a sandbox with allow-top-navigation.
+</body>
+</html>
--- a/content/html/content/test/mochitest.ini
+++ b/content/html/content/test/mochitest.ini
@@ -64,31 +64,33 @@ support-files =
   file_iframe_sandbox_c_if1.html
   file_iframe_sandbox_c_if2.html
   file_iframe_sandbox_c_if3.html
   file_iframe_sandbox_c_if4.html
   file_iframe_sandbox_c_if5.html
   file_iframe_sandbox_c_if6.html
   file_iframe_sandbox_c_if7.html
   file_iframe_sandbox_c_if8.html
+  file_iframe_sandbox_close.html
   file_iframe_sandbox_d_if1.html
   file_iframe_sandbox_d_if10.html
   file_iframe_sandbox_d_if11.html
   file_iframe_sandbox_d_if12.html
   file_iframe_sandbox_d_if13.html
   file_iframe_sandbox_d_if14.html
   file_iframe_sandbox_d_if15.html
   file_iframe_sandbox_d_if16.html
   file_iframe_sandbox_d_if17.html
   file_iframe_sandbox_d_if18.html
   file_iframe_sandbox_d_if19.html
   file_iframe_sandbox_d_if2.html
   file_iframe_sandbox_d_if20.html
   file_iframe_sandbox_d_if21.html
   file_iframe_sandbox_d_if22.html
+  file_iframe_sandbox_d_if23.html
   file_iframe_sandbox_d_if3.html
   file_iframe_sandbox_d_if4.html
   file_iframe_sandbox_d_if5.html
   file_iframe_sandbox_d_if6.html
   file_iframe_sandbox_d_if7.html
   file_iframe_sandbox_d_if8.html
   file_iframe_sandbox_d_if9.html
   file_iframe_sandbox_e_if1.html
@@ -109,24 +111,43 @@ support-files =
   file_iframe_sandbox_e_if9.html
   file_iframe_sandbox_f_if1.html
   file_iframe_sandbox_f_if2.html
   file_iframe_sandbox_f_if2.html^headers^
   file_iframe_sandbox_fail.js
   file_iframe_sandbox_form_fail.html
   file_iframe_sandbox_form_pass.html
   file_iframe_sandbox_g_if1.html
+  file_iframe_sandbox_h_if1.html
+  file_iframe_sandbox_j_if1.html
+  file_iframe_sandbox_j_if2.html
+  file_iframe_sandbox_j_if3.html
+  file_iframe_sandbox_k_if1.html
+  file_iframe_sandbox_k_if2.html
+  file_iframe_sandbox_k_if3.html
+  file_iframe_sandbox_k_if4.html
+  file_iframe_sandbox_k_if5.html
+  file_iframe_sandbox_k_if6.html
+  file_iframe_sandbox_k_if7.html
+  file_iframe_sandbox_k_if8.html
+  file_iframe_sandbox_k_if9.html
   file_iframe_sandbox_navigation_fail.html
   file_iframe_sandbox_navigation_pass.html
   file_iframe_sandbox_navigation_start.html
   file_iframe_sandbox_open_window_fail.html
+  file_iframe_sandbox_open_window_pass.html
   file_iframe_sandbox_pass.js
   file_iframe_sandbox_top_navigation_fail.html
   file_iframe_sandbox_top_navigation_pass.html
+  file_iframe_sandbox_window_form_fail.html
+  file_iframe_sandbox_window_form_pass.html
   file_iframe_sandbox_window_navigation_fail.html
+  file_iframe_sandbox_window_navigation_pass.html
+  file_iframe_sandbox_window_top_navigation_pass.html
+  file_iframe_sandbox_window_top_navigation_fail.html
   file_iframe_sandbox_worker.js
   file_srcdoc-2.html
   file_srcdoc.html
   form_submit_server.sjs
   image.png
   image-allow-credentials.png
   image-allow-credentials.png^headers^
   nnc_lockup.gif
@@ -356,19 +377,22 @@ support-files =
 [test_formSubmission2.html]
 [test_formelements.html]
 [test_fullscreen-api.html]
 [test_hidden.html]
 [test_html_attributes_reflection.html]
 [test_htmlcollection.html]
 [test_iframe_sandbox_general.html]
 [test_iframe_sandbox_inheritance.html]
+[test_iframe_sandbox_modal.html]
 [test_iframe_sandbox_navigation.html]
 [test_iframe_sandbox_navigation2.html]
 [test_iframe_sandbox_plugins.html]
+[test_iframe_sandbox_popups.html]
+[test_iframe_sandbox_popups_inheritance.html]
 [test_iframe_sandbox_same_origin.html]
 [test_iframe_sandbox_workers.html]
 [test_img_attributes_reflection.html]
 [test_li_attributes_reflection.html]
 [test_link_attributes_reflection.html]
 [test_map_attributes_reflection.html]
 [test_meta_attributes_reflection.html]
 [test_mod_attributes_reflection.html]
--- a/content/html/content/test/test_iframe_sandbox_general.html
+++ b/content/html/content/test/test_iframe_sandbox_general.html
@@ -1,234 +1,239 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=341604
-Implement HTML5 sandbox attribute for IFRAMEs - general tests
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 341604</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<script type="application/javascript">
-
-SimpleTest.expectAssertions(1);
-
-/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs - general tests **/
-
-SimpleTest.waitForExplicitFinish();
-
-// a postMessage handler that is used by sandboxed iframes without
-// 'allow-same-origin' to communicate pass/fail back to this main page.
-// it expects to be called with an object like {ok: true/false, desc:
-// <description of the test> which it then forwards to ok()
-window.addEventListener("message", receiveMessage, false);
-
-function receiveMessage(event)
-{
-  ok_wrapper(event.data.ok, event.data.desc);
-}
-
-var completedTests = 0;
-var passedTests = 0;
-
-function ok_wrapper(result, desc) {
-  ok(result, desc);
-
-  completedTests++;
-
-  if (result) {
-    passedTests++;
-  }
-
-  if (completedTests == 23) {
-    is(passedTests, 23, "There are 23 general tests that should pass");
-    SimpleTest.finish();
-  }
-}
-
-function doTest() {
-  // passes if good
-  // 1) test that inline scripts (<script>) can run in an iframe sandboxed with "allow-scripts"
-  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
-
-  // passes if good
-  // 2) test that <script src=...> can run in an iframe sandboxed with "allow-scripts"
-  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
-
-  // passes if good
-  // 3) test that script in an event listener (body onload) can run in an iframe sandboxed with "allow-scripts"
-  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
-
-  // passes if good
-  // 4) test that script in an javascript:url can run in an iframe sandboxed with "allow-scripts"
-  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
-
-  // fails if bad
-  // 5) test that inline scripts cannot run in an iframe sandboxed without "allow-scripts"
-  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
-
-  // fails if bad
-  // 6) test that <script src=...> cannot run in an iframe sandboxed without "allow-scripts"
-  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
-
-  // fails if bad
-  // 7) test that script in an event listener (body onload) cannot run in an iframe sandboxed without "allow-scripts"
-  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
-
-  // fails if bad
-  // 8) test that script in an event listener (img onerror) cannot run in an iframe sandboxed without "allow-scripts"
-  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
-  
-  // fails if bad
-  // 9) test that script in an javascript:url cannot run in an iframe sandboxed without "allow-scripts"
-  // (done in file_iframe_sandbox_c_if_5.html which has sandbox='allow-same-origin')
-  var if_w = document.getElementById('if_5').contentWindow;
-  sendMouseEvent({type:'click'}, 'a_link', if_w);
-
-  // passes if good
-  // 10) test that a new iframe has sandbox attribute
-  var ifr = document.createElement("iframe");
-  ok_wrapper("sandbox" in ifr, "a new iframe should have a sandbox attribute");
-
-  // passes if good
-  // 11) test that the sandbox attribute's default value is an empty string
-  ok_wrapper(ifr.sandbox === "", "default sandbox attribute should be an empty string");
-
-  // passes if good
-  // 12) test that a sandboxed iframe with 'allow-forms' can submit forms
-  // (done in file_iframe_sandbox_c_if3.html which has 'allow-forms' and 'allow-scripts')
-
-  // fails if bad
-  // 13) test that a sandboxed iframe without 'allow-forms' can NOT submit forms
-  // (done in file_iframe_sandbox_c_if1.html which only has 'allow-scripts')
-
-  // fails if bad
-  // 14) test that a sandboxed iframe can't open a new window using the target.attribute
-  // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
-  // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
-  // function that calls window.parent.ok_wrapper
-
-  // passes if good
-  // 15) test that a sandboxed iframe can't open a new window using window.open
-  // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
-  // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
-  // function that calls window.parent.ok_wrapper
-
-  // passes if good
-  // 16) test that a sandboxed iframe can't open a new window using window.ShowModalDialog
-  // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
-  // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
-  // function that calls window.parent.ok_wrapper
-  
-  // passes twice if good
-  // 17) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
-  // is separated with two spaces 
-  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "  allow-scripts  allow-same-origin  "
-  
-  // passes twice if good
-  // 18) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
-  // is separated with tabs
-  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x09;allow-scripts&#x09;allow-same-origin&#x09;"
-  
-  // passes twice if good
-  // 19) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
-  // is separated with line feeds
-  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x0a;allow-scripts&#x0a;allow-same-origin&#x0a;"
-  
-  // passes twice if good
-  // 20) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
-  // is separated with form feeds
-  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x0c;allow-scripts&#x0c;allow-same-origin&#x0c;"
-  
-  // passes twice if good
-  // 21) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
-  // is separated with carriage returns
-  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x0d;allow-scripts&#x0d;allow-same-origin&#x0d;"
-
-  // fails if bad
-  // 22) test that an iframe with sandbox="" does NOT have script in a src attribute created by a javascript: 
-  // URL executed
-  // done by this page, see if_7
-
-  // passes if good
-  // 23) test that an iframe with sandbox="allow-scripts" DOES have script in a src attribute created by a javascript: 
-  // URL executed
-  // done by this page, see if_8
-
-  // fails if bad
-  // 24) test that an iframe with sandbox="", starting out with a document already loaded, does NOT have script in a newly
-  // set src attribute created by a javascript: URL executed
-  // done by this page, see if_9
-
-  // passes if good
-  // 25) test that an iframe with sandbox="allow-scripts", starting out with a document already loaded, DOES have script
-  // in a newly set src attribute created by a javascript: URL executed
-  // done by this page, see if_10
-
-  // passes if good or fails if bad
-  // 26) test that an sandboxed document without 'allow-same-origin' can NOT access indexedDB
-  // done via file_iframe_sandbox_c_if7.html, which has sandbox='allow-scripts'
-
-  // passes if good or fails if bad
-  // 26) test that an sandboxed document without 'allow-same-origin' can access indexedDB
-  // done via file_iframe_sandbox_c_if8.html, which has sandbox='allow-scripts allow-same-origin'
-}
-
-addLoadEvent(doTest);
-
-var started_if_9 = false;
-var started_if_10 = false;
-
-function start_if_9() {
-  if (started_if_9)
-    return;
-
-  started_if_9 = true;
-  sendMouseEvent({type:'click'}, 'a_button');
-}
-
-function start_if_10() {
-  if (started_if_10)
-    return;
-
-  started_if_10 = true;
-  sendMouseEvent({type:'click'}, 'a_button2');
-}
-
-function do_if_9() {
-  var if_9 = document.getElementById('if_9');
-  if_9.src = 'javascript:"<html><script>window.parent.ok_wrapper(false, \'an iframe sandboxed without allow-scripts should not execute script in a javascript URL in a newly set src attribute\');<\/script><\/html>"';
-}
-
-function do_if_10() {
-  var if_10 = document.getElementById('if_10');
-  if_10.src = 'javascript:"<html><script>window.parent.ok_wrapper(true, \'an iframe sandboxed with allow-scripts should execute script in a javascript URL in a newly set src attribute\');<\/script><\/html>"';
-}
-</script>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
-<p id="display"></p>
-<div id="content">
-<iframe sandbox="allow-same-origin allow-scripts" id="if_1" src="file_iframe_sandbox_c_if1.html" height="10" width="10"></iframe>
-<iframe sandbox="" id="if_2" src="file_iframe_sandbox_c_if2.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-forms allow-scripts" id="if_3" src="file_iframe_sandbox_c_if3.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin allow-scripts" id="if_4" src="file_iframe_sandbox_c_if4.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin" id="if_5" src="file_iframe_sandbox_c_if5.html" height="10" width="10"></iframe>
-<iframe sandbox="  allow-same-origin  allow-scripts  " id="if_6_a" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
-<iframe sandbox="&#x09;allow-same-origin&#x09;allow-scripts&#x09;" id="if_6_b" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
-<iframe sandbox="&#x0a;allow-same-origin&#x0a;allow-scripts&#x0a;" id="if_6_c" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
-<iframe sandbox="&#x0c;allow-same-origin&#x0c;allow-scripts&#x0c;" id="if_6_d" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
-<iframe sandbox="&#x0d;allow-same-origin&#x0d;allow-scripts&#x0d;" id="if_6_e" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin" id='if_7' src="javascript:'<html><script>window.parent.ok_wrapper(false, \'an iframe sandboxed without allow-scripts should not execute script in a javascript URL in its src attribute\');<\/script><\/html>';" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin allow-scripts" id='if_8' src="javascript:'<html><script>window.parent.ok_wrapper(true, \'an iframe sandboxed without allow-scripts should execute script in a javascript URL in its src attribute\');<\/script><\/html>';" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin" onload='start_if_9()' id='if_9' src="about:blank" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin allow-scripts" onload='start_if_10()' id='if_10' src="about:blank" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts" id='if_11' src="file_iframe_sandbox_c_if7.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin allow-scripts" id='if_12' src="file_iframe_sandbox_c_if8.html" height="10" width="10"></iframe>
-<input type='button' id="a_button" onclick='do_if_9()'>
-<input type='button' id="a_button2" onclick='do_if_10()'>
-</div>
-</body>
-</html>
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=341604
+Implement HTML5 sandbox attribute for IFRAMEs - general tests
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Tests for Bug 341604 and Bug 766282</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="application/javascript">
+/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs - general tests **/
+
+SimpleTest.expectAssertions(0, 1);
+SimpleTest.waitForExplicitFinish();
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+// it expects to be called with an object like {ok: true/false, desc:
+// <description of the test> which it then forwards to ok()
+window.addEventListener("message", receiveMessage, false);
+
+function receiveMessage(event)
+{
+  ok_wrapper(event.data.ok, event.data.desc);
+}
+
+var completedTests = 0;
+var passedTests = 0;
+
+function ok_wrapper(result, desc) {
+  ok(result, desc);
+
+  completedTests++;
+
+  if (result) {
+    passedTests++;
+  }
+
+  if (completedTests == 23) {
+    is(passedTests, completedTests, "There are " + completedTests + " general tests that should pass");
+    SimpleTest.finish();
+  }
+}
+
+function doTest() {
+  // passes if good
+  // 1) test that inline scripts (<script>) can run in an iframe sandboxed with "allow-scripts"
+  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
+
+  // passes if good
+  // 2) test that <script src=...> can run in an iframe sandboxed with "allow-scripts"
+  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
+
+  // passes if good
+  // 3) test that script in an event listener (body onload) can run in an iframe sandboxed with "allow-scripts"
+  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
+
+  // passes if good
+  // 4) test that script in an javascript:url can run in an iframe sandboxed with "allow-scripts"
+  // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts')
+
+  // fails if bad
+  // 5) test that inline scripts cannot run in an iframe sandboxed without "allow-scripts"
+  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
+
+  // fails if bad
+  // 6) test that <script src=...> cannot run in an iframe sandboxed without "allow-scripts"
+  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
+
+  // fails if bad
+  // 7) test that script in an event listener (body onload) cannot run in an iframe sandboxed without "allow-scripts"
+  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
+
+  // fails if bad
+  // 8) test that script in an event listener (img onerror) cannot run in an iframe sandboxed without "allow-scripts"
+  // (done in file_iframe_sandbox_c_if2.html which has sandbox='')
+
+  // fails if bad
+  // 9) test that script in an javascript:url cannot run in an iframe sandboxed without "allow-scripts"
+  // (done in file_iframe_sandbox_c_if_5.html which has sandbox='allow-same-origin')
+  var if_w = document.getElementById('if_5').contentWindow;
+  sendMouseEvent({type:'click'}, 'a_link', if_w);
+
+  // passes if good
+  // 10) test that a new iframe has sandbox attribute
+  var ifr = document.createElement("iframe");
+  ok_wrapper("sandbox" in ifr, "a new iframe should have a sandbox attribute");
+
+  // passes if good
+  // 11) test that the sandbox attribute's default value is an empty string
+  ok_wrapper(ifr.sandbox === "", "default sandbox attribute should be an empty string");
+
+  // passes if good
+  // 12) test that a sandboxed iframe with 'allow-forms' can submit forms
+  // (done in file_iframe_sandbox_c_if3.html which has 'allow-forms' and 'allow-scripts')
+
+  // fails if bad
+  // 13) test that a sandboxed iframe without 'allow-forms' can NOT submit forms
+  // (done in file_iframe_sandbox_c_if1.html which only has 'allow-scripts')
+
+  // fails if bad
+  // 14) test that a sandboxed iframe can't open a new window using the target.attribute
+  // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
+  // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
+  // function that calls window.parent.ok_wrapper
+
+  // passes if good
+  // 15) test that a sandboxed iframe can't open a new window using window.open
+  // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
+  // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
+  // function that calls window.parent.ok_wrapper
+
+  // passes if good
+  // 16) test that a sandboxed iframe can't open a new window using window.ShowModalDialog
+  // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
+  // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
+  // function that calls window.parent.ok_wrapper
+
+  // passes twice if good
+  // 17) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
+  // is separated with two spaces
+  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "  allow-scripts  allow-same-origin  "
+
+  // passes twice if good
+  // 18) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
+  // is separated with tabs
+  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x09;allow-scripts&#x09;allow-same-origin&#x09;"
+
+  // passes twice if good
+  // 19) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
+  // is separated with line feeds
+  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x0a;allow-scripts&#x0a;allow-same-origin&#x0a;"
+
+  // passes twice if good
+  // 20) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
+  // is separated with form feeds
+  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x0c;allow-scripts&#x0c;allow-same-origin&#x0c;"
+
+  // passes twice if good
+  // 21) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute
+  // is separated with carriage returns
+  // done via file_iframe_sandbox_c_if6.html which is sandboxed with "&#x0d;allow-scripts&#x0d;allow-same-origin&#x0d;"
+
+  // fails if bad
+  // 22) test that an iframe with sandbox="" does NOT have script in a src attribute created by a javascript:
+  // URL executed
+  // done by this page, see if_7
+
+  // passes if good
+  // 23) test that an iframe with sandbox="allow-scripts" DOES have script in a src attribute created by a javascript:
+  // URL executed
+  // done by this page, see if_8
+
+  // fails if bad
+  // 24) test that an iframe with sandbox="", starting out with a document already loaded, does NOT have script in a newly
+  // set src attribute created by a javascript: URL executed
+  // done by this page, see if_9
+
+  // passes if good
+  // 25) test that an iframe with sandbox="allow-scripts", starting out with a document already loaded, DOES have script
+  // in a newly set src attribute created by a javascript: URL executed
+  // done by this page, see if_10
+
+  // passes if good or fails if bad
+  // 26) test that an sandboxed document without 'allow-same-origin' can NOT access indexedDB
+  // done via file_iframe_sandbox_c_if7.html, which has sandbox='allow-scripts'
+
+  // passes if good or fails if bad
+  // 27) test that an sandboxed document with 'allow-same-origin' can access indexedDB
+  // done via file_iframe_sandbox_c_if8.html, which has sandbox='allow-scripts allow-same-origin'
+
+  // fails if bad
+  // 28) Test that a sandboxed iframe can't open a new window using the target.attribute for a
+  // non-existing browsing context (BC341604).
+  // This is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin"
+  // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok()
+  // function that calls window.parent.ok_wrapper.
+}
+
+addLoadEvent(doTest);
+
+var started_if_9 = false;
+var started_if_10 = false;
+
+function start_if_9() {
+  if (started_if_9)
+    return;
+
+  started_if_9 = true;
+  sendMouseEvent({type:'click'}, 'a_button');
+}
+
+function start_if_10() {
+  if (started_if_10)
+    return;
+
+  started_if_10 = true;
+  sendMouseEvent({type:'click'}, 'a_button2');
+}
+
+function do_if_9() {
+  var if_9 = document.getElementById('if_9');
+  if_9.src = 'javascript:"<html><script>window.parent.ok_wrapper(false, \'an iframe sandboxed without allow-scripts should not execute script in a javascript URL in a newly set src attribute\');<\/script><\/html>"';
+}
+
+function do_if_10() {
+  var if_10 = document.getElementById('if_10');
+  if_10.src = 'javascript:"<html><script>window.parent.ok_wrapper(true, \'an iframe sandboxed with allow-scripts should execute script in a javascript URL in a newly set src attribute\');<\/script><\/html>"';
+}
+</script>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
+<p id="display"></p>
+<div id="content">
+<iframe sandbox="allow-same-origin allow-scripts" id="if_1" src="file_iframe_sandbox_c_if1.html" height="10" width="10"></iframe>
+<iframe sandbox="" id="if_2" src="file_iframe_sandbox_c_if2.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-forms allow-scripts" id="if_3" src="file_iframe_sandbox_c_if3.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin allow-scripts" id="if_4" src="file_iframe_sandbox_c_if4.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin" id="if_5" src="file_iframe_sandbox_c_if5.html" height="10" width="10"></iframe>
+<iframe sandbox="  allow-same-origin  allow-scripts  " id="if_6_a" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
+<iframe sandbox="&#x09;allow-same-origin&#x09;allow-scripts&#x09;" id="if_6_b" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
+<iframe sandbox="&#x0a;allow-same-origin&#x0a;allow-scripts&#x0a;" id="if_6_c" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
+<iframe sandbox="&#x0c;allow-same-origin&#x0c;allow-scripts&#x0c;" id="if_6_d" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
+<iframe sandbox="&#x0d;allow-same-origin&#x0d;allow-scripts&#x0d;" id="if_6_e" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin" id='if_7' src="javascript:'<html><script>window.parent.ok_wrapper(false, \'an iframe sandboxed without allow-scripts should not execute script in a javascript URL in its src attribute\');<\/script><\/html>';" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin allow-scripts" id='if_8' src="javascript:'<html><script>window.parent.ok_wrapper(true, \'an iframe sandboxed without allow-scripts should execute script in a javascript URL in its src attribute\');<\/script><\/html>';" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin" onload='start_if_9()' id='if_9' src="about:blank" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin allow-scripts" onload='start_if_10()' id='if_10' src="about:blank" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts" id='if_11' src="file_iframe_sandbox_c_if7.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin allow-scripts" id='if_12' src="file_iframe_sandbox_c_if8.html" height="10" width="10"></iframe>
+<input type='button' id="a_button" onclick='do_if_9()'>
+<input type='button' id="a_button2" onclick='do_if_10()'>
+</div>
+</body>
+</html>
--- a/content/html/content/test/test_iframe_sandbox_inheritance.html
+++ b/content/html/content/test/test_iframe_sandbox_inheritance.html
@@ -1,168 +1,205 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=341604
-Implement HTML5 sandbox attribute for IFRAMEs - inheritance tests
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 341604</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<script type="application/javascript">
-/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
-/** Inheritance Tests **/
-
-// Assertion failure in docshell/shistory/src/nsSHEntry.cpp (currently line 625).
-// Bug 901876 raised.
-SimpleTest.expectAssertions(1);
-SimpleTest.waitForExplicitFinish();
-  
-// A postMessage handler that is used by sandboxed iframes without
-// 'allow-same-origin' to communicate pass/fail back to this main page.
-// It expects to be called with an object like {ok: true/false, desc:
-// <description of the test> which it then forwards to ok().
-window.addEventListener("message", receiveMessage, false);
-
-var completedTests = 0;
-var passedTests = 0;
-
-function receiveMessage(event)
-{
-  ok_wrapper(event.data.ok, event.data.desc);
-}
-
-function ok_wrapper(result, desc) {
-  ok(result, desc);
-
-  completedTests++;
-
-  if (result) {
-	  passedTests++;
-  } 
-
-  if (completedTests == 13) {
-    is(passedTests, completedTests, "there should be " + completedTests + " passed inheritance tests");
-    SimpleTest.finish();
-  }
-}
-
-function doTest() {
-  // fails if bad
-  // 1) an iframe with no sandbox attribute inside an iframe that has sandbox = ""
-  // should not be able to execute scripts (cannot ever loosen permissions)
-  // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if1.html)
-
-  // fails if bad
-  // 2) an iframe with sandbox = "allow-scripts" inside an iframe that has sandbox = ""
-  // should not be able to execute scripts (cannot ever loosen permissions)
-  // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if1.html)
-
-  // fails if bad
-  // 3) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts"
-  // should not be same origin with the top window
-  // (done by file_iframe_sandbox_a_if4.html contained within file_iframe_sandbox_a_if3.html)
-
-  // fails if bad
-  // 4) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts"
-  // should not be same origin with its parent
-  // (done by file_iframe_sandbox_a_if4.html contained within file_iframe_sandbox_a_if3.html)
-
-  // passes if good
-  // 5) an iframe with 'allow-same-origin' and 'allow-scripts' inside an iframe with 'allow-same-origin'
-  // and 'allow-scripts' should be same origin with the top window
-  // (done by file_iframe_sandbox_a_if6.html contained within file_iframe_sandbox_a_if5.html)
-
-  // passes if good
-  // 6) an iframe with 'allow-same-origin' and 'allow-scripts' inside an iframe with 'allow-same-origin'
-  // and 'allow-scripts' should be same origin with its parent
-  // (done by file_iframe_sandbox_a_if6.html contained within file_iframe_sandbox_a_if5.html)
-
-  // passes if good
-  // 7) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts"
-  // should be able to execute scripts
-  // (done by file_iframe_sandbox_a_if7.html contained within file_iframe_sandbox_a_if3.html)
-
-  // fails if bad
-  // 8) an iframe with sandbox="" inside an iframe that has allow-scripts should not be able
-  // to execute scripts
-  // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if3.html)
-
-  // passes if good
-  // 9) make sure that changing the sandbox flags on an iframe (if_8) doesn't affect
-  // the sandboxing of subloads of content within that iframe
-  var if_8 = document.getElementById('if_8');
-  if_8.sandbox = 'allow-scripts';
-  if_8.contentWindow.doSubload();
-
-  // passes if good
-  // 10) a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same
-  // origin with this document
-  // done by file_iframe_sandbox_a_if11.html which is contained with file_iframe_sandbox_a_if10.html
-
-  // passes if good
-  // 11) a <frame> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same
-  // origin with its parent frame or this document
-  // done by file_iframe_sandbox_a_if12.html which is contained with file_iframe_sandbox_a_if11.html
-
-  // passes if good, fails if bad
-  // 12) An <object> inside an <iframe> sandboxed with 'allow-scripts' should not be same
-  // origin with this document
-  // Done by file_iframe_sandbox_a_if14.html which is contained within file_iframe_sandbox_a_if13.html
-
-  // passes if good, fails if bad
-  // 13) An <object> inside an <object> inside an <iframe> sandboxed with 'allow-scripts' should not be same
-  // origin with its parent frame or this document
-  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if14.html
-
-  // passes if good, fails if bad
-  // 14) An <object> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same
-  // origin with its parent frame or this document
-  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if16.html
-  // which is contained within file_iframe_sandbox_a_if10.html
-
-  // passes if good
-  // 15) An <object> inside an <object> inside an <iframe> sandboxed with 'allow-scripts allow-forms'
-  // should be able to submit forms.
-  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if14.html
-
-  // passes if good
-  // 16) An <object> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts allow-forms'
-  // should be able to submit forms.
-  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if16.html
-  // which is contained within file_iframe_sandbox_a_if10.html
-
-  // fails if bad
-  // 17) An <object> inside an <iframe> sandboxed with 'allow-same-origin'
-  // should not be able to run scripts.
-  // Done by iframe "if_no_scripts" using a data: load.
-
-  // passes if good
-  // 18) An <object> inside an <iframe> sandboxed with 'allow-scripts allow-same-origin'
-  // should be able to run scripts and be same origin with this document.
-  // Done by iframe "if_scripts" using a data: load.
-
-  // passes if good, fails if bad
-  // 19) Make sure that the parent's document's sandboxing flags are copied when
-  // changing the sandbox flags on an iframe inside an iframe.
-  // Done in file_iframe_sandbox_a_if17.html and file_iframe_sandbox_a_if18.html
-}
-
-addLoadEvent(doTest);
-</script>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
-<p id="display"></p>
-<div id="content">
-<iframe sandbox="" id="if_1" src="file_iframe_sandbox_a_if1.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts" id="if_3" src="file_iframe_sandbox_a_if3.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts allow-same-origin" id="if_5" src="file_iframe_sandbox_a_if5.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts allow-same-origin" id="if_8" src="file_iframe_sandbox_a_if8.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts allow-forms" id="if_10" src="file_iframe_sandbox_a_if10.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts allow-forms" id="if_13" src="file_iframe_sandbox_a_if13.html" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin" id="if_no_scripts" src="data:text/html,<object%20data='data:text/html,<script>parent.parent.ok_wrapper(false, &quot;an object inside an iframe sandboxed with only allow-same-origin should not be able to run scripts&quot;)</script>'></object>" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts allow-same-origin" id="if_scripts" src="data:text/html,<object%20data='data:text/html,<script>parent.parent.ok_wrapper(true, &quot;an object inside an iframe sandboxed with allow-scripts allow-same-origin should be able to run scripts and call functions in the parent of the iframe&quot;)</script>'></object>" height="10" width="10"></iframe>
-<iframe sandbox="allow-same-origin" id="if_19" src="data:text/html,<iframe%20data='data:text/html,<script>parent.parent.ok_wrapper(true, &quot;an object inside an iframe sandboxed with allow-scripts allow-same-origin should be able to run scripts and call functions in the parent of the iframe&quot;)</script>'></object>" height="10" width="10"></iframe>
-<iframe sandbox="allow-scripts" id="if_17" src="file_iframe_sandbox_a_if17.html" height="10" width="10"></iframe>
-</div>
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=341604
+Implement HTML5 sandbox attribute for IFRAMEs - inheritance tests
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 341604</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="application/javascript">
+/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
+/** Inheritance Tests **/
+
+// Assertion failure in docshell/shistory/src/nsSHEntry.cpp (currently line 625).
+// Bug 901876 raised.
+SimpleTest.expectAssertions(1);
+SimpleTest.waitForExplicitFinish();
+
+// A postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+// It expects to be called with an object like {ok: true/false, desc:
+// <description of the test> which it then forwards to ok().
+window.addEventListener("message", receiveMessage, false);
+
+function receiveMessage(event) {
+  switch (event.data.type) {
+    case "attempted":
+      testAttempted();
+      break;
+    case "ok":
+      ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      break;
+    default:
+      // allow for old style message
+      if (event.data.ok != undefined) {
+        ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      }
+  }
+}
+
+var attemptedTests = 0;
+var passedTests = 0;
+var totalTestsToPass = 15;
+var totalTestsToAttempt = 19;
+
+function ok_wrapper(result, desc, addToAttempted = true) {
+  ok(result, desc);
+
+  if (result) {
+    passedTests++;
+  }
+
+  if (addToAttempted) {
+    testAttempted();
+  }
+}
+
+// Added so that tests that don't register unless they fail,
+// can at least notify that they've attempted to run.
+function testAttempted() {
+  attemptedTests++;
+  if (attemptedTests == totalTestsToAttempt) {
+    // Make sure all tests have had a chance to complete.
+    setTimeout(function() {finish();}, 1000);
+  }
+}
+
+var finishCalled = false;
+
+function finish() {
+  if (!finishCalled) {
+    finishCalled = true;
+    is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " inheritance tests that should pass");
+
+    SimpleTest.finish();
+  }
+}
+
+function doTest() {
+  // fails if bad
+  // 1) an iframe with no sandbox attribute inside an iframe that has sandbox = ""
+  // should not be able to execute scripts (cannot ever loosen permissions)
+  // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if1.html)
+  testAttempted();
+
+  // fails if bad
+  // 2) an iframe with sandbox = "allow-scripts" inside an iframe that has sandbox = ""
+  // should not be able to execute scripts (cannot ever loosen permissions)
+  // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if1.html)
+  testAttempted();
+
+  // passes if good and fails if bad
+  // 3) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts"
+  // should not be same origin with the top window
+  // (done by file_iframe_sandbox_a_if4.html contained within file_iframe_sandbox_a_if3.html)
+
+  // passes if good and fails if bad
+  // 4) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts"
+  // should not be same origin with its parent
+  // (done by file_iframe_sandbox_a_if4.html contained within file_iframe_sandbox_a_if3.html)
+
+  // passes if good
+  // 5) an iframe with 'allow-same-origin' and 'allow-scripts' inside an iframe with 'allow-same-origin'
+  // and 'allow-scripts' should be same origin with the top window
+  // (done by file_iframe_sandbox_a_if6.html contained within file_iframe_sandbox_a_if5.html)
+
+  // passes if good
+  // 6) an iframe with 'allow-same-origin' and 'allow-scripts' inside an iframe with 'allow-same-origin'
+  // and 'allow-scripts' should be same origin with its parent
+  // (done by file_iframe_sandbox_a_if6.html contained within file_iframe_sandbox_a_if5.html)
+
+  // passes if good
+  // 7) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts"
+  // should be able to execute scripts
+  // (done by file_iframe_sandbox_a_if7.html contained within file_iframe_sandbox_a_if3.html)
+
+  // fails if bad
+  // 8) an iframe with sandbox="" inside an iframe that has allow-scripts should not be able
+  // to execute scripts
+  // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if3.html)
+  testAttempted();
+
+  // passes if good
+  // 9) make sure that changing the sandbox flags on an iframe (if_8) doesn't affect
+  // the sandboxing of subloads of content within that iframe
+  var if_8 = document.getElementById('if_8');
+  if_8.sandbox = 'allow-scripts';
+  if_8.contentWindow.doSubload();
+
+  // passes if good
+  // 10) a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same
+  // origin with this document
+  // done by file_iframe_sandbox_a_if11.html which is contained with file_iframe_sandbox_a_if10.html
+
+  // passes if good
+  // 11) a <frame> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same
+  // origin with its parent frame or this document
+  // done by file_iframe_sandbox_a_if12.html which is contained with file_iframe_sandbox_a_if11.html
+
+  // passes if good, fails if bad
+  // 12) An <object> inside an <iframe> sandboxed with 'allow-scripts' should not be same
+  // origin with this document
+  // Done by file_iframe_sandbox_a_if14.html which is contained within file_iframe_sandbox_a_if13.html
+
+  // passes if good, fails if bad
+  // 13) An <object> inside an <object> inside an <iframe> sandboxed with 'allow-scripts' should not be same
+  // origin with its parent frame or this document
+  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if14.html
+
+  // passes if good, fails if bad
+  // 14) An <object> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same
+  // origin with its parent frame or this document
+  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if16.html
+  // which is contained within file_iframe_sandbox_a_if10.html
+
+  // passes if good
+  // 15) An <object> inside an <object> inside an <iframe> sandboxed with 'allow-scripts allow-forms'
+  // should be able to submit forms.
+  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if14.html
+
+  // passes if good
+  // 16) An <object> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts allow-forms'
+  // should be able to submit forms.
+  // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if16.html
+  // which is contained within file_iframe_sandbox_a_if10.html
+
+  // fails if bad
+  // 17) An <object> inside an <iframe> sandboxed with 'allow-same-origin'
+  // should not be able to run scripts.
+  // Done by iframe "if_no_scripts" using a data: load.
+  testAttempted();
+
+  // passes if good
+  // 18) An <object> inside an <iframe> sandboxed with 'allow-scripts allow-same-origin'
+  // should be able to run scripts and be same origin with this document.
+  // Done by iframe "if_scripts" using a data: load.
+
+  // passes if good, fails if bad
+  // 19) Make sure that the parent's document's sandboxing flags are copied when
+  // changing the sandbox flags on an iframe inside an iframe.
+  // Done in file_iframe_sandbox_a_if17.html and file_iframe_sandbox_a_if18.html
+}
+
+addLoadEvent(doTest);
+</script>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
+<p id="display"></p>
+<div id="content">
+<iframe sandbox="" id="if_1" src="file_iframe_sandbox_a_if1.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts" id="if_3" src="file_iframe_sandbox_a_if3.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-same-origin" id="if_5" src="file_iframe_sandbox_a_if5.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-same-origin" id="if_8" src="file_iframe_sandbox_a_if8.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-forms" id="if_10" src="file_iframe_sandbox_a_if10.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-forms" id="if_13" src="file_iframe_sandbox_a_if13.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin" id="if_no_scripts" src="data:text/html,<object%20data='data:text/html,<script>parent.parent.ok_wrapper(false, &quot;an object inside an iframe sandboxed with only allow-same-origin should not be able to run scripts&quot;)</script>'></object>" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-same-origin" id="if_scripts" src="data:text/html,<object%20data='data:text/html,<script>parent.parent.ok_wrapper(true, &quot;an object inside an iframe sandboxed with allow-scripts allow-same-origin should be able to run scripts and call functions in the parent of the iframe&quot;)</script>'></object>" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin" id="if_19" src="data:text/html,<iframe%20data='data:text/html,<script>parent.parent.ok_wrapper(true, &quot;an object inside an iframe sandboxed with allow-scripts allow-same-origin should be able to run scripts and call functions in the parent of the iframe&quot;)</script>'></object>" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts" id="if_17" src="file_iframe_sandbox_a_if17.html" height="10" width="10"></iframe>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_iframe_sandbox_modal.html
@@ -0,0 +1,121 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=766282
+implement allow-popups directive for iframe sandbox
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Tests for Bug 766282</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+// A postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+window.addEventListener("message", receiveMessage, false);
+
+function receiveMessage(event) {
+  switch (event.data.type) {
+    case "attempted":
+      testAttempted();
+      break;
+    case "ok":
+      ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      break;
+    default:
+      // allow for old style message
+      if (event.data.ok != undefined) {
+        ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      }
+  }
+}
+
+var attemptedTests = 0;
+var passedTests = 0;
+var totalTestsToPass = 5;
+var totalTestsToAttempt = 5;
+
+function ok_wrapper(result, desc, addToAttempted = true) {
+  ok(result, desc);
+
+  if (result) {
+    passedTests++;
+  }
+
+  if (addToAttempted) {
+    testAttempted();
+  }
+}
+
+// Added so that tests that don't register unless they fail,
+// can at least notify that they've attempted to run.
+function testAttempted() {
+  attemptedTests++;
+  if (attemptedTests == totalTestsToAttempt) {
+    // Make sure all tests have had a chance to complete.
+    setTimeout(function() {finish();}, 1000);
+  }
+}
+
+var finishCalled = false;
+
+function finish() {
+  if (!finishCalled) {
+    finishCalled = true;
+    is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " modal tests that should pass");
+
+    SimpleTest.finish();
+  }
+}
+
+function doTest() {
+  // passes if good and fails if bad
+  // 1) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups
+  // allow-same-origin" should not have its origin sandbox flag set and be able to access
+  // document.cookie. (Done by file_iframe_sandbox_k_if5.html opened from
+  // file_iframe_sandbox_j_if1.html) using showModalDialog.)
+
+  // passes if good
+  // 2) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups
+  // allow-top-navigation" should not have its top-level navigation sandbox flag set and be able to
+  // navigate top. (Done by file_iframe_sandbox_k_if5.html (and if6) opened from
+  // file_iframe_sandbox_j_if1.html) using showModalDialog.)
+
+  // passes if good
+  // 3) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups
+  // all-forms" should not have its forms sandbox flag set and be able to submit forms.
+  // (Done by file_iframe_sandbox_k_if7.html opened from
+  // file_iframe_sandbox_j_if1.html) using showModalDialog.)
+
+  // passes if good
+  // 4) Make sure that the sandbox flags copied to a new browsing context are taken from the
+  // current active document not the browsing context (iframe / docShell).
+  // This is done by removing allow-same-origin and calling doSubOpens from file_iframe_sandbox_j_if2.html,
+  // which opens file_iframe_sandbox_k_if9.html using showModalDialog.
+  var if_2 = document.getElementById('if_2');
+  if_2.sandbox = 'allow-scripts allow-popups';
+  if_2.contentWindow.doSubOpens();
+
+  // passes if good
+  // 5) Test that a sandboxed iframe with "allow-popups" can open a new window using window.ShowModalDialog.
+  // This is done via file_iframe_sandbox_j_if3.html which is sandboxed with "allow-popups allow-scripts
+  // allow-same-origin". The window it attempts to open calls window.opener.ok(true, ...) and
+  // file_iframe_j_if3.html has an ok() function that calls window.parent.ok_wrapper.
+}
+
+addLoadEvent(doTest);
+</script>
+
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=766282">Mozilla Bug 766282</a> - implement allow-popups directive for iframe sandbox
+<p id="display"></p>
+<div id="content">
+<iframe sandbox="allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation" id="if_1" src="file_iframe_sandbox_j_if1.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-popups allow-same-origin" id="if_2" src="file_iframe_sandbox_j_if2.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-popups allow-same-origin allow-scripts" id="if_3" src="file_iframe_sandbox_j_if3.html" height="10" width="10"></iframe>
+</div>
--- a/content/html/content/test/test_iframe_sandbox_navigation.html
+++ b/content/html/content/test/test_iframe_sandbox_navigation.html
@@ -21,30 +21,36 @@ SimpleTest.waitForExplicitFinish();
 // 'allow-same-origin'/other windows to communicate pass/fail back to this main page.
 // it expects to be called with an object like {ok: true/false, desc:
 // <description of the test> which it then forwards to ok()
 window.addEventListener("message", receiveMessage, false);
 
 var testPassesReceived = 0;
 
 function receiveMessage(event) {
-  // this message is part of if_10's test
-  if (event.data.test == 'if_10') {
-    doIf10TestPart2();
-  } else if (event.data == "test attempted") {
-    testAttempted();
-  } else {
-    ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+  switch (event.data.type) {
+    case "attempted":
+      testAttempted();
+      break;
+    case "ok":
+      ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      break;
+    case "if_10":
+      doIf10TestPart2();
+      break;
+    default:
+      // allow for old style message
+      if (event.data.ok != undefined) {
+        ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      }
   }
 }
 
 // Open windows for tests to attempt to navigate later.
 var windowsToClose = new Array();
-windowsToClose.push(window.open("about:blank", "window_to_navigate"));
-windowsToClose.push(window.open("about:blank", "window_to_navigate2"));
 
 var attemptedTests = 0;
 var passedTests = 0;
 var totalTestsToPass = 7;
 var totalTestsToAttempt = 13;
 
 function ok_wrapper(result, desc, addToAttempted = true) {
   ok(result, desc);
@@ -70,30 +76,32 @@ function testAttempted() {
 
 var finishCalled = false;
 
 function finish() {
   if (!finishCalled) {
     finishCalled = true;
     is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " navigation tests that should pass");
 
-    for (var i = 0; i < windowsToClose.length; i++) {
-      windowsToClose[i].close();
-    }
+    closeWindows();
 
     SimpleTest.finish();
   }
 }
 
 function checkTestsFinished() {
   // If our own finish() has not been called, probably failed due to a timeout, so close remaining windows.
   if (!finishCalled) {
-    for (var i = 0; i < windowsToClose.length; i++) {
-      windowsToClose[i].close();
-    }
+    closeWindows();
+  }
+}
+
+function closeWindows() {
+  for (var i = 0; i < windowsToClose.length; i++) {
+    windowsToClose[i].close();
   }
 }
 
 function doTest() {
   // passes if good
   // 1) A sandboxed iframe is allowed to navigate itself
   // (done by file_iframe_sandbox_d_if1.html which has 'allow-scripts' and navigates to
   // file_iframe_sandbox_navigation_pass.html).
--- a/content/html/content/test/test_iframe_sandbox_navigation2.html
+++ b/content/html/content/test/test_iframe_sandbox_navigation2.html
@@ -21,32 +21,41 @@ SimpleTest.waitForExplicitFinish();
 // 'allow-same-origin'/other windows to communicate pass/fail back to this main page.
 // it expects to be called with an object like {ok: true/false, desc:
 // <description of the test> which it then forwards to ok()
 window.addEventListener("message", receiveMessage, false);
 
 var testPassesReceived = 0;
 
 function receiveMessage(event) {
-  if (event.data == "test attempted") {
-    testAttempted();
-  } else {
-    ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+  switch (event.data.type) {
+    case "attempted":
+      testAttempted();
+      break;
+    case "ok":
+      ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      break;
+    default:
+      // allow for old style message
+      if (event.data.ok != undefined) {
+        ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      }
   }
 }
 
 // Open windows for tests to attempt to navigate later.
 var windowsToClose = new Array();
 windowsToClose.push(window.open("about:blank", "window_to_navigate"));
 windowsToClose.push(window.open("about:blank", "window_to_navigate2"));
+var iframesWithWindowsToClose = new Array();
 
 var attemptedTests = 0;
 var passedTests = 0;
-var totalTestsToPass = 10;
-var totalTestsToAttempt = 13;
+var totalTestsToPass = 12;
+var totalTestsToAttempt = 15;
 
 function ok_wrapper(result, desc, addToAttempted = true) {
   ok(result, desc);
 
   if (result) {
     passedTests++;
   }
 
@@ -163,25 +172,39 @@ function doTest() {
   window.open("file_iframe_sandbox_e_if13.html");
 
   // passes if good, fails if bad
   // 26) iframe with sandbox='allow-scripts' should not be able to navigate top using its real name
   // (not with _top e.g. window.open(..., "topname")) as allow-top-navigation is not specified.
   // file_iframe_sandbox_e_if15.html contains file_iframe_sandbox_e_if16.html, which
   // attempts to navigate top by name using window.open().
   window.open("file_iframe_sandbox_e_if15.html");
+
+  // passes if good
+  // 27) iframe with sandbox='allow-scripts allow-popups' should be able to
+  // navigate a window, that it has opened, using it's name.
+  // file_iframe_sandbox_d_if23.html in if_23 opens a window and then attempts
+  // to navigate it using it's name in the target of an anchor.
+  iframesWithWindowsToClose.push("if_23");
+
+  // passes if good, fails if bad
+  // 28) iframe with sandbox='allow-scripts allow-popups' should be able to
+  // navigate a window, that it has opened, using window.open(..., "<name>").
+  // file_iframe_sandbox_d_if23.html in if_23 opens a window and then attempts
+  // to navigate it using it's name in the target of window.open().
 }
 
 addLoadEvent(doTest);
 </script>
 <body onunload="checkTestsFinished()">
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
 <p id="display"></p>
 <div id="content">
 <iframe sandbox="allow-same-origin allow-scripts allow-top-navigation" id="if_14" src="file_iframe_sandbox_d_if14.html" height="10" width="10"></iframe>
 <iframe id="if_15" name="if_parent" src="file_iframe_sandbox_d_if15.html" height="10" width="10"></iframe>
 <iframe sandbox="allow-scripts" id="if_17" src="file_iframe_sandbox_d_if17.html" height="10" width="10"></iframe>
 <iframe sandbox="allow-scripts" id="if_18" src="file_iframe_sandbox_d_if18.html" height="10" width="10"></iframe>
 <iframe sandbox="allow-scripts" id="if_19" src="file_iframe_sandbox_d_if19.html" height="10" width="10"></iframe>
 <iframe id="if_21" name="if_parent2" src="file_iframe_sandbox_d_if21.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-popups" id="if_23" src="file_iframe_sandbox_d_if23.html" height="10" width="10"></iframe>
 </div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_iframe_sandbox_popups.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=766282
+implement allow-popups directive for iframe sandbox
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Tests for Bug 766282</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+// it expects to be called with an object like {ok: true/false, desc:
+// <description of the test> which it then forwards to ok()
+window.addEventListener("message", receiveMessage, false);
+
+function receiveMessage(event)
+{
+  ok_wrapper(event.data.ok, event.data.desc);
+}
+
+var completedTests = 0;
+var passedTests = 0;
+
+function ok_wrapper(result, desc) {
+  ok(result, desc);
+
+  completedTests++;
+
+  if (result) {
+    passedTests++;
+  }
+
+  if (completedTests == 3) {
+    is(passedTests, completedTests, "There are " + completedTests + " popups tests that should pass");
+    SimpleTest.finish();
+  }
+}
+
+function doTest() {
+  // passes if good
+  // 1) Test that a sandboxed iframe with "allow-popups" can open a new window using the target.attribute.
+  // This is done via file_iframe_sandbox_h_if1.html which is sandboxed with "allow-popups allow-scripts allow-same-origin".
+  // The window it attempts to open calls window.opener.ok(true, ...) and file_iframe_h_if1.html has an ok()
+  // function that calls window.parent.ok_wrapper.
+
+  // passes if good
+  // 2) Test that a sandboxed iframe with "allow-popups" can open a new window using window.open.
+  // This is done via file_iframe_sandbox_h_if1.html which is sandboxed with "allow-popups allow-scripts allow-same-origin".
+  // The window it attempts to open calls window.opener.ok(true, ...) and file_iframe_h_if1.html has an ok()
+  // function that calls window.parent.ok_wrapper.
+
+  // passes if good, fails if bad
+  // 3) Test that a sandboxed iframe with "allow-popups" can open a new window using the target.attribute
+  // for a non-existing browsing context (BC766282).
+  // This is done via file_iframe_sandbox_h_if1.html which is sandboxed with "allow-popups allow-scripts allow-same-origin".
+  // The window it attempts to open calls window.opener.ok(true, ...) and file_iframe_h_if1.html has an ok()
+  // function that calls window.parent.ok_wrapper.
+}
+
+addLoadEvent(doTest);
+
+</script>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=766282">Mozilla Bug 766282</a> - implement allow-popups directive for iframe sandbox
+<p id="display"></p>
+<div id="content">
+<iframe sandbox="allow-popups allow-same-origin allow-scripts" id="if1" src="file_iframe_sandbox_h_if1.html" height="10" width="10"></iframe>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_iframe_sandbox_popups_inheritance.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=766282
+Implement HTML5 sandbox allow-popuos directive for IFRAMEs - inheritance tests
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Tests for Bug 766282</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<script type="application/javascript">
+
+SimpleTest.expectAssertions(0, 5);
+SimpleTest.waitForExplicitFinish();
+
+// A postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+window.addEventListener("message", receiveMessage, false);
+
+function receiveMessage(event) {
+  switch (event.data.type) {
+    case "attempted":
+      testAttempted();
+      break;
+    case "ok":
+      ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      break;
+    default:
+      // allow for old style message
+      if (event.data.ok != undefined) {
+        ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted);
+      }
+  }
+}
+
+var iframesWithWindowsToClose = new Array();
+
+var attemptedTests = 0;
+var passedTests = 0;
+var totalTestsToPass = 15;
+var totalTestsToAttempt = 21;
+
+function ok_wrapper(result, desc, addToAttempted = true) {
+  ok(result, desc);
+
+  if (result) {
+    passedTests++;
+  }
+
+  if (addToAttempted) {
+    testAttempted();
+  }
+}
+
+// Added so that tests that don't register unless they fail,
+// can at least notify that they've attempted to run.
+function testAttempted() {
+  attemptedTests++;
+  if (attemptedTests == totalTestsToAttempt) {
+    // Make sure all tests have had a chance to complete.
+    setTimeout(function() {finish();}, 1000);
+  }
+}
+
+var finishCalled = false;
+
+function finish() {
+  if (!finishCalled) {
+    finishCalled = true;
+    is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " inheritance tests that should pass");
+
+    closeWindows();
+
+    SimpleTest.finish();
+  }
+}
+
+function checkTestsFinished() {
+  // If our own finish() has not been called, probably failed due to a timeout, so close remaining windows.
+  if (!finishCalled) {
+    closeWindows();
+  }
+}
+
+function closeWindows() {
+  for (var i = 0; i < iframesWithWindowsToClose.length; i++) {
+    document.getElementById(iframesWithWindowsToClose[i]).contentWindow.postMessage({type: "closeWindows"}, "*");
+  }
+}
+
+function doTest() {
+  // passes if good and fails if bad
+  // 1,2,3) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups
+  // allow-same-origin" should not have its origin sandbox flag set and be able to access document.cookie.
+  // (Done by file_iframe_sandbox_k_if5.html opened from file_iframe_sandbox_k_if4.html)
+  // This is repeated for 3 different ways of opening the window,
+  // see file_iframe_sandbox_k_if4.html for details.
+
+  // passes if good
+  // 4,5,6) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups
+  // allow-top-navigation" should not have its top-level navigation sandbox flag set and be able to
+  // navigate top. (Done by file_iframe_sandbox_k_if5.html (and if6) opened from
+  // file_iframe_sandbox_k_if4.html).  This is repeated for 3 different ways of opening the window,
+  // see file_iframe_sandbox_k_if4.html for details.
+
+  // passes if good
+  // 7,8,9) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups
+  // all-forms" should not have its forms sandbox flag set and be able to submit forms.
+  // (Done by file_iframe_sandbox_k_if7.html opened from file_iframe_sandbox_k_if4.html)
+  // This is repeated for 3 different ways of opening the window,
+  // see file_iframe_sandbox_k_if4.html for details.
+
+  // passes if good
+  // 10,11,12) Make sure that the sandbox flags copied to a new browsing context are taken from the
+  // current active document not the browsing context (iframe / docShell).
+  // This is done by removing allow-same-origin and calling doSubOpens from file_iframe_sandbox_k_if8.html,
+  // which opens file_iframe_sandbox_k_if9.html in 3 different ways.
+  // It then navigates to file_iframe_sandbox_k_if1.html to run tests 13 - 21 below.
+  var if_8_1 = document.getElementById('if_8_1');
+  if_8_1.sandbox = 'allow-scripts allow-popups';
+  if_8_1.contentWindow.doSubOpens();
+
+  // passes if good and fails if bad
+  // 13,14,15) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups"
+  // should have its origin sandbox flag set and not be able to access document.cookie.
+  // This is done by file_iframe_sandbox_k_if8.html navigating to file_iframe_sandbox_k_if1.html
+  // after allow-same-origin has been removed from iframe if_8_1.  file_iframe_sandbox_k_if1.html
+  // opens file_iframe_sandbox_k_if2.html in 3 different ways to perform the tests.
+  iframesWithWindowsToClose.push("if_8_1");
+
+  // fails if bad
+  // 16,17,18) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups"
+  // should have its forms sandbox flag set and not be able to submit forms.
+  // This is done by file_iframe_sandbox_k_if2.html, see test 10 for details of how this is opened.
+
+  // fails if bad
+  // 19,20,21) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups"
+  // should have its top-level navigation sandbox flag set and not be able to navigate top.
+  // This is done by file_iframe_sandbox_k_if2.html, see test 10 for details of how this is opened.
+}
+
+addLoadEvent(doTest);
+</script>
+
+<body onunload="checkTestsFinished()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=766282">Mozilla Bug 766282</a> - Implement HTML5 sandbox allow-popups directive for IFRAMEs
+<p id="display"></p>
+<div id="content">
+<iframe sandbox="allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation" id="if_4" src="file_iframe_sandbox_k_if4.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts allow-popups allow-same-origin" id="if_8_1" src="file_iframe_sandbox_k_if8.html" height="10" width="10"></iframe>
+</div>
+</body>
+</html>
--- a/content/xbl/src/nsXBLProtoImplField.cpp
+++ b/content/xbl/src/nsXBLProtoImplField.cpp
@@ -366,17 +366,17 @@ nsXBLProtoImplField::InstallAccessors(JS
   }
   js::SetFunctionNativeReserved(set, XBLPROTO_SLOT, wrappedClassObj);
   js::SetFunctionNativeReserved(set, FIELD_SLOT,
                                 JS::StringValue(JSID_TO_STRING(id)));
 
   // Now, re-enter the class object's scope, wrap the getters/setters, and define
   // them there.
   JSAutoCompartment ac2(aCx, aTargetClassObject);
-  if (!JS_WrapObject(aCx, get.address()) || !JS_WrapObject(aCx, set.address()) ||
+  if (!JS_WrapObject(aCx, &get) || !JS_WrapObject(aCx, &set) ||
       !JS_WrapId(aCx, id.address()))
   {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, JS::UndefinedValue(),
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp, get.get()),
                                JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, set.get()),
@@ -419,17 +419,17 @@ nsXBLProtoImplField::InstallField(nsIScr
 
   // First, enter the xbl scope, wrap the node, and use that as the scope for
   // the evaluation.
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScope(cx, aBoundNode));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
   JSAutoCompartment ac(cx, scopeObject);
 
   JS::Rooted<JSObject*> wrappedNode(cx, aBoundNode);
-  if (!JS_WrapObject(cx, wrappedNode.address()))
+  if (!JS_WrapObject(cx, &wrappedNode))
       return NS_ERROR_OUT_OF_MEMORY;
 
   JS::Rooted<JS::Value> result(cx);
   JS::CompileOptions options(cx);
   options.setFileAndLine(uriSpec.get(), mLineNumber)
          .setVersion(JSVERSION_LATEST);
   rv = aContext->EvaluateString(nsDependentString(mFieldText,
                                                   mFieldTextLength),
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -116,17 +116,17 @@ nsXBLProtoImplMethod::InstallMember(JSCo
     JS::Rooted<JSObject*> method(aCx, ::JS_CloneFunctionObject(aCx, jsMethodObject, scopeObject));
     if (!method) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     // Then, enter the content compartment, wrap the method pointer, and define
     // the wrapped version on the class object.
     JSAutoCompartment ac2(aCx, aTargetClassObject);
-    if (!JS_WrapObject(aCx, method.address()))
+    if (!JS_WrapObject(aCx, &method))
       return NS_ERROR_OUT_OF_MEMORY;
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*method));
     if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
                                static_cast<const jschar*>(mName),
                                name.Length(), value,
                                nullptr, nullptr, JSPROP_ENUMERATE)) {
       return NS_ERROR_OUT_OF_MEMORY;
@@ -322,17 +322,17 @@ nsXBLProtoImplAnonymousMethod::Execute(n
     return NS_ERROR_UNEXPECTED;
   MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
 
   JS::Rooted<JSObject*> thisObject(cx, &v.toObject());
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScope(cx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   JSAutoCompartment ac(cx, scopeObject);
-  if (!JS_WrapObject(cx, thisObject.address()))
+  if (!JS_WrapObject(cx, &thisObject))
       return NS_ERROR_OUT_OF_MEMORY;
 
   // Clone the function object, using thisObject as the parent so "this" is in
   // the scope chain of the resulting function (for backwards compat to the
   // days when this was an event handler).
   JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, GetCompiledMethod(), thisObject));
   if (!method)
     return NS_ERROR_OUT_OF_MEMORY;
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -147,18 +147,18 @@ nsXBLProtoImplProperty::InstallMember(JS
       if (!(setter = ::JS_CloneFunctionObject(aCx, mSetter.GetJSFunction(), scopeObject)))
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     // Now, enter the content compartment, wrap the getter/setter, and define
     // them on the class object.
     JSAutoCompartment ac2(aCx, aTargetClassObject);
     nsDependentString name(mName);
-    if (!JS_WrapObject(aCx, getter.address()) ||
-        !JS_WrapObject(aCx, setter.address()) ||
+    if (!JS_WrapObject(aCx, &getter) ||
+        !JS_WrapObject(aCx, &setter) ||
         !::JS_DefineUCProperty(aCx, aTargetClassObject,
                                static_cast<const jschar*>(mName),
                                name.Length(), JSVAL_VOID,
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get()),
                                JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get()),
                                mJSAttributes))
       return NS_ERROR_OUT_OF_MEMORY;
   }
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -294,17 +294,17 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
   // Bind it to the bound element. Note that if we're using a separate XBL scope,
   // we'll actually be binding the event handler to a cross-compartment wrapper
   // to the bound element's reflector.
 
   // First, enter our XBL scope. This is where the generic handler should have
   // been compiled, above.
   JSAutoCompartment ac(cx, scopeObject);
   JS::Rooted<JSObject*> genericHandler(cx, handler.get());
-  bool ok = JS_WrapObject(cx, genericHandler.address());
+  bool ok = JS_WrapObject(cx, &genericHandler);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   MOZ_ASSERT(!js::IsCrossCompartmentWrapper(genericHandler));
 
   // Wrap the native into the XBL scope. This creates a reflector in the document
   // scope if one doesn't already exist, and potentially wraps it cross-
   // compartment into our scope (via aAllowWrapping=true).
   JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
   rv = nsContentUtils::WrapNative(cx, scopeObject, scriptTarget, targetV.address(), nullptr,
@@ -312,17 +312,17 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Next, clone the generic handler to be parented to the target.
   JS::Rooted<JSObject*> bound(cx, JS_CloneFunctionObject(cx, genericHandler, &targetV.toObject()));
   NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
 
   // Now, wrap the bound handler into the content compartment and use it.
   JSAutoCompartment ac2(cx, globalObject);
-  if (!JS_WrapObject(cx, bound.address())) {
+  if (!JS_WrapObject(cx, &bound)) {
     return NS_ERROR_FAILURE;
   }
 
   nsRefPtr<EventHandlerNonNull> handlerCallback =
     new EventHandlerNonNull(bound);
 
   nsEventHandler eventHandler(handlerCallback);
 
@@ -388,17 +388,17 @@ nsXBLPrototypeHandler::EnsureEventHandle
                                            nsAtomCString(aName), argCount,
                                            argNames, handlerText, handlerFun.address());
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(handlerFun, NS_ERROR_FAILURE);
 
   // Wrap the handler into the content scope, since we're about to stash it
   // on the DOM window and such.
   JSAutoCompartment ac2(cx, globalObject);
-  bool ok = JS_WrapObject(cx, handlerFun.address());
+  bool ok = JS_WrapObject(cx, &handlerFun);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   aHandler.set(handlerFun);
   NS_ENSURE_TRUE(aHandler, NS_ERROR_FAILURE);
 
   if (pWindow) {
     pWindow->CacheXBLPrototypeHandler(this, aHandler);
   }
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3185,72 +3185,21 @@ nsDocShell::FindItemWithName(const PRUni
 
         if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
             foundItem = nullptr;
         }
 
         // DoFindItemWithName only returns active items and we don't check if
         // the item is active for the special cases.
         if (foundItem) {
-
-            // If our document is sandboxed, we need to do some extra checks.
-            uint32_t sandboxFlags = 0;
-
-            nsCOMPtr<nsIDocument> doc = do_GetInterface(aOriginalRequestor);
-
-            if (doc) {
-                sandboxFlags = doc->GetSandboxFlags();
+            if (IsSandboxedFrom(foundItem, aOriginalRequestor)) {
+                return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+            } else {
+                foundItem.swap(*_retval);
             }
-
-            if (sandboxFlags) {
-                nsCOMPtr<nsIDocShellTreeItem> root;
-                GetSameTypeRootTreeItem(getter_AddRefs(root));
-
-                // Is the found item not a top level browsing context and not ourself ?
-                nsCOMPtr<nsIDocShellTreeItem> selfAsItem = static_cast<nsIDocShellTreeItem *>(this);
-                if (foundItem != root && foundItem != selfAsItem) {
-                    // Are we an ancestor of the foundItem ?
-                    bool isAncestor = false;
-
-                    nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
-                    foundItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
-                    while (parentAsItem) {
-                        if (parentAsItem == selfAsItem) {
-                            isAncestor = true;
-                            break;
-                        }
-                        nsCOMPtr<nsIDocShellTreeItem> tmp = parentAsItem;
-                        tmp->GetSameTypeParent(getter_AddRefs(parentAsItem));
-                    }
-
-                    if (!isAncestor) {
-                        // No, we are not an ancestor and our document is
-                        // sandboxed, we can't allow this.
-                        foundItem = nullptr;
-                    }
-                } else {
-                    // Top level browsing context - is it an ancestor of ours ?
-                    nsCOMPtr<nsIDocShellTreeItem> tmp;
-                    GetSameTypeParent(getter_AddRefs(tmp));
-
-                    while (tmp) {
-                        if (tmp && tmp == foundItem) {
-                            // This is an ancestor, and we are sandboxed.
-                            // Unless allow-top-navigation is set, we can't allow this.
-                            if (sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION) {
-                                foundItem = nullptr;
-                            }
-                            break;
-                        }
-                        tmp->GetParent(getter_AddRefs(tmp));
-                    }
-                }
-            }
-
-            foundItem.swap(*_retval);
         }
         return NS_OK;
     }
 }
 
 nsresult
 nsDocShell::DoFindItemWithName(const PRUnichar* aName,
                                nsISupports* aRequestor,
@@ -3313,16 +3262,80 @@ nsDocShell::DoFindItemWithName(const PRU
     if (mTreeOwner && mTreeOwner != reqAsTreeOwner) {
         return mTreeOwner->
             FindItemWithName(aName, this, aOriginalRequestor, _retval);
     }
 
     return NS_OK;
 }
 
+/* static */
+bool
+nsDocShell::IsSandboxedFrom(nsIDocShellTreeItem* aTargetItem,
+                            nsIDocShellTreeItem* aAccessingItem)
+{
+    // aAccessingItem cannot be sandboxed from itself.
+    if (SameCOMIdentity(aTargetItem, aAccessingItem)) {
+        return false;
+    }
+
+    uint32_t sandboxFlags = 0;
+
+    nsCOMPtr<nsIDocument> doc = do_GetInterface(aAccessingItem);
+    if (doc) {
+        sandboxFlags = doc->GetSandboxFlags();
+    }
+
+    // If no flags, aAccessingItem is not sandboxed at all.
+    if (!sandboxFlags) {
+        return false;
+    }
+
+    // If aTargetItem has an ancestor, it is not top level.
+    nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget;
+    aTargetItem->GetSameTypeParent(getter_AddRefs(ancestorOfTarget));
+    if (ancestorOfTarget) {
+        do {
+            // aAccessingItem is not sandboxed if it is an ancestor of target.
+            if (SameCOMIdentity(aAccessingItem, ancestorOfTarget)) {
+                return false;
+            }
+            nsCOMPtr<nsIDocShellTreeItem> tempTreeItem;
+            ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem));
+            tempTreeItem.swap(ancestorOfTarget);
+        } while (ancestorOfTarget);
+
+        // Otherwise, aAccessingItem is sandboxed from aTargetItem.
+        return true;
+    }
+
+    // aTargetItem is top level, is aAccessingItem the "one permitted sandboxed
+    // navigator", i.e. did aAccessingItem open aTargetItem?
+    nsCOMPtr<nsIDocShell> targetDocShell = do_QueryInterface(aTargetItem);
+    nsCOMPtr<nsIDocShell> permittedNavigator;
+    targetDocShell->
+        GetOnePermittedSandboxedNavigator(getter_AddRefs(permittedNavigator));
+    if (SameCOMIdentity(aAccessingItem, permittedNavigator)) {
+        return false;
+    }
+
+    // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, aAccessingItem is
+    // not sandboxed from its top.
+    if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
+        nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
+        aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem));
+        if (SameCOMIdentity(aTargetItem, rootTreeItem)) {
+            return false;
+        }
+    }
+
+    // Otherwise, aAccessingItem is sandboxed from aTargetItem.
+    return true;
+}
+
 NS_IMETHODIMP
 nsDocShell::GetTreeOwner(nsIDocShellTreeOwner ** aTreeOwner)
 {
     NS_ENSURE_ARG_POINTER(aTreeOwner);
 
     *aTreeOwner = mTreeOwner;
     NS_IF_ADDREF(*aTreeOwner);
     return NS_OK;
@@ -5050,16 +5063,18 @@ nsDocShell::Destroy()
         if (shPrivate) {
             shPrivate->EvictAllContentViewers();
         }
         mSessionHistory = nullptr;
     }
 
     SetTreeOwner(nullptr);
 
+    mOnePermittedSandboxedNavigator = nullptr;
+
     // required to break ref cycle
     mSecurityUI = nullptr;
 
     // Cancel any timers that were set for this docshell; this is needed
     // to break the cycle between us and the timers.
     CancelRefreshURITimers();
 
     if (mInPrivateBrowsing) {
@@ -5399,16 +5414,41 @@ nsDocShell::SetSandboxFlags(uint32_t aSa
 NS_IMETHODIMP
 nsDocShell::GetSandboxFlags(uint32_t  *aSandboxFlags)
 {
     *aSandboxFlags = mSandboxFlags;
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator)
+{
+    if (mOnePermittedSandboxedNavigator) {
+        NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
+        return NS_OK;
+    }
+
+    mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
+    NS_ASSERTION(mOnePermittedSandboxedNavigator,
+             "One Permitted Sandboxed Navigator must support weak references.");
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator)
+{
+    NS_ENSURE_ARG_POINTER(aSandboxedNavigator);
+    nsCOMPtr<nsIDocShell> permittedNavigator =
+        do_QueryReferent(mOnePermittedSandboxedNavigator);
+    NS_IF_ADDREF(*aSandboxedNavigator = permittedNavigator);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags)
 {
     mDefaultLoadFlags = aDefaultLoadFlags;
 
     // Tell the load group to set these flags all requests in the group
     if (mLoadGroup) {
         mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags);
     } else {
@@ -8714,18 +8754,20 @@ nsDocShell::InternalLoad(nsIURI * aURI,
     int16_t shouldLoad = nsIContentPolicy::ACCEPT;
     uint32_t contentType;
     bool isNewDocShell = false;
     bool isTargetTopLevelDocShell = false;
     nsCOMPtr<nsIDocShell> targetDocShell;
     if (aWindowTarget && *aWindowTarget) {
         // Locate the target DocShell.
         nsCOMPtr<nsIDocShellTreeItem> targetItem;
-        FindItemWithName(aWindowTarget, nullptr, this,
-                         getter_AddRefs(targetItem));
+        if (FindItemWithName(aWindowTarget, nullptr, this,
+               getter_AddRefs(targetItem)) == NS_ERROR_DOM_INVALID_ACCESS_ERR) {
+            return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+        }
 
         targetDocShell = do_QueryInterface(targetItem);
         // If the targetDocShell doesn't exist, then this is a new docShell
         // and we should consider this a TYPE_DOCUMENT load
         isNewDocShell = !targetDocShell;
 
         // If the targetDocShell and the rootDocShell are the same, then the
         // targetDocShell is the top level document and hence we should
@@ -8842,29 +8884,27 @@ nsDocShell::InternalLoad(nsIURI * aURI,
     if (aWindowTarget && *aWindowTarget) {
         // We've already done our owner-inheriting.  Mask out that bit, so we
         // don't try inheriting an owner from the target window if we came up
         // with a null owner above.
         aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
         
         bool isNewWindow = false;
         if (!targetDocShell) {
-            // If the docshell's document is sandboxed and was trying to
-            // navigate/load a frame it wasn't allowed to access, the
-            // FindItemWithName above will have returned null for the target
-            // item - we don't want to actually open a new window in this case
-            // though. Check if we are sandboxed and bail out here if so.
+            // If the docshell's document is sandboxed, only open a new window
+            // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
+            // (i.e. if allow-popups is specified)
             NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
             nsIDocument* doc = mContentViewer->GetDocument();
             uint32_t sandboxFlags = 0;
 
             if (doc) {
                 sandboxFlags = doc->GetSandboxFlags();
-                if (sandboxFlags & SANDBOXED_NAVIGATION) {
-                    return NS_ERROR_FAILURE;
+                if (sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
+                    return NS_ERROR_DOM_INVALID_ACCESS_ERR;
                 }
             }
 
             nsCOMPtr<nsPIDOMWindow> win =
                 do_GetInterface(GetAsSupports(this));
             NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
 
             nsDependentString name(aWindowTarget);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -766,16 +766,17 @@ protected:
     int32_t                    mItemType;
 
     // Index into the SHTransaction list, indicating the previous and current
     // transaction at the time that this DocShell begins to load
     int32_t                    mPreviousTransIndex;
     int32_t                    mLoadedTransIndex;
 
     uint32_t                   mSandboxFlags;
+    nsWeakPtr                  mOnePermittedSandboxedNavigator;
 
     // mFullscreenAllowed stores how we determine whether fullscreen is allowed
     // when GetFullscreenAllowed() is called. Fullscreen is allowed in a
     // docshell when all containing iframes have the allowfullscreen
     // attribute set to true. When mFullscreenAllowed is CHECK_ATTRIBUTES
     // we check this docshell's containing frame for the allowfullscreen
     // attribute, and recurse onto the parent docshell to ensure all containing
     // frames also have the allowfullscreen attribute. If we find an ancestor
@@ -875,16 +876,20 @@ private:
 
     // Separate function to do the actual name (i.e. not _top, _self etc.)
     // searching for FindItemWithName.
     nsresult DoFindItemWithName(const PRUnichar* aName,
                                 nsISupports* aRequestor,
                                 nsIDocShellTreeItem* aOriginalRequestor,
                                 nsIDocShellTreeItem** _retval);
 
+    // Check whether accessing item is sandboxed from the target item.
+    static bool IsSandboxedFrom(nsIDocShellTreeItem* aTargetItem,
+                                nsIDocShellTreeItem* aAccessingItem);
+
 #ifdef DEBUG
     // We're counting the number of |nsDocShells| to help find leaks
     static unsigned long gNumberOfDocShells;
 #endif /* DEBUG */
 
 public:
     class InterfaceRequestorProxy : public nsIInterfaceRequestor {
     public:
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -38,17 +38,17 @@ interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(5f4d82fc-3220-4f7e-9b00-626f1033318a)]
+[scriptable, builtinclass, uuid(4ca172c3-67bf-4e6d-89a3-cbfb929c370d)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -794,16 +794,23 @@ interface nsIDocShell : nsIDocShellTreeI
    * loaded.
    * The sandbox flags of a document depend on the sandbox flags on its
    * docshell and of its parent document, if any.
    * See nsSandboxFlags.h for the possible flags.
    */
   attribute unsigned long sandboxFlags;
 
   /**
+   * When a new browsing context is opened by a sandboxed document, it needs to
+   * keep track of the browsing context that opened it, so that it can be
+   * navigated by it.  This is the "one permitted sandboxed navigator".
+   */
+  attribute nsIDocShell onePermittedSandboxedNavigator;
+
+  /**
    * This member variable determines whether a document has Mixed Active Content that
    * was initially blocked from loading, but the user has choosen to override the
    * block and allow the content to load. mMixedContentChannel is set to the document's
    * channel when the user allows mixed content. The nsMixedContentBlocker content policy
    * checks if the document's root channel matches the mMixedContentChannel.  If it matches,
    * then Mixed Content is loaded.  If it does match, mixed content is blocked.
    *
    * A match implies that there is definitely mixed active content on a page that was
--- a/dom/base/MessagePort.cpp
+++ b/dom/base/MessagePort.cpp
@@ -134,17 +134,17 @@ PostMessageReadStructuredClone(JSContext
   if (tag == SCTAG_DOM_MESSAGEPORT) {
     NS_ASSERTION(!data, "Data should be empty");
 
     MessagePort* port;
     if (JS_ReadBytes(reader, &port, sizeof(port))) {
       JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
       if (global) {
         JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
-        if (JS_WrapObject(cx, obj.address())) {
+        if (JS_WrapObject(cx, &obj)) {
           port->BindToOwner(scInfo->mPort->GetOwner());
           return obj;
         }
       }
     }
   }
 
   const JSStructuredCloneCallbacks* runtimeCallbacks =
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1549,17 +1549,17 @@ Navigator::DoNewResolve(JSContext* aCx, 
       }
 
       domObject = construct(aCx, naviObj);
       if (!domObject) {
         return Throw(aCx, NS_ERROR_FAILURE);
       }
     }
 
-    if (!JS_WrapObject(aCx, domObject.address())) {
+    if (!JS_WrapObject(aCx, &domObject)) {
       return false;
     }
 
     aValue.setObject(*domObject);
     return true;
   }
 
   NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2780,17 +2780,17 @@ GetXPCProto(nsIXPConnect *aXPConnect, JS
   NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED);
 
   nsresult rv =
     aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci,
                                           aProto);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JS::Rooted<JSObject*> proto_obj(cx, (*aProto)->GetJSObject());
-  if (!JS_WrapObject(cx, proto_obj.address())) {
+  if (!JS_WrapObject(cx, &proto_obj)) {
     return NS_ERROR_FAILURE;
   }
 
   NS_IF_RELEASE(*aProto);
   return aXPConnect->HoldObject(cx, proto_obj, aProto);
 }
 
 // Either ci_data must be non-null or name_struct must be non-null and of type
@@ -2917,17 +2917,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec
       JS::Rooted<JSObject*> xpc_proto_proto(cx);
       if (!::JS_GetPrototype(cx, dot_prototype, &xpc_proto_proto)) {
         return NS_ERROR_UNEXPECTED;
       }
 
       if (proto &&
           (!xpc_proto_proto ||
            JS_GetClass(xpc_proto_proto) == sObjectClass)) {
-        if (!JS_WrapObject(cx, proto.address()) ||
+        if (!JS_WrapObject(cx, &proto) ||
             !JS_SetPrototype(cx, dot_prototype, proto)) {
           return NS_ERROR_UNEXPECTED;
         }
       }
     } else {
       JSAutoCompartment ac(cx, winobj);
       if (!proto) {
         proto = JS_GetObjectPrototype(cx, winobj);
@@ -3066,17 +3066,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
                                                        defineOnGlobal));
       if (!interfaceObject) {
         return NS_ERROR_FAILURE;
       }
 
       if (defineOnXray) {
         // This really should be handled by the Xray for the window.
         ac.destroy();
-        if (!JS_WrapObject(cx, interfaceObject.address()) ||
+        if (!JS_WrapObject(cx, &interfaceObject) ||
             !JS_DefinePropertyById(cx, obj, id,
                                    JS::ObjectValue(*interfaceObject), JS_PropertyStub,
                                    JS_StrictPropertyStub, 0)) {
           return NS_ERROR_FAILURE;
         }
 
       }
 
@@ -3639,17 +3639,17 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     JS::Rooted<JSObject*> funObj(cx);
     JSFunction *fun = ::JS_NewFunction(cx, ContentWindowGetter, 0, 0,
                                        obj, "_content");
     if (!fun) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     funObj = ::JS_GetFunctionObject(fun);
 
-    if (!JS_WrapObject(cx, funObj.address()) ||
+    if (!JS_WrapObject(cx, &funObj) ||
         !JS_DefinePropertyById(cx, obj, id, JSVAL_VOID,
                                JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj.get()),
                                JS_StrictPropertyStub,
                                JSPROP_ENUMERATE | JSPROP_GETTER |
                                JSPROP_SHARED)) {
       return NS_ERROR_FAILURE;
     }
 
@@ -3740,17 +3740,17 @@ nsWindowSH::OuterObject(nsIXPConnectWrap
 
   JS::Rooted<JSObject*> winObj(cx, win->FastGetGlobalJSObject());
   MOZ_ASSERT(winObj);
 
   // Note that while |wrapper| is same-compartment with cx, the outer window
   // might not be. If we're running script in an inactive scope and evalute
   // |this|, the outer window is actually a cross-compartment wrapper. So we
   // need to wrap here.
-  if (!JS_WrapObject(cx, winObj.address())) {
+  if (!JS_WrapObject(cx, &winObj)) {
     *_retval = nullptr;
     return NS_ERROR_UNEXPECTED;
   }
 
   *_retval = winObj;
   return NS_OK;
 }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4000,18 +4000,18 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* 
     // expandos on Xrays as needed.
 
     JS::Rooted<JSObject*> otherObj(cx, glob->GetGlobalJSObject());
     NS_ENSURE_STATE(otherObj);
 
     JS::Rooted<JSObject*> thisObj(cx, mJSObject);
     NS_ENSURE_STATE(mJSObject);
 
-    if (!JS_WrapObject(cx, otherObj.address()) ||
-        !JS_WrapObject(cx, thisObj.address()) ||
+    if (!JS_WrapObject(cx, &otherObj) ||
+        !JS_WrapObject(cx, &thisObj) ||
         !JS_DefineProperty(cx, thisObj, "opener", JS::ObjectValue(*otherObj),
                            JS_PropertyStub, JS_StrictPropertyStub,
                            JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
@@ -6817,17 +6817,17 @@ PostMessageReadStructuredClone(JSContext
   if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MESSAGEPORT) {
     NS_ASSERTION(!data, "Data should be empty");
 
     MessagePort* port;
     if (JS_ReadBytes(reader, &port, sizeof(port))) {
       JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
       if (global) {
         JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
-        if (JS_WrapObject(cx, obj.address())) {
+        if (JS_WrapObject(cx, &obj)) {
           port->BindToOwner(scInfo->window);
           return obj;
         }
       }
     }
   }
 
   const JSStructuredCloneCallbacks* runtimeCallbacks =
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -684,17 +684,17 @@ NativeInterface2JSObjectAndThrowIfFailed
   nsWrapperCache *cache = aHelper.GetWrapperCache();
 
   if (cache && cache->IsDOMBinding()) {
       JS::RootedObject obj(aCx, cache->GetWrapper());
       if (!obj) {
           obj = cache->WrapObject(aCx, aScope);
       }
 
-      if (obj && aAllowNativeWrapper && !JS_WrapObject(aCx, obj.address())) {
+      if (obj && aAllowNativeWrapper && !JS_WrapObject(aCx, &obj)) {
         return false;
       }
 
       if (obj) {
         *aRetval = JS::ObjectValue(*obj);
         return true;
       }
   }
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1263,17 +1263,17 @@ WrapCallThisObject(JSContext* cx, JS::Ha
     // wrap anything for us.
     obj = WrapNativeParent(cx, scope, p);
     if (!obj) {
       return nullptr;
     }
   }
 
   // But all that won't necessarily put things in the compartment of cx.
-  if (!JS_WrapObject(cx, obj.address())) {
+  if (!JS_WrapObject(cx, &obj)) {
     return nullptr;
   }
 
   return obj;
 }
 
 // Helper for calling WrapNewBindingObject with smart pointers
 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4606,19 +4606,19 @@ def wrapTypeIntoCurrentCompartment(type,
         else:
             value = value + ".address()"
         return CGGeneric("if (!JS_WrapValue(cx, %s)) {\n"
                          "  return false;\n"
                          "}" % value)
 
     if type.isObject():
         if isMember:
-            value = "&%s" % value
-        else:
-            value = value + ".address()"
+            value = "JS::MutableHandleObject::fromMarkedLocation(&%s)" % value
+        else:
+            value = "&" + value
         return CGGeneric("if (!JS_WrapObject(cx, %s)) {\n"
                          "  return false;\n"
                          "}" % value)
 
     if type.isSpiderMonkeyInterface():
         origValue = value
         if type.nullable():
             value = "%s.Value()" % value
@@ -9900,17 +9900,17 @@ class CGJSImplClass(CGBindingImplClass):
     def getWrapObjectBody(self):
         return ("JS::Rooted<JSObject*> obj(aCx, %sBinding::Wrap(aCx, aScope, this));\n"
                 "if (!obj) {\n"
                 "  return nullptr;\n"
                 "}\n"
                 "\n"
                 "// Now define it on our chrome object\n"
                 "JSAutoCompartment ac(aCx, mImpl->Callback());\n"
-                "if (!JS_WrapObject(aCx, obj.address())) {\n"
+                "if (!JS_WrapObject(aCx, &obj)) {\n"
                 "  return nullptr;\n"
                 "}\n"
                 'if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", JS::ObjectValue(*obj), nullptr, nullptr, 0)) {\n'
                 "  return nullptr;\n"
                 "}\n"
                 "return obj;" % self.descriptor.name)
 
     def getGetParentObjectReturnType(self):
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -87,17 +87,17 @@ public:
 
   inline JSObject *Obj() const {
     MOZ_ASSERT(inited());
     return mObj;
   }
 
   inline bool WrapIntoNewCompartment(JSContext* cx)
   {
-    return JS_WrapObject(cx, &mObj);
+    return JS_WrapObject(cx, JS::MutableHandleObject::fromMarkedLocation(&mObj));
   }
 
 protected:
   inline void DoInit(JSObject* obj)
   {
     mObj = UnboxArray(obj, &mLength, &mData);
   }
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -289,33 +289,38 @@ TabParent::ActorDestroy(ActorDestroyReas
   if (sEventCapturer == this) {
     sEventCapturer = nullptr;
   }
   if (mIMETabParent == this) {
     mIMETabParent = nullptr;
   }
   nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+  nsRefPtr<nsFrameMessageManager> fmm;
   if (frameLoader) {
+    fmm = frameLoader->GetFrameMessageManager();
     nsCOMPtr<Element> frameElement(mFrameElement);
     ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr);
     frameLoader->DestroyChild();
 
     if (why == AbnormalShutdown && os) {
       os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
                           "oop-frameloader-crashed", nullptr);
       nsContentUtils::DispatchTrustedEvent(frameElement->OwnerDoc(), frameElement,
                                            NS_LITERAL_STRING("oop-browser-crashed"),
                                            true, true);
     }
   }
 
   if (os) {
     os->NotifyObservers(NS_ISUPPORTS_CAST(nsITabParent*, this), "ipc:browser-destroyed", nullptr);
   }
+  if (fmm) {
+    fmm->Disconnect();
+  }
 }
 
 bool
 TabParent::RecvMoveFocus(const bool& aForward)
 {
   nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
   if (fm) {
     nsCOMPtr<nsIDOMElement> dummy;
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1070,17 +1070,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
 // compartment for callers that plan to hold onto the result or do anything
 // substantial with it.
 static JSObject *
 GetNPObjectWrapper(JSContext *cx, JSObject *aObj, bool wrapResult = true)
 {
   JS::Rooted<JSObject*> obj(cx, aObj);
   while (obj && (obj = js::CheckedUnwrap(obj))) {
     if (JS_GetClass(obj) == &sNPObjectJSWrapperClass) {
-      if (wrapResult && !JS_WrapObject(cx, obj.address())) {
+      if (wrapResult && !JS_WrapObject(cx, &obj)) {
         return NULL;
       }
       return obj;
     }
     if (!::JS_GetPrototype(cx, obj, &obj)) {
       return NULL;
     }
   }
@@ -1725,17 +1725,17 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
 
     return nullptr;
   }
 
   if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) {
     // npobj is one of our own, return its existing JSObject.
 
     JS::Rooted<JSObject*> obj(cx, ((nsJSObjWrapper *)npobj)->mJSObj);
-    if (!JS_WrapObject(cx, obj.address())) {
+    if (!JS_WrapObject(cx, &obj)) {
       return NULL;
     }
     return obj;
   }
 
   if (!npp) {
     NS_ERROR("No npp passed to nsNPObjWrapper::GetNewOrUsed()!");
 
@@ -1762,17 +1762,17 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
 
     return nullptr;
   }
 
   if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObj) {
     // Found a live NPObject wrapper. It may not be in the same compartment
     // as cx, so we need to wrap it before returning it.
     JS::Rooted<JSObject*> obj(cx, entry->mJSObj);
-    if (!JS_WrapObject(cx, obj.address())) {
+    if (!JS_WrapObject(cx, &obj)) {
       return NULL;
     }
     return obj;
   }
 
   entry->mNPObj = npobj;
   entry->mNpp = npp;
 
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -220,33 +220,16 @@ public:
   }
 
 private:
   nsCOMPtr<nsIDOMGeoPosition> mPosition;
   nsRefPtr<nsGeolocationRequest> mRequest;
   nsRefPtr<Geolocation> mLocator;
 };
 
-class RequestRestartTimerEvent : public nsRunnable
-{
-public:
-  RequestRestartTimerEvent(nsGeolocationRequest* aRequest)
-    : mRequest(aRequest)
-  {
-  }
-
-  NS_IMETHOD Run() {
-    mRequest->SetTimeoutTimer();
-    return NS_OK;
-  }
-
-private:
-  nsRefPtr<nsGeolocationRequest> mRequest;
-};
-
 ////////////////////////////////////////////////////
 // PositionError
 ////////////////////////////////////////////////////
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError)
   NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError)
@@ -631,24 +614,22 @@ NS_INTERFACE_MAP_BEGIN(nsGeolocationServ
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsGeolocationService)
 NS_IMPL_RELEASE(nsGeolocationService)
 
 
 static bool sGeoEnabled = true;
 static bool sGeoInitPending = true;
-static bool sGeoIgnoreLocationFilter = false;
 static int32_t sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up.
 
 nsresult nsGeolocationService::Init()
 {
   Preferences::AddIntVarCache(&sProviderTimeout, "geo.timeout", sProviderTimeout);
   Preferences::AddBoolVarCache(&sGeoEnabled, "geo.enabled", sGeoEnabled);
-  Preferences::AddBoolVarCache(&sGeoIgnoreLocationFilter, "geo.ignore.location_filter", sGeoIgnoreLocationFilter);
 
   if (!sGeoEnabled) {
     return NS_ERROR_FAILURE;
   }
 
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     sGeoInitPending = false;
     return NS_OK;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -237,20 +237,16 @@ WEBIDL_FILES = [
     'OfflineAudioCompletionEvent.webidl',
     'OfflineAudioContext.webidl',
     'OfflineResourceList.webidl',
     'OscillatorNode.webidl',
     'PaintRequest.webidl',
     'PaintRequestList.webidl',
     'PannerNode.webidl',
     'ParentNode.webidl',
-    'PeerConnectionImpl.webidl',
-    'PeerConnectionImplEnums.webidl',
-    'PeerConnectionObserver.webidl',
-    'PeerConnectionObserverEnums.webidl',
     'Performance.webidl',
     'PerformanceNavigation.webidl',
     'PerformanceTiming.webidl',
     'PeriodicWave.webidl',
     'PhoneNumberService.webidl',
     'Plugin.webidl',
     'PluginArray.webidl',
     'Position.webidl',
@@ -439,16 +435,20 @@ if CONFIG['MOZ_WEBGL']:
         'WebGL2RenderingContext.webidl',
         'WebGLRenderingContext.webidl',
     ]
 
 if CONFIG['MOZ_WEBRTC']:
     WEBIDL_FILES += [
         'DataChannel.webidl',
         'MediaStreamList.webidl',
+        'PeerConnectionImpl.webidl',
+        'PeerConnectionImplEnums.webidl',
+        'PeerConnectionObserver.webidl',
+        'PeerConnectionObserverEnums.webidl',
     ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     WEBIDL_FILES += [
         'SpeechGrammar.webidl',
         'SpeechGrammarList.webidl',
         'SpeechRecognition.webidl',
         'SpeechRecognitionAlternative.webidl',
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
@@ -470,17 +470,20 @@ nsWindowWatcher::OpenWindowInternal(nsID
   if (aFeatures) {
     features.Assign(aFeatures);
     featuresSpecified = true;
     features.StripWhitespace();
   }
 
   // try to find an extant window with the given name
   nsCOMPtr<nsIDOMWindow> foundWindow;
-  SafeGetWindowByName(name, aParent, getter_AddRefs(foundWindow));
+  if (SafeGetWindowByName(name, aParent, getter_AddRefs(foundWindow)) ==
+      NS_ERROR_DOM_INVALID_ACCESS_ERR) {
+    return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+  }
   GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
 
   // no extant window? make a new one.
 
   // If no parent, consider it chrome.
   bool hasChromeParent = true;
   if (aParent) {
     // Check if the parent document has chrome privileges.
@@ -538,31 +541,36 @@ nsWindowWatcher::OpenWindowInternal(nsID
     // the initial about:blank document to be system, so that the subsequent XUL
     // load can reuse the inner window and avoid blowing away expandos. As such,
     // we decide whether to load with the principal of the caller or of the parent
     // based on whether the docshell type is chrome or content.
 
     callerContextGuard.Push(cx);
   }
 
+  uint32_t activeDocsSandboxFlags = 0;
   if (!newDocShellItem) {
     // We're going to either open up a new window ourselves or ask a
     // nsIWindowProvider for one.  In either case, we'll want to set the right
     // name on it.
     windowNeedsName = true;
 
-    // If the parent trying to open a new window is sandboxed,
-    // this is not allowed and we fail here.
+    // If the parent trying to open a new window is sandboxed
+    // without 'allow-popups', this is not allowed and we fail here.
     if (aParent) {
       nsCOMPtr<nsIDOMDocument> domdoc;
       aParent->GetDocument(getter_AddRefs(domdoc));
       nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
 
-      if (doc && (doc->GetSandboxFlags() & SANDBOXED_NAVIGATION)) {
-        return NS_ERROR_FAILURE;
+      if (doc) {
+        // Save sandbox flags for copying to new browsing context (docShell).
+        activeDocsSandboxFlags = doc->GetSandboxFlags();
+        if (activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
+          return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+        }
       }
     }
 
     // Now check whether it's ok to ask a window provider for a window.  Don't
     // do it if we're opening a dialog or if our parent is a chrome window or
     // if we're opening something that has modal, dialog, or chrome flags set.
     nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(aParent);
     if (!aDialog && !chromeWin &&
@@ -704,16 +712,26 @@ nsWindowWatcher::OpenWindowInternal(nsID
   }
 
   // better have a window to use by this point
   if (!newDocShellItem)
     return rv;
 
   nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem));
   NS_ENSURE_TRUE(newDocShell, NS_ERROR_UNEXPECTED);
+
+  // Set up sandboxing attributes if the window is new.
+  // The flags can only be non-zero for new windows.
+  if (activeDocsSandboxFlags != 0) {
+    newDocShell->SetSandboxFlags(activeDocsSandboxFlags);
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aParent);
+    if (window) {
+      newDocShell->SetOnePermittedSandboxedNavigator(window->GetDocShell());
+    }
+  }
   
   rv = ReadyOpenedDocShellItem(newDocShellItem, aParent, windowIsNew, _retval);
   if (NS_FAILED(rv))
     return rv;
 
   /* disable persistence of size/position in popups (determined by
      determining whether the features parameter specifies width or height
      in any way). We consider any overriding of the window's size or position
@@ -1294,37 +1312,38 @@ nsWindowWatcher::GetChromeForWindow(nsID
 NS_IMETHODIMP
 nsWindowWatcher::GetWindowByName(const PRUnichar *aTargetName, 
                                  nsIDOMWindow *aCurrentWindow,
                                  nsIDOMWindow **aResult)
 {
   if (!aResult) {
     return NS_ERROR_INVALID_ARG;
   }
+  nsresult rv;
 
   *aResult = nullptr;
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem;
 
   nsCOMPtr<nsIDocShellTreeItem> startItem;
   GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem));
   if (startItem) {
     // Note: original requestor is null here, per idl comments
-    startItem->FindItemWithName(aTargetName, nullptr, nullptr,
+    rv = startItem->FindItemWithName(aTargetName, nullptr, nullptr,
                                 getter_AddRefs(treeItem));
   }
   else {
     // Note: original requestor is null here, per idl comments
-    FindItemWithName(aTargetName, nullptr, nullptr, getter_AddRefs(treeItem));
+    rv = FindItemWithName(aTargetName, nullptr, nullptr, getter_AddRefs(treeItem));
   }
 
   nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(treeItem);
   domWindow.swap(*aResult);
 
-  return NS_OK;
+  return rv;
 }
 
 bool
 nsWindowWatcher::AddEnumerator(nsWatcherWindowEnumerator* inEnumerator)
 {
   // (requires a lock; assumes it's called by someone holding the lock)
   return mEnumeratorList.AppendElement(inEnumerator) != nullptr;
 }
@@ -1726,37 +1745,38 @@ nsWindowWatcher::GetCallerTreeItem(nsIDo
 }
 
 nsresult
 nsWindowWatcher::SafeGetWindowByName(const nsAString& aName,
                                      nsIDOMWindow* aCurrentWindow,
                                      nsIDOMWindow** aResult)
 {
   *aResult = nullptr;
+  nsresult rv;
   
   nsCOMPtr<nsIDocShellTreeItem> startItem;
   GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem));
 
   nsCOMPtr<nsIDocShellTreeItem> callerItem = GetCallerTreeItem(startItem);
 
   const nsAFlatString& flatName = PromiseFlatString(aName);
 
   nsCOMPtr<nsIDocShellTreeItem> foundItem;
   if (startItem) {
-    startItem->FindItemWithName(flatName.get(), nullptr, callerItem,
+    rv = startItem->FindItemWithName(flatName.get(), nullptr, callerItem,
                                 getter_AddRefs(foundItem));
   }
   else {
-    FindItemWithName(flatName.get(), nullptr, callerItem,
+    rv = FindItemWithName(flatName.get(), nullptr, callerItem,
                      getter_AddRefs(foundItem));
   }
 
   nsCOMPtr<nsIDOMWindow> foundWin = do_GetInterface(foundItem);
   foundWin.swap(*aResult);
-  return NS_OK;
+  return rv;
 }
 
 /* Fetch the nsIDOMWindow corresponding to the given nsIDocShellTreeItem.
    This forces the creation of a script context, if one has not already
    been created. Note it also sets the window's opener to the parent,
    if applicable -- because it's just convenient, that's all. null aParent
    is acceptable. */
 nsresult
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -209,30 +209,30 @@ gfxDWriteFontFamily::LocalizedName(nsASt
     if (FAILED(hr)) {
         return;
     }
 
     aLocalizedName = nsDependentString(famName.Elements());
 }
 
 void
-gfxDWriteFontFamily::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                         FontListSizes*    aSizes) const
+gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                            FontListSizes* aSizes) const
 {
-    gfxFontFamily::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxFontFamily::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     // TODO:
     // This doesn't currently account for |mDWFamily|
 }
 
 void
-gfxDWriteFontFamily::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                         FontListSizes*    aSizes) const
+gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                            FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontEntry
 
 gfxDWriteFontEntry::~gfxDWriteFontEntry()
 {
 }
@@ -551,30 +551,30 @@ gfxDWriteFontEntry::IsCJKFont()
             mIsCJK = true;
         }
     }
 
     return mIsCJK;
 }
 
 void
-gfxDWriteFontEntry::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                        FontListSizes*    aSizes) const
+gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                           FontListSizes* aSizes) const
 {
-    gfxFontEntry::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     // TODO:
     // This doesn't currently account for the |mFont| and |mFontFile| members
 }
 
 void
-gfxDWriteFontEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                        FontListSizes*    aSizes) const
+gfxDWriteFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                           FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontList
 
 gfxDWriteFontList::gfxDWriteFontList()
     : mInitialized(false), mForceGDIClassicMaxFontSize(0.0)
 {
@@ -1213,39 +1213,39 @@ gfxDWriteFontList::ResolveFontName(const
     if (mNonExistingFonts.Contains(keyName)) {
         return false;
     }
 
     return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
 }
 
 void
-gfxDWriteFontList::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                       FontListSizes*    aSizes) const
+gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                          FontListSizes* aSizes) const
 {
-    gfxPlatformFontList::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 
     aSizes->mFontListSize +=
         mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
                                              aMallocSizeOf);
 
     aSizes->mFontListSize +=
         mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf);
     for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
         aSizes->mFontListSize +=
             mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     }
 }
 
 void
-gfxDWriteFontList::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                       FontListSizes*    aSizes) const
+gfxDWriteFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                          FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 static HRESULT GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
 {
     HRESULT hr;
     nsRefPtr<IDWriteFontFamily> family;
 
     // clean out previous value
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -44,20 +44,20 @@ public:
     virtual ~gfxDWriteFontFamily();
     
     virtual void FindStyleVariations();
 
     virtual void LocalizedName(nsAString& aLocalizedName);
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
 protected:
     /** This font family's directwrite fontfamily object */
     nsRefPtr<IDWriteFontFamily> mDWFamily;
     bool mForceGDIClassic;
 };
 
 /**
@@ -148,20 +148,20 @@ public:
 
     nsresult ReadCMAP();
 
     bool IsCJKFont();
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
     bool GetForceGDIClassic() { return mForceGDIClassic; }
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
 protected:
     friend class gfxDWriteFont;
     friend class gfxDWriteFontList;
 
     virtual nsresult CopyFontTable(uint32_t aTableTag,
                                    FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
@@ -361,20 +361,20 @@ public:
     bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
 
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily);
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
     gfxFloat GetForceGDIClassicMaxFontSize() { return mForceGDIClassicMaxFontSize; }
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
 private:
     friend class gfxDWriteFontFamily;
 
     nsresult GetFontSubstitutes();
 
     void GetDirectWriteSubstitutes();
 
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -666,33 +666,33 @@ gfxDWriteFont::MeasureGlyphWidth(uint16_
         if (SUCCEEDED(hr)) {
             return NS_lround(metrics.advanceWidth * mFUnitsConvFactor);
         }
     }
     return 0;
 }
 
 void
-gfxDWriteFont::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                   FontCacheSizes*   aSizes) const
+gfxDWriteFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                      FontCacheSizes* aSizes) const
 {
-    gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     aSizes->mFontInstances += aMallocSizeOf(mMetrics);
     if (mGlyphWidths) {
         aSizes->mFontInstances +=
             mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf);
     }
 }
 
 void
-gfxDWriteFont::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                   FontCacheSizes*   aSizes) const
+gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                      FontCacheSizes* aSizes) const
 {
     aSizes->mFontInstances += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 TemporaryRef<ScaledFont>
 gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
 {
   bool wantCairo = aTarget->GetType() == BACKEND_CAIRO;
   if (mAzureScaledFont && mAzureScaledFontIsCairo == wantCairo) {
     return mAzureScaledFont;
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -54,20 +54,20 @@ public:
                                Spacing *aSpacing);
 
     virtual bool ProvidesGlyphWidths();
 
     virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
 
     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions();
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_DWRITE; }
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget);
 
     virtual cairo_scaled_font_t *GetCairoScaledFont();
 
 protected:
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -533,30 +533,30 @@ FT2FontEntry::GetFontTable(uint32_t aTab
     }
 
     // otherwise, use the default method (which in turn will call our
     // implementation of CopyFontTable)
     return gfxFontEntry::GetFontTable(aTableTag);
 }
 
 void
-FT2FontEntry::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                  FontListSizes*    aSizes) const
+FT2FontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                     FontListSizes* aSizes) const
 {
-    gfxFontEntry::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     aSizes->mFontListSize +=
         mFilename.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
 }
 
 void
-FT2FontEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                  FontListSizes*    aSizes) const
+FT2FontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                     FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 /*
  * FT2FontFamily
  * A standard gfxFontFamily; just adds a method used to support sending
  * the font list from chrome to content via IPC.
  */
 
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -80,20 +80,20 @@ public:
 
     virtual nsresult CopyFontTable(uint32_t aTableTag,
                                    FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
     // Check for various kinds of brokenness, and set flags on the entry
     // accordingly so that we avoid using bad font tables
     void CheckForBrokenFont(gfxFontFamily *aFamily);
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
     FT_Face mFTFace;
     cairo_font_face_t *mFontFace;
 
     nsCString mFilename;
     uint8_t   mFTFontIndex;
 };
 
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -637,30 +637,30 @@ gfxFT2Font::FillGlyphDataForChar(uint32_
 
     gd->glyphIndex = gid;
     gd->lsbDelta = face->glyph->lsb_delta;
     gd->rsbDelta = face->glyph->rsb_delta;
     gd->xAdvance = face->glyph->advance.x;
 }
 
 void
-gfxFT2Font::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                FontCacheSizes*   aSizes) const
+gfxFT2Font::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                   FontCacheSizes* aSizes) const
 {
-    gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     aSizes->mFontInstances +=
         mCharGlyphCache.SizeOfExcludingThis(nullptr, aMallocSizeOf);
 }
 
 void
-gfxFT2Font::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                FontCacheSizes*   aSizes) const
+gfxFT2Font::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                   FontCacheSizes* aSizes) const
 {
     aSizes->mFontInstances += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 #ifdef USE_SKIA
 mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
 gfxFT2Font::GetGlyphRenderingOptions()
 {
   mozilla::gfx::FontHinting hinting;
 
--- a/gfx/thebes/gfxFT2Fonts.h
+++ b/gfx/thebes/gfxFT2Fonts.h
@@ -57,20 +57,20 @@ public: // new functions
         if (entry->mData.glyphIndex == 0xffffffffU) {
             // this is a new entry, fill it
             FillGlyphDataForChar(ch, &entry->mData);
         }
 
         return &entry->mData;
     }
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
 
 #ifdef USE_SKIA
     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions> GetGlyphRenderingOptions();
 #endif
 
 protected:
     virtual bool ShapeText(gfxContext      *aContext,
                            const PRUnichar *aText,
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -702,58 +702,54 @@ gfxFontEntry::CheckForGraphiteTables()
 {
     AutoTable silfTable(this, TRUETYPE_TAG('S','i','l','f'));
     mHasGraphiteTables = silfTable && hb_blob_get_length(silfTable) > 0;
 }
 
 /* static */ size_t
 gfxFontEntry::FontTableHashEntry::SizeOfEntryExcludingThis
     (FontTableHashEntry *aEntry,
-     MallocSizeOf   aMallocSizeOf,
-     void*               aUserArg)
-{
-    FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
+     MallocSizeOf aMallocSizeOf,
+     void* aUserArg)
+{
+    size_t n = 0;
     if (aEntry->mBlob) {
-        sizes->mFontTableCacheSize += aMallocSizeOf(aEntry->mBlob);
+        n += aMallocSizeOf(aEntry->mBlob);
     }
     if (aEntry->mSharedBlobData) {
-        sizes->mFontTableCacheSize +=
-            aEntry->mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
-    }
-
-    // the size of the table is recorded in the FontListSizes record,
-    // so we return 0 here for the function result
-    return 0;
+        n += aEntry->mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
+    }
+    return n;
 }
 
 void
-gfxFontEntry::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                  FontListSizes*    aSizes) const
+gfxFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                     FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
 
     // cmaps are shared so only non-shared cmaps are included here
     if (mCharacterMap && mCharacterMap->mBuildOnTheFly) {
         aSizes->mCharMapsSize +=
             mCharacterMap->SizeOfIncludingThis(aMallocSizeOf);
     }
     if (mFontTableCache) {
         aSizes->mFontTableCacheSize +=
             mFontTableCache->SizeOfExcludingThis(
                 FontTableHashEntry::SizeOfEntryExcludingThis,
-                aMallocSizeOf, aSizes);
+                aMallocSizeOf);
     }
 }
 
 void
-gfxFontEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                  FontListSizes*    aSizes) const
+gfxFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                     FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 //////////////////////////////////////////////////////////////////////////////
 //
 // class gfxFontFamily
 //
 //////////////////////////////////////////////////////////////////////////////
 
@@ -1325,42 +1321,42 @@ gfxFontFamily::FindFont(const nsAString&
         gfxFontEntry *fe = mAvailableFonts[i].get();
         if (fe && fe->Name() == aPostscriptName)
             return fe;
     }
     return nullptr;
 }
 
 void
-gfxFontFamily::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                   FontListSizes*    aSizes) const
+gfxFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                      FontListSizes* aSizes) const
 {
     aSizes->mFontListSize +=
         mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     aSizes->mCharMapsSize +=
         mFamilyCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
 
     aSizes->mFontListSize +=
         mAvailableFonts.SizeOfExcludingThis(aMallocSizeOf);
     for (uint32_t i = 0; i < mAvailableFonts.Length(); ++i) {
         gfxFontEntry *fe = mAvailableFonts[i];
         if (fe) {
-            fe->SizeOfIncludingThis(aMallocSizeOf, aSizes);
+            fe->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
         }
     }
 }
 
 void
-gfxFontFamily::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                   FontListSizes*    aSizes) const
+gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                      FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
-}
- 
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
 /*
  * gfxFontCache - global cache of gfxFont instances.
  * Expires unused fonts after a short interval;
  * notifies fonts to age their cached shaped-word records;
  * observes memory-pressure notification and tells fonts to clear their
  * shaped-word caches to free up memory.
  */
 
@@ -1377,18 +1373,18 @@ gfxFontCache::MemoryReporter::GetName(ns
 
 NS_IMETHODIMP
 gfxFontCache::MemoryReporter::CollectReports
     (nsIMemoryReporterCallback* aCb,
      nsISupports* aClosure)
 {
     FontCacheSizes sizes;
 
-    gfxFontCache::GetCache()->SizeOfIncludingThis(&FontCacheMallocSizeOf,
-                                                  &sizes);
+    gfxFontCache::GetCache()->AddSizeOfIncludingThis(&FontCacheMallocSizeOf,
+                                                     &sizes);
 
     aCb->Callback(EmptyCString(),
                   NS_LITERAL_CSTRING("explicit/gfx/font-cache"),
                   nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
                   sizes.mFontInstances,
                   NS_LITERAL_CSTRING("Memory used for active font instances."),
                   aClosure);
 
@@ -1591,45 +1587,46 @@ PLDHashOperator
 gfxFontCache::ClearCachedWordsForFont(HashEntry* aHashEntry, void* aUserData)
 {
     aHashEntry->mFont->ClearCachedWords();
     return PL_DHASH_NEXT;
 }
 
 /*static*/
 size_t
-gfxFontCache::SizeOfFontEntryExcludingThis(HashEntry*        aHashEntry,
-                                           MallocSizeOf aMallocSizeOf,
-                                           void*             aUserArg)
+gfxFontCache::AddSizeOfFontEntryExcludingThis(HashEntry* aHashEntry,
+                                              MallocSizeOf aMallocSizeOf,
+                                              void* aUserArg)
 {
     HashEntry *entry = static_cast<HashEntry*>(aHashEntry);
     FontCacheSizes *sizes = static_cast<FontCacheSizes*>(aUserArg);
-    entry->mFont->SizeOfExcludingThis(aMallocSizeOf, sizes);
-
-    // The font records its size in the |sizes| parameter, so we return zero
+    entry->mFont->AddSizeOfExcludingThis(aMallocSizeOf, sizes);
+
+    // The entry's size is recorded in the |sizes| parameter, so we return zero
     // here to the hashtable enumerator.
     return 0;
 }
 
 void
-gfxFontCache::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                  FontCacheSizes*   aSizes) const
+gfxFontCache::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                     FontCacheSizes* aSizes) const
 {
     // TODO: add the overhead of the expiration tracker (generation arrays)
 
-    mFonts.SizeOfExcludingThis(SizeOfFontEntryExcludingThis,
-                               aMallocSizeOf, aSizes);
+    aSizes->mFontInstances +=
+        mFonts.SizeOfExcludingThis(AddSizeOfFontEntryExcludingThis,
+                                   aMallocSizeOf, aSizes);
 }
 
 void
-gfxFontCache::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                  FontCacheSizes*   aSizes) const
+gfxFontCache::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                     FontCacheSizes* aSizes) const
 {
     aSizes->mFontInstances += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 #define MAX_SSXX_VALUE 99
 #define MAX_CVXX_VALUE 99
 
 static void
 LookupAlternateValues(gfxFontFeatureValueSet *featureLookup,
                       const nsAString& aFamily,
@@ -3828,36 +3825,36 @@ gfxFont::SynthesizeSpaceWidth(uint32_t a
 gfxFont::WordCacheEntrySizeOfExcludingThis(CacheHashEntry*   aHashEntry,
                                            MallocSizeOf aMallocSizeOf,
                                            void*             aUserArg)
 {
     return aMallocSizeOf(aHashEntry->mShapedWord.get());
 }
 
 void
-gfxFont::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                             FontCacheSizes*   aSizes) const
+gfxFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                FontCacheSizes* aSizes) const
 {
     for (uint32_t i = 0; i < mGlyphExtentsArray.Length(); ++i) {
         aSizes->mFontInstances +=
             mGlyphExtentsArray[i]->SizeOfIncludingThis(aMallocSizeOf);
     }
     if (mWordCache) {
         aSizes->mShapedWords +=
             mWordCache->SizeOfExcludingThis(WordCacheEntrySizeOfExcludingThis,
                                             aMallocSizeOf);
     }
 }
 
 void
-gfxFont::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                             FontCacheSizes*   aSizes) const
+gfxFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                FontCacheSizes* aSizes) const
 {
     aSizes->mFontInstances += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 void
 gfxFont::AddGlyphChangeObserver(GlyphChangeObserver *aObserver)
 {
     if (!mGlyphChangeObservers) {
         mGlyphChangeObservers = new nsTHashtable<nsPtrHashKey<GlyphChangeObserver> >;
     }
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -405,22 +405,22 @@ public:
     virtual void ReleaseGrFace(gr_face* aFace);
 
     // Release any SVG-glyphs document this font may have loaded.
     void DisconnectSVG();
 
     // Called to notify that aFont is being destroyed. Needed when we're tracking
     // the fonts belonging to this font entry.
     void NotifyFontDestroyed(gfxFont* aFont);
-    
+
     // For memory reporting
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
     nsString         mName;
     nsString         mFamilyName;
 
     bool             mItalic      : 1;
     bool             mFixedPitch  : 1;
     bool             mIsProxy     : 1;
     bool             mIsValid     : 1;
@@ -610,18 +610,18 @@ private:
         // Return a strong reference to the blob.
         // Callers must hb_blob_destroy the returned blob.
         hb_blob_t *GetBlob() const;
 
         void Clear();
 
         static size_t
         SizeOfEntryExcludingThis(FontTableHashEntry *aEntry,
-                                 mozilla::MallocSizeOf   aMallocSizeOf,
-                                 void*               aUserArg);
+                                 mozilla::MallocSizeOf aMallocSizeOf,
+                                 void* aUserArg);
 
     private:
         static void DeleteFontTableBlobData(void *aBlobData);
         // not implemented
         FontTableHashEntry& operator=(FontTableHashEntry& toCopy);
 
         FontTableBlobData *mSharedBlobData;
         hb_blob_t *mBlob;
@@ -771,20 +771,20 @@ public:
     void SortAvailableFonts();
 
     // check whether the family fits into the simple 4-face model,
     // so we can use simplified style-matching;
     // if so set the mIsSimpleFamily flag (defaults to False before we've checked)
     void CheckForSimpleFamily();
 
     // For memory reporter
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
     // Only used for debugging checks - does a linear search
     bool ContainsFace(gfxFontEntry* aFontEntry) {
         uint32_t i, numFonts = mAvailableFonts.Length();
         for (i = 0; i < numFonts; i++) {
             if (mAvailableFonts[i] == aFontEntry) {
                 return true;
             }
@@ -939,20 +939,20 @@ public:
         mFonts.Clear();
         AgeAllGenerations();
     }
 
     void FlushShapedWordCaches() {
         mFonts.EnumerateEntries(ClearCachedWordsForFont, nullptr);
     }
 
-    void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                             FontCacheSizes*   aSizes) const;
-    void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                             FontCacheSizes*   aSizes) const;
+    void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                FontCacheSizes* aSizes) const;
+    void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                FontCacheSizes* aSizes) const;
 
 protected:
     class MemoryReporter MOZ_FINAL
         : public nsIMemoryReporter
     {
     public:
         NS_DECL_ISUPPORTS
         NS_DECL_NSIMEMORYREPORTER
@@ -994,19 +994,19 @@ protected:
         static PLDHashNumber HashKey(const KeyTypePointer aKey) {
             return mozilla::HashGeneric(aKey->mStyle->Hash(), aKey->mFontEntry);
         }
         enum { ALLOW_MEMMOVE = true };
 
         gfxFont* mFont;
     };
 
-    static size_t SizeOfFontEntryExcludingThis(HashEntry*        aHashEntry,
-                                               mozilla::MallocSizeOf aMallocSizeOf,
-                                               void*             aUserArg);
+    static size_t AddSizeOfFontEntryExcludingThis(HashEntry* aHashEntry,
+                                                  mozilla::MallocSizeOf aMallocSizeOf,
+                                                  void* aUserArg);
 
     nsTHashtable<HashEntry> mFonts;
 
     static PLDHashOperator ClearCachedWordsForFont(HashEntry* aHashEntry, void*);
     static PLDHashOperator AgeCachedWordsForFont(HashEntry* aHashEntry, void*);
     static void WordCacheExpirationTimerCallback(nsITimer* aTimer, void* aCache);
     nsCOMPtr<nsITimer>      mWordCacheExpirationTimer;
 };
@@ -1665,20 +1665,20 @@ public:
         if (mWordCache) {
             mWordCache->Clear();
         }
     }
 
     // Glyph rendering/geometry has changed, so invalidate data as necessary.
     void NotifyGlyphsChanged();
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
 
     typedef enum {
         FONT_TYPE_DWRITE,
         FONT_TYPE_GDI,
         FONT_TYPE_FT2,
         FONT_TYPE_MAC,
         FONT_TYPE_OS2,
         FONT_TYPE_CAIRO
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -560,26 +560,26 @@ gfxGDIFont::GetGlyphWidth(gfxContext *aC
         mGlyphWidths->Put(aGID, width);
         return width;
     }
 
     return -1;
 }
 
 void
-gfxGDIFont::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                FontCacheSizes*   aSizes) const
+gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                   FontCacheSizes* aSizes) const
 {
-    gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     aSizes->mFontInstances += aMallocSizeOf(mMetrics);
     if (mGlyphWidths) {
         aSizes->mFontInstances +=
             mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf);
     }
 }
 
 void
-gfxGDIFont::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                FontCacheSizes*   aSizes) const
+gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                   FontCacheSizes* aSizes) const
 {
     aSizes->mFontInstances += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
--- a/gfx/thebes/gfxGDIFont.h
+++ b/gfx/thebes/gfxGDIFont.h
@@ -49,20 +49,20 @@ public:
     /* required for MathML to suppress effects of ClearType "padding" */
     virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption);
 
     virtual bool ProvidesGlyphWidths() { return true; }
 
     // get hinted glyph width in pixels as 16.16 fixed-point value
     virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_GDI; }
 
 protected:
     virtual void CreatePlatformShaper();
 
     /* override to check for uniscribe failure and fall back to GDI */
     virtual bool ShapeText(gfxContext      *aContext,
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -409,21 +409,21 @@ GDIFontEntry::CreateFontEntry(const nsAS
     GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic,
                                         aWeight, aStretch, aUserFontData,
                                         aFamilyHasItalicFace);
 
     return fe;
 }
 
 void
-GDIFontEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                  FontListSizes*    aSizes) const
+GDIFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                     FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 /***************************************************************
  *
  * GDIFontFamily
  *
  */
 
@@ -883,30 +883,30 @@ gfxGDIFontList::ResolveFontName(const ns
 
     if (gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName))
         return true;
 
     return false;
 }
 
 void
-gfxGDIFontList::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                    FontListSizes*    aSizes) const
+gfxGDIFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                       FontListSizes* aSizes) const
 {
-    gfxPlatformFontList::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     aSizes->mFontListSize +=
         mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
                                              aMallocSizeOf);
     aSizes->mFontListSize +=
         mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf);
     for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
         aSizes->mFontListSize +=
             mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     }
 }
 
 void
-gfxGDIFontList::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                    FontListSizes*    aSizes) const
+gfxGDIFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                       FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -235,18 +235,18 @@ public:
     }
 
     virtual bool SkipDuringSystemFallback() { 
         return !HasCmapTable(); // explicitly skip non-SFNT fonts
     }
 
     virtual bool TestCharacterMap(uint32_t aCh);
 
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
     // create a font entry for a font with a given name
     static GDIFontEntry* CreateFontEntry(const nsAString& aName,
                                          gfxWindowsFontType aFontType,
                                          bool aItalic,
                                          uint16_t aWeight, int16_t aStretch,
                                          gfxUserFontData* aUserFontData,
                                          bool aFamilyHasItalicFace);
@@ -317,20 +317,20 @@ public:
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData, uint32_t aLength);
 
     virtual bool ResolveFontName(const nsAString& aFontName,
                                    nsAString& aResolvedFontName);
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
 private:
     friend class gfxWindowsPlatform;
 
     gfxGDIFontList();
 
     nsresult GetFontSubstitutes();
 
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -414,23 +414,23 @@ gfxMacFont::GetScaledFont(DrawTarget *aT
     nativeFont.mFont = GetCGFontRef();
     mAzureScaledFont = mozilla::gfx::Factory::CreateScaledFontWithCairo(nativeFont, GetAdjustedSize(), mScaledFont);
   }
 
   return mAzureScaledFont;
 }
 
 void
-gfxMacFont::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
-                                FontCacheSizes*   aSizes) const
+gfxMacFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                   FontCacheSizes* aSizes) const
 {
-    gfxFont::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
     // mCGFont is shared with the font entry, so not counted here;
     // and we don't have APIs to measure the cairo mFontFace object
 }
 
 void
-gfxMacFont::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                FontCacheSizes*   aSizes) const
+gfxMacFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                   FontCacheSizes* aSizes) const
 {
     aSizes->mFontInstances += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -38,20 +38,20 @@ public:
     virtual RunMetrics Measure(gfxTextRun *aTextRun,
                                uint32_t aStart, uint32_t aEnd,
                                BoundingBoxType aBoundingBoxType,
                                gfxContext *aContextForTightBoundingBox,
                                Spacing *aSpacing);
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget);
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontCacheSizes*   aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontCacheSizes* aSizes) const;
 
     virtual FontType GetType() const { return FONT_TYPE_MAC; }
 
 protected:
     virtual void CreatePlatformShaper();
 
     // override to prefer CoreText shaping with fonts that depend on AAT
     virtual bool ShapeText(gfxContext      *aContext,
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -40,18 +40,18 @@ public:
     }
 
     virtual CGFontRef GetFontRef();
 
     // override gfxFontEntry table access function to bypass table cache,
     // use CGFontRef API to get direct access to system font data
     virtual hb_blob_t *GetFontTable(uint32_t aTag) MOZ_OVERRIDE;
 
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
     nsresult ReadCMAP();
 
     bool RequiresAATLayout() const { return mRequiresAAT; }
 
     bool IsCFF();
 
 protected:
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -421,21 +421,21 @@ MacOSFontEntry::HasFontTable(uint32_t aT
         return false;
     }
 
     ::CFRelease(tableData);
     return true;
 }
 
 void
-MacOSFontEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
-                                    FontListSizes*    aSizes) const
+MacOSFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                       FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
 
 /* gfxMacFontFamily */
 #pragma mark-
 
 class gfxMacFontFamily : public gfxFontFamily
 {
 public:
@@ -768,50 +768,16 @@ bool
 gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
 {
     gfxFontFamily *family = FindFamily(aFontName);
     if (family) {
         family->LocalizedName(aFamilyName);
         return true;
     }
 
-    // Gecko 1.8 used Quickdraw font api's which produce a slightly different set of "family"
-    // names.  Try to resolve based on these names, in case this is stored in an old profile
-    // 1.8: "Futura", "Futura Condensed" ==> 1.9: "Futura"
-
-    // convert the name to a Pascal-style Str255 to try as Quickdraw name
-    Str255 qdname;
-    NS_ConvertUTF16toUTF8 utf8name(aFontName);
-    qdname[0] = std::max<size_t>(255, strlen(utf8name.get()));
-    memcpy(&qdname[1], utf8name.get(), qdname[0]);
-
-    // look up the Quickdraw name
-    ATSFontFamilyRef atsFamily = ::ATSFontFamilyFindFromQuickDrawName(qdname);
-    if (atsFamily == (ATSFontFamilyRef)kInvalidFontFamily) {
-        return false;
-    }
-
-    // if we found a family, get its ATS name
-    CFStringRef cfName;
-    OSStatus status = ::ATSFontFamilyGetName(atsFamily, kATSOptionFlagsDefault, &cfName);
-    if (status != noErr) {
-        return false;
-    }
-
-    // then use this to locate the family entry and retrieve its localized name
-    nsAutoString familyName;
-    GetStringForNSString((const NSString*)cfName, familyName);
-    ::CFRelease(cfName);
-
-    family = FindFamily(familyName);
-    if (family) {
-        family->LocalizedName(aFamilyName);
-        return true;
-    }
-
     return false;
 }
 
 void
 gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
                                         void* aUserArg)
 {
     // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -87,18 +87,18 @@ gfxPlatformFontList::MemoryReporter::Col
     (nsIMemoryReporterCallback* aCb,
      nsISupports* aClosure)
 {
     FontListSizes sizes;
     sizes.mFontListSize = 0;
     sizes.mFontTableCacheSize = 0;
     sizes.mCharMapsSize = 0;
 
-    gfxPlatformFontList::PlatformFontList()->SizeOfIncludingThis(&FontListMallocSizeOf,
-                                                                 &sizes);
+    gfxPlatformFontList::PlatformFontList()->AddSizeOfIncludingThis(&FontListMallocSizeOf,
+                                                                    &sizes);
 
     aCb->Callback(EmptyCString(),
                   NS_LITERAL_CSTRING("explicit/gfx/font-list"),
                   nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
                   sizes.mFontListSize,
                   NS_LITERAL_CSTRING("Memory used to manage the list of font families and faces."),
                   aClosure);
 
@@ -758,17 +758,17 @@ gfxPlatformFontList::GetPrefsAndStartLoa
 
 static size_t
 SizeOfFamilyEntryExcludingThis(const nsAString&               aKey,
                                const nsRefPtr<gfxFontFamily>& aFamily,
                                MallocSizeOf                   aMallocSizeOf,
                                void*                          aUserArg)
 {
     FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
-    aFamily->SizeOfExcludingThis(aMallocSizeOf, sizes);
+    aFamily->AddSizeOfExcludingThis(aMallocSizeOf, sizes);
 
     sizes->mFontListSize += aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
 
     // we return zero here because the measurements have been added directly
     // to the relevant fields of the FontListSizes record
     return 0;
 }
 
@@ -828,18 +828,18 @@ SizeOfSharedCmapExcludingThis(CharMapHas
     sizes->mCharMapsSize += size;
 
     // we return zero here because the measurements have been added directly
     // to the relevant fields of the FontListSizes record
     return 0;
 }
 
 void
-gfxPlatformFontList::SizeOfExcludingThis(MallocSizeOf   aMallocSizeOf,
-                                         FontListSizes* aSizes) const
+gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+                                            FontListSizes* aSizes) const
 {
     aSizes->mFontListSize +=
         mFontFamilies.SizeOfExcludingThis(SizeOfFamilyEntryExcludingThis,
                                           aMallocSizeOf, aSizes);
 
     aSizes->mFontListSize +=
         mOtherFamilyNames.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
                                               aMallocSizeOf);
@@ -867,14 +867,14 @@ gfxPlatformFontList::SizeOfExcludingThis
                                                      aMallocSizeOf);
 
     aSizes->mFontListSize +=
         mSharedCmaps.SizeOfExcludingThis(SizeOfSharedCmapExcludingThis,
                                          aMallocSizeOf, aSizes);
 }
 
 void
-gfxPlatformFontList::SizeOfIncludingThis(MallocSizeOf   aMallocSizeOf,
-                                         FontListSizes* aSizes) const
+gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
+                                            FontListSizes* aSizes) const
 {
     aSizes->mFontListSize += aMallocSizeOf(this);
-    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
 }
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -157,20 +157,20 @@ public:
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const uint8_t *aFontData,
                                            uint32_t aLength) = 0;
 
     // get the standard family name on the platform for a given font name
     // (platforms may override, eg Mac)
     virtual bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
-    virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
-    virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
-                                     FontListSizes*    aSizes) const;
+    virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
+    virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+                                        FontListSizes* aSizes) const;
 
     // search for existing cmap that matches the input
     // return the input if no match is found
     gfxCharacterMap* FindCharMap(gfxCharacterMap *aCmap);
 
     // add a cmap to the shared cmap set
     gfxCharacterMap* AddCmap(const gfxCharacterMap *aCharMap);
 
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -552,17 +552,17 @@ JavaScriptParent::getPropertyNames(JSCon
     return true;
 }
 
 JSObject *
 JavaScriptParent::unwrap(JSContext *cx, ObjectId objId)
 {
     RootedObject obj(cx, findObject(objId));
     if (obj) {
-        if (!JS_WrapObject(cx, obj.address()))
+        if (!JS_WrapObject(cx, &obj))
             return nullptr;
         return obj;
     }
 
     if (objId > MAX_CPOW_IDS) {
         JS_ReportError(cx, "unusable CPOW id");
         return nullptr;
     }
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -411,25 +411,26 @@ JavaScriptShared::toDescriptor(JSContext
         else
             out.setSetter(UnknownStrictPropertyStub);
     }
 
     return true;
 }
 
 bool
-CpowIdHolder::ToObject(JSContext *cx, JSObject **objp)
+CpowIdHolder::ToObject(JSContext *cx, JS::MutableHandleObject objp)
 {
     return js_->Unwrap(cx, cpows_, objp);
 }
 
 bool
-JavaScriptShared::Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JSObject **objp)
+JavaScriptShared::Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows,
+                         JS::MutableHandleObject objp)
 {
-    *objp = nullptr;
+    objp.set(nullptr);
 
     if (!aCpows.Length())
         return true;
 
     RootedObject obj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
     if (!obj)
         return false;
 
@@ -449,17 +450,17 @@ JavaScriptShared::Unwrap(JSContext *cx, 
                                  nullptr,
                                  nullptr,
                                  JSPROP_ENUMERATE))
         {
             return false;
         }
     }
 
-    *objp = obj;
+    objp.set(obj);
     return true;
 }
 
 bool
 JavaScriptShared::Wrap(JSContext *cx, HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows)
 {
     if (!aObj)
         return true;
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -24,17 +24,17 @@ class CpowIdHolder : public CpowHolder
 {
   public:
     CpowIdHolder(JavaScriptShared *js, const InfallibleTArray<CpowEntry> &cpows)
       : js_(js),
         cpows_(cpows)
     {
     }
 
-    bool ToObject(JSContext *cx, JSObject **objp);
+    bool ToObject(JSContext *cx, JS::MutableHandleObject objp);
 
   private:
     JavaScriptShared *js_;
     const InfallibleTArray<CpowEntry> &cpows_;
 };
 
 // Map ids -> JSObjects
 class ObjectStore
@@ -82,17 +82,17 @@ class ObjectIdCache
 class JavaScriptShared
 {
   public:
     bool init();
 
     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, JSObject **objp);
+    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 toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
     bool fromDescriptor(JSContext *cx, JS::Handle<JSPropertyDescriptor> desc, PPropertyDescriptor *out);
     bool toDescriptor(JSContext *cx, const PPropertyDescriptor &in,
                       JS::MutableHandle<JSPropertyDescriptor> out);
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -24,17 +24,16 @@
 #include "unicode/ucal.h"
 #include "unicode/ucol.h"
 #include "unicode/udat.h"
 #include "unicode/udatpg.h"
 #include "unicode/uenum.h"
 #include "unicode/unum.h"
 #include "unicode/ustring.h"
 #endif
-#include "unicode/utypes.h"
 #include "vm/DateTime.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/Stack.h"
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
 
@@ -958,17 +957,19 @@ intl_CompareStrings(JSContext *cx, UColl
     const jschar *chars1 = str1->getChars(cx);
     if (!chars1)
         return false;
     size_t length2 = str2->length();
     const jschar *chars2 = str2->getChars(cx);
     if (!chars2)
         return false;
 
-    UCollationResult uresult = ucol_strcoll(coll, chars1, length1, chars2, length2);
+    UCollationResult uresult = ucol_strcoll(coll, JSCharToUChar(chars1),
+                                            length1, JSCharToUChar(chars2),
+                                            length2);
 
     int32_t res;
     switch (uresult) {
         case UCOL_LESS: res = -1; break;
         case UCOL_EQUAL: res = 0; break;
         case UCOL_GREATER: res = 1; break;
         default: MOZ_ASSUME_UNREACHABLE("ucol_strcoll returned bad UCollationResult");
     }
@@ -1300,17 +1301,17 @@ NewUNumberFormat(JSContext *cx, HandleOb
         return nullptr;
 
     if (equal(style, "currency")) {
         if (!JSObject::getProperty(cx, internals, internals, cx->names().currency, &value))
             return nullptr;
         currency = value.toString();
         MOZ_ASSERT(currency->length() == 3, "IsWellFormedCurrencyCode permits only length-3 strings");
         // uCurrency remains owned by currency.
-        uCurrency = JS_GetStringCharsZ(cx, currency);
+        uCurrency = JSCharToUChar(JS_GetStringCharsZ(cx, currency));
         if (!uCurrency)
             return nullptr;
 
         if (!JSObject::getProperty(cx, internals, internals, cx->names().currencyDisplay, &value))
             return nullptr;
         JSAutoByteString currencyDisplay(cx, value.toString());
         if (!currencyDisplay)
             return nullptr;
@@ -1407,23 +1408,24 @@ intl_FormatNumber(JSContext *cx, UNumber
     // FormatNumber doesn't consider -0.0 to be negative.
     if (IsNegativeZero(x))
         x = 0.0;
 
     StringBuffer chars(cx);
     if (!chars.resize(INITIAL_STRING_BUFFER_SIZE))
         return false;
     UErrorCode status = U_ZERO_ERROR;
-    int size = unum_formatDouble(nf, x, chars.begin(), INITIAL_STRING_BUFFER_SIZE, nullptr,
-                                 &status);
+    int size = unum_formatDouble(nf, x, JSCharToUChar(chars.begin()),
+                                 INITIAL_STRING_BUFFER_SIZE, nullptr, &status);
     if (status == U_BUFFER_OVERFLOW_ERROR) {
         if (!chars.resize(size))
             return false;
         status = U_ZERO_ERROR;
-        unum_formatDouble(nf, x, chars.begin(), size, nullptr, &status);
+        unum_formatDouble(nf, x, JSCharToUChar(chars.begin()),
+                          size, nullptr, &status);
     }
     if (U_FAILURE(status)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
 
     // Trim any unused characters.
     if (!chars.resize(size))
@@ -1774,43 +1776,45 @@ js::intl_patternForSkeleton(JSContext *c
     JSAutoByteString locale(cx, args[0].toString());
     if (!locale)
         return false;
     RootedString jsskeleton(cx, args[1].toString());
     const jschar *skeleton = JS_GetStringCharsZ(cx, jsskeleton);
     if (!skeleton)
         return false;
     SkipRoot skip(cx, &skeleton);
-    uint32_t skeletonLen = u_strlen(skeleton);
+    uint32_t skeletonLen = u_strlen(JSCharToUChar(skeleton));
 
     UErrorCode status = U_ZERO_ERROR;
     UDateTimePatternGenerator *gen = udatpg_open(icuLocale(locale.ptr()), &status);
     if (U_FAILURE(status)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
     ScopedICUObject<UDateTimePatternGenerator> toClose(gen, udatpg_close);
 
-    int32_t size = udatpg_getBestPattern(gen, skeleton, skeletonLen, nullptr, 0, &status);
+    int32_t size = udatpg_getBestPattern(gen, JSCharToUChar(skeleton),
+                                         skeletonLen, nullptr, 0, &status);
     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
     ScopedJSFreePtr<UChar> pattern(cx->pod_malloc<UChar>(size + 1));
     if (!pattern)
         return false;
     pattern[size] = '\0';
     status = U_ZERO_ERROR;
-    udatpg_getBestPattern(gen, skeleton, skeletonLen, pattern, size, &status);
+    udatpg_getBestPattern(gen, JSCharToUChar(skeleton),
+                          skeletonLen, pattern, size, &status);
     if (U_FAILURE(status)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
 
-    RootedString str(cx, JS_NewUCStringCopyZ(cx, pattern));
+    RootedString str(cx, JS_NewUCStringCopyZ(cx, reinterpret_cast<jschar*>(pattern.get())));
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
 /**
  * Returns a new UDateFormat with the locale and date-time formatting options
@@ -1848,25 +1852,25 @@ NewUDateFormat(JSContext *cx, HandleObje
     RootedId id(cx, NameToId(cx->names().timeZone));
     bool hasP;
     if (!JSObject::hasProperty(cx, internals, id, &hasP))
         return nullptr;
     if (hasP) {
         if (!JSObject::getProperty(cx, internals, internals, cx->names().timeZone, &value))
             return nullptr;
         if (!value.isUndefined()) {
-            uTimeZone = JS_GetStringCharsZ(cx, value.toString());
+            uTimeZone = JSCharToUChar(JS_GetStringCharsZ(cx, value.toString()));
             if (!uTimeZone)
                 return nullptr;
             uTimeZoneLength = u_strlen(uTimeZone);
         }
     }
     if (!JSObject::getProperty(cx, internals, internals, cx->names().pattern, &value))
         return nullptr;
-    uPattern = JS_GetStringCharsZ(cx, value.toString());
+    uPattern = JSCharToUChar(JS_GetStringCharsZ(cx, value.toString()));
     if (!uPattern)
         return nullptr;
     uPatternLength = u_strlen(uPattern);
 
     UErrorCode status = U_ZERO_ERROR;
 
     // If building with ICU headers before 50.1, use UDAT_IGNORE instead of
     // UDAT_PATTERN.
@@ -1895,22 +1899,22 @@ intl_FormatDateTime(JSContext *cx, UDate
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DATE_NOT_FINITE);
         return false;
     }
 
     StringBuffer chars(cx);
     if (!chars.resize(INITIAL_STRING_BUFFER_SIZE))
         return false;
     UErrorCode status = U_ZERO_ERROR;
-    int size = udat_format(df, x, chars.begin(), INITIAL_STRING_BUFFER_SIZE, nullptr, &status);
+    int size = udat_format(df, x, JSCharToUChar(chars.begin()), INITIAL_STRING_BUFFER_SIZE, nullptr, &status);
     if (status == U_BUFFER_OVERFLOW_ERROR) {
         if (!chars.resize(size))
             return false;
         status = U_ZERO_ERROR;
-        udat_format(df, x, chars.begin(), size, nullptr, &status);
+        udat_format(df, x, JSCharToUChar(chars.begin()), size, nullptr, &status);
     }
     if (U_FAILURE(status)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
         return false;
     }
 
     // Trim any unused characters.
     if (!chars.resize(size))
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -3,16 +3,17 @@
  * 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 builtin_Intl_h
 #define builtin_Intl_h
 
 #include "NamespaceImports.h"
+#include "unicode/utypes.h"
 
 /*
  * The Intl module specified by standard ECMA-402,
  * ECMAScript Internationalization API Specification.
  */
 
 /**
  * Initializes the Intl Object and its standard built-in properties.
@@ -173,11 +174,26 @@ intl_patternForSkeleton(JSContext *cx, u
  *
  * Spec: ECMAScript Internationalization API Specification, 12.3.2.
  *
  * Usage: formatted = intl_FormatDateTime(dateTimeFormat, x)
  */
 extern bool
 intl_FormatDateTime(JSContext *cx, unsigned argc, Value *vp);
 
+/**
+ * Cast jschar* strings to UChar* strings used by ICU.
+ */
+inline const UChar *
+JSCharToUChar(const jschar *chars)
+{
+  return reinterpret_cast<const UChar *>(chars);
+}
+
+inline UChar *
+JSCharToUChar(jschar *chars)
+{
+  return reinterpret_cast<UChar *>(chars);
+}
+
 } // namespace js
 
 #endif /* builtin_Intl_h */
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -3,18 +3,18 @@
  * 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/. */
 
 #include "ctypes/CTypes.h"
 
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MemoryReporting.h"
-
-#include <limits>
+#include "mozilla/NumericLimits.h"
+
 #include <math.h>
 #include <stdint.h>
 
 #if defined(XP_WIN) || defined(XP_OS2)
 #include <float.h>
 #endif
 
 #if defined(SOLARIS)
@@ -33,16 +33,17 @@
 
 #include "jsnum.h"
 #include "jsprf.h"
 
 #include "builtin/TypeRepresentation.h"
 #include "ctypes/Library.h"
 
 using namespace std;
+using mozilla::NumericLimits;
 
 namespace js {
 namespace ctypes {
 
 size_t
 GetDeflatedUTF8StringLength(JSContext *maybecx, const jschar *chars,
                             size_t nchars)
 {
@@ -1418,17 +1419,17 @@ JS_STATIC_ASSERT(sizeof(char) == 1);
 JS_STATIC_ASSERT(sizeof(short) == 2);
 JS_STATIC_ASSERT(sizeof(int) == 4);
 JS_STATIC_ASSERT(sizeof(unsigned) == 4);
 JS_STATIC_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);
 JS_STATIC_ASSERT(sizeof(long long) == 8);
 JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t));
 JS_STATIC_ASSERT(sizeof(float) == 4);
 JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*));
-JS_STATIC_ASSERT(numeric_limits<double>::is_signed);
+JS_STATIC_ASSERT(NumericLimits<double>::is_signed);
 
 // Templated helper to convert FromType to TargetType, for the default case
 // where the trivial POD constructor will do.
 template<class TargetType, class FromType>
 struct ConvertImpl {
   static JS_ALWAYS_INLINE TargetType Convert(FromType d) {
     return TargetType(d);
   }
@@ -1483,77 +1484,77 @@ static JS_ALWAYS_INLINE bool IsAlwaysExa
   // This means that:
   // 1) TargetType must be the same or more bits wide as FromType. For integers
   //    represented in 'n' bits, unsigned variants will have 'n' digits while
   //    signed will have 'n - 1'. For floating point types, 'digits' is the
   //    mantissa width.
   // 2) If FromType is signed, TargetType must also be signed. (Floating point
   //    types are always signed.)
   // 3) If TargetType is an exact integral type, FromType must be also.
-  if (numeric_limits<TargetType>::digits < numeric_limits<FromType>::digits)
-    return false;
-
-  if (numeric_limits<FromType>::is_signed &&
-      !numeric_limits<TargetType>::is_signed)
-    return false;
-
-  if (!numeric_limits<FromType>::is_exact &&
-      numeric_limits<TargetType>::is_exact)
+  if (NumericLimits<TargetType>::digits < NumericLimits<FromType>::digits)
+    return false;
+
+  if (NumericLimits<FromType>::is_signed &&
+      !NumericLimits<TargetType>::is_signed)
+    return false;
+
+  if (!NumericLimits<FromType>::is_exact &&
+      NumericLimits<TargetType>::is_exact)
     return false;
 
   return true;
 }
 
 // Templated helper to determine if FromType 'i' converts losslessly to
 // TargetType 'j'. Default case where both types are the same signedness.
 template<class TargetType, class FromType, bool TargetSigned, bool FromSigned>
 struct IsExactImpl {
   static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
-    JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
+    JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
     return FromType(j) == i;
   }
 };
 
 // Specialization where TargetType is unsigned, FromType is signed.
 template<class TargetType, class FromType>
 struct IsExactImpl<TargetType, FromType, false, true> {
   static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
-    JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
+    JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
     return i >= 0 && FromType(j) == i;
   }
 };
 
 // Specialization where TargetType is signed, FromType is unsigned.
 template<class TargetType, class FromType>
 struct IsExactImpl<TargetType, FromType, true, false> {
   static JS_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
-    JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
+    JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
     return TargetType(i) >= 0 && FromType(j) == i;
   }
 };
 
 // Convert FromType 'i' to TargetType 'result', returning true iff 'result'
 // is an exact representation of 'i'.
 template<class TargetType, class FromType>
 static JS_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
 {
   // Require that TargetType is integral, to simplify conversion.
-  JS_STATIC_ASSERT(numeric_limits<TargetType>::is_exact);
+  JS_STATIC_ASSERT(NumericLimits<TargetType>::is_exact);
 
   *result = Convert<TargetType>(i);
 
   // See if we can avoid a dynamic check.
   if (IsAlwaysExact<TargetType, FromType>())
     return true;
 
   // Return 'true' if 'i' is exactly representable in 'TargetType'.
   return IsExactImpl<TargetType,
                      FromType,
-                     numeric_limits<TargetType>::is_signed,
-                     numeric_limits<FromType>::is_signed>::Test(i, *result);
+                     NumericLimits<TargetType>::is_signed,
+                     NumericLimits<FromType>::is_signed>::Test(i, *result);
 }
 
 // Templated helper to determine if Type 'i' is negative. Default case
 // where IntegerType is unsigned.
 template<class Type, bool IsSigned>
 struct IsNegativeImpl {
   static JS_ALWAYS_INLINE bool Test(Type i) {
     return false;
@@ -1567,17 +1568,17 @@ struct IsNegativeImpl<Type, true> {
     return i < 0;
   }
 };
 
 // Determine whether Type 'i' is negative.
 template<class Type>
 static JS_ALWAYS_INLINE bool IsNegative(Type i)
 {
-  return IsNegativeImpl<Type, numeric_limits<Type>::is_signed>::Test(i);
+  return IsNegativeImpl<Type, NumericLimits<Type>::is_signed>::Test(i);
 }
 
 // Implicitly convert val to bool, allowing bool, int, and double
 // arguments numerically equal to 0 or 1.
 static bool
 jsvalToBool(JSContext* cx, jsval val, bool* result)
 {
   if (JSVAL_IS_BOOLEAN(val)) {
@@ -1601,17 +1602,17 @@ jsvalToBool(JSContext* cx, jsval val, bo
 
 // Implicitly convert val to IntegerType, allowing bool, int, double,
 // Int64, UInt64, and CData integer types 't' where all values of 't' are
 // representable by IntegerType.
 template<class IntegerType>
 static bool
 jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
 {
-  JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
+  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
   if (JSVAL_IS_INT(val)) {
     // Make sure the integer fits in the alotted precision, and has the right
     // sign.
     int32_t i = JSVAL_TO_INT(val);
     return ConvertExact(i, result);
   }
   if (JSVAL_IS_DOUBLE(val)) {
@@ -1690,17 +1691,17 @@ jsvalToInteger(JSContext* cx, jsval val,
 
 // Implicitly convert val to FloatType, allowing int, double,
 // Int64, UInt64, and CData numeric types 't' where all values of 't' are
 // representable by FloatType.
 template<class FloatType>
 static bool
 jsvalToFloat(JSContext *cx, jsval val, FloatType* result)
 {
-  JS_STATIC_ASSERT(!numeric_limits<FloatType>::is_exact);
+  JS_STATIC_ASSERT(!NumericLimits<FloatType>::is_exact);
 
   // The following casts may silently throw away some bits, but there's
   // no good way around it. Sternly requiring that the 64-bit double
   // argument be exactly representable as a 32-bit float is
   // unrealistic: it would allow 1/2 to pass but not 1/3.
   if (JSVAL_IS_INT(val)) {
     *result = FloatType(JSVAL_TO_INT(val));
     return true;
@@ -1746,29 +1747,29 @@ jsvalToFloat(JSContext *cx, jsval val, F
   // does it. It's likely to be a mistake.
   return false;
 }
 
 template<class IntegerType>
 static bool
 StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
 {
-  JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
+  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
   const jschar* cp = string->getChars(nullptr);
   if (!cp)
     return false;
 
   const jschar* end = cp + string->length();
   if (cp == end)
     return false;
 
   IntegerType sign = 1;
   if (cp[0] == '-') {
-    if (!numeric_limits<IntegerType>::is_signed)
+    if (!NumericLimits<IntegerType>::is_signed)
       return false;
 
     sign = -1;
     ++cp;
   }
 
   // Assume base-10, unless the string begins with '0x' or '0X'.
   IntegerType base = 10;
@@ -1806,17 +1807,17 @@ StringToInteger(JSContext* cx, JSString*
 // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
 template<class IntegerType>
 static bool
 jsvalToBigInteger(JSContext* cx,
                   jsval val,
                   bool allowString,
                   IntegerType* result)
 {
-  JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
+  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
   if (JSVAL_IS_INT(val)) {
     // Make sure the integer fits in the alotted precision, and has the right
     // sign.
     int32_t i = JSVAL_TO_INT(val);
     return ConvertExact(i, result);
   }
   if (JSVAL_IS_DOUBLE(val)) {
@@ -1877,17 +1878,17 @@ jsvalToSize(JSContext* cx, jsval val, bo
 // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
 template<class IntegerType>
 static bool
 jsidToBigInteger(JSContext* cx,
                   jsid val,
                   bool allowString,
                   IntegerType* result)
 {
-  JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
+  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
   if (JSID_IS_INT(val)) {
     // Make sure the integer fits in the alotted precision, and has the right
     // sign.
     int32_t i = JSID_TO_INT(val);
     return ConvertExact(i, result);
   }
   if (allowString && JSID_IS_STRING(val)) {
@@ -1942,17 +1943,17 @@ SizeTojsval(JSContext* cx, size_t size, 
   return true;
 }
 
 // Forcefully convert val to IntegerType when explicitly requested.
 template<class IntegerType>
 static bool
 jsvalToIntegerExplicit(jsval val, IntegerType* result)
 {
-  JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
+  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
   if (JSVAL_IS_DOUBLE(val)) {
     // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
     double d = JSVAL_TO_DOUBLE(val);
     *result = mozilla::IsFinite(d) ? IntegerType(d) : 0;
     return true;
   }
   if (!JSVAL_IS_PRIMITIVE(val)) {
@@ -2023,17 +2024,17 @@ jsvalToPtrExplicit(JSContext* cx, jsval 
   }
   return false;
 }
 
 template<class IntegerType, class CharType, size_t N, class AP>
 void
 IntegerToString(IntegerType i, int radix, Vector<CharType, N, AP>& result)
 {
-  JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
+  JS_STATIC_ASSERT(NumericLimits<IntegerType>::is_exact);
 
   // The buffer must be big enough for all the bits of IntegerType to fit,
   // in base-2, including '-'.
   CharType buffer[sizeof(IntegerType) * 8 + 1];
   CharType* end = buffer + sizeof(buffer) / sizeof(CharType);
   CharType* cp = end;
 
   // Build the string in reverse. We use multiplication and subtraction
@@ -2107,32 +2108,32 @@ ConvertToJS(JSContext* cx,
       *result = JS_NumberValue(double(value));                                 \
     break;                                                                     \
   }
 #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
   case TYPE_##name: {                                                          \
     /* Return an Int64 or UInt64 object - do not convert to a JS number. */    \
     uint64_t value;                                                            \
     RootedObject proto(cx);                                                    \
-    if (!numeric_limits<type>::is_signed) {                                    \
+    if (!NumericLimits<type>::is_signed) {                                     \
       value = *static_cast<type*>(data);                                       \
       /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */           \
       proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO);          \
       if (!proto)                                                              \
         return false;                                                          \
     } else {                                                                   \
       value = int64_t(*static_cast<type*>(data));                              \
       /* Get ctypes.Int64.prototype from ctypes.CType.prototype. */            \
-      proto = CType::GetProtoFromType(cx, typeObj, SLOT_INT64PROTO);     \
+      proto = CType::GetProtoFromType(cx, typeObj, SLOT_INT64PROTO);           \
       if (!proto)                                                              \
         return false;                                                          \
     }                                                                          \
                                                                                \
     JSObject* obj = Int64Base::Construct(cx, proto, value,                     \
-      !numeric_limits<type>::is_signed);                                       \
+      !NumericLimits<type>::is_signed);                                        \
     if (!obj)                                                                  \
       return false;                                                            \
     *result = OBJECT_TO_JSVAL(obj);                                            \
     break;                                                                     \
   }
 #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
   case TYPE_##name: {                                                          \
     type value = *static_cast<type*>(data);                                    \
@@ -2972,17 +2973,17 @@ BuildDataSource(JSContext* cx,
 #define DEFINE_INT_TYPE(name, type, ffiType)                                   \
   case TYPE_##name:                                                            \
     /* Serialize as a primitive decimal integer. */                            \
     IntegerToString(*static_cast<type*>(data), 10, result);                    \
     break;
 #define DEFINE_WRAPPED_INT_TYPE(name, type, ffiType)                           \
   case TYPE_##name:                                                            \
     /* Serialize as a wrapped decimal integer. */                              \
-    if (!numeric_limits<type>::is_signed)                                      \
+    if (!NumericLimits<type>::is_signed)                                       \
       AppendString(result, "ctypes.UInt64(\"");                                \
     else                                                                       \
       AppendString(result, "ctypes.Int64(\"");                                 \
                                                                                \
     IntegerToString(*static_cast<type*>(data), 10, result);                    \
     AppendString(result, "\")");                                               \
     break;
 #define DEFINE_FLOAT_TYPE(name, type, ffiType)                                 \
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3231,20 +3231,20 @@ EmitVariables(ExclusiveContext *cx, Byte
 
         ParseNode *pn3;
         if (!pn2->isKind(PNK_NAME)) {
 #if JS_HAS_DESTRUCTURING
             if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) {
                 /*
                  * Emit variable binding ops, but not destructuring ops.  The
                  * parser (see Parser::variables) has ensured that our caller
-                 * will be the PNK_FOR/PNK_FORIN case in EmitTree, and that
-                 * case will emit the destructuring code only after emitting an
-                 * enumerating opcode and a branch that tests whether the
-                 * enumeration ended.
+                 * will be the PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree, and
+                 * that case will emit the destructuring code only after
+                 * emitting an enumerating opcode and a branch that tests
+                 * whether the enumeration ended.
                  */
                 JS_ASSERT(emitOption == DefineVars);
                 JS_ASSERT(pn->pn_count == 1);
                 if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2))
                     return false;
                 break;
             }
 #endif
@@ -4740,22 +4740,22 @@ EmitNormalFor(ExclusiveContext *cx, Byte
 
     /* Now fixup all breaks and continues. */
     return PopStatementBCE(cx, bce);
 }
 
 static inline bool
 EmitFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
-    if (pn->pn_left->isKind(PNK_FORIN)) {
-        // FIXME: Give for-of loops their own PNK.  Bug 922066.
-        if (pn->pn_iflags == JSITER_FOR_OF)
-            return EmitForOf(cx, bce, pn, top);
+    if (pn->pn_left->isKind(PNK_FORIN))
         return EmitForIn(cx, bce, pn, top);
-    }
+
+    if (pn->pn_left->isKind(PNK_FOROF))
+        return EmitForOf(cx, bce, pn, top);
+
     JS_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
     return EmitNormalFor(cx, bce, pn, top);
 }
 
 static JS_NEVER_INLINE bool
 EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     cx->maybePause();
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -327,20 +327,20 @@ class FullParseHandler
         BinaryNode *pn = new_<BinaryNode>(PNK_FOR, op, TokenPos(begin, body->pn_pos.end),
                                           forHead, body);
         if (!pn)
             return null();
         pn->pn_iflags = iflags;
         return pn;
     }
 
-    ParseNode *newForHead(bool isForInOrOf, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3,
+    ParseNode *newForHead(ParseNodeKind kind, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3,
                           const TokenPos &pos)
     {
-        ParseNodeKind kind = isForInOrOf ? PNK_FORIN : PNK_FORHEAD;
+        JS_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF || kind == PNK_FORHEAD);
         return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos);
     }
 
     ParseNode *newSwitchStatement(uint32_t begin, ParseNode *discriminant, ParseNode *caseList) {
         TokenPos pos(begin, caseList->pn_pos.end);
         return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
     }
 
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -126,16 +126,17 @@ class UpvarCookie
     F(YIELD_STAR) \
     F(GENEXP) \
     F(ARRAYCOMP) \
     F(ARRAYPUSH) \
     F(LEXICALSCOPE) \
     F(LET) \
     F(SEQ) \
     F(FORIN) \
+    F(FOROF) \
     F(FORHEAD) \
     F(ARGSBODY) \
     F(SPREAD) \
     F(MODULE) \
     \
     /* Unary operators. */ \
     F(TYPEOF) \
     F(VOID) \
@@ -247,26 +248,33 @@ enum ParseNodeKind
  *                          pn_right: PNK_STATEMENTLIST node for this case's
  *                            statements
  * PNK_DEFAULT  binary      pn_left: null
  *                          pn_right: PNK_STATEMENTLIST node for this default's
  *                            statements
  *                          pn_val: constant value if lookup or table switch
  * PNK_WHILE    binary      pn_left: cond, pn_right: body
  * PNK_DOWHILE  binary      pn_left: body, pn_right: cond
- * PNK_FOR      binary      pn_left: either PNK_FORIN (for-in statement) or
- *                            PNK_FORHEAD (for(;;) statement)
+ * PNK_FOR      binary      pn_left: either PNK_FORIN (for-in statement),
+ *                            PNK_FOROF (for-of) or PNK_FORHEAD (for(;;))
  *                          pn_right: body
  * PNK_FORIN    ternary     pn_kid1:  PNK_VAR to left of 'in', or nullptr
  *                            its pn_xflags may have PNX_POPVAR
  *                            bit set
  *                          pn_kid2: PNK_NAME or destructuring expr
  *                            to left of 'in'; if pn_kid1, then this
  *                            is a clone of pn_kid1->pn_head
  *                          pn_kid3: object expr to right of 'in'
+ * PNK_FOROF    ternary     pn_kid1:  PNK_VAR to left of 'of', or nullptr
+ *                            its pn_xflags may have PNX_POPVAR
+ *                            bit set
+ *                          pn_kid2: PNK_NAME or destructuring expr
+ *                            to left of 'of'; if pn_kid1, then this
+ *                            is a clone of pn_kid1->pn_head
+ *                          pn_kid3: expr to right of 'of'
  * PNK_FORHEAD  ternary     pn_kid1:  init expr before first ';' or nullptr
  *                          pn_kid2:  cond expr before second ';' or nullptr
  *                          pn_kid3:  update expr after second ';' or nullptr
  * PNK_THROW    unary       pn_op: JSOP_THROW, pn_kid: exception
  * PNK_TRY      ternary     pn_kid1: try block
  *                          pn_kid2: null or PNK_CATCHLIST list of
  *                          PNK_LEXICALSCOPE nodes, each with pn_expr pointing
  *                          to a PNK_CATCH node
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3827,27 +3827,29 @@ Parser<ParseHandler>::matchInOrOf(bool *
         return true;
     }
     return false;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion version,
-                                                 bool isForDecl, bool isForEach, bool isForOf)
+                                                 bool isForDecl, bool isForEach,
+                                                 ParseNodeKind headKind)
 {
     if (isForDecl) {
         if (pn1->pn_count > 1)
             return false;
         if (pn1->isOp(JSOP_DEFCONST))
             return false;
+
 #if JS_HAS_DESTRUCTURING
         // In JS 1.7 only, for (var [K, V] in EXPR) has a special meaning.
         // Hence all other destructuring decls are banned there.
-        if (version == JSVERSION_1_7 && !isForEach && !isForOf) {
+        if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN) {
             ParseNode *lhs = pn1->pn_head;
             if (lhs->isKind(PNK_ASSIGN))
                 lhs = lhs->pn_left;
 
             if (lhs->isKind(PNK_OBJECT))
                 return false;
             if (lhs->isKind(PNK_ARRAY) && lhs->pn_count != 2)
                 return false;
@@ -3863,17 +3865,17 @@ Parser<FullParseHandler>::isValidForStat
       case PNK_ELEM:
         return true;
 
 #if JS_HAS_DESTRUCTURING
       case PNK_ARRAY:
       case PNK_OBJECT:
         // In JS 1.7 only, for ([K, V] in EXPR) has a special meaning.
         // Hence all other destructuring left-hand sides are banned there.
-        if (version == JSVERSION_1_7 && !isForEach && !isForOf)
+        if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN)
             return pn1->isKind(PNK_ARRAY) && pn1->pn_count == 2;
         return true;
 #endif
 
       default:
         return false;
     }
 }
@@ -3977,38 +3979,46 @@ Parser<FullParseHandler>::forStatement()
     /*
      * We can be sure that it's a for/in loop if there's still an 'in'
      * keyword here, even if JavaScript recognizes 'in' as an operator,
      * as we've excluded 'in' from being parsed in RelExpr by setting
      * pc->parsingForInit.
      */
     StmtInfoPC letStmt(context); /* used if blockObj != nullptr. */
     ParseNode *pn2, *pn3;      /* forHead->pn_kid2 and pn_kid3. */
-    bool isForOf;
-    bool isForInOrOf = pn1 && matchInOrOf(&isForOf);
-    if (isForInOrOf) {
+    ParseNodeKind headKind = PNK_FORHEAD;
+    if (pn1) {
+        bool isForOf;
+        if (matchInOrOf(&isForOf))
+            headKind = isForOf ? PNK_FOROF : PNK_FORIN;
+    }
+
+    if (headKind == PNK_FOROF || headKind == PNK_FORIN) {
         /*
          * Parse the rest of the for/in or for/of head.
          *
          * Here pn1 is everything to the left of 'in' or 'of'. At the end of
          * this block, pn1 is a decl or nullptr, pn2 is the assignment target
          * that receives the enumeration value each iteration, and pn3 is the
          * rhs of 'in'.
          */
-        forStmt.type = isForOf ? STMT_FOR_OF_LOOP : STMT_FOR_IN_LOOP;
-
-        /* Set iflags and rule out invalid combinations. */
-        if (isForOf && isForEach) {
-            report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
-            return null();
+        if (headKind == PNK_FOROF) {
+            forStmt.type = STMT_FOR_OF_LOOP;
+            forStmt.type = (headKind == PNK_FOROF) ? STMT_FOR_OF_LOOP : STMT_FOR_IN_LOOP;
+            if (isForEach) {
+                report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
+                return null();
+            }
+        } else {
+            forStmt.type = STMT_FOR_IN_LOOP;
+            iflags |= JSITER_ENUMERATE;
         }
-        iflags |= (isForOf ? JSITER_FOR_OF : JSITER_ENUMERATE);
 
         /* Check that the left side of the 'in' or 'of' is valid. */
-        if (!isValidForStatementLHS(pn1, versionNumber(), isForDecl, isForEach, isForOf)) {
+        if (!isValidForStatementLHS(pn1, versionNumber(), isForDecl, isForEach, headKind)) {
             report(ParseError, false, pn1, JSMSG_BAD_FOR_LEFTSIDE);
             return null();
         }
 
         /*
          * After the following if-else, pn2 will point to the name or
          * destructuring pattern on in's left. pn1 will point to the decl, if
          * any, else nullptr. Note that the "declaration with initializer" case
@@ -4024,22 +4034,24 @@ Parser<FullParseHandler>::forStatement()
             {
                 /*
                  * Declaration with initializer.
                  *
                  * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
                  * 'const' to hoist the initializer or the entire decl out of
                  * the loop head.
                  */
-#if JS_HAS_BLOCK_SCOPE
+                if (headKind == PNK_FOROF) {
+                    report(ParseError, false, pn2, JSMSG_INVALID_FOR_OF_INIT);
+                    return null();
+                }
                 if (blockObj) {
                     report(ParseError, false, pn2, JSMSG_INVALID_FOR_IN_INIT);
                     return null();
                 }
-#endif /* JS_HAS_BLOCK_SCOPE */
 
                 hoistedVar = pn1;
 
                 /*
                  * All of 'var x = i' is hoisted above 'for (x in o)'.
                  *
                  * Request JSOP_POP here since the var is for a simple
                  * name (it is not a destructuring binding's left-hand
@@ -4108,30 +4120,32 @@ Parser<FullParseHandler>::forStatement()
 
           case PNK_ARRAY:
           case PNK_OBJECT:
             if (versionNumber() == JSVERSION_1_7) {
                 /*
                  * Destructuring for-in requires [key, value] enumeration
                  * in JS1.7.
                  */
-                if (!isForEach && !isForOf)
+                if (!isForEach && headKind == PNK_FORIN)
                     iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           default:;
         }
     } else {
         if (isForEach) {
             reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP);
             return null();
         }
 
+        headKind = PNK_FORHEAD;
+
         if (blockObj) {
             /*
              * Desugar 'for (let A; B; C) D' into 'let (A) { for (; B; C) D }'
              * to induce the correct scoping for A.
              */
             forLetImpliedBlock = pushLetScope(blockObj, &letStmt);
             if (!forLetImpliedBlock)
                 return null();
@@ -4160,17 +4174,17 @@ Parser<FullParseHandler>::forStatement()
             if (!pn3)
                 return null();
         }
     }
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     TokenPos headPos(begin, pos().end);
-    ParseNode *forHead = handler.newForHead(isForInOrOf, pn1, pn2, pn3, headPos);
+    ParseNode *forHead = handler.newForHead(headKind, pn1, pn2, pn3, headPos);
     if (!forHead)
         return null();
 
     /* Parse the loop body. */
     ParseNode *body = statement();
     if (!body)
         return null();
 
@@ -5928,23 +5942,25 @@ Parser<FullParseHandler>::comprehensionT
             return null();
         }
 
         bool isForOf;
         if (!matchInOrOf(&isForOf)) {
             report(ParseError, false, null(), JSMSG_IN_AFTER_FOR_NAME);
             return null();
         }
+        ParseNodeKind headKind = PNK_FORIN;
         if (isForOf) {
             if (pn2->pn_iflags != JSITER_ENUMERATE) {
                 JS_ASSERT(pn2->pn_iflags == (JSITER_FOREACH | JSITER_ENUMERATE));
                 report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
                 return null();
             }
-            pn2->pn_iflags = JSITER_FOR_OF;
+            pn2->pn_iflags = 0;
+            headKind = PNK_FOROF;
         }
 
         ParseNode *pn4 = expr();
         if (!pn4)
             return null();
         MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
         if (isGenexp && pc->lastYieldOffset != startYieldOffset) {
@@ -5967,16 +5983,17 @@ Parser<FullParseHandler>::comprehensionT
                 /* Destructuring requires [key, value] enumeration in JS1.7. */
                 if (!pn3->isKind(PNK_ARRAY) || pn3->pn_count != 2) {
                     report(ParseError, false, null(), JSMSG_BAD_FOR_LEFTSIDE);
                     return null();
                 }
 
                 JS_ASSERT(pn2->isOp(JSOP_ITER));
                 JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
+                JS_ASSERT(headKind == PNK_FORIN);
                 pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           case TOK_NAME:
             data.pn = pn3;
             if (!data.binder(&data, name, this))
@@ -5998,17 +6015,17 @@ Parser<FullParseHandler>::comprehensionT
         vars->makeEmpty();
         vars->append(pn3);
 
         /* Definitions can't be passed directly to EmitAssignment as lhs. */
         pn3 = cloneLeftHandSide(pn3);
         if (!pn3)
             return null();
 
-        pn2->pn_left = handler.newTernary(PNK_FORIN, vars, pn3, pn4);
+        pn2->pn_left = handler.newTernary(headKind, vars, pn3, pn4);
         if (!pn2->pn_left)
             return null();
         *pnp = pn2;
         pnp = &pn2->pn_right;
     } while (tokenStream.matchToken(TOK_FOR));
 
     if (tokenStream.matchToken(TOK_IF)) {
         pn2 = TernaryNode::create(PNK_IF, &handler);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -573,18 +573,18 @@ class Parser : private AutoGCRooter, pub
 
     bool checkFunctionArguments();
     bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom);
     bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind,
                                  bool *pbodyProcessed);
     bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body);
     bool addFreeVariablesFromLazyFunction(JSFunction *fun, ParseContext<ParseHandler> *pc);
 
-    bool isValidForStatementLHS(Node pn1, JSVersion version,
-                                bool forDecl, bool forEach, bool forOf);
+    bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
+                                ParseNodeKind headKind);
     bool checkAndMarkAsIncOperand(Node kid, TokenKind tt, bool preorder);
     bool checkStrictAssignment(Node lhs, AssignmentFlavor flavor);
     bool checkStrictBinding(PropertyName *name, Node pn);
     bool defineArg(Node funcpn, HandlePropertyName name,
                    bool disallowDuplicateArgs = false, Node *duplicatedArg = nullptr);
     Node pushLexicalScope(StmtInfoPC *stmt);
     Node pushLexicalScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
     Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/for-of/syntax-3.js
@@ -0,0 +1,19 @@
+// For-of can't have initializers.
+
+load(libdir + 'asserts.js');
+
+function assertSyntaxError(str) {
+  assertThrowsInstanceOf(function () { return Function(str); }, SyntaxError);
+}
+
+assertSyntaxError("for (var x = 1 of []) {}");
+assertSyntaxError("for (var [x] = 1 of []) {}");
+assertSyntaxError("for (var {x} = 1 of []) {}");
+
+assertSyntaxError("for (let x = 1 of []) {}");
+assertSyntaxError("for (let [x] = 1 of []) {}");
+assertSyntaxError("for (let {x} = 1 of []) {}");
+
+assertSyntaxError("for (const x = 1 of []) {}");
+assertSyntaxError("for (const [x] = 1 of []) {}");
+assertSyntaxError("for (const {x} = 1 of []) {}");
--- a/js/src/jit-test/tests/ion/900683.js
+++ b/js/src/jit-test/tests/ion/900683.js
@@ -13,25 +13,25 @@ ParallelArray(11701, function() {
 function foo() {
   return "foo";
 }
 
 function test() {
 var a = [1, 2, 3];
 var s = '';
 for (var x of a)
-  for (var i=0 of 'y')
+  for (var i of 'y')
     s += '' + foo()
 } test();
 
 ignoreComments = [];
 
 function bug909276() {
 var actual = '';
-for (var next = 0 of ignoreComments) {
+for (var next of ignoreComments) {
   actual += a;
   for (var b in x) {
     actual += b.eval("args = [-0, NaN, -1/0]; this.f(-0, NaN, -1/0);");
   }
 }
 var y = Iterator([1,2,3], true);
 for (var c in y) {}
 } bug909276();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug922118.js
@@ -0,0 +1,30 @@
+var lfcode = new Array();
+lfcode.push("1");
+lfcode.push("");
+lfcode.push("0");
+lfcode.push("function arguments() { };");
+lfcode.push("1");
+lfcode.push("\
+var GLOBAL_PROPERTIES = new Array();\
+var i = 0;\
+for ( p in this ) {\
+if (p.startsWith('a')) GLOBAL_PROPERTIES[i++] = p;\
+}\
+for ( i = 0; i < GLOBAL_PROPERTIES.length; i++ ) {\
+    eval(GLOBAL_PROPERTIES[i]);\
+}\
+");
+while (true) {
+    var file = lfcode.shift(); if (file == undefined) { break; }
+    loadFile(file)
+}
+function loadFile(lfVarx) {
+    if (lfVarx.substr(-3) != ".js" && lfVarx.length != 1) {
+        switch (lfRunTypeId) {
+        case 0: evaluate(lfVarx); break;
+        case 1: eval(lfVarx); break;
+        }
+    } else if (!isNaN(lfVarx)) {
+        lfRunTypeId = parseInt(lfVarx);
+    }
+}
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2281,28 +2281,28 @@ CodeGenerator::visitGetDynamicName(LGetD
     masm.loadValue(Address(StackPointer, 0), out);
     masm.adjustStack(sizeof(Value));
 
     Assembler::Condition cond = masm.testUndefined(Assembler::Equal, out);
     return bailoutIf(cond, lir->snapshot());
 }
 
 bool
-CodeGenerator::visitFilterArguments(LFilterArguments *lir)
+CodeGenerator::visitFilterArgumentsOrEval(LFilterArgumentsOrEval *lir)
 {
     Register string = ToRegister(lir->getString());
     Register temp1 = ToRegister(lir->temp1());
     Register temp2 = ToRegister(lir->temp2());
 
     masm.loadJSContext(temp2);
 
     masm.setupUnalignedABICall(2, temp1);
     masm.passABIArg(temp2);
     masm.passABIArg(string);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, FilterArguments));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, FilterArgumentsOrEval));
 
     Label bail;
     masm.branchIfFalseBool(ReturnReg, &bail);
     return bailoutFrom(&bail, lir->snapshot());
 }
 
 typedef bool (*DirectEvalFn)(JSContext *, HandleObject, HandleScript, HandleValue, HandleString,
                              jsbytecode *, MutableHandleValue);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -112,17 +112,17 @@ class CodeGenerator : public CodeGenerat
     bool visitCallGeneric(LCallGeneric *call);
     bool visitCallKnown(LCallKnown *call);
     bool emitCallInvokeFunction(LApplyArgsGeneric *apply, Register extraStackSize);
     void emitPushArguments(LApplyArgsGeneric *apply, Register extraStackSpace);
     void emitPopArguments(LApplyArgsGeneric *apply, Register extraStackSize);
     bool visitApplyArgsGeneric(LApplyArgsGeneric *apply);
     bool visitBail(LBail *lir);
     bool visitGetDynamicName(LGetDynamicName *lir);
-    bool visitFilterArguments(LFilterArguments *lir);
+    bool visitFilterArgumentsOrEval(LFilterArgumentsOrEval *lir);
     bool visitCallDirectEval(LCallDirectEval *lir);
     bool visitDoubleToInt32(LDoubleToInt32 *lir);
     bool visitFloat32ToInt32(LFloat32ToInt32 *lir);
     bool visitNewSlots(LNewSlots *lir);
     bool visitNewParallelArrayVMCall(LNewParallelArray *lir);
     bool visitNewParallelArray(LNewParallelArray *lir);
     bool visitOutOfLineNewParallelArray(OutOfLineNewParallelArray *ool);
     bool visitNewArrayCallVM(LNewArray *lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5298,17 +5298,17 @@ IonBuilder::jsop_eval(uint32_t argc)
                 CallInfo evalCallInfo(/* constructing = */ false);
                 if (!evalCallInfo.init(current, /* argc = */ 0))
                     return false;
 
                 return makeCall(nullptr, evalCallInfo, false);
             }
         }
 
-        MInstruction *filterArguments = MFilterArguments::New(string);
+        MInstruction *filterArguments = MFilterArgumentsOrEval::New(string);
         current->add(filterArguments);
 
         MInstruction *ins = MCallDirectEval::New(scopeChain, string, thisValue, pc);
         current->add(ins);
         current->push(ins);
 
         types::TemporaryTypeSet *types = bytecodeTypes(pc);
         return resumeAfter(ins) && pushTypeBarrier(ins, types, true);
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -3494,50 +3494,50 @@ GenerateSetDenseElement(JSContext *cx, M
         Address capacity(elements, ObjectElements::offsetOfCapacity());
         masm.branch32(Assembler::BelowOrEqual, capacity, index, &outOfBounds);
 
         // Guard on the initialized length.
         Address initLength(elements, ObjectElements::offsetOfInitializedLength());
         masm.branch32(Assembler::Below, initLength, index, &outOfBounds);
 
         // if (initLength == index)
-        Label markElem, storeElem;
+        Label markElem, postBarrier;
         masm.branch32(Assembler::NotEqual, initLength, index, &markElem);
         {
             // Increase initialize length.
             Int32Key newLength(index);
             masm.bumpKey(&newLength, 1);
             masm.storeKey(newLength, initLength);
 
             // Increase length if needed.
             Label bumpedLength;
             Address length(elements, ObjectElements::offsetOfLength());
             masm.branch32(Assembler::AboveOrEqual, length, index, &bumpedLength);
             masm.storeKey(newLength, length);
             masm.bind(&bumpedLength);
 
             // Restore the index.
             masm.bumpKey(&newLength, -1);
-            masm.jump(&storeElem);
+            masm.jump(&postBarrier);
         }
         // else
         {
             // Mark old element.
             masm.bind(&markElem);
             if (cx->zone()->needsBarrier())
                 masm.callPreBarrier(target, MIRType_Value);
         }
 
         // Call post barrier if necessary, and recalculate elements pointer if it got cobbered.
+        masm.bind(&postBarrier);
         Register postBarrierScratch = elements;
         if (masm.maybeCallPostBarrier(object, value, postBarrierScratch))
             masm.loadPtr(Address(object, JSObject::offsetOfElements()), elements);
 
         // Store the value.
-        masm.bind(&storeElem);
         masm.storeConstantOrRegister(value, target);
     }
     attacher.jumpRejoin(masm);
 
     // All failures flow to here.
     masm.bind(&outOfBounds);
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -1300,30 +1300,30 @@ class LGetDynamicName : public LCallInst
     const LDefinition *temp2() {
         return getTemp(1);
     }
     const LDefinition *temp3() {
         return getTemp(2);
     }
 };
 
-class LFilterArguments : public LCallInstructionHelper<0, 1, 2>
-{
-  public:
-    LIR_HEADER(FilterArguments)
-
-    LFilterArguments(const LAllocation &string, const LDefinition &temp1, const LDefinition &temp2)
+class LFilterArgumentsOrEval : public LCallInstructionHelper<0, 1, 2>
+{
+  public:
+    LIR_HEADER(FilterArgumentsOrEval)
+
+    LFilterArgumentsOrEval(const LAllocation &string, const LDefinition &temp1, const LDefinition &temp2)
     {
         setOperand(0, string);
         setTemp(0, temp1);
         setTemp(1, temp2);
     }
 
-    MFilterArguments *mir() const {
-        return mir_->toFilterArguments();
+    MFilterArgumentsOrEval *mir() const {
+        return mir_->toFilterArgumentsOrEval();
     }
 
     const LAllocation *getString() {
         return getOperand(0);
     }
     const LDefinition *temp1() {
         return getTemp(0);
     }
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -43,17 +43,17 @@
     _(DefVar)                       \
     _(DefFun)                       \
     _(CallKnown)                    \
     _(CallGeneric)                  \
     _(CallNative)                   \
     _(ApplyArgsGeneric)             \
     _(Bail)                         \
     _(GetDynamicName)               \
-    _(FilterArguments)              \
+    _(FilterArgumentsOrEval)        \
     _(CallDirectEval)               \
     _(StackArgT)                    \
     _(StackArgV)                    \
     _(CreateThis)                   \
     _(CreateThisWithProto)          \
     _(CreateThisWithTemplate)       \
     _(CreateArgumentsObject)        \
     _(GetArgumentsObjectArg)        \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -537,24 +537,24 @@ LIRGenerator::visitGetDynamicName(MGetDy
                                                tempFixed(CallTempReg2),
                                                tempFixed(CallTempReg3),
                                                tempFixed(CallTempReg4));
 
     return assignSnapshot(lir) && defineReturn(lir, ins);
 }
 
 bool
-LIRGenerator::visitFilterArguments(MFilterArguments *ins)
+LIRGenerator::visitFilterArgumentsOrEval(MFilterArgumentsOrEval *ins)
 {
     MDefinition *string = ins->getString();
     JS_ASSERT(string->type() == MIRType_String);
 
-    LFilterArguments *lir = new LFilterArguments(useFixed(string, CallTempReg0),
-                                                 tempFixed(CallTempReg1),
-                                                 tempFixed(CallTempReg2));
+    LFilterArgumentsOrEval *lir = new LFilterArgumentsOrEval(useFixed(string, CallTempReg0),
+                                                             tempFixed(CallTempReg1),
+                                                             tempFixed(CallTempReg2));
 
     return assignSnapshot(lir) && add(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitCallDirectEval(MCallDirectEval *ins)
 {
     MDefinition *scopeChain = ins->getScopeChain();
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -110,17 +110,17 @@ class LIRGenerator : public LIRGenerator
     bool visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins);
     bool visitReturnFromCtor(MReturnFromCtor *ins);
     bool visitComputeThis(MComputeThis *ins);
     bool visitCall(MCall *call);
     bool visitApplyArgs(MApplyArgs *apply);
     bool visitBail(MBail *bail);
     bool visitAssertFloat32(MAssertFloat32 *ins);
     bool visitGetDynamicName(MGetDynamicName *ins);
-    bool visitFilterArguments(MFilterArguments *ins);
+    bool visitFilterArgumentsOrEval(MFilterArgumentsOrEval *ins);
     bool visitCallDirectEval(MCallDirectEval *ins);
     bool visitTest(MTest *test);
     bool visitFunctionDispatch(MFunctionDispatch *ins);
     bool visitTypeObjectDispatch(MTypeObjectDispatch *ins);
     bool visitCompare(MCompare *comp);
     bool visitTypeOf(MTypeOf *ins);
     bool visitToId(MToId *ins);
     bool visitBitNot(MBitNot *ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1972,35 +1972,34 @@ class MGetDynamicName
     TypePolicy *typePolicy() {
         return this;
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
-// Bailout if the input string contains 'arguments'
-class MFilterArguments
+// Bailout if the input string contains 'arguments' or 'eval'.
+class MFilterArgumentsOrEval
   : public MAryInstruction<1>,
     public StringPolicy<0>
 {
   protected:
-    MFilterArguments(MDefinition *string)
+    MFilterArgumentsOrEval(MDefinition *string)
     {
         setOperand(0, string);
         setGuard();
         setResultType(MIRType_None);
     }
 
   public:
-    INSTRUCTION_HEADER(FilterArguments)
-
-    static MFilterArguments *
-    New(MDefinition *string) {
-        return new MFilterArguments(string);
+    INSTRUCTION_HEADER(FilterArgumentsOrEval)
+
+    static MFilterArgumentsOrEval *New(MDefinition *string) {
+        return new MFilterArgumentsOrEval(string);
     }
 
     MDefinition *getString() const {
         return getOperand(0);
     }
 
     TypePolicy *typePolicy() {
         return this;
@@ -3967,22 +3966,18 @@ class MConcatPar
     {
         setMovable();
         setResultType(MIRType_String);
     }
 
   public:
     INSTRUCTION_HEADER(ConcatPar)
 
-    static MConcatPar *New(MDefinition *slice, MDefinition *left, MDefinition *right) {
-        return new MConcatPar(slice, left, right);
-    }
-
     static MConcatPar *New(MDefinition *slice, MConcat *concat) {
-        return New(slice, concat->lhs(), concat->rhs());
+        return new MConcatPar(slice, concat->lhs(), concat->rhs());
     }
 
     MDefinition *forkJoinSlice() const {
         return getOperand(0);
     }
     MDefinition *lhs() const {
         return getOperand(1);
     }
@@ -4548,16 +4543,23 @@ struct LambdaFunctionInfo
     LambdaFunctionInfo(JSFunction *fun)
       : fun(fun), flags(fun->flags),
         scriptOrLazyScript(fun->hasScript()
                            ? (gc::Cell *) fun->nonLazyScript()
                            : (gc::Cell *) fun->lazyScript()),
         singletonType(fun->hasSingletonType()),
         useNewTypeForClone(types::UseNewTypeForClone(fun))
     {}
+
+    LambdaFunctionInfo(const LambdaFunctionInfo &info)
+      : fun((JSFunction *) info.fun), flags(info.flags),
+        scriptOrLazyScript(info.scriptOrLazyScript),
+        singletonType(info.singletonType),
+        useNewTypeForClone(info.useNewTypeForClone)
+    {}
 };
 
 class MLambda
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
     LambdaFunctionInfo info_;
 
@@ -4588,35 +4590,31 @@ class MLambda
 
 class MLambdaPar
   : public MBinaryInstruction,
     public SingleObjectPolicy
 {
     LambdaFunctionInfo info_;
 
     MLambdaPar(MDefinition *slice, MDefinition *scopeChain, JSFunction *fun,
-               types::TemporaryTypeSet *resultTypes)
-      : MBinaryInstruction(slice, scopeChain), info_(fun)
-    {
-        JS_ASSERT(!fun->hasSingletonType());
-        JS_ASSERT(!types::UseNewTypeForClone(fun));
+               types::TemporaryTypeSet *resultTypes, const LambdaFunctionInfo &info)
+      : MBinaryInstruction(slice, scopeChain), info_(info)
+    {
+        JS_ASSERT(!info_.singletonType);
+        JS_ASSERT(!info_.useNewTypeForClone);
         setResultType(MIRType_Object);
         setResultTypeSet(resultTypes);
     }
 
   public:
     INSTRUCTION_HEADER(LambdaPar);
 
-    static MLambdaPar *New(MDefinition *slice, MDefinition *scopeChain, JSFunction *fun) {
-        return new MLambdaPar(slice, scopeChain, fun, MakeSingletonTypeSet(fun));
-    }
-
     static MLambdaPar *New(MDefinition *slice, MLambda *lambda) {
         return new MLambdaPar(slice, lambda->scopeChain(), lambda->info().fun,
-                              lambda->resultTypeSet());
+                              lambda->resultTypeSet(), lambda->info());
     }
 
     MDefinition *forkJoinSlice() const {
         return getOperand(0);
     }
 
     MDefinition *scopeChain() const {
         return getOperand(1);
@@ -7911,21 +7909,16 @@ class MRestPar
     {
         setResultType(MIRType_Object);
         setResultTypeSet(resultTypes);
     }
 
   public:
     INSTRUCTION_HEADER(RestPar);
 
-    static MRestPar *New(MDefinition *slice, MDefinition *numActuals, unsigned numFormals,
-                         JSObject *templateObject) {
-        return new MRestPar(slice, numActuals, numFormals, templateObject,
-                            MakeSingletonTypeSet(templateObject));
-    }
     static MRestPar *New(MDefinition *slice, MRest *rest) {
         return new MRestPar(slice, rest->numActuals(), rest->numFormals(),
                             rest->templateObject(), rest->resultTypeSet());
     }
 
     MDefinition *forkJoinSlice() const {
         return getOperand(0);
     }
@@ -8211,24 +8204,18 @@ class MNewCallObjectPar : public MBinary
           templateObj_(templateObj)
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(NewCallObjectPar);
 
-    static MNewCallObjectPar *New(MDefinition *slice, JSObject *templateObj,
-                                  MDefinition *slots)
-    {
-        return new MNewCallObjectPar(slice, templateObj, slots);
-    }
-
     static MNewCallObjectPar *New(MDefinition *slice, MNewCallObject *callObj) {
-        return New(slice, callObj->templateObject(), callObj->slots());
+        return new MNewCallObjectPar(slice, callObj->templateObject(), callObj->slots());
     }
 
     MDefinition *forkJoinSlice() const {
         return getOperand(0);
     }
 
     MDefinition *slots() const {
         return getOperand(1);
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -38,17 +38,17 @@ namespace jit {
     _(ComputeThis)                                                          \
     _(PrepareCall)                                                          \
     _(PassArg)                                                              \
     _(Call)                                                                 \
     _(ApplyArgs)                                                            \
     _(Bail)                                                                 \
     _(AssertFloat32)                                                        \
     _(GetDynamicName)                                                       \
-    _(FilterArguments)                                                      \
+    _(FilterArgumentsOrEval)                                                \
     _(CallDirectEval)                                                       \
     _(BitNot)                                                               \
     _(TypeOf)                                                               \
     _(ToId)                                                                 \
     _(BitAnd)                                                               \
     _(BitOr)                                                                \
     _(BitXor)                                                               \
     _(Lsh)                                                                  \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -131,17 +131,17 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(ComputeThis)
     SAFE_OP(PrepareCall)
     SAFE_OP(PassArg)
     CUSTOM_OP(Call)
     UNSAFE_OP(ApplyArgs)
     UNSAFE_OP(Bail)
     UNSAFE_OP(AssertFloat32)
     UNSAFE_OP(GetDynamicName)
-    UNSAFE_OP(FilterArguments)
+    UNSAFE_OP(FilterArgumentsOrEval)
     UNSAFE_OP(CallDirectEval)
     SAFE_OP(BitNot)
     UNSAFE_OP(TypeOf)
     SAFE_OP(ToId)
     SAFE_OP(BitAnd)
     SAFE_OP(BitOr)
     SAFE_OP(BitXor)
     SAFE_OP(Lsh)
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -611,28 +611,31 @@ GetDynamicName(JSContext *cx, JSObject *
         if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
             return;
     }
 
     vp->setUndefined();
 }
 
 bool
-FilterArguments(JSContext *cx, JSString *str)
+FilterArgumentsOrEval(JSContext *cx, JSString *str)
 {
     // getChars() is fallible, but cannot GC: it can only allocate a character
     // for the flattened string. If this call fails then the calling Ion code
     // will bailout, resume in the interpreter and likely fail again when
     // trying to flatten the string and unwind the stack.
     const jschar *chars = str->getChars(cx);
     if (!chars)
         return false;
 
     static const jschar arguments[] = {'a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's'};
-    return !StringHasPattern(chars, str->length(), arguments, mozilla::ArrayLength(arguments));
+    static const jschar eval[] = {'e', 'v', 'a', 'l'};
+
+    return !StringHasPattern(chars, str->length(), arguments, mozilla::ArrayLength(arguments)) &&
+        !StringHasPattern(chars, str->length(), eval, mozilla::ArrayLength(eval));
 }
 
 #ifdef JSGC_GENERATIONAL
 void
 PostWriteBarrier(JSRuntime *rt, JSObject *obj)
 {
     JS_ASSERT(!IsInsideNursery(rt, obj));
     rt->gcStoreBuffer.putWholeCell(obj);
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -623,17 +623,17 @@ bool OperatorIn(JSContext *cx, HandleVal
 bool OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out);
 
 bool GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval);
 
 bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval);
 
 void GetDynamicName(JSContext *cx, JSObject *scopeChain, JSString *str, Value *vp);
 
-bool FilterArguments(JSContext *cx, JSString *str);
+bool FilterArgumentsOrEval(JSContext *cx, JSString *str);
 
 #ifdef JSGC_GENERATIONAL
 void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
 void PostGlobalWriteBarrier(JSRuntime *rt, JSObject *obj);
 #endif
 
 uint32_t GetIndexFromString(JSString *str);
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -216,17 +216,17 @@ MSG_DEF(JSMSG_UNDEFINED_PROP,         16
 MSG_DEF(JSMSG_USELESS_EXPR,           163, 0, JSEXN_TYPEERR, "useless expression")
 MSG_DEF(JSMSG_REDECLARED_PARAM,       164, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
 MSG_DEF(JSMSG_NEWREGEXP_FLAGGED,      165, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
 MSG_DEF(JSMSG_RESERVED_SLOT_RANGE,    166, 0, JSEXN_RANGEERR, "reserved slot index out of range")
 MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode JSPrincipals")
 MSG_DEF(JSMSG_CANT_SEAL_OBJECT,       168, 1, JSEXN_ERR, "can't seal {0} objects")
 MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS,    169, 0, JSEXN_SYNTAXERR, "too many catch variables")
 MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 170, 0, JSEXN_RANGEERR, "repeat count must be non-negative")
-MSG_DEF(JSMSG_UNUSED171,              171, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_INVALID_FOR_OF_INIT,    171, 0, JSEXN_SYNTAXERR, "for-of loop variable declaration may not have an initializer")
 MSG_DEF(JSMSG_UNUSED172,              172, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED173,              173, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED174,              174, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_NESTING_GENERATOR,      175, 0, JSEXN_TYPEERR, "already executing generator")
 MSG_DEF(JSMSG_UNUSED176,              176, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED177,              177, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED178,              178, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED179,              179, 0, JSEXN_NONE, "")
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -32,17 +32,17 @@ struct OuterWrapper : js::Wrapper
 OuterWrapper
 OuterWrapper::singleton;
 
 static JSObject *
 wrap(JSContext *cx, JS::HandleObject toWrap, JS::HandleObject target)
 {
     JSAutoCompartment ac(cx, target);
     JS::RootedObject wrapper(cx, toWrap);
-    if (!JS_WrapObject(cx, wrapper.address()))
+    if (!JS_WrapObject(cx, &wrapper))
         return nullptr;
     return wrapper;
 }
 
 static JSObject *
 SameCompartmentWrap(JSContext *cx, JS::HandleObject obj)
 {
     JS_GC(JS_GetRuntime(cx));
--- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
+++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
@@ -72,17 +72,17 @@ BEGIN_TEST(test_CallNonGenericMethodOnPr
     JS::RootedFunction customMethodB(cx, JS_NewFunction(cx, CustomMethod, 0, 0, customB, "customMethodB"));
     CHECK(customMethodB);
 
     JS::RootedValue rval(cx);
     CHECK(JS_CallFunction(cx, customB, customMethodB, 0, nullptr, rval.address()));
     CHECK_SAME(rval, Int32Value(42));
 
     JS::RootedObject wrappedCustomA(cx, customA);
-    CHECK(JS_WrapObject(cx, wrappedCustomA.address()));
+    CHECK(JS_WrapObject(cx, &wrappedCustomA));
 
     JS::RootedValue rval2(cx);
     CHECK(JS_CallFunction(cx, wrappedCustomA, customMethodB, 0, nullptr, rval2.address()));
     CHECK_SAME(rval, Int32Value(42));
   }
 
   return true;
 }
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -154,17 +154,17 @@ BEGIN_TEST(testDebugger_debuggerObjectVs
 
     {
         JSAutoCompartment ae(cx, debuggee);
         CHECK(JS_SetDebugMode(cx, true));
         CHECK(JS_InitStandardClasses(cx, debuggee));
     }
 
     JS::RootedObject debuggeeWrapper(cx, debuggee);
-    CHECK(JS_WrapObject(cx, debuggeeWrapper.address()));
+    CHECK(JS_WrapObject(cx, &debuggeeWrapper));
     JS::RootedValue v(cx, JS::ObjectValue(*debuggeeWrapper));
     CHECK(JS_SetProperty(cx, global, "debuggee", v));
 
     EVAL("var dbg = new Debugger(debuggee);\n"
          "var hits = 0;\n"
          "dbg.onDebuggerStatement = function () { hits++; };\n"
          "debuggee.eval('debugger;');\n"
          "hits;\n",
@@ -192,17 +192,17 @@ BEGIN_TEST(testDebugger_newScriptHook)
     JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
     CHECK(g);
     {
         JSAutoCompartment ae(cx, g);
         CHECK(JS_InitStandardClasses(cx, g));
     }
 
     JS::RootedObject gWrapper(cx, g);
-    CHECK(JS_WrapObject(cx, gWrapper.address()));
+    CHECK(JS_WrapObject(cx, &gWrapper));
     JS::RootedValue v(cx, JS::ObjectValue(*gWrapper));
     CHECK(JS_SetProperty(cx, global, "g", v));
 
     EXEC("var dbg = Debugger(g);\n"
          "var hits = 0;\n"
          "dbg.onNewScript = function (s) {\n"
          "    hits += Number(s instanceof Debugger.Script);\n"
          "};\n");
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1131,27 +1131,23 @@ JS_SetCompartmentPrivate(JSCompartment *
 
 JS_PUBLIC_API(void *)
 JS_GetCompartmentPrivate(JSCompartment *compartment)
 {
     return compartment->data;
 }
 
 JS_PUBLIC_API(bool)
-JS_WrapObject(JSContext *cx, JSObject **objp)
+JS_WrapObject(JSContext *cx, MutableHandleObject objp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    RootedObject obj(cx, *objp);
-    if (obj)
-        JS::ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
-    if (!cx->compartment()->wrap(cx, &obj))
-        return false;
-    *objp = obj;
-    return true;
+    if (objp)
+        JS::ExposeGCThingToActiveJS(objp, JSTRACE_OBJECT);
+    return cx->compartment()->wrap(cx, objp);
 }
 
 JS_PUBLIC_API(bool)
 JS_WrapValue(JSContext *cx, jsval *vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (vp)
@@ -1253,17 +1249,17 @@ JS_TransplantObject(JSContext *cx, Handl
     // old object, and update the relevant cross-compartment wrappers.
     if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
         MOZ_CRASH();
 
     // Lastly, update the original object to point to the new one.
     if (origobj->compartment() != destination) {
         RootedObject newIdentityWrapper(cx, newIdentity);
         AutoCompartment ac(cx, origobj);
-        if (!JS_WrapObject(cx, newIdentityWrapper.address()))
+        if (!JS_WrapObject(cx, &newIdentityWrapper))
             MOZ_CRASH();
         JS_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
         if (!JSObject::swap(cx, origobj, newIdentityWrapper))
             MOZ_CRASH();
         origobj->compartment()->putWrapper(ObjectValue(*newIdentity), origv);
     }
 
     // The new identity object might be one of several things. Return it to avoid
@@ -1344,17 +1340,17 @@ js_TransplantObjectWithWrapper(JSContext
             options.setForceForegroundFinalization(true);
         RootedObject reflectorGuts(cx, NewDeadProxyObject(cx, JS_GetGlobalForObject(cx, origobj),
                                                           options));
         if (!reflectorGuts || !JSObject::swap(cx, origobj, reflectorGuts))
             MOZ_CRASH();
 
         // Turn origwrapper into a CCW to the new object.
         RootedObject wrapperGuts(cx, targetobj);
-        if (!JS_WrapObject(cx, wrapperGuts.address()))
+        if (!JS_WrapObject(cx, &wrapperGuts))
             MOZ_CRASH();
         JS_ASSERT(Wrapper::wrappedObject(wrapperGuts) == targetobj);
         if (!JSObject::swap(cx, origwrapper, wrapperGuts))
             MOZ_CRASH();
         origwrapper->compartment()->putWrapper(ObjectValue(*targetobj),
                                                ObjectValue(*origwrapper));
     }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1752,17 +1752,17 @@ JS_SetWrapObjectCallbacks(JSRuntime *rt,
 
 extern JS_PUBLIC_API(void)
 JS_SetCompartmentPrivate(JSCompartment *compartment, void *data);
 
 extern JS_PUBLIC_API(void *)
 JS_GetCompartmentPrivate(JSCompartment *compartment);
 
 extern JS_PUBLIC_API(bool)
-JS_WrapObject(JSContext *cx, JSObject **objp);
+JS_WrapObject(JSContext *cx, JS::MutableHandleObject objp);
 
 extern JS_PUBLIC_API(bool)
 JS_WrapValue(JSContext *cx, jsval *vp);
 
 extern JS_PUBLIC_API(bool)
 JS_WrapId(JSContext *cx, jsid *idp);
 
 extern JS_PUBLIC_API(JSObject *)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -634,17 +634,16 @@ ErrorFromException(JS::Value val);
  * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's
  * XDR_BYTECODE_VERSION.
  */
 #define JSITER_ENUMERATE  0x1   /* for-in compatible hidden default iterator */
 #define JSITER_FOREACH    0x2   /* return [key, value] pair rather than key */
 #define JSITER_KEYVALUE   0x4   /* destructuring for-in wants [key, value] */
 #define JSITER_OWNONLY    0x8   /* iterate over obj's own properties only */
 #define JSITER_HIDDEN     0x10  /* also enumerate non-enumerable properties */
-#define JSITER_FOR_OF     0x20  /* harmony for-of loop */
 
 JS_FRIEND_API(bool)
 RunningWithTrustedPrincipals(JSContext *cx);
 
 inline uintptr_t
 GetNativeStackLimit(JSContext *cx)
 {
     StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -559,47 +559,16 @@ UpdateNativeIterator(NativeIterator *ni,
     // Update the object for which the native iterator is associated, so
     // SuppressDeletedPropertyHelper will recognize the iterator as a match.
     ni->obj = obj;
 }
 
 bool
 js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp)
 {
-    if (flags == JSITER_FOR_OF) {
-        // for-of loop. The iterator is simply |obj[@@iterator]()|.
-        RootedValue method(cx);
-        if (!JSObject::getProperty(cx, obj, obj, cx->names().std_iterator, &method))
-            return false;
-
-        // Throw if obj[@@iterator] isn't callable. js::Invoke is about to check
-        // for this kind of error anyway, but it would throw an inscrutable
-        // error message about |method| rather than this nice one about |obj|.
-        if (!method.isObject() || !method.toObject().isCallable()) {
-            RootedValue val(cx, ObjectOrNullValue(obj));
-            char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
-            if (!bytes)
-                return false;
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes);
-            js_free(bytes);
-            return false;
-        }
-
-        if (!Invoke(cx, ObjectOrNullValue(obj), method, 0, nullptr, vp))
-            return false;
-
-        JSObject *resultObj = ToObject(cx, vp);
-        if (!resultObj)
-            return false;
-        vp.setObject(*resultObj);
-        return true;
-    }
-
-    JS_ASSERT(!(flags & JSITER_FOR_OF));
-
     Vector<Shape *, 8> shapes(cx);
     uint32_t key = 0;
 
     bool keysOnly = (flags == JSITER_ENUMERATE);
 
     if (obj) {
         if (JSIteratorOp op = obj->getClass()->ext.iteratorObject) {
             JSObject *iterobj = op(cx, obj, !(flags & JSITER_FOREACH));
@@ -1317,16 +1286,56 @@ const Class StopIterationObject::class_ 
     nullptr,                 /* finalize    */
     nullptr,                 /* checkAccess */
     nullptr,                 /* call        */
     stopiter_hasInstance,
     nullptr                  /* construct   */
 };
 
 bool
+ForOfIterator::init(HandleValue iterable)
+{
+    RootedObject iterableObj(cx, ToObject(cx, iterable));
+    if (!iterableObj)
+        return false;
+
+    // The iterator is the result of calling obj[@@iterator]().
+    InvokeArgs args(cx);
+    if (!args.init(0))
+        return false;
+    args.setThis(ObjectValue(*iterableObj));
+
+    RootedValue callee(cx);
+    if (!JSObject::getProperty(cx, iterableObj, iterableObj, cx->names().std_iterator, &callee))
+        return false;
+
+    // Throw if obj[@@iterator] isn't callable. js::Invoke is about to check
+    // for this kind of error anyway, but it would throw an inscrutable
+    // error message about |method| rather than this nice one about |obj|.
+    if (!callee.isObject() || !callee.toObject().isCallable()) {
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, NullPtr());
+        if (!bytes)
+            return false;
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes);
+        js_free(bytes);
+        return false;
+    }
+
+    args.setCallee(callee);
+    if (!Invoke(cx, args))
+        return false;
+
+    iterator = ToObject(cx, args.rval());
+    if (!iterator)
+        return false;
+
+    return true;
+}
+
+bool
 ForOfIterator::next(MutableHandleValue vp, bool *done)
 {
     JS_ASSERT(iterator);
 
     RootedValue method(cx);
     if (!JSObject::getProperty(cx, iterator, iterator, cx->names().next, &method))
         return false;
 
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -203,17 +203,17 @@ bool
 UnwindIteratorForException(JSContext *cx, js::HandleObject obj);
 
 void
 UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj);
 
 bool
 IteratorConstructor(JSContext *cx, unsigned argc, Value *vp);
 
-}
+} /* namespace js */
 
 extern bool
 js_SuppressDeletedProperty(JSContext *cx, js::HandleObject obj, jsid id);
 
 extern bool
 js_SuppressDeletedElement(JSContext *cx, js::HandleObject obj, uint32_t index);
 
 extern bool
@@ -260,24 +260,17 @@ class ForOfIterator
     RootedObject iterator;
 
     ForOfIterator(const ForOfIterator &) MOZ_DELETE;
     ForOfIterator &operator=(const ForOfIterator &) MOZ_DELETE;
 
   public:
     ForOfIterator(JSContext *cx) : cx(cx), iterator(cx) { }
 
-    bool init(HandleValue iterable) {
-        RootedValue iterv(cx, iterable);
-        if (!ValueToIterator(cx, JSITER_FOR_OF, &iterv))
-            return false;
-        iterator = &iterv.get().toObject();
-        return true;
-    }
-
+    bool init(HandleValue iterable);
     bool next(MutableHandleValue val, bool *done);
 };
 
 /*
  * Create an object of the form { value: VALUE, done: DONE }.
  * ES6 draft from 2013-09-05, section 25.4.3.4.
  */
 extern JSObject *
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -1541,18 +1541,20 @@ class ASTSerializer
         if (!pn) {
             dst.setMagic(JS_SERIALIZE_NO_NODE);
             return true;
         }
         return statement(pn, dst);
     }
 
     bool forInit(ParseNode *pn, MutableHandleValue dst);
-    bool forOfOrIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
-                   MutableHandleValue dst);
+    bool forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
+               MutableHandleValue dst);
+    bool forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
+               MutableHandleValue dst);
     bool statement(ParseNode *pn, MutableHandleValue dst);
     bool blockStatement(ParseNode *pn, MutableHandleValue dst);
     bool switchStatement(ParseNode *pn, MutableHandleValue dst);
     bool switchCase(ParseNode *pn, MutableHandleValue dst);
     bool tryStatement(ParseNode *pn, MutableHandleValue dst);
     bool catchClause(ParseNode *pn, bool *isGuarded, MutableHandleValue dst);
 
     bool optExpression(ParseNode *pn, MutableHandleValue dst) {
@@ -2013,27 +2015,34 @@ ASTSerializer::forInit(ParseNode *pn, Mu
     }
 
     return (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
            ? variableDeclaration(pn, false, dst)
            : expression(pn, dst);
 }
 
 bool
-ASTSerializer::forOfOrIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
+ASTSerializer::forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
+                         MutableHandleValue dst)
+{
+    RootedValue expr(cx);
+
+    return expression(head->pn_kid3, &expr) &&
+        builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst);
+}
+
+bool
+ASTSerializer::forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
                          MutableHandleValue dst)
 {
     RootedValue expr(cx);
     bool isForEach = loop->pn_iflags & JSITER_FOREACH;
-    bool isForOf = loop->pn_iflags & JSITER_FOR_OF;
-    JS_ASSERT(!isForOf || !isForEach);
 
     return expression(head->pn_kid3, &expr) &&
-        (isForOf ? builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst) :
-         builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst));
+        builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst);
 }
 
 bool
 ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst)
 {
     JS_CHECK_RECURSION(cx, return false);
     switch (pn->getKind()) {
       case PNK_MODULE:
@@ -2134,17 +2143,27 @@ ASTSerializer::statement(ParseNode *pn, 
 
         if (head->isKind(PNK_FORIN)) {
             RootedValue var(cx);
             return (!head->pn_kid1
                     ? pattern(head->pn_kid2, nullptr, &var)
                     : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
                     ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
                     : variableDeclaration(head->pn_kid1, false, &var)) &&
-                forOfOrIn(pn, head, var, stmt, dst);
+                forIn(pn, head, var, stmt, dst);
+        }
+
+        if (head->isKind(PNK_FOROF)) {
+            RootedValue var(cx);
+            return (!head->pn_kid1
+                    ? pattern(head->pn_kid2, nullptr, &var)
+                    : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
+                    ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
+                    : variableDeclaration(head->pn_kid1, false, &var)) &&
+                forOf(pn, head, var, stmt, dst);
         }
 
         RootedValue init(cx), test(cx), update(cx);
 
         return forInit(head->pn_kid1, &init) &&
                optExpression(head->pn_kid2, &test) &&
                optExpression(head->pn_kid3, &update) &&
                builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
@@ -2164,17 +2183,17 @@ ASTSerializer::statement(ParseNode *pn, 
         if (!variableDeclaration(prelude, false, &var))
             return false;
 
         ParseNode *head = loop->pn_left;
         JS_ASSERT(head->isKind(PNK_FORIN));
 
         RootedValue stmt(cx);
 
-        return statement(loop->pn_right, &stmt) && forOfOrIn(loop, head, var, stmt, dst);
+        return statement(loop->pn_right, &stmt) && forIn(loop, head, var, stmt, dst);
       }
 
       case PNK_BREAK:
       case PNK_CONTINUE:
       {
         RootedValue label(cx);
         RootedAtom pnAtom(cx, pn->pn_atom);
         return optIdentifier(pnAtom, nullptr, &label) &&
@@ -2257,20 +2276,20 @@ ASTSerializer::leftAssociate(ParseNode *
 
 bool
 ASTSerializer::comprehensionBlock(ParseNode *pn, MutableHandleValue dst)
 {
     LOCAL_ASSERT(pn->isArity(PN_BINARY));
 
     ParseNode *in = pn->pn_left;
 
-    LOCAL_ASSERT(in && in->isKind(PNK_FORIN));
+    LOCAL_ASSERT(in && (in->isKind(PNK_FORIN) || in->isKind(PNK_FOROF)));
 
     bool isForEach = pn->pn_iflags & JSITER_FOREACH;
-    bool isForOf = pn->pn_iflags & JSITER_FOR_OF;
+    bool isForOf = in->isKind(PNK_FOROF);
 
     RootedValue patt(cx), src(cx);
     return pattern(in->pn_kid2, nullptr, &patt) &&
            expression(in->pn_kid3, &src) &&
            builder.comprehensionBlock(patt, src, isForEach, isForOf, &in->pn_pos, dst);
 }
 
 bool
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -338,17 +338,17 @@ JS_NondeterministicGetWeakMapKeys(JSCont
     if (!arr)
         return false;
     ObjectValueMap *map = obj->as<WeakMapObject>().getMap();
     if (map) {
         // Prevent GC from mutating the weakmap while iterating.
         gc::AutoSuppressGC suppress(cx);
         for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
             RootedObject key(cx, r.front().key);
-            if (!JS_WrapObject(cx, key.address()))
+            if (!cx->compartment()->wrap(cx, &key))
                 return false;
             if (!js_NewbornArrayPush(cx, arr, ObjectValue(*key)))
                 return false;
         }
     }
     *ret = arr;
     return true;
 }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3729,17 +3729,17 @@ NewGlobalObject(JSContext *cx, JS::Compa
 
 static bool
 NewGlobal(JSContext *cx, unsigned argc, jsval *vp)
 {
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    if (argc == 1 && args[0].isObject()) {
+    if (args.length() == 1 && args[0].isObject()) {
         RootedObject opts(cx, &args[0].toObject());
         RootedValue v(cx);
 
         if (!JS_GetProperty(cx, opts, "sameZoneAs", &v))
             return false;
         if (v.isObject())
             options.setSameZoneAs(UncheckedUnwrap(&v.toObject()));
 
@@ -3748,20 +3748,20 @@ NewGlobal(JSContext *cx, unsigned argc, 
         if (v.isBoolean())
             options.setInvisibleToDebugger(v.toBoolean());
     }
 
     RootedObject global(cx, NewGlobalObject(cx, options));
     if (!global)
         return false;
 
-    if (!JS_WrapObject(cx, global.address()))
+    if (!JS_WrapObject(cx, &global))
         return false;
 
-    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(global));
+    args.rval().setObject(*global);
     return true;
 }
 
 static bool
 EnableStackWalkingAssertion(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (argc == 0 || !JSVAL_IS_BOOLEAN(JS_ARGV(cx, vp)[0])) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS,
--- a/js/src/tests/js1_8_5/extensions/reflect-parse.js
+++ b/js/src/tests/js1_8_5/extensions/reflect-parse.js
@@ -676,18 +676,16 @@ assertError("for (const [x,y,z] of foo);
 assertError("for each (const x in foo);", SyntaxError);
 assertError("for each (const {a:x,b:y,c:z} in foo);", SyntaxError);
 assertError("for each (const [x,y,z] in foo);", SyntaxError);
 
 // destructuring in for-in and for-each-in loop heads with initializers
 
 assertStmt("for (var {a:x,b:y,c:z} = 22 in foo);", forInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertStmt("for (var [x,y,z] = 22 in foo);", forInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
-assertStmt("for (var {a:x,b:y,c:z} = 22 of foo);", forOfStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
-assertStmt("for (var [x,y,z] = 22 of foo);", forOfStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertStmt("for each (var {a:x,b:y,c:z} = 22 in foo);", forEachInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertStmt("for each (var [x,y,z] = 22 in foo);", forEachInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
 assertError("for (x = 22 in foo);", SyntaxError);
 assertError("for ({a:x,b:y,c:z} = 22 in foo);", SyntaxError);
 assertError("for ([x,y,z] = 22 in foo);", SyntaxError);
 assertError("for (const x = 22 in foo);", SyntaxError);
 assertError("for (const {a:x,b:y,c:z} = 22 in foo);", SyntaxError);
 assertError("for (const [x,y,z] = 22 in foo);", SyntaxError);
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -450,16 +450,53 @@ class AutoSetForkJoinSlice
     ~AutoSetForkJoinSlice() {
         PR_SetThreadPrivate(ForkJoinSlice::ThreadPrivateIndex, nullptr);
     }
 };
 
 } // namespace js
 
 ///////////////////////////////////////////////////////////////////////////
+// ForkJoinActivation
+//
+// Takes care of tidying up GC before we enter a fork join section. Also
+// pauses the barrier verifier, as we cannot enter fork join with the runtime
+// or the zone needing barriers.
+
+ForkJoinActivation::ForkJoinActivation(JSContext *cx)
+  : Activation(cx, ForkJoin),
+    prevIonTop_(cx->mainThread().ionTop),
+    av_(cx->runtime(), false)
+{
+    // Note: we do not allow GC during parallel sections.
+    // Moreover, we do not wish to worry about making
+    // write barriers thread-safe.  Therefore, we guarantee
+    // that there is no incremental GC in progress and force
+    // a minor GC to ensure no cross-generation pointers get
+    // created:
+
+    if (JS::IsIncrementalGCInProgress(cx->runtime())) {
+        JS::PrepareForIncrementalGC(cx->runtime());
+        JS::FinishIncrementalGC(cx->runtime(), JS::gcreason::API);
+    }
+
+    MinorGC(cx->runtime(), JS::gcreason::API);
+
+    cx->runtime()->gcHelperThread.waitBackgroundSweepEnd();
+
+    JS_ASSERT(!cx->runtime()->needsBarrier());
+    JS_ASSERT(!cx->zone()->needsBarrier());
+}
+
+ForkJoinActivation::~ForkJoinActivation()
+{
+    cx_->mainThread().ionTop = prevIonTop_;
+}
+
+///////////////////////////////////////////////////////////////////////////
 // js::ForkJoin() and ParallelDo class
 //
 // These are the top-level objects that manage the parallel execution.
 // They handle parallel compilation (if necessary), triggering
 // parallel execution, and recovering from bailouts.
 
 static const char *ForkJoinModeString(ForkJoinMode mode);
 
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -4,16 +4,18 @@
  * 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 vm_ForkJoin_h
 #define vm_ForkJoin_h
 
 #include "jscntxt.h"
 
+#include "gc/GCInternals.h"
+
 #include "jit/Ion.h"
 
 ///////////////////////////////////////////////////////////////////////////
 // Read Me First
 //
 // The ForkJoin abstraction:
 // -------------------------
 //
@@ -194,16 +196,31 @@
 // - No load balancing is performed between worker threads.  That means that
 //   the fork-join system is best suited for problems that can be slice into
 //   uniform bits.
 //
 ///////////////////////////////////////////////////////////////////////////
 
 namespace js {
 
+class ForkJoinActivation : public Activation
+{
+    uint8_t *prevIonTop_;
+
+    // We ensure that incremental GC be finished before we enter into a fork
+    // join section, but the runtime/zone might still be marked as needing
+    // barriers due to being in the middle of verifying barriers. Pause
+    // verification during the fork join section.
+    gc::AutoStopVerifyingBarriers av_;
+
+  public:
+    ForkJoinActivation(JSContext *cx);
+    ~ForkJoinActivation();
+};
+
 class ForkJoinSlice;
 
 bool ForkJoin(JSContext *cx, CallArgs &args);
 
 // Returns the number of slices that a fork-join op will have when
 // executed.
 uint32_t ForkJoinSlices(JSContext *cx);
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1331,42 +1331,16 @@ jit::JitActivation::setActive(JSContext 
         prevIonJSContext_ = cx->mainThread().ionJSContext;
         cx->mainThread().ionJSContext = cx;
     } else {
         cx->mainThread().ionTop = prevIonTop_;
         cx->mainThread().ionJSContext = prevIonJSContext_;
     }
 }
 
-ForkJoinActivation::ForkJoinActivation(JSContext *cx)
-  : Activation(cx, ForkJoin),
-    prevIonTop_(cx->mainThread().ionTop)
-{
-    // Note: we do not allow GC during parallel sections.
-    // Moreover, we do not wish to worry about making
-    // write barriers thread-safe.  Therefore, we guarantee
-    // that there is no incremental GC in progress and force
-    // a minor GC to ensure no cross-generation pointers get
-    // created:
-
-    if (JS::IsIncrementalGCInProgress(cx->runtime())) {
-        JS::PrepareForIncrementalGC(cx->runtime());
-        JS::FinishIncrementalGC(cx->runtime(), JS::gcreason::API);
-    }
-
-    MinorGC(cx->runtime(), JS::gcreason::API);
-
-    cx->runtime()->gcHelperThread.waitBackgroundSweepEnd();
-}
-
-ForkJoinActivation::~ForkJoinActivation()
-{
-    cx_->mainThread().ionTop = prevIonTop_;
-}
-
 InterpreterFrameIterator &
 InterpreterFrameIterator::operator++()
 {
     JS_ASSERT(!done());
     if (fp_ != activation_->entry_) {
         pc_ = fp_->prevpc();
         sp_ = fp_->prevsp();
         fp_ = fp_->prev();
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1395,25 +1395,16 @@ class JitActivationIterator : public Act
     }
 
     // Returns the bottom and top addresses of the current JitActivation.
     void jitStackRange(uintptr_t *&min, uintptr_t *&end);
 };
 
 } // namespace jit
 
-class ForkJoinActivation : public Activation
-{
-    uint8_t *prevIonTop_;
-
-  public:
-    ForkJoinActivation(JSContext *cx);
-    ~ForkJoinActivation();
-};
-
 // Iterates over the frames of a single InterpreterActivation.
 class InterpreterFrameIterator
 {
     InterpreterActivation *activation_;
     StackFrame *fp_;
     jsbytecode *pc_;
     Value *sp_;
 
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -1094,17 +1094,17 @@ mozJSComponentLoader::Import(const nsACS
     if (targetObject) {
         ac.construct(cx, targetObject);
     }
 
     RootedObject global(cx);
     nsresult rv = ImportInto(registryLocation, targetObject, cx, &global);
 
     if (global) {
-        if (!JS_WrapObject(cx, global.address())) {
+        if (!JS_WrapObject(cx, &global)) {
             NS_ERROR("can't wrap return value");
             return NS_ERROR_FAILURE;
         }
 
         *retval = ObjectValue(*global);
     }
     return rv;
 }
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -275,17 +275,17 @@ ExportFunction(JSContext *cx, unsigned a
         if (!JS_ObjectIsCallable(cx, funObj)) {
             JS_ReportError(cx, "First argument must be a function");
             return false;
         }
 
         // The function forwarder will live in the target compartment. Since
         // this function will be referenced from its private slot, to avoid a
         // GC hazard, we must wrap it to the same compartment.
-        if (!JS_WrapObject(cx, funObj.address()))
+        if (!JS_WrapObject(cx, &funObj))
             return false;
 
         RootedId id(cx);
         if (!JS_ValueToId(cx, args[2], id.address()))
             return false;
 
         // And now, let's create the forwarder function in the target compartment
         // for the function the be exported.
@@ -343,17 +343,18 @@ CloneNonReflectorsRead(JSContext *cx, JS
         MOZ_ASSERT(!data);
 
         size_t idx;
         if (JS_ReadBytes(reader, &idx, sizeof(size_t))) {
             RootedObject reflector(cx, reflectors->handleAt(idx));
             MOZ_ASSERT(reflector, "No object pointer?");
             MOZ_ASSERT(IsReflector(reflector), "Object pointer must be a reflector!");
 
-            JS_WrapObject(cx, reflector.address());
+            if (!JS_WrapObject(cx, &reflector))
+                return nullptr;
             JS_ASSERT(WrapperFactory::IsXrayWrapper(reflector) ||
                       IsReflector(reflector));
 
             return reflector;
         }
     }
 
     JS_ReportError(cx, "CloneNonReflectorsRead error");
@@ -1001,17 +1002,17 @@ xpc::CreateSandboxObject(JSContext *cx, 
     // benefit. So we just switch it off here.
     xpc::GetCompartmentPrivate(sandbox)->wantXrays =
       AccessCheck::isChrome(sandbox) ? false : options.wantXrays;
 
     {
         JSAutoCompartment ac(cx, sandbox);
 
         if (options.proto) {
-            bool ok = JS_WrapObject(cx, options.proto.address());
+            bool ok = JS_WrapObject(cx, &options.proto);
             if (!ok)
                 return NS_ERROR_XPC_UNEXPECTED;
 
             if (xpc::WrapperFactory::IsXrayWrapper(options.proto) && !options.wantXrays) {
                 RootedValue v(cx, ObjectValue(*options.proto));
                 if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, v.address()))
                     return NS_ERROR_FAILURE;
                 options.proto = &v.toObject();
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2977,39 +2977,42 @@ nsXPCComponents_Utils::GetJSTestingFunct
 }
 
 /* void getGlobalForObject(); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetGlobalForObject(const Value& object,
                                           JSContext *cx,
                                           Value *retval)
 {
-  // First argument must be an object.
-  if (JSVAL_IS_PRIMITIVE(object))
-    return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-  // Wrappers are parented to their the global in their home compartment. But
-  // when getting the global for a cross-compartment wrapper, we really want
-  // a wrapper for the foreign global. So we need to unwrap before getting the
-  // parent, enter the compartment for the duration of the call, and wrap the
-  // result.
-  Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(object));
-  obj = js::UncheckedUnwrap(obj);
-  {
-    JSAutoCompartment ac(cx, obj);
-    obj = JS_GetGlobalForObject(cx, obj);
-  }
-  JS_WrapObject(cx, obj.address());
-  *retval = OBJECT_TO_JSVAL(obj);
-
-  // Outerize if necessary.
-  if (JSObjectOp outerize = js::GetObjectClass(obj)->ext.outerObject)
+    // First argument must be an object.
+    if (JSVAL_IS_PRIMITIVE(object))
+        return NS_ERROR_XPC_BAD_CONVERT_JS;
+
+    // Wrappers are parented to their the global in their home compartment. But
+    // when getting the global for a cross-compartment wrapper, we really want
+    // a wrapper for the foreign global. So we need to unwrap before getting the
+    // parent, enter the compartment for the duration of the call, and wrap the
+    // result.
+    Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(object));
+    obj = js::UncheckedUnwrap(obj);
+    {
+        JSAutoCompartment ac(cx, obj);
+        obj = JS_GetGlobalForObject(cx, obj);
+    }
+
+    if (!JS_WrapObject(cx, &obj))
+        return NS_ERROR_FAILURE;
+
+    *retval = OBJECT_TO_JSVAL(obj);
+
+    // Outerize if necessary.
+    if (JSObjectOp outerize = js::GetObjectClass(obj)->ext.outerObject)
       *retval = OBJECT_TO_JSVAL(outerize(cx, obj));
 
-  return NS_OK;
+    return NS_OK;
 }
 
 /* jsval createObjectIn(in jsval vobj); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::CreateObjectIn(const Value &vobj, JSContext *cx, Value *rval)
 {
     if (!cx)
         return NS_ERROR_FAILURE;
@@ -3022,17 +3025,17 @@ nsXPCComponents_Utils::CreateObjectIn(co
     RootedObject obj(cx);
     {
         JSAutoCompartment ac(cx, scope);
         obj = JS_NewObject(cx, nullptr, nullptr, scope);
         if (!obj)
             return NS_ERROR_FAILURE;
     }
 
-    if (!JS_WrapObject(cx, obj.address()))
+    if (!JS_WrapObject(cx, &obj))
         return NS_ERROR_FAILURE;
 
     *rval = ObjectValue(*obj);
     return NS_OK;
 }
 
 /* jsval createObjectIn(in jsval vobj); */
 NS_IMETHODIMP
@@ -3049,17 +3052,17 @@ nsXPCComponents_Utils::CreateArrayIn(con
     RootedObject obj(cx);
     {
         JSAutoCompartment ac(cx, scope);
         obj =  JS_NewArrayObject(cx, 0, nullptr);
         if (!obj)
             return NS_ERROR_FAILURE;
     }
 
-    if (!JS_WrapObject(cx, obj.address()))
+    if (!JS_WrapObject(cx, &obj))
         return NS_ERROR_FAILURE;
 
     *rval = ObjectValue(*obj);
     return NS_OK;
 }
 
 /* jsval createDateIn(in jsval vobj, in long long msec); */
 NS_IMETHODIMP
@@ -3076,18 +3079,19 @@ nsXPCComponents_Utils::CreateDateIn(cons
     {
         JSObject *scope = js::UncheckedUnwrap(&vobj.toObject());
         JSAutoCompartment ac(cx, scope);
         obj =  JS_NewDateObjectMsec(cx, msec);
         if (!obj)
             return NS_ERROR_FAILURE;
     }
 
-    if (!JS_WrapObject(cx, obj.address()))
+    if (!JS_WrapObject(cx, &obj))
         return NS_ERROR_FAILURE;
+
     *rval = ObjectValue(*obj);
     return NS_OK;
 }
 
 /* void makeObjectPropsNormal(jsval vobj); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::MakeObjectPropsNormal(const Value &vobj, JSContext *cx)
 {
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -836,32 +836,32 @@ XPCConvert::NativeInterface2JSObject(jsv
         if (cache->IsDOMBinding()) {
             if (!flat) {
                 JS::Rooted<JSObject*> global(cx, xpcscope->GetGlobalJSObject());
                 flat = cache->WrapObject(cx, global);
                 if (!flat)
                     return false;
             }
 
-            if (allowNativeWrapper && !JS_WrapObject(cx, flat.address()))
+            if (allowNativeWrapper && !JS_WrapObject(cx, &flat))
                 return false;
 
             return CreateHolderIfNeeded(flat, d, dest);
         }
     } else {
         flat = nullptr;
     }
 
     // Don't double wrap CPOWs. This is a temporary measure for compatibility
     // with objects that don't provide necessary QIs (such as objects under
     // the new DOM bindings). We expect the other side of the CPOW to have
     // the appropriate wrappers in place.
     RootedObject cpow(cx, UnwrapNativeCPOW(aHelper.Object()));
     if (cpow) {
-        if (!JS_WrapObject(cx, cpow.address()))
+        if (!JS_WrapObject(cx, &cpow))
             return false;
         *d = JS::ObjectValue(*cpow);
         return true;
     }
 
     // We can't simply construct a slim wrapper. Go ahead and create an
     // XPCWrappedNative for this object. At this point, |flat| could be
     // non-null, meaning that either we already have a wrapped native from
@@ -926,17 +926,17 @@ XPCConvert::NativeInterface2JSObject(jsv
         if (pErr)
             *pErr = NS_OK;
         return true;
     }
 
     // The call to wrap here handles both cross-compartment and same-compartment
     // security wrappers.
     RootedObject original(cx, flat);
-    if (!JS_WrapObject(cx, flat.address()))
+    if (!JS_WrapObject(cx, &flat))
         return false;
 
     *d = OBJECT_TO_JSVAL(flat);
 
     if (dest) {
         // The strongWrapper still holds the original flat object.
         if (flat == original) {
             *dest = strongWrapper.forget().get();
--- a/js/xpconnect/src/XPCJSWeakReference.cpp
+++ b/js/xpconnect/src/XPCJSWeakReference.cpp
@@ -80,15 +80,15 @@ xpcJSWeakReference::Get(JSContext* aCx, 
         return NS_OK;
     }
 
     // Most users of XPCWrappedJS don't need to worry about
     // re-wrapping because things are implicitly rewrapped by
     // xpcconvert. However, because we're doing this directly
     // through the native call context, we need to call
     // JS_WrapObject().
-    if (!JS_WrapObject(aCx, obj.address())) {
+    if (!JS_WrapObject(aCx, &obj)) {
         return NS_ERROR_FAILURE;
     }
 
     *aRetval = OBJECT_TO_JSVAL(obj);
     return NS_OK;
 }
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1231,17 +1231,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
                                 bool ok =
                                   XPCConvert::NativeInterface2JSObject(
                                       v.address(), nullptr, helper, nullptr,
                                       nullptr, false, nullptr);
                                 if (!ok) {
                                     goto pre_call_clean_up;
                                 }
                                 thisObj = JSVAL_TO_OBJECT(v);
-                                if (!JS_WrapObject(cx, thisObj.address()))
+                                if (!JS_WrapObject(cx, &thisObj))
                                     goto pre_call_clean_up;
                             }
                         }
                     }
                 }
             }
         } else {
             if (!JS_GetProperty(cx, obj, name, &fval))
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -210,17 +210,17 @@ XPCWrappedNativeScope::GetComponentsJSOb
     nsCOMPtr<XPCWrappedNative> wrapper;
     XPCWrappedNative::GetNewOrUsed(helper, this, iface, getter_AddRefs(wrapper));
     if (!wrapper)
         return nullptr;
 
     // The call to wrap() here is necessary even though the object is same-
     // compartment, because it applies our security wrapper.
     JS::RootedObject obj(cx, wrapper->GetFlatJSObject());
-    if (!JS_WrapObject(cx, obj.address()))
+    if (!JS_WrapObject(cx, &obj))
         return nullptr;
     return obj;
 }
 
 JSObject*
 XPCWrappedNativeScope::EnsureXBLScope(JSContext *cx)
 {
     JS::RootedObject global(cx, GetGlobalJSObject());
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -79,17 +79,17 @@ WrapperFactory::CreateXrayWaiver(JSConte
     RootedObject proto(cx);
     if (!js::GetObjectProto(cx, obj, &proto))
         return nullptr;
     if (proto && !(proto = WaiveXray(cx, proto)))
         return nullptr;
 
     // Create the waiver.
     JSAutoCompartment ac(cx, obj);
-    if (!JS_WrapObject(cx, proto.address()))
+    if (!JS_WrapObject(cx, &proto))
         return nullptr;
     JSObject *waiver = Wrapper::New(cx, obj, proto,
                                     JS_GetGlobalForObject(cx, obj),
                                     &XrayWaiver);
     if (!waiver)
         return nullptr;
 
     // Add the new waiver to the map. It's important that we only ever have
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -374,17 +374,17 @@ JSObject *
 XrayTraits::getExpandoObjectInternal(JSContext *cx, HandleObject target,
                                      nsIPrincipal *origin,
                                      JSObject *exclusiveGlobalArg)
 {
     // The expando object lives in the compartment of the target, so all our
     // work needs to happen there.
     RootedObject exclusiveGlobal(cx, exclusiveGlobalArg);
     JSAutoCompartment ac(cx, target);
-    if (!JS_WrapObject(cx, exclusiveGlobal.address()))
+    if (!JS_WrapObject(cx, &exclusiveGlobal))
         return nullptr;
 
     // Iterate through the chain, looking for a same-origin object.
     RootedObject head(cx, getExpandoChain(target));
     while (head) {
         if (expandoObjectMatchesConsumer(cx, head, origin, exclusiveGlobal))
             return head;
         head = JS_GetReservedSlot(head, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
@@ -452,17 +452,17 @@ XrayTraits::ensureExpandoObject(JSContex
     if (!expandoObject) {
         // If the object is a sandbox, we don't want it to share expandos with
         // anyone else, so we tag it with the sandbox global.
         //
         // NB: We first need to check the class, _then_ wrap for the target's
         // compartment.
         RootedObject consumerGlobal(cx, js::GetGlobalForObjectCrossCompartment(wrapper));
         bool isSandbox = !strcmp(js::GetObjectJSClass(consumerGlobal)->name, "Sandbox");
-        if (!JS_WrapObject(cx, consumerGlobal.address()))
+        if (!JS_WrapObject(cx, &consumerGlobal))
             return nullptr;
         expandoObject = attachExpandoObject(cx, target, ObjectPrincipal(wrapper),
                                             isSandbox ? (HandleObject)consumerGlobal : NullPtr());
     }
     return expandoObject;
 }
 
 bool
@@ -471,17 +471,17 @@ XrayTraits::cloneExpandoChain(JSContext 
     MOZ_ASSERT(js::IsObjectInContextCompartment(dst, cx));
     MOZ_ASSERT(getExpandoChain(dst) == nullptr);
 
     RootedObject oldHead(cx, getExpandoChain(src));
     while (oldHead) {
         RootedObject exclusive(cx, JS_GetReservedSlot(oldHead,
                                                       JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL)
                                                      .toObjectOrNull());
-        if (!JS_WrapObject(cx, exclusive.address()))
+        if (!JS_WrapObject(cx, &exclusive))
             return false;
         JSObject *newHead = attachExpandoObject(cx, dst, GetExpandoObjectPrincipal(oldHead),
                                                 exclusive);
         if (!JS_CopyPropertiesFrom(cx, newHead, oldHead))
             return false;
         oldHead = JS_GetReservedSlot(oldHead, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
     }
     return true;
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -736,20 +736,16 @@ nsPresContext::GetUserPreferences()
     Preferences::GetInt("browser.display.focus_ring_style", mFocusRingStyle);
 
   mBodyTextColor = mDefaultColor;
   
   // * use fonts?
   mUseDocumentFonts =
     Preferences::GetInt("browser.display.use_document_fonts") != 0;
 
-  // * replace backslashes with Yen signs? (bug 245770)
-  mEnableJapaneseTransform =
-    Preferences::GetBool("layout.enable_japanese_specific_transform");
-
   mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
 
   ResetCachedFontPrefs();
 
   // * image animation
   const nsAdoptingCString& animatePref =
     Preferences::GetCString("image.animation_mode");
   if (animatePref.Equals("normal"))
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1242,17 +1242,16 @@ protected:
   unsigned              mFocusRingStyle : 1;
   unsigned              mDrawImageBackground : 1;
   unsigned              mDrawColorBackground : 1;
   unsigned              mNeverAnimate : 1;
   unsigned              mIsRenderingOnlySelection : 1;
   unsigned              mPaginated : 1;
   unsigned              mCanPaginatedScroll : 1;
   unsigned              mDoScaledTwips : 1;
-  unsigned              mEnableJapaneseTransform : 1;
   unsigned              mIsRootPaginatedDocument : 1;
   unsigned              mPrefBidiDirection : 1;
   unsigned              mPrefScrollbarSide : 2;
   unsigned              mPendingSysColorChanged : 1;
   unsigned              mPendingThemeChanged : 1;
   unsigned              mPendingUIResolutionChanged : 1;
   unsigned              mPendingMediaFeatureValuesChanged : 1;
   unsigned              mPrefChangePendingNeedsReflow : 1;
--- a/layout/generic/nsTextFrameUtils.cpp
+++ b/layout/generic/nsTextFrameUtils.cpp
@@ -7,24 +7,16 @@
 
 #include "nsUnicharUtils.h"
 #include "nsBidiUtils.h"
 #include "nsIContent.h"
 #include "nsStyleStruct.h"
 #include "nsTextFragment.h"
 #include <algorithm>
 
-// XXX TODO implement transform of backslash to yen that nsTextTransform does
-// when requested by PresContext->LanguageSpecificTransformType(). Do it with
-// a new factory type that just munges the input stream. But first, check
-// that we really still need this, it's only enabled via a hidden pref
-// which defaults false...
-
-#define UNICODE_ZWSP 0x200B
-  
 static bool IsDiscardable(PRUnichar ch, uint32_t* aFlags)
 {
   // Unlike IS_DISCARDABLE, we don't discard \r. \r will be ignored by gfxTextRun
   // and discarding it would force us to copy text in many cases of preformatted
   // text containing \r\n.
   if (ch == CH_SHY) {
     *aFlags |= nsTextFrameUtils::TEXT_HAS_SHY;
     return true;
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1555,17 +1555,17 @@ random-if(!winWidget) == 574907-2.html 5
 random-if(!winWidget) fails-if(winWidget&&!d2d) random-if(winWidget&&d2d) != 574907-3.html 574907-3-notref.html
 == 577838-1.html 577838-1-ref.html
 == 577838-2.html 577838-2-ref.html
 fails-if(Android) == 579323-1.html 579323-1-ref.html
 == 579349-1.html 579349-1-ref.html
 == 579655-1.html 579655-1-ref.html
 skip-if(B2G) fails-if(Android) == 579808-1.html 579808-1-ref.html
 skip-if(B2G) fails-if(Android) random-if(layersGPUAccelerated) == 579985-1.html 579985-1-ref.html # bug 623452 for WinXP; this bug was only for a regression in BasicLayers anyway
-skip-if(B2G) fails-if(Android) == 580160-1.html 580160-1-ref.html
+skip-if(B2G) skip-if(Android) == 580160-1.html 580160-1-ref.html # bug 920927 for Android; issues without the test-plugin
 HTTP(..) == 580863-1.html 580863-1-ref.html
 skip-if(B2G) fails-if(Android) random-if(layersGPUAccelerated) fails-if(/^Windows\x20NT\x205\.1/.test(http.oscpu))  == 581317-1.html 581317-1-ref.html # bug 623456 for WinXP
 == 581579-1.html 581579-1-ref.html
 == 582037-1a.html 582037-1-ref.html
 == 582037-1b.html 582037-1-ref.html
 skip-if(B2G) == 582037-2a.html 582037-2-ref.html
 skip-if(B2G) == 582037-2b.html 582037-2-ref.html
 asserts(1-2) == 582146-1.html about:blank
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -48,17 +48,16 @@
         './src/softphonewrapper',
         './src/peerconnection',
         './include',
         './src/sipcc/include',
         './src/sipcc/cpr/include',
         '../../../ipc/chromium/src',
         '../../../ipc/chromium/src/base/third_party/nspr',
         '../../../xpcom/base',
-        '$(DEPTH)/dist/include',
         '../../../dom/base',
         '../../../content/media',
         '../../../media/mtransport',
         '../trunk',
         '../trunk/webrtc/video_engine/include',
         '../trunk/webrtc/voice_engine/include',
         '../trunk/webrtc/modules/interface',
         '../trunk/webrtc/peerconnection',
@@ -281,17 +280,16 @@
         './src/sipcc/core/ccapp',
         './src/sipcc/core/sdp',
         './src/sipcc/core/gsm/h',
         './src/sipcc/plat/common',
         '../../../media/mtransport',
         '../../../dom/base',
         '../trunk/third_party/libsrtp/srtp/include',
         '../trunk/third_party/libsrtp/srtp/crypto/include',
-        '$(DEPTH)/dist/include',
         # Danger: this is to include config.h. This could be bad.
         '../trunk/third_party/libsrtp/config',
       ],
 
       #
       # DEPENDENCIES
       #
       'dependencies': [
--- a/media/webrtc/trunk/third_party/libyuv/libyuv.gyp
+++ b/media/webrtc/trunk/third_party/libyuv/libyuv.gyp
@@ -22,23 +22,16 @@
              '<(DEPTH)/third_party/libjpeg_turbo/libjpeg.gyp:libjpeg',
           ],
         }, {
           'link_settings': {
             'libraries': [
               '-ljpeg',
             ],
           },
-          'conditions': [
-            ['build_with_mozilla==1', {
-              'include_dirs': [
-                '$(DEPTH)/dist/include',
-              ],
-            }],
-          ],
         }],
       ],
       'defines': [
         'HAVE_JPEG',
         # 'LIBYUV_BUILDING_SHARED_LIBRARY',
       ],
       'include_dirs': [
         'include',
@@ -51,26 +44,16 @@
         ],
       },
       'conditions': [
         ['yuv_disable_asm==1', {
           'defines': [
             'YUV_DISABLE_ASM',
           ],
         }],
-        ['build_with_mozilla==1', {
-          'include_dirs': [
-            '$(DEPTH)/dist/include',
-          ],
-          'direct_dependent_settings': {
-            'include_dirs': [
-              '$(DEPTH)/dist/include',
-            ],
-          },
-        }],
       ],
       'sources': [
         # includes.
         'include/libyuv.h',
         'include/libyuv/basic_types.h',
         'include/libyuv/compare.h',
         'include/libyuv/convert.h',
         'include/libyuv/convert_argb.h',
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/mozmake.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/mozmake.py
@@ -71,20 +71,18 @@ ifeq (WINNT,$(OS_TARGET))
 # These get set via VC project file settings for normal GYP builds.
 DEFINES += -DUNICODE -D_UNICODE
 LOCAL_INCLUDES += -I"$(MOZ_DIRECTX_SDK_PATH)/include"
 endif
 
 # Don't use STL wrappers when compiling Google code.
 STL_FLAGS =
 
-# Skip Mozilla-specific include locations.
-# Specific GYP files can add them back by adding
-# $(DIST)/include to their includes.
-INCLUDES = -I. $(LOCAL_INCLUDES)
+# Skip most Mozilla-specific include locations.
+INCLUDES = -I. $(LOCAL_INCLUDES) -I$(DEPTH)/dist/include
 
 # Ensure that subdirs for sources get created before compiling
 ifdef OBJS
 SUB_SRCDIRS := $(addsuffix .dirstamp,$(addprefix $(CURDIR)/,$(sort $(dir $(OBJS)))))
 $(OBJS): $(SUB_SRCDIRS)
 $(SUB_SRCDIRS):
 	$(MKDIR) -p $(dir $@)
 	touch $@
--- a/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp
+++ b/media/webrtc/trunk/webrtc/common_audio/common_audio.gyp
@@ -16,36 +16,22 @@
       'type': 'static_library',
       'dependencies': [
         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
       ],
       'include_dirs': [
         'resampler/include',
         'signal_processing/include',
       ],
-      'target_conditions': [
-        ['build_with_mozilla==1', {
-          'include_dirs': [
-            '$(DEPTH)/dist/include',
-          ],
-        }],
-      ],
       'direct_dependent_settings': {
         'include_dirs': [
           'resampler/include',
           'signal_processing/include',
           'vad/include',
         ],
-        'conditions': [
-          ['build_with_mozilla==1', {
-            'include_dirs': [
-              '$(DEPTH)/dist/include',
-            ],
-          }],
-        ],
       },
       'sources': [
         'audio_util.cc',
         'include/audio_util.h',
         'resampler/include/push_resampler.h',
         'resampler/include/resampler.h',
         'resampler/push_resampler.cc',
         'resampler/push_sinc_resampler.cc',
--- a/media/webrtc/trunk/webrtc/modules/video_capture/video_capture.gypi
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/video_capture.gypi
@@ -20,18 +20,16 @@
       'cflags_mozilla': [
         '$(NSPR_CFLAGS)',
       ],
 
       'include_dirs': [
         'include',
         '../interface',
         '<(webrtc_root)/common_video/libyuv/include',
-# added for mozilla for use_system_libjpeg
-        '$(DIST)/include',
       ],
       'sources': [
         'device_info_impl.cc',
         'device_info_impl.h',
         'include/video_capture.h',
         'include/video_capture_defines.h',
         'include/video_capture_factory.h',
         'video_capture_config.h',
--- a/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/vp8.gyp
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/codecs/vp8/vp8.gyp
@@ -26,19 +26,16 @@
         '<(webrtc_root)/modules/interface',
       ],
       'conditions': [
         ['build_libvpx==1', {
           'dependencies': [
             '<(DEPTH)/third_party/libvpx/libvpx.gyp:libvpx',
           ],
         },{
-          'include_dirs': [
-            '$(DIST)/include',
-          ],
           'link_settings': {
             'libraries': [
               '$(LIBVPX_OBJ)/libvpx.a',
             ],
           },
         }],
       ],
       'direct_dependent_settings': {
--- a/mfbt/Char16.h
+++ b/mfbt/Char16.h
@@ -4,18 +4,16 @@
  * 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/. */
 
 /* Implements a UTF-16 character type. */
 
 #ifndef mozilla_Char16_h
 #define mozilla_Char16_h
 
-#include "mozilla/Assertions.h"
-
 /*
  * C11 and C++11 introduce a char16_t type and support for UTF-16 string and
  * character literals. C++11's char16_t is a distinct builtin type. C11's
  * char16_t is a typedef for uint_least16_t. Technically, char16_t is a 16-bit
  * code unit of a Unicode code point, not a "character".
  *
  * For now, Char16.h only supports C++ because we don't want mix different C
  * and C++ definitions of char16_t in the same code base.
--- a/mfbt/HashFunctions.h
+++ b/mfbt/HashFunctions.h
@@ -43,16 +43,17 @@
  * in nsHashKeys.h.
  */
 
 #ifndef mozilla_HashFunctions_h
 #define mozilla_HashFunctions_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Char16.h"
 #include "mozilla/Types.h"
 
 #include <stdint.h>
 
 #ifdef __cplusplus
 namespace mozilla {
 
 /**
@@ -321,16 +322,32 @@ HashString(const uint16_t* str)
 
 MOZ_WARN_UNUSED_RESULT
 inline uint32_t
 HashString(const uint16_t* str, size_t length)
 {
   return detail::HashKnownLength(str, length);
 }
 
+#ifdef MOZ_CHAR16_IS_NOT_WCHAR
+MOZ_WARN_UNUSED_RESULT
+inline uint32_t
+HashString(const char16_t* str)
+{
+  return detail::HashUntilZero(str);
+}
+
+MOZ_WARN_UNUSED_RESULT
+inline uint32_t
+HashString(const char16_t* str, size_t length)
+{
+  return detail::HashKnownLength(str, length);
+}
+#endif
+
 /*
  * On Windows, wchar_t (PRUnichar) is not the same as uint16_t, even though it's
  * the same width!
  */
 #ifdef WIN32
 MOZ_WARN_UNUSED_RESULT
 inline uint32_t
 HashString(const wchar_t* str)
--- a/mfbt/NullPtr.h
+++ b/mfbt/NullPtr.h
@@ -7,27 +7,26 @@
 /*
  * Implements a workaround for compilers which do not support the C++11 nullptr
  * constant.
  */
 
 #ifndef mozilla_NullPtr_h
 #define mozilla_NullPtr_h
 
-#include "mozilla/Compiler.h"
-
 #if defined(__clang__)
 #  ifndef __has_extension
 #    define __has_extension __has_feature
 #  endif
 #  if __has_extension(cxx_nullptr)
 #    define MOZ_HAVE_CXX11_NULLPTR
 #  endif
 #elif defined(__GNUC__)
 #  if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
+#    include "mozilla/Compiler.h"
 #    if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0)
 #      define MOZ_HAVE_CXX11_NULLPTR
 #    endif
 #  endif
 #elif _MSC_VER >= 1600
 # define MOZ_HAVE_CXX11_NULLPTR
 #endif
 
new file mode 100644
--- /dev/null
+++ b/mfbt/NumericLimits.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* Compatibility with std::numeric_limits<char16_t>. */
+
+#ifndef mozilla_NumericLimits_h
+#define mozilla_NumericLimits_h
+
+#include "mozilla/Char16.h"
+
+#include <limits>
+#include <stdint.h>
+
+namespace mozilla {
+
+/**
+ * The NumericLimits class provides a compatibility layer with std::numeric_limits
+ * for char16_t, otherwise it is exactly the same as std::numeric_limits.
+ * Code which does not need std::numeric_limits<char16_t> should avoid using
+ * NumericLimits.
+ */
+template<typename T>
+class NumericLimits : public std::numeric_limits<T>
+{
+};
+
+#ifdef MOZ_CHAR16_IS_NOT_WCHAR
+template<>
+class NumericLimits<char16_t> : public std::numeric_limits<uint16_t>
+{
+  // char16_t and uint16_t numeric limits should be exactly the same.
+};
+#endif
+
+} // namespace mozilla
+
+#endif /* mozilla_NumericLimits_h */
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -34,16 +34,17 @@ EXPORTS_mozilla_FILES += \
   LinkedList.h \
   MathAlgorithms.h \
   Maybe.h \
   MemoryChecking.h \
   MemoryReporting.h \
   MSIntTypes.h \
   Move.h \
   NullPtr.h \
+  NumericLimits.h \
   PodOperations.h \
   Poison.h \
   Range.h \
   RangedPtr.h \
   ReentrancyGuard.h \
   RefPtr.h \
   Scoped.h \
   SHA1.h \
--- a/mobile/android/chrome/content/PluginHelper.js
+++ b/mobile/android/chrome/content/PluginHelper.js
@@ -180,30 +180,45 @@ var PluginHelper = {
         // If the plugin is hidden, or if the overlay is too small, show a 
         // doorhanger notification
         if (PluginHelper.isTooSmall(plugin, overlay)) {
           PluginHelper.delayAndShowDoorHanger(aTab);
         } else {
           // There's a large enough visible overlay that we don't need to show
           // the doorhanger.
           aTab.shouldShowPluginDoorhanger = false;
+          overlay.style.visibility = "visible";
         }
 
         // Add click to play listener to the overlay
         overlay.addEventListener("click", function(e) {
           if (!e.isTrusted)
             return;
           e.preventDefault();
           let win = e.target.ownerDocument.defaultView.top;
           let tab = BrowserApp.getTabForWindow(win);
           tab.clickToPlayPluginsActivated = true;
           PluginHelper.playAllPlugins(win);
 
           NativeWindow.doorhanger.hide("ask-to-play-plugins", tab.id);
         }, true);
+
+        // Add handlers for over- and underflow in case the plugin gets resized
+        plugin.addEventListener("overflow", function(event) {
+          overlay.style.visibility = "hidden";
+          PluginHelper.delayAndShowDoorHanger(aTab);
+        });
+        plugin.addEventListener("underflow", function(event) {
+          // This is also triggered if only one dimension underflows,
+          // the other dimension might still overflow
+          if (!PluginHelper.isTooSmall(plugin, overlay)) {
+            overlay.style.visibility = "visible";
+          }
+        });
+
         break;
       }
 
       case "PluginPlayPreview": {
         let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
         let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
         let mimeType = PluginHelper.getPluginMimeType(plugin);
         let playPreviewInfo = pluginHost.getPlayPreviewInfo(mimeType);
@@ -252,16 +267,17 @@ var PluginHelper = {
 
       case "PluginNotFound": {
         // On devices where we don't support Flash, there will be a
         // "Learn More..." link in the missing plugin error message.
         let learnMoreLink = doc.getAnonymousElementByAttribute(plugin, "class", "unsupportedLearnMoreLink");
         let learnMoreUrl = Services.urlFormatter.formatURLPref("app.support.baseURL");
         learnMoreUrl += "why-cant-firefox-mobile-play-flash-on-my-device";
         learnMoreLink.href = learnMoreUrl;
+        overlay.style.visibility = "visible";
         break;
       }
     }
   },
 
   // Helper to get the binding handler type from a plugin object
   _getBindingType: function(plugin) {
     if (!(plugin instanceof Ci.nsIObjectLoadingContent))
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1805,21 +1805,16 @@ pref("layout.word_select.stop_at_punctua
 //     delete deselects the selection and then deletes word
 // 2 = caret moves to selection edge and is not visible during selection; 
 //     word delete deletes the selection (Mac and Linux default)
 // 3 = caret moves and blinks as when there is no selection; word delete
 //     deletes the selection
 // Windows default is 1 for word delete behavior, the rest as for 2.
 pref("layout.selection.caret_style", 0);
 
-// pref to control whether or not to replace backslashes with Yen signs
-// in documents encoded in one of Japanese legacy encodings (EUC-JP, 
-// Shift_JIS, ISO-2022-JP)
-pref("layout.enable_japanese_specific_transform", false);
-
 // pref to force frames to be resizable
 pref("layout.frames.force_resizability", false);
 
 // pref to report CSS errors to the error console
 pref("layout.css.report_errors", true);
 
 // Should the :visited selector ever match (otherwise :link matches instead)?
 pref("layout.css.visited_links_enabled", true);
--- a/netwerk/cache2/AppCacheStorage.cpp
+++ b/netwerk/cache2/AppCacheStorage.cpp
@@ -1,15 +1,15 @@
 /* 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/. */
 
+#include "CacheLog.h"
 #include "AppCacheStorage.h"
 #include "CacheStorageService.h"
-#include "CacheLog.h"
 
 #include "OldWrappers.h"
 
 #include "nsICacheEntryDoomCallback.h"
 
 #include "nsICacheService.h"
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheService.h"
--- a/netwerk/cache2/CacheFileChunk.cpp
+++ b/netwerk/cache2/CacheFileChunk.cpp
@@ -1,15 +1,15 @@
 /* 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/. */
 
+#include "CacheLog.h"
 #include "CacheFileChunk.h"
 
-#include "CacheLog.h"
 #include "CacheFile.h"
 #include "nsThreadUtils.h"
 #include "nsAlgorithm.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
 
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -1,15 +1,15 @@
 /* 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/. */
 
+#include "CacheLog.h"
 #include "CacheFileIOManager.h"
 
-#include "CacheLog.h"
 #include "../cache/nsCacheUtils.h"
 #include "CacheHashUtils.h"
 #include "CacheStorageService.h"
 #include "nsThreadUtils.h"
 #include "nsIFile.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/DebugOnly.h"
 #include "nsDirectoryServiceUtils.h"
--- a/netwerk/cache2/CacheFileInputStream.cpp
+++ b/netwerk/cache2/CacheFileInputStream.cpp
@@ -1,15 +1,15 @@
 /* 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/. */
 
+#include "CacheLog.h"
 #include "CacheFileInputStream.h"
 
-#include "CacheLog.h"
 #include "CacheFile.h"
 #include "nsStreamUtils.h"
 #include "nsThreadUtils.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
 
--- a/netwerk/cache2/CacheFileMetadata.cpp
+++ b/netwerk/cache2/CacheFileMetadata.cpp
@@ -1,15 +1,15 @@
 /* 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/. */
 
+#include "CacheLog.h"
 #include "CacheFileMetadata.h"
 
-#include "CacheLog.h"
 #include "CacheFileIOManager.h"
 #include "CacheHashUtils.h"
 #include "CacheFileChunk.h"
 #include "../cache/nsCacheUtils.h"
 #include "mozilla/Telemetry.h"
 #include "prnetdb.h"
 
 
--- a/netwerk/cache2/CacheFileOutputStream.cpp
+++ b/netwerk/cache2/CacheFileOutputStream.cpp
@@ -1,15 +1,15 @@
 /* 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/. */
 
+#include "CacheLog.h"
 #include "CacheFileOutputStream.h"
 
-#include "CacheLog.h"
 #include "CacheFile.h"
 #include "nsStreamUtils.h"
 #include "nsThreadUtils.h"
 #include "mozilla/DebugOnly.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
--- a/netwerk/cache2/CacheLog.h
+++ b/netwerk/cache2/CacheLog.h
@@ -1,16 +1,22 @@
 /* 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 CacheLog__h__
 #define CacheLog__h__
 
+#if defined(MOZ_LOGGING)
 #define FORCE_PR_LOG
+#endif
+
+#if defined(PR_LOG)
+#error "If nsCache.h #included it must come before any files that #include prlog.h"
+#endif
 
 #include "prlog.h"
 
 namespace mozilla {
 namespace net {
 
 #if defined(PR_LOGGING)
 extern PRLogModuleInfo* GetCache2Log();
--- a/netwerk/cache2/CacheStorage.cpp
+++ b/netwerk/cache2/CacheStorage.cpp
@@ -1,16 +1,16 @@
 /* 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/. */
 
+#include "CacheLog.h"
 #include "CacheStorage.h"
 #include "CacheStorageService.h"
 #include "CacheEntry.h"
-#include "CacheLog.h"
 
 #include "OldWrappers.h"
 
 #include "nsICacheEntryDoomCallback.h"
 
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheService.h"
 #include "nsIURI.h"
--- a/netwerk/cache2/OldWrappers.cpp
+++ b/netwerk/cache2/OldWrappers.cpp
@@ -1,14 +1,14 @@
 // Stuff to link the old imp to the new api - will go away!
 
+#include "CacheLog.h"
 #include "OldWrappers.h"
 #include "CacheStorage.h"
 #include "CacheStorageService.h"
-#include "CacheLog.h"
 #include "LoadContextInfo.h"
 
 #include "nsIURI.h"
 #include "nsICacheService.h"
 #include "nsICacheSession.h"
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheService.h"
 #include "nsIStreamTransportService.h"
--- a/netwerk/dns/effective_tld_names.dat
+++ b/netwerk/dns/effective_tld_names.dat
@@ -6566,16 +6566,194 @@ xxx
 *.za
 
 // zm : http://en.wikipedia.org/wiki/.zm
 *.zm
 
 // zw : http://en.wikipedia.org/wiki/.zw
 *.zw
 
+
+// xn--80asehdb : 2013-07-14 CORE Association
+онлайн
+
+// xn--80aswg : 2013-07-14 CORE Association
+сайт
+
+// xn--ngbc5azd : 2013-07-14 International Domain Registry Pty. Ltd.
+شبكة
+
+// xn--unup4y : 2013-07-14 Spring Fields, LLC
+游戏
+
+// xn--vhquv : 2013-08-28 Dash McCook, LLC
+企业
+
+// camera : 2013-08-28 Atomic Maple, LLC
+camera
+
+// clothing : 2013-08-28 Steel Lake, LLC
+clothing
+
+// lighting : 2013-08-28 John McCook, LLC
+lighting
+
+// singles : 2013-08-28 Fern Madison, LLC
+singles
+
+// ventures : 2013-08-28 Binky Lake, LLC
+ventures
+
+// voyage : 2013-08-28 Ruby House, LLC
+voyage
+
+// guru : 2013-08-28 Pioneer Cypress, LLC
+guru
+
+// holdings : 2013-08-28 John Madison, LLC
+holdings
+
+// equipment : 2013-08-28 Corn Station, LLC
+equipment
+
+// bike : 2013-08-28 Grand Hollow, LLC
+bike
+
+// estate : 2013-08-28 Trixy Park, LLC
+estate
+
+// tattoo : 2013-08-30 Uniregistry,Corp.
+tattoo
+
+// xn--3ds443g : 2013-09-09 TLD Registry Limited
+在线
+
+// xn--fiq228c5hs : 2013-09-09 TLD Registry Limited
+中文网
+
+// land : 2013-09-10 Pine Moon, LLC 
+land
+
+// plumbing : 2013-09-10 Spring Tigers, LLC 
+plumbing
+
+// contractors : 2013-09-10 Magic Woods, LLC 
+contractors
+
+// sexy : 2013-09-11 Uniregistry,Corp. 
+sexy
+
+// menu : 2013-09-11 Wedding TLD2, LLC 
+menu
+
+// xn--rhqv96g : 2013-09-11 Stable Tone Limited 
+世界
+
+// uno : 2013-09-11 Dot Latin, LLC 
+uno
+
+// gallery : 2013-09-13 Sugar House, LLC 
+gallery
+
+// technology : 2013-09-13 Auburn Falls 
+technology
+
+// xn--3bst00m : 2013-09-13 Eagle Horizon Limited 
+集团
+
+// reviews : 2013-09-13 Extra Cover, LLC 
+reviews
+
+// guide : 2013-09-13 Snow Moon, LLC 
+guide
+
+// xn--6qq986b3x1 : 2013-09-13 Tycoon Treasure Limited 
+我爱你
+
+// graphics : 2013-09-13 Over Madison, LLC 
+graphics
+
+// construction : 2013-09-13 Fox Dynamite, LLC 
+construction
+
+// onl : 2013-09-16 I-Registry Ltd. 
+onl
+
+// xn--q9jyb4c : 2013-09-17 Charleston Road Registry 
+みんな
+
+// diamonds : 2013-09-23 John Edge, LLC 
+diamonds
+
+// kiwi : 2013-09-23 Dot Kiwi Limited 
+kiwi
+
+// enterprises : 2013-09-23 Snow Oaks LLC 
+enterprises
+
+// today : 2013-09-23 Pearl Woods, LLC 
+today
+
+// futbol : 2013-09-23 Atomic Falls, LLC 
+futbol
+
+// photography : 2013-09-23 Sugar Glen, LLC 
+photography
+
+// tips : 2013-09-23 Corn Willow, LLC 
+tips
+
+// directory : 2013-09-23 Extra Madison, LLC 
+directory
+
+// kitchen : 2013-09-23 Just Goodbye, LLC 
+kitchen
+
+// xn--6frz82g : 2013-09-24 Afilias Limited 
+移动
+
+// kim : 2013-09-24 Afilias Limited 
+kim
+
+// xn--cg4bki : 2013-09-27 Samsung SDS Co., LTD 
+삼성
+
+// monash : 2013-10-01 Monash University 
+monash
+
+// wed : 2013-10-02 Atgron, Inc. 
+wed
+
+// pink : 2013-10-02 Afilias Limited 
+pink
+
+// ruhr : 2013-10-02 regiodot GmbH & Co. KG 
+ruhr
+
+// buzz : 2013-10-03 DOTSTRATEGY CO. 
+buzz
+
+// careers : 2013-10-03 Wild Corner, LLC 
+careers
+
+// shoes : 2013-10-03 Binky Galley, LLC 
+shoes
+
+// xn--4gbrim : 2013-10-07 Suhub Electronic Establishment 
+موقع
+
+// career : 2013-10-09 dotCareer, LLC 
+career
+
+// otsuka : 2013-10-11 Otsuka Holdings Co. Ltd. 
+otsuka
+
+// xn--fiQ64b : 2013-10-14 CITIC Group Corporation 
+中信
+
 // ===END ICANN DOMAINS===
 // ===BEGIN PRIVATE DOMAINS===
 
 // Amazon CloudFront : https://aws.amazon.com/cloudfront/
 // Requested by Donavan Miller <donavanm@amazon.com> 2013-03-22
 cloudfront.net
 
 // Amazon Elastic Compute Cloud: https://aws.amazon.com/ec2/
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -2509,75 +2509,85 @@ nsHttpChannel::OpenCacheEntry(bool using
         }
     }
 
     nsCOMPtr<nsICacheStorageService> cacheStorageService =
         do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsRefPtr<LoadContextInfo> info = GetLoadContextInfo(this);
-
     nsCOMPtr<nsICacheStorage> cacheStorage;
+    nsCOMPtr<nsIURI> openURI;
+    if (!mFallbackKey.IsEmpty() && mFallbackChannel) {
+        // This is a fallback channel, open fallback URI instead
+        rv = NS_NewURI(getter_AddRefs(openURI), mFallbackKey);
+        NS_ENSURE_SUCCESS(rv, rv);
+    }
+    else {
+        openURI = mURI;
+    }
+
+    uint32_t cacheEntryOpenFlags;
+    bool offline = gIOService->IsOffline();
+    if (offline || (mLoadFlags & INHIBIT_CACHING)) {
+        if (BYPASS_LOCAL_CACHE(mLoadFlags) && !offline) {
+            goto bypassCacheEntryOpen;
+        }
+        cacheEntryOpenFlags = nsICacheStorage::OPEN_READONLY;
+        mCacheEntryIsReadOnly = true;
+    }
+    else if (BYPASS_LOCAL_CACHE(mLoadFlags) && !mApplicationCache) {
+        cacheEntryOpenFlags = nsICacheStorage::OPEN_TRUNCATE;
+    }
+    else {
+        cacheEntryOpenFlags = nsICacheStorage::OPEN_NORMALLY;
+    }
+
     if (mApplicationCache) {
-        rv = cacheStorageService->AppCacheStorage(info, mApplicationCache,
-                                                  getter_AddRefs(cacheStorage));
+        rv = cacheStorageService->AppCacheStorage(info, 
+            mApplicationCache,
+            getter_AddRefs(cacheStorage));
     }
     else if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
         rv = cacheStorageService->MemoryCacheStorage(info, // ? choose app cache as well...
             getter_AddRefs(cacheStorage));
     }
     else {
         rv = cacheStorageService->DiskCacheStorage(info,
             mChooseApplicationCache || (mLoadFlags & LOAD_CHECK_OFFLINE_CACHE),
             getter_AddRefs(cacheStorage));
     }
     NS_ENSURE_SUCCESS(rv, rv);
 
-    uint32_t cacheEntryOpenFlags;
-    if (BYPASS_LOCAL_CACHE(mLoadFlags) && !mApplicationCache)
-        cacheEntryOpenFlags = nsICacheStorage::OPEN_TRUNCATE;
-    else
-        cacheEntryOpenFlags = nsICacheStorage::OPEN_NORMALLY;
-
     if (mLoadAsBlocking || mLoadUnblocked ||
         (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)) {
         cacheEntryOpenFlags |= nsICacheStorage::OPEN_PRIORITY;
     }
 
     // Only for backward compatibility with the old cache back end.
     // When removed, remove the flags and related code snippets.
     if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY)
         cacheEntryOpenFlags |= nsICacheStorage::OPEN_BYPASS_IF_BUSY;
 
-    nsCOMPtr<nsIURI> openURI;
-    if (!mFallbackKey.IsEmpty() && mFallbackChannel) {
-        // This is a fallback channel, open fallback URI instead
-        rv = NS_NewURI(getter_AddRefs(openURI), mFallbackKey);
-        NS_ENSURE_SUCCESS(rv, rv);
-    }
-    else {
-        openURI = mURI;
-    }
-
     rv = cacheStorage->AsyncOpenURI(
         openURI, mPostID ? nsPrintfCString("%d", mPostID) : EmptyCString(),
         cacheEntryOpenFlags, this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     waitFlags.Keep(WAIT_FOR_CACHE_ENTRY);
 
+bypassCacheEntryOpen:
     if (!mApplicationCacheForWrite)
         return NS_OK;
 
     // If there is an app cache to write to, open the entry right now in parallel.
 
     // make sure we're not abusing this function
     NS_PRECONDITION(!mOfflineCacheEntry, "cache entry already open");
 
-    bool offline = gIOService->IsOffline();
     if (offline) {
         // only put things in the offline cache while online
         return NS_OK;
     }
 
     if (mLoadFlags & INHIBIT_CACHING) {
         // respect demand not to cache
         return NS_OK;
@@ -3000,17 +3010,17 @@ nsHttpChannel::OnCacheEntryAvailableInte
         else {
             rv = OnOfflineCacheEntryAvailable(entry, aNew, aAppCache, status);
         }
     }
     else {
         rv = OnNormalCacheEntryAvailable(entry, aNew, status);
     }
 
-    if (NS_FAILED(rv) && mLoadFlags & LOAD_ONLY_FROM_CACHE) {
+    if (NS_FAILED(rv) && (mLoadFlags & LOAD_ONLY_FROM_CACHE)) {
         // If we have a fallback URI (and we're not already
         // falling back), process the fallback asynchronously.
         if (!mFallbackChannel && !mFallbackKey.IsEmpty()) {
             return AsyncCall(&nsHttpChannel::HandleAsyncFallback);
         }
         return NS_ERROR_DOCUMENT_NOT_CACHED;
     }
 
@@ -3026,28 +3036,20 @@ nsHttpChannel::OnCacheEntryAvailableInte
 
 nsresult
 nsHttpChannel::OnNormalCacheEntryAvailable(nsICacheEntry *aEntry,
                                            bool aNew,
                                            nsresult aEntryStatus)
 {
     mCacheEntriesToWaitFor &= ~WAIT_FOR_CACHE_ENTRY;
 
-    if (aNew) {
-      bool offline = gIOService->IsOffline();
-      if ((mLoadFlags & INHIBIT_CACHING) && !offline) {
-          // Don't allow caching in this case, just throw the entry away
-          return NS_OK;
-      }
-
-      if ((mLoadFlags & LOAD_ONLY_FROM_CACHE)) {
-          // if this channel is only allowed to pull from the cache, then
-          // we must fail if we were unable to open a cache entry for read.
-          return NS_ERROR_DOCUMENT_NOT_CACHED;
-      }
+    if ((mLoadFlags & LOAD_ONLY_FROM_CACHE) && (NS_FAILED(aEntryStatus) || aNew)) {
+        // if this channel is only allowed to pull from the cache, then
+        // we must fail if we were unable to open a cache entry for read.
+        return NS_ERROR_DOCUMENT_NOT_CACHED;
     }
 
     if (NS_SUCCEEDED(aEntryStatus)) {
         mCacheEntry = aEntry;
         mCacheEntryIsWriteOnly = aNew;
 
         if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) {
             mozilla::Telemetry::Accumulate(Telemetry::HTTP_OFFLINE_CACHE_DOCUMENT_LOAD,
--- a/python/mach/mach/dispatcher.py
+++ b/python/mach/mach/dispatcher.py
@@ -178,17 +178,17 @@ class CommandAction(argparse.Action):
                 if group is None:
                     title, description, _priority = r.categories[category]
                     group = parser.add_argument_group(title, description)
 
                 description = handler.description
                 group.add_argument(command, help=description,
                     action='store_true')
 
-        if disabled_commands:
+        if disabled_commands and 'disabled' in r.categories:
             title, description, _priority = r.categories['disabled']
             group = parser.add_argument_group(title, description)
             for c in disabled_commands:
                 group.add_argument(c['command'], help=c['description'],
                     action='store_true')
 
         parser.print_help()
 
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -294,33 +294,33 @@ CertErrorRunnable::CheckCertOverrides()
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
 
   int32_t port;
   mInfoObject->GetPort(&port);
 
   nsCString hostWithPortString;
-  hostWithPortString.AppendASCII(mInfoObject->GetHostName());
+  hostWithPortString.AppendASCII(mInfoObject->GetHostNameRaw());
   hostWithPortString.AppendLiteral(":");
   hostWithPortString.AppendInt(port);
 
   uint32_t remaining_display_errors = mCollectedErrors;
 
   nsresult nsrv;
 
   // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
   // connections must be dropped when there are any certificate errors
   // (STS Spec section 7.3).
   bool strictTransportSecurityEnabled = false;
   nsCOMPtr<nsISiteSecurityService> sss
     = do_GetService(NS_SSSERVICE_CONTRACTID, &nsrv);
   if (NS_SUCCEEDED(nsrv)) {
     nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS,
-                             mInfoObject->GetHostName(),
+                             mInfoObject->GetHostNameRaw(),
                              mProviderFlags,
                              &strictTransportSecurityEnabled);
   }
   if (NS_FAILED(nsrv)) {
     return new SSLServerCertVerificationResult(mInfoObject,
                                                mDefaultErrorCodeToReport);
   }
 
@@ -408,17 +408,17 @@ CertErrorRunnable::CheckCertOverrides()
   SSLServerCertVerificationResult *result = 
     new SSLServerCertVerificationResult(mInfoObject, 
                                         errorCodeToReport,
                                         Telemetry::HistogramCount,
                                         -1,
                                         OverridableCertErrorMessage);
 
   LogInvalidCertError(mInfoObject,
-                      nsDependentCString(mInfoObject->GetHostName()),
+                      mInfoObject->GetHostName(),
                       hostWithPortString,
                       port,
                       result->mErrorCode,
                       result->mErrorMessageType,
                       mCert);
 
   return result;
 }
@@ -505,17 +505,17 @@ CreateCertErrorRunnable(PRErrorCode defa
   uint32_t collected_errors = 0;
 
   if (infoObject->IsCertIssuerBlacklisted()) {
     collected_errors |= nsICertOverrideService::ERROR_UNTRUSTED;
     errorCodeTrust = defaultErrorCodeToReport;
   }
 
   // Check the name field against the desired hostname.
-  if (CERT_VerifyCertName(cert, infoObject->GetHostName()) != SECSuccess) {
+  if (CERT_VerifyCertName(cert, infoObject->GetHostNameRaw()) != SECSuccess) {
     collected_errors |= nsICertOverrideService::ERROR_MISMATCH;
     errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
   }
 
   CERTVerifyLogNode *i_node;
   for (i_node = verify_log->head; i_node; i_node = i_node->next)
   {
     switch (i_node->error)
@@ -878,17 +878,17 @@ AuthCertificate(TransportSecurityInfo * 
                                                infoObject);
     if (rv != SECSuccess) {
       return rv;
     }
   }
 
   CERTCertList *verifyCertChain = nullptr;
   SECOidTag evOidPolicy;
-  rv = PSM_SSL_PKIX_AuthCertificate(cert, infoObject, infoObject->GetHostName(),
+  rv = PSM_SSL_PKIX_AuthCertificate(cert, infoObject, infoObject->GetHostNameRaw(),
                                     &verifyCertChain, &evOidPolicy);
 
   // We want to remember the CA certs in the temp db, so that the application can find the
   // complete chain at any time it might need it.
   // But we keep only those CA certs in the temp db, that we didn't already know.
 
   RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
   RefPtr<nsNSSCertificate> nsc;
--- a/security/manager/ssl/src/TransportSecurityInfo.h
+++ b/security/manager/ssl/src/TransportSecurityInfo.h
@@ -44,19 +44,19 @@ public:
   NS_DECL_NSISSLSTATUSPROVIDER
   NS_DECL_NSIASSOCIATEDCONTENTSECURITY
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
 
   nsresult SetSecurityState(uint32_t aState);
   nsresult SetShortSecurityDescription(const PRUnichar *aText);
 
-  const char * GetHostName() const {
-    return mHostName.get();
-  }
+  const nsACString & GetHostName() const { return mHostName; }
+  const char * GetHostNameRaw() const { return mHostName.get(); }
+
   nsresult GetHostName(char **aHostName);
   nsresult SetHostName(const char *aHostName);
 
   int32_t GetPort() const { return mPort; }
   nsresult GetPort(int32_t *aPort);
   nsresult SetPort(int32_t aPort);
 
   PRErrorCode GetErrorCode() const;
--- a/security/manager/ssl/src/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/src/nsNSSCallbacks.cpp
@@ -1027,26 +1027,35 @@ void HandshakeCallback(PRFileDesc* fd, v
   SECStatus rv;
 
   nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
 
   // certificate validation sets FirstServerHelloReceived, so if that flag
   // is absent at handshake time we have a resumed session. Check this before
   // PreliminaryHandshakeDone() because that function also sets that flag.
   bool isResumedSession = !(infoObject->GetFirstServerHelloReceived());
-
   // Do the bookkeeping that needs to be done after the
   // server's ServerHello...ServerHelloDone have been processed, but that doesn't
   // need the handshake to be completed.
   PreliminaryHandshakeDone(fd);
 
-  // If the handshake completed, then we know the site is TLS tolerant (if this
-  // was a TLS connection).
-  nsSSLIOLayerHelpers& ioLayerHelpers = infoObject->SharedState().IOLayerHelpers();
-  ioLayerHelpers.rememberTolerantSite(infoObject);
+  nsSSLIOLayerHelpers& ioLayerHelpers
+    = infoObject->SharedState().IOLayerHelpers();
+
+  SSLVersionRange versions(infoObject->GetTLSVersionRange());
+
+  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+         ("[%p] HandshakeCallback: succeeded using TLS version range (0x%04x,0x%04x)\n",
+          fd, static_cast<unsigned int>(versions.min),
+              static_cast<unsigned int>(versions.max)));
+
+  // If the handshake completed, then we know the site is TLS tolerant
+  ioLayerHelpers.rememberTolerantAtVersion(infoObject->GetHostName(),
+                                           infoObject->GetPort(),
+                                           versions.max);
 
   PRBool siteSupportsSafeRenego;
   rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
                                         &siteSupportsSafeRenego);
   MOZ_ASSERT(rv == SECSuccess);
   if (rv != SECSuccess) {
     siteSupportsSafeRenego = false;
   }
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -59,32 +59,45 @@ using namespace mozilla::psm;
                        //file.
 
 namespace {
 
 NSSCleanupAutoPtrClass(void, PR_FREEIF)
 
 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 
+void
+getSiteKey(const nsACString & hostName, uint16_t port,
+           /*out*/ nsCSubstring & key)
+{
+  key = hostName;
+  key.AppendASCII(":");
+  key.AppendInt(port);
+}
+
+void
+getSiteKey(const nsNSSSocketInfo & socketInfo, /*out*/ nsCSubstring & key)
+{
+  getSiteKey(socketInfo.GetHostName(), socketInfo.GetPort(), key);
+}
+
 /* SSM_UserCertChoice: enum for cert choice info */
 typedef enum {ASK, AUTO} SSM_UserCertChoice;
 
 } // unnamed namespace
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
 #endif
 
 nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
   : mFd(nullptr),
     mCertVerificationState(before_cert_verification),
     mSharedState(aState),
     mForSTARTTLS(false),
-    mSSL3Enabled(false),
-    mTLSEnabled(false),
     mHandshakePending(true),
     mHasCleartextPhase(false),
     mHandshakeInProgress(false),
     mAllowTLSIntoleranceTimeout(true),
     mRememberClientAuthCertificate(false),
     mPreliminaryHandshakeDone(false),
     mHandshakeStartTime(0),
     mFirstServerHelloReceived(false),
@@ -96,16 +109,18 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedS
     mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
     mKEAExpected(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
     mSymmetricCipherUsed(nsISSLSocketControl::SYMMETRIC_CIPHER_UNKNOWN),
     mSymmetricCipherExpected(nsISSLSocketControl::SYMMETRIC_CIPHER_UNKNOWN),
     mProviderFlags(providerFlags),
     mSocketCreationTimestamp(TimeStamp::Now()),
     mPlaintextBytesRead(0)
 {
+  mTLSVersionRange.min = 0;
+  mTLSVersionRange.max = 0;
 }
 
 NS_IMPL_ISUPPORTS_INHERITED2(nsNSSSocketInfo, TransportSecurityInfo,
                              nsISSLSocketControl,
                              nsIClientAuthUserDecision)
 
 NS_IMETHODIMP
 nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags)
@@ -324,17 +339,17 @@ nsNSSSocketInfo::JoinConnection(const ns
     return NS_OK;
 
   // Make sure NPN has been completed and matches requested npnProtocol
   if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
     return NS_OK;
 
   // If this is the same hostname then the certicate status does not
   // need to be considered. They are joinable.
-  if (GetHostName() && hostname.Equals(GetHostName())) {
+  if (hostname.Equals(GetHostName())) {
     *_retval = true;
     return NS_OK;
   }
 
   // Before checking the server certificate we need to make sure the
   // handshake has completed.
   if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
     return NS_OK;
@@ -589,35 +604,22 @@ bool nsNSSSocketInfo::HandshakeTimeout()
 
   PRIntervalTime now = PR_IntervalNow();
   bool result = (now - mHandshakeStartTime) > handshakeTimeoutInterval;
   return result;
 }
 
 void nsSSLIOLayerHelpers::Cleanup()
 {
-  if (mTLSIntolerantSites) {
-    delete mTLSIntolerantSites;
-    mTLSIntolerantSites = nullptr;
-  }
-
-  if (mTLSTolerantSites) {
-    delete mTLSTolerantSites;
-    mTLSTolerantSites = nullptr;
-  }
+  mTLSIntoleranceInfo.Clear();
 
   if (mRenegoUnrestrictedSites) {
     delete mRenegoUnrestrictedSites;
     mRenegoUnrestrictedSites = nullptr;
   }
-
-  if (mutex) {
-    delete mutex;
-    mutex = nullptr;
-  }
 }
 
 static void
 nsHandleSSLError(nsNSSSocketInfo *socketInfo, 
                  ::mozilla::psm::SSLErrorMessageType errtype, 
                  PRErrorCode err)
 {
   if (!NS_IsMainThread()) {
@@ -636,33 +638,28 @@ nsHandleSSLError(nsNSSSocketInfo *socket
   }
 
   nsresult rv;
   NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
   if (NS_FAILED(rv))
     return;
 
-  nsXPIDLCString hostName;
-  socketInfo->GetHostName(getter_Copies(hostName));
-
-  int32_t port;
-  socketInfo->GetPort(&port);
-
   // Try to get a nsISSLErrorListener implementation from the socket consumer.
   nsCOMPtr<nsIInterfaceRequestor> cb;
   socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
   if (cb) {
     nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(cb);
     if (sel) {
       nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(socketInfo);
-      nsCString hostWithPortString = hostName;
-      hostWithPortString.AppendLiteral(":");
-      hostWithPortString.AppendInt(port);
-    
+
+      nsCString hostWithPortString;
+      getSiteKey(socketInfo->GetHostName(), socketInfo->GetPort(),
+                 hostWithPortString);
+
       bool suppressMessage = false; // obsolete, ignored
       rv = sel->NotifySSLError(csi, err, hostWithPortString, &suppressMessage);
     }
   }
   
   // We must cancel first, which sets the error code.
   socketInfo->SetCanceled(err, PlainErrorMessage);
   nsXPIDLString errorString;
@@ -734,68 +731,114 @@ nsSSLIOLayerConnect(PRFileDesc* fd, cons
     return status;
   }
 
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*)fd));
   return status;
 }
 
 void
-nsSSLIOLayerHelpers::getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key)
+nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString & hostName,
+                                               int16_t port, uint16_t tolerant)
 {
-  int32_t port;
-  socketInfo->GetPort(&port);
-
-  nsXPIDLCString host;
-  socketInfo->GetHostName(getter_Copies(host));
-
-  key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
+  nsCString key;
+  getSiteKey(hostName, port, key);
+
+  MutexAutoLock lock(mutex);
+
+  IntoleranceEntry entry;
+  if (mTLSIntoleranceInfo.Get(key, &entry)) {
+    entry.AssertInvariant();
+    entry.tolerant = std::max(entry.tolerant, tolerant);
+    if (entry.intolerant != 0 && entry.intolerant <= entry.tolerant) {
+      entry.intolerant = entry.tolerant + 1;
+    }
+  } else {
+    entry.tolerant = tolerant;
+    entry.intolerant = 0;
+  }
+
+  entry.AssertInvariant();
+
+  mTLSIntoleranceInfo.Put(key, entry);
 }
 
-// Call this function to report a site that is possibly TLS intolerant.
-// This function will return true, if the given socket is currently using TLS,
-// and it's allowed to retry. Retrying only makes sense if an older
-// protocol is enabled.
+// returns true if we should retry the handshake
 bool
-nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo)
+nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString & hostName,
+                                                 int16_t port,
+                                                 uint16_t minVersion,
+                                                 uint16_t intolerant)
 {
-  nsAutoCString key;
-  getSiteKey(socketInfo, key);
-
-  if (!socketInfo->IsTLSEnabled()) {
-    // We did not offer TLS but failed with an intolerant error using
-    // a different protocol. To give TLS a try on next connection attempt again
-    // drop this site from the list of intolerant sites. TLS failure might be 
-    // caused only by a traffic congestion while the server is TLS tolerant.
-    removeIntolerantSite(key);
+  nsCString key;
+  getSiteKey(hostName, port, key);
+
+  MutexAutoLock lock(mutex);
+
+  if (intolerant <= minVersion) {
+    // We can't fall back any further. Assume that intolerance isn't the issue.
+    IntoleranceEntry entry;
+    if (mTLSIntoleranceInfo.Get(key, &entry)) {
+      entry.AssertInvariant();
+      entry.intolerant = 0;
+      entry.AssertInvariant();
+      mTLSIntoleranceInfo.Put(key, entry);
+    }
+
     return false;
   }
 
-  if (socketInfo->IsSSL3Enabled()) {
-    // Add this site to the list of TLS intolerant sites.
-    addIntolerantSite(key);
+  IntoleranceEntry entry;
+  if (mTLSIntoleranceInfo.Get(key, &entry)) {
+    entry.AssertInvariant();
+    if (intolerant <= entry.tolerant) {
+      // We already know the server is tolerant at an equal or higher version.
+      return false;
+    }
+    if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
+      // We already know that the server is intolerant at a lower version.
+      return true;
+    }
+  } else {
+    entry.tolerant = 0;
   }
-  else {
-    return false; // doesn't make sense to retry
-  }
-  
-  return socketInfo->IsTLSEnabled();
+
+  entry.intolerant = intolerant;
+  entry.AssertInvariant();
+  mTLSIntoleranceInfo.Put(key, entry);
+
+  return true;
 }
 
 void
-nsSSLIOLayerHelpers::rememberTolerantSite(nsNSSSocketInfo *socketInfo)
+nsSSLIOLayerHelpers::adjustForTLSIntolerance(const nsACString & hostName,
+                                             int16_t port,
+                                             /*in/out*/ SSLVersionRange & range)
 {
-  if (!socketInfo->IsTLSEnabled())
-    return;
-
-  nsAutoCString key;
-  getSiteKey(socketInfo, key);
-
-  MutexAutoLock lock(*mutex);
-  nsSSLIOLayerHelpers::mTLSTolerantSites->PutEntry(key);
+  IntoleranceEntry entry;
+
+  {
+    nsCString key;
+    getSiteKey(hostName, port, key);
+
+    MutexAutoLock lock(mutex);
+    if (!mTLSIntoleranceInfo.Get(key, &entry)) {
+      return;
+    }
+  }
+
+  entry.AssertInvariant();
+
+  if (entry.intolerant != 0) {
+    // We've tried connecting at a higher range but failed, so try at the
+    // version we haven't tried yet, unless we have reached the minimum.
+    if (range.min < entry.intolerant) {
+      range.max = entry.intolerant - 1;
+    }
+  }
 }
 
 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
 PRDescIdentity nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity;
 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
 PRIOMethods nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods;
 
@@ -1032,18 +1075,21 @@ int32_t checkHandshake(int32_t bytesTran
       if (PR_WOULD_BLOCK_ERROR == err) {
         socketInfo->SetHandshakeInProgress(true);
         return bytesTransfered;
       }
 
       if (!wantRetry // no decision yet
           && isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
       {
-        nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
-        wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
+        SSLVersionRange range = socketInfo->GetTLSVersionRange();
+        wantRetry = socketInfo->SharedState().IOLayerHelpers()
+                      .rememberIntolerantAtVersion(socketInfo->GetHostName(),
+                                                   socketInfo->GetPort(),
+                                                   range.min, range.max);
       }
     }
     
     // This is the common place where we trigger non-cert-errors on a SSL
     // socket. This might be reached at any time of the connection.
     //
     // The socketInfo->GetErrorCode() check is here to ensure we don't try to
     // do the synchronous dispatch to the main thread unnecessarily after we've
@@ -1061,23 +1107,29 @@ int32_t checkHandshake(int32_t bytesTran
   }
   else if (wasReading && 0 == bytesTransfered) // zero bytes on reading, socket closed
   {
     if (handleHandshakeResultNow)
     {
       if (!wantRetry // no decision yet
           && !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
       {
-        nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
-        wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
+        SSLVersionRange range = socketInfo->GetTLSVersionRange();
+        wantRetry = socketInfo->SharedState().IOLayerHelpers()
+                        .rememberIntolerantAtVersion(socketInfo->GetHostName(),
+                                                     socketInfo->GetPort(),
+                                                     range.min, range.max);
       }
     }
   }
 
   if (wantRetry) {
+    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+           ("[%p] checkHandshake: will retry with lower max TLS version\n",
+            ssl_layer_fd));
     // We want to cause the network layer to retry the connection.
     PR_SetError(PR_CONNECT_RESET_ERROR, 0);
     if (wasReading)
       bytesTransfered = -1;
   }
 
   // TLS intolerant servers only cause the first transfer to fail, so let's 
   // set the HandshakePending attribute to false so that we don't try the logic
@@ -1148,22 +1200,21 @@ nsSSLIOLayerPoll(PRFileDesc * fd, int16_
   // cert validation is complete.
   int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
                                     (void*)fd, (int) result));
   return result;
 }
 
 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
-: mutex(nullptr)
-, mTLSIntolerantSites(nullptr)
-, mTLSTolerantSites(nullptr)
+: mutex("nsSSLIOLayerHelpers.mutex")
 , mRenegoUnrestrictedSites(nullptr)
 , mTreatUnsafeNegotiationAsBroken(false)
 , mWarnLevelMissingRFC5746(1)
+, mTLSIntoleranceInfo(16)
 , mFalseStartRequireNPN(true)
 , mFalseStartRequireForwardSecrecy(false)
 {
 }
 
 static int _PSM_InvalidInt(void)
 {
     PR_ASSERT(!"I/O method is invalid");
@@ -1376,21 +1427,30 @@ static int32_t PlaintextRecv(PRFileDesc 
 
   if ((bytesRead > 0) && socketInfo)
     socketInfo->AddPlaintextBytesRead(bytesRead);
   return bytesRead;
 }
 
 nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
 {
-  Preferences::RemoveObserver(mPrefObserver, "security.ssl.renego_unrestricted_hosts");
-  Preferences::RemoveObserver(mPrefObserver, "security.ssl.treat_unsafe_negotiation_as_broken");
-  Preferences::RemoveObserver(mPrefObserver, "security.ssl.warn_missing_rfc5746");
-  Preferences::RemoveObserver(mPrefObserver, "security.ssl.false_start.require-npn");
-  Preferences::RemoveObserver(mPrefObserver, "security.ssl.false_start.require-forward-secrecy");
+  // mPrefObserver will only be set if this->Init was called. The GTest tests
+  // do not call Init.
+  if (mPrefObserver) {
+    Preferences::RemoveObserver(mPrefObserver,
+      "security.ssl.renego_unrestricted_hosts");
+    Preferences::RemoveObserver(mPrefObserver,
+        "security.ssl.treat_unsafe_negotiation_as_broken");
+    Preferences::RemoveObserver(mPrefObserver,
+        "security.ssl.warn_missing_rfc5746");
+    Preferences::RemoveObserver(mPrefObserver,
+        "security.ssl.false_start.require-npn");
+    Preferences::RemoveObserver(mPrefObserver,
+        "security.ssl.false_start.require-forward-secrecy");
+  }
 }
 
 nsresult nsSSLIOLayerHelpers::Init()
 {
   if (!nsSSLIOLayerInitialized) {
     nsSSLIOLayerInitialized = true;
     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
     nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
@@ -1427,26 +1487,17 @@ nsresult nsSSLIOLayerHelpers::Init()
     nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
     nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
 
     nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
     nsSSLPlaintextLayerMethods  = *PR_GetDefaultIOMethods();
     nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
   }
 
-  mutex = new Mutex("nsSSLIOLayerHelpers.mutex");
-
-  mTLSIntolerantSites = new nsTHashtable<nsCStringHashKey>(1);
-
-  // Initialize the tolerant site hashtable to 16 items at the start seems
-  // reasonable as most servers are TLS tolerant. We just want to lower 
-  // the rate of hashtable array reallocation.
-  mTLSTolerantSites = new nsTHashtable<nsCStringHashKey>(16);
-
-  mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>(1);
+  mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>(16);
 
   nsCString unrestricted_hosts;
   Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
   if (!unrestricted_hosts.IsEmpty()) {
     setRenegoUnrestrictedSites(unrestricted_hosts);
   }
 
   bool enabled = false;
@@ -1474,90 +1525,69 @@ nsresult nsSSLIOLayerHelpers::Init()
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.ssl.false_start.require-forward-secrecy");
   return NS_OK;
 }
 
 void nsSSLIOLayerHelpers::clearStoredData()
 {
   mRenegoUnrestrictedSites->Clear();
-  mTLSTolerantSites->Clear();
-  mTLSIntolerantSites->Clear();
-}
-
-void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
-{
-  MutexAutoLock lock(*mutex);
-  // Remember intolerant site only if it is not known as tolerant
-  if (!mTLSTolerantSites->Contains(str))
-    mTLSIntolerantSites->PutEntry(str);
-}
-
-void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
-{
-  MutexAutoLock lock(*mutex);
-  mTLSIntolerantSites->RemoveEntry(str);
-}
-
-bool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
-{
-  MutexAutoLock lock(*mutex);
-  return mTLSIntolerantSites->Contains(str);
+  mTLSIntoleranceInfo.Clear();
 }
 
 void nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString &str)
 {
-  MutexAutoLock lock(*mutex);
+  MutexAutoLock lock(mutex);
   
   if (mRenegoUnrestrictedSites) {
     delete mRenegoUnrestrictedSites;
     mRenegoUnrestrictedSites = nullptr;
   }
 
-  mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>(1);
+  mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
   if (!mRenegoUnrestrictedSites)
     return;
   
   nsCCharSeparatedTokenizer toker(str, ',');
 
   while (toker.hasMoreTokens()) {
     const nsCSubstring &host = toker.nextToken();
     if (!host.IsEmpty()) {
       mRenegoUnrestrictedSites->PutEntry(host);
     }
   }
 }
 
 bool nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString &str)
 {
-  MutexAutoLock lock(*mutex);
+  MutexAutoLock lock(mutex);
   return mRenegoUnrestrictedSites->Contains(str);
 }
 
 void nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
 {
-  MutexAutoLock lock(*mutex);
+  MutexAutoLock lock(mutex);
   mTreatUnsafeNegotiationAsBroken = broken;
 }
 
 bool nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
 {
-  MutexAutoLock lock(*mutex);
+  MutexAutoLock lock(mutex);
   return mTreatUnsafeNegotiationAsBroken;
 }
 
 void nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(int32_t level)
 {
-  MutexAutoLock lock(*mutex);
+  MutexAutoLock lock(mutex);
   mWarnLevelMissingRFC5746 = level;
 }
 
 int32_t nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746()
 {
-  MutexAutoLock lock(*mutex);
+  MutexAutoLock lock(mutex);
   return mWarnLevelMissingRFC5746;
 }
 
 nsresult
 nsSSLIOLayerNewSocket(int32_t family,
                       const char *host,
                       int32_t port,
                       const char *proxyHost,
@@ -2604,41 +2634,41 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, b
     infoObject->SetHasCleartextPhase(true);
   }
 
   // Let's see if we're trying to connect to a site we know is
   // TLS intolerant.
   nsAutoCString key;
   key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
 
-  if (infoObject->SharedState().IOLayerHelpers().isKnownAsIntolerantSite(key)) {
-    if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, false))
-      return NS_ERROR_FAILURE;
-
-    infoObject->SetAllowTLSIntoleranceTimeout(false);
-      
-    // We assume that protocols that use the STARTTLS mechanism should support
-    // modern hellos. For other protocols, if we suspect a site 
-    // does not support TLS, let's also use V2 hellos.
-    // One advantage of this approach, if a site only supports the older
-    // hellos, it is more likely that we will get a reasonable error code
-    // on our single retry attempt.
-  }
-
-  PRBool enabled;
-  if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_SSL3, &enabled)) {
+  SSLVersionRange range;
+  if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
     return NS_ERROR_FAILURE;
   }
-  infoObject->SetSSL3Enabled(enabled);
-  if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_TLS, &enabled)) {
+
+  infoObject->SharedState().IOLayerHelpers()
+    .adjustForTLSIntolerance(infoObject->GetHostName(), infoObject->GetPort(),
+                             range);
+  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+         ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
+          fd, static_cast<unsigned int>(range.min),
+              static_cast<unsigned int>(range.max)));
+
+  if (SSL_VersionRangeSet(fd, &range) != SECSuccess) {
     return NS_ERROR_FAILURE;
   }
-  infoObject->SetTLSEnabled(enabled);
-
-  enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
+  infoObject->SetTLSVersionRange(range);
+
+  // If min == max, then we don't need the intolerance timeout since we have no
+  // lower version to fall back to.
+  if (range.min == range.max) {
+    infoObject->SetAllowTLSIntoleranceTimeout(false);
+  }
+
+  bool enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
   if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) {
     return NS_ERROR_FAILURE;
   }
 
   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
     return NS_ERROR_FAILURE;
   }
 
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -9,16 +9,17 @@
 
 #include "TransportSecurityInfo.h"
 #include "nsISSLSocketControl.h"
 #include "nsIClientAuthDialogs.h"
 #include "nsNSSCertificate.h"
 #include "nsDataHashtable.h"
 #include "nsTHashtable.h"
 #include "mozilla/TimeStamp.h"
+#include "sslt.h"
 
 namespace mozilla {
 namespace psm {
 class SharedSSLState;
 }
 }
 
 class nsIObserver;
@@ -51,16 +52,19 @@ public:
   void SetHandshakeInProgress(bool aIsIn);
   bool GetHandshakeInProgress() { return mHandshakeInProgress; }
   void SetFirstServerHelloReceived() { mFirstServerHelloReceived = true; }
   bool GetFirstServerHelloReceived() { return mFirstServerHelloReceived; }
   bool HandshakeTimeout();
 
   void SetAllowTLSIntoleranceTimeout(bool aAllow);
 
+  void SetTLSVersionRange(SSLVersionRange range) { mTLSVersionRange = range; }
+  SSLVersionRange GetTLSVersionRange() const { return mTLSVersionRange; };
+
   PRStatus CloseSocketAndDestroy(
                 const nsNSSShutDownPreventionLock & proofOfLock);
   
   void SetNegotiatedNPN(const char *value, uint32_t length);
   void SetHandshakeCompleted(bool aResumedSession);
   void NoteTimeUntilReady();
 
   bool GetJoined() { return mJoined; }
@@ -82,22 +86,16 @@ public:
   void SetCertVerificationResult(PRErrorCode errorCode,
               ::mozilla::psm::SSLErrorMessageType errorMessageType);
   
   // for logging only
   PRBool IsWaitingForCertVerification() const
   {
     return mCertVerificationState == waiting_for_cert_verification;
   }
-
-  bool IsSSL3Enabled() const { return mSSL3Enabled; }
-  void SetSSL3Enabled(bool enabled) { mSSL3Enabled = enabled; }
-  bool IsTLSEnabled() const { return mTLSEnabled; }
-  void SetTLSEnabled(bool enabled) { mTLSEnabled = enabled; }
-
   void AddPlaintextBytesRead(uint64_t val) { mPlaintextBytesRead += val; }
 
   bool IsPreliminaryHandshakeDone() const { return mPreliminaryHandshakeDone; }
   void SetPreliminaryHandshakeDone() { mPreliminaryHandshakeDone = true; }
 
   void SetKEAUsed(uint16_t kea) { mKEAUsed = kea; }
   inline int16_t GetKEAExpected() // infallible in nsISSLSocketControl
   {
@@ -120,18 +118,17 @@ public:
 
 private:
   PRFileDesc* mFd;
 
   CertVerificationState mCertVerificationState;
 
   mozilla::psm::SharedSSLState& mSharedState;
   bool mForSTARTTLS;
-  bool mSSL3Enabled;
-  bool mTLSEnabled;
+  SSLVersionRange mTLSVersionRange;
   bool mHandshakePending;
   bool mHasCleartextPhase;
   bool mHandshakeInProgress;
   bool mAllowTLSIntoleranceTimeout;
   bool mRememberClientAuthCertificate;
   bool mPreliminaryHandshakeDone; // after false start items are complete
   PRIntervalTime mHandshakeStartTime;
   bool mFirstServerHelloReceived;
@@ -167,46 +164,53 @@ public:
   void Cleanup();
 
   static bool nsSSLIOLayerInitialized;
   static PRDescIdentity nsSSLIOLayerIdentity;
   static PRDescIdentity nsSSLPlaintextLayerIdentity;
   static PRIOMethods nsSSLIOLayerMethods;
   static PRIOMethods nsSSLPlaintextLayerMethods;
 
-  mozilla::Mutex *mutex;
-  nsTHashtable<nsCStringHashKey> *mTLSIntolerantSites;
-  nsTHashtable<nsCStringHashKey> *mTLSTolerantSites;
-
   nsTHashtable<nsCStringHashKey> *mRenegoUnrestrictedSites;
   bool mTreatUnsafeNegotiationAsBroken;
   int32_t mWarnLevelMissingRFC5746;
 
   void setTreatUnsafeNegotiationAsBroken(bool broken);
   bool treatUnsafeNegotiationAsBroken();
-
   void setWarnLevelMissingRFC5746(int32_t level);
   int32_t getWarnLevelMissingRFC5746();
 
-  static void getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key);
-  bool rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo);
-  void rememberTolerantSite(nsNSSSocketInfo *socketInfo);
+private:
+  struct IntoleranceEntry
+  {
+    uint16_t tolerant;
+    uint16_t intolerant;
 
-  void addIntolerantSite(const nsCString &str);
-  void removeIntolerantSite(const nsCString &str);
-  bool isKnownAsIntolerantSite(const nsCString &str);
+    void AssertInvariant() const
+    {
+      MOZ_ASSERT(intolerant == 0 || tolerant < intolerant);
+    }
+  };
+  nsDataHashtable<nsCStringHashKey, IntoleranceEntry> mTLSIntoleranceInfo;
+public:
+  void rememberTolerantAtVersion(const nsACString & hostname, int16_t port,
+                                 uint16_t tolerant);
+  bool rememberIntolerantAtVersion(const nsACString & hostname, int16_t port,
+                                   uint16_t intolerant, uint16_t minVersion);
+  void adjustForTLSIntolerance(const nsACString & hostname, int16_t port,
+                               /*in/out*/ SSLVersionRange & range);
 
   void setRenegoUnrestrictedSites(const nsCString &str);
   bool isRenegoUnrestrictedSite(const nsCString &str);
-
   void clearStoredData();
 
   bool mFalseStartRequireNPN;
   bool mFalseStartRequireForwardSecrecy;
 private:
+  mozilla::Mutex mutex;
   nsCOMPtr<nsIObserver> mPrefObserver;
 };
 
 nsresult nsSSLIOLayerNewSocket(int32_t family,
                                const char *host,
                                int32_t port,
                                const char *proxyHost,
                                int32_t proxyPort,
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/Makefile.in
@@ -0,0 +1,16 @@
+#! gmake
+# 
+# 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/.
+
+include $(DEPTH)/config/autoconf.mk
+
+EXPORT_LIBRARY = 1
+
+LOCAL_INCLUDES = \
+  -I$(topsrcdir)/security/manager/ssl/src \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "nsNSSIOLayer.h"
+#include "sslproto.h"
+
+#include "gtest/gtest.h"
+
+NS_NAMED_LITERAL_CSTRING(HOST, "example.org");
+const int16_t PORT = 443;
+
+class TLSIntoleranceTest : public ::testing::Test
+{
+protected:
+  nsSSLIOLayerHelpers helpers;
+};
+
+TEST_F(TLSIntoleranceTest, Test_1_2_through_3_0)
+{
+  // No adjustment made when there is no entry for the site.
+  {
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+
+    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                    range.min, range.max));
+  }
+
+  {
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+
+    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                    range.min, range.max));
+  }
+
+  {
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.max);
+
+    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                    range.min, range.max));
+  }
+
+  {
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.max);
+
+    // false because we reached the floor set by range.min
+    ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                     range.min, range.max));
+  }
+
+  {
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    // When rememberIntolerantAtVersion returns false, it also resets the
+    // intolerance information for the server.
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+  }
+}
+
+TEST_F(TLSIntoleranceTest, Test_Tolerant_Overrides_Intolerant_1)
+{
+  ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                  SSL_LIBRARY_VERSION_3_0,
+                                                  SSL_LIBRARY_VERSION_TLS_1_0));
+  helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_0);
+  SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                            SSL_LIBRARY_VERSION_TLS_1_2 };
+  helpers.adjustForTLSIntolerance(HOST, PORT, range);
+  ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+  ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_0, range.max);
+}
+
+TEST_F(TLSIntoleranceTest, Test_Tolerant_Overrides_Intolerant_2)
+{
+  ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                  SSL_LIBRARY_VERSION_3_0,
+                                                  SSL_LIBRARY_VERSION_TLS_1_0));
+  helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_1);
+  SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                            SSL_LIBRARY_VERSION_TLS_1_2 };
+  helpers.adjustForTLSIntolerance(HOST, PORT, range);
+  ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+  ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+}
+
+TEST_F(TLSIntoleranceTest, Test_Intolerant_Does_Not_Override_Tolerant)
+{
+  // No adjustment made when there is no entry for the site.
+  helpers.rememberTolerantAtVersion(HOST, PORT, SSL_LIBRARY_VERSION_TLS_1_0);
+  // false because we reached the floor set by rememberTolerantAtVersion.
+  ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                   SSL_LIBRARY_VERSION_3_0,
+                                                   SSL_LIBRARY_VERSION_TLS_1_0));
+  SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                            SSL_LIBRARY_VERSION_TLS_1_2 };
+  helpers.adjustForTLSIntolerance(HOST, PORT, range);
+  ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+  ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+}
+
+TEST_F(TLSIntoleranceTest, Test_Port_Is_Relevant)
+{
+  helpers.rememberTolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_2);
+  ASSERT_FALSE(helpers.rememberIntolerantAtVersion(HOST, 1,
+                                                   SSL_LIBRARY_VERSION_3_0,
+                                                   SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, 2,
+                                                  SSL_LIBRARY_VERSION_3_0,
+                                                  SSL_LIBRARY_VERSION_TLS_1_2));
+
+  {
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, 1, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+  }
+
+  {
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, 2, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/gtest/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+MODULE = 'ssltest'
+
+LIBRARY_NAME = 'ssltest'
+
+LIBXUL_LIBRARY = True
+
+GTEST_CPP_SOURCES += [
+	'TLSIntoleranceTest.cpp',
+]
--- a/security/manager/ssl/tests/moz.build
+++ b/security/manager/ssl/tests/moz.build
@@ -1,12 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DIRS += ['unit']
-TEST_DIRS += ['mochitest']
+
+TEST_DIRS += [
+	'gtest',
+	'mochitest',
+]
 
 MODULE = 'pipnss'
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
--- a/security/manager/ssl/tests/unit/moz.build
+++ b/security/manager/ssl/tests/unit/moz.build
@@ -2,9 +2,8 @@
 # vim: set filetype=python:
 # 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/.
 
 DIRS += ['tlsserver']
 
 MODULE = 'pipnss'
-
--- a/testing/marionette/client/marionette/client.py
+++ b/testing/marionette/client/marionette/client.py
@@ -47,17 +47,17 @@ class MarionetteClient(object):
         response = self.sock.recv(10)
         sep = response.find(':')
         length = response[0:sep]
         if length != '':
             response = response[sep + 1:]
             response += self._recv_n_bytes(int(length) + 1 + len(length) - 10)
             return json.loads(response)
         else:
-            raise InvalidResponseException("Could not successfully complete " \
+            raise InvalidResponseException("Could not successfully complete "
                                            "transport of message to Gecko, "
                                            "socket closed?",
                                            status=ErrorCodes.INVALID_RESPONSE)
 
     def connect(self, timeout=240.0):
         """ Connect to the server and process the hello message we expect
             to receive in response.
         """
@@ -70,17 +70,17 @@ class MarionetteClient(object):
             # another connection attemp