Merge inbound to m-c
authorWes Kocher <wkocher@mozilla.com>
Tue, 15 Oct 2013 20:15:17 -0700
changeset 164644 1990042c0ae6cb896c03d637edb2159bb1c7c90f
parent 164603 71909c62bc14f4eb4ad0c535207ad8d92a6066e6 (current diff)
parent 164643 a2e78dec2ccf750bc511d0b53d059bc35fcfdc06 (diff)
child 164653 9f63bbc005279333095be0000696dcf12629b16d
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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'
+