Merge mozilla-central into build-system
authorGregory Szorc <gps@mozilla.com>
Mon, 25 Feb 2013 22:09:18 -0800
changeset 123264 f5edb9df59386952a904d6b0251ec83479b3cffb
parent 123263 632f21df7be14b26688adeb73634e8cfde685c1b (current diff)
parent 122954 dd821b465e9797c8b04e0f41caed222c9eeed414 (diff)
child 123265 1ef658c8d6462e0c54ae57f713a2a3320e75253c
push id24376
push userMs2ger@gmail.com
push dateThu, 28 Feb 2013 17:05:14 +0000
treeherdermozilla-central@c65d59d33aa8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone22.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 mozilla-central into build-system Only conflict was configure.in amd was due to context, not changed lines themselves.
browser/branding/aurora/Makefile.in
browser/branding/nightly/Makefile.in
browser/branding/official/Makefile.in
browser/branding/unofficial/Makefile.in
browser/metro/shell/Makefile.in
browser/metro/shell/VisualElementsManifest.xml.in
configure.in
content/html/content/src/nsHTMLIFrameElement.cpp
content/html/content/src/nsHTMLIFrameElement.h
content/xbl/builtin/Makefile.in
js/src/configure.in
js/xpconnect/tests/mochitest/test_bug553407.html
mobile/android/base/Makefile.in
toolkit/modules/Makefile.in
--- a/browser/base/content/test/test_bug787619.html
+++ b/browser/base/content/test/test_bug787619.html
@@ -13,17 +13,17 @@
 
   <a id="wrapper">
     <embed id="plugin" style="width: 200px; height: 200px" type="application/x-test">
   </a>
 
   <script class="testbody" type="application/javascript;version=1.7">
   SimpleTest.waitForExplicitFinish();
 
-  const Ci = Components.interfaces;
+  const Ci = SpecialPowers.Ci;
   let wrapperClickCount = 0;
 
   function test1() {
     let plugin = document.getElementById('plugin');
     ok(plugin, 'got plugin element');
     let objLC = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
     ok(!objLC.activated, 'plugin should not be activated');
 
--- a/browser/branding/aurora/Makefile.in
+++ b/browser/branding/aurora/Makefile.in
@@ -59,9 +59,16 @@ BRANDING_FILES := \
 	document-os2.ico \
 	$(NULL)
 endif
 
 BRANDING_DEST := $(DIST)/branding
 BRANDING_TARGET := export
 INSTALL_TARGETS += BRANDING
 
+ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows metro)
+VISUALMANIFEST := VisualElementsManifest.xml
+VISUALMANIFEST_FLAGS := -Fsubstitution -DMOZ_APP_DISPLAYNAME=${MOZ_APP_DISPLAYNAME}
+VISUALMANIFEST_PATH := $(DIST)/bin
+PP_TARGETS += VISUALMANIFEST
+endif
+
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/branding/aurora/VisualElementsManifest.xml
@@ -0,0 +1,16 @@
+<Application
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <VisualElements
+      DisplayName="@MOZ_APP_DISPLAYNAME@"
+      Logo="tileresources\VisualElements_logo.png"
+      SmallLogo="tileresources\VisualElements_smalllogo.png"
+      ForegroundText="light"
+      BackgroundColor="#1c112e">
+    <DefaultTile
+        ShortName="@MOZ_APP_DISPLAYNAME@"
+        ShowName="allLogos"
+            />
+    <SplashScreen
+        Image="tileresources\VisualElements_splashscreen.png" />
+  </VisualElements>
+</Application>
--- a/browser/branding/nightly/Makefile.in
+++ b/browser/branding/nightly/Makefile.in
@@ -59,9 +59,16 @@ BRANDING_FILES := \
 	document-os2.ico \
 	$(NULL)
 endif
 
 BRANDING_DEST := $(DIST)/branding
 BRANDING_TARGET := export
 INSTALL_TARGETS += BRANDING
 
+ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows metro)
+VISUALMANIFEST := VisualElementsManifest.xml
+VISUALMANIFEST_FLAGS := -Fsubstitution -DMOZ_APP_DISPLAYNAME=${MOZ_APP_DISPLAYNAME}
+VISUALMANIFEST_PATH := $(DIST)/bin
+PP_TARGETS += VISUALMANIFEST
+endif
+
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/branding/nightly/VisualElementsManifest.xml
@@ -0,0 +1,16 @@
+<Application
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <VisualElements
+      DisplayName="@MOZ_APP_DISPLAYNAME@"
+      Logo="tileresources\VisualElements_logo.png"
+      SmallLogo="tileresources\VisualElements_smalllogo.png"
+      ForegroundText="light"
+      BackgroundColor="#001226">
+    <DefaultTile
+        ShortName="@MOZ_APP_DISPLAYNAME@"
+        ShowName="allLogos"
+            />
+    <SplashScreen
+        Image="tileresources\VisualElements_splashscreen.png" />
+  </VisualElements>
+</Application>
--- a/browser/branding/official/Makefile.in
+++ b/browser/branding/official/Makefile.in
@@ -59,9 +59,16 @@ BRANDING_FILES := \
 	document-os2.ico \
 	$(NULL)
 endif
 
 BRANDING_DEST := $(DIST)/branding
 BRANDING_TARGET := export
 INSTALL_TARGETS += BRANDING
 
+ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows metro)
+VISUALMANIFEST := VisualElementsManifest.xml
+VISUALMANIFEST_FLAGS := -Fsubstitution -DMOZ_APP_DISPLAYNAME=${MOZ_APP_DISPLAYNAME}
+VISUALMANIFEST_PATH := $(DIST)/bin
+PP_TARGETS += VISUALMANIFEST
+endif
+
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/branding/official/VisualElementsManifest.xml
@@ -0,0 +1,16 @@
+<Application
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <VisualElements
+      DisplayName="@MOZ_APP_DISPLAYNAME@"
+      Logo="tileresources\VisualElements_logo.png"
+      SmallLogo="tileresources\VisualElements_smalllogo.png"
+      ForegroundText="light"
+      BackgroundColor="#1895f5">
+    <DefaultTile
+        ShortName="@MOZ_APP_DISPLAYNAME@"
+        ShowName="allLogos"
+            />
+    <SplashScreen
+        Image="tileresources\VisualElements_splashscreen.png" />
+  </VisualElements>
+</Application>
--- a/browser/branding/unofficial/Makefile.in
+++ b/browser/branding/unofficial/Makefile.in
@@ -59,9 +59,16 @@ BRANDING_FILES := \
 	document-os2.ico \
 	$(NULL)
 endif
 
 BRANDING_DEST := $(DIST)/branding
 BRANDING_TARGET := export
 INSTALL_TARGETS += BRANDING
 
+ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows metro)
+VISUALMANIFEST := VisualElementsManifest.xml
+VISUALMANIFEST_FLAGS := -Fsubstitution -DMOZ_APP_DISPLAYNAME=${MOZ_APP_DISPLAYNAME}
+VISUALMANIFEST_PATH := $(DIST)/bin
+PP_TARGETS += VISUALMANIFEST
+endif
+
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/branding/unofficial/VisualElementsManifest.xml
@@ -0,0 +1,16 @@
+<Application
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <VisualElements
+      DisplayName="@MOZ_APP_DISPLAYNAME@"
+      Logo="tileresources\VisualElements_logo.png"
+      SmallLogo="tileresources\VisualElements_smalllogo.png"
+      ForegroundText="light"
+      BackgroundColor="#001226">
+    <DefaultTile
+        ShortName="@MOZ_APP_DISPLAYNAME@"
+        ShowName="allLogos"
+            />
+    <SplashScreen
+        Image="tileresources\VisualElements_splashscreen.png" />
+  </VisualElements>
+</Application>
--- a/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
+++ b/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
@@ -3,16 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that chrome debugging works.
 
 var gClient = null;
 var gTab = null;
+var gHomeTab = null;
 var gThreadClient = null;
 var gNewGlobal = false;
 var gAttached = false;
 var gChromeScript = false;
 const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
 
 function test()
 {
@@ -28,18 +29,17 @@ function test()
         gClient.addListener("newScript", onNewScript);
 
         gClient.attachThread(dbg, function(aResponse, aThreadClient) {
           gThreadClient = aThreadClient;
           ok(!aResponse.error, "Attached to the chrome debugger.");
           gAttached = true;
 
           // Ensure that a new global will be created.
-          let frame = content.document.createElement("iframe");
-          content.document.querySelector("body").appendChild(frame);
+          gHomeTab = gBrowser.addTab("about:home");
 
           finish_test();
         });
       });
     });
   });
 }
 
@@ -53,16 +53,17 @@ function onNewScript(aEvent, aScript)
 
 function finish_test()
 {
   if (!gAttached || !gChromeScript) {
     return;
   }
   gClient.removeListener("newScript", onNewScript);
   gThreadClient.resume(function(aResponse) {
+    removeTab(gHomeTab);
     removeTab(gTab);
     gClient.close(function() {
       ok(gNewGlobal, "Received newGlobal event.");
       ok(gChromeScript, "Received newScript event for a chrome: script.");
       finish();
     });
   });
 }
--- a/browser/metro/base/content/input.js
+++ b/browser/metro/base/content/input.js
@@ -214,17 +214,17 @@ var TouchModule = {
     // stop kinetic panning if targetScrollbox has changed
     if (this._kinetic.isActive() && this._dragger != dragger)
       this._kinetic.end();
 
     this._targetScrollbox = targetScrollInterface ? targetScrollInterface.element : targetScrollbox;
     this._targetScrollInterface = targetScrollInterface;
 
     if (!this._targetScrollbox) {
-      return false;
+      return;
     }
 
     // XXX shouldn't dragger always be valid here?
     if (dragger) {
       let draggable = dragger.isDraggable(targetScrollbox, targetScrollInterface);
       dragData.locked = !draggable.x || !draggable.y;
       if (draggable.x || draggable.y) {
         this._dragger = dragger;
--- a/browser/metro/shell/Makefile.in
+++ b/browser/metro/shell/Makefile.in
@@ -8,20 +8,13 @@ srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 MODULE    = metro
 
 include $(DEPTH)/config/autoconf.mk
 
 export::
 	$(NSINSTALL) $(srcdir)/resources.pri $(DIST)/bin
-	$(RM) $(DIST)/bin/VisualElementsManifest.xml
-	$(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) -DMOZ_APP_DISPLAYNAME=${MOZ_APP_DISPLAYNAME} \
-	  $(srcdir)/VisualElementsManifest.xml.in > $(DIST)/bin/VisualElementsManifest.xml
 
 install::
 	$(NSINSTALL) $(srcdir)/resources.pri $(DIST)/bin
 
-# bug 744566
-#	$(RM) $(DIST)/bin/resources.pri
-# 	$(MAKEPRI) new -v -pr $(srcdir)/tileresources -cf $(srcdir)/priconfig.xml -mn $(srcdir)/AppManifest.xml -of $(DIST)/bin/resources.pri -o
-
 include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/browser/metro/shell/VisualElementsManifest.xml.in
+++ /dev/null
@@ -1,16 +0,0 @@
-<Application
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <VisualElements
-      DisplayName="@MOZ_APP_DISPLAYNAME@"
-      Logo="tileresources\VisualElements_logo.png"
-      SmallLogo="tileresources\VisualElements_smalllogo.png"
-      ForegroundText="light"
-      BackgroundColor="#1895f5">
-    <DefaultTile
-        ShortName="@MOZ_APP_DISPLAYNAME@"
-        ShowName="allLogos"
-            />
-    <SplashScreen
-        Image="tileresources\VisualElements_splashscreen.png" />
-  </VisualElements>
-</Application>
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -89,16 +89,25 @@ if test "$CLANG_CXX"; then
     ## from C.
     ##
     ## mismatched-tags is disabled (bug 780474) mostly because it's useless.
     ## Worse, it's not supported by gcc, so it will cause tryserver bustage
     ## without any easy way for non-Clang users to check for it.
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-mismatched-tags"
 fi
 
+if test -z "$GNU_CC"; then
+    case "$target" in
+    *-mingw*)
+        ## Warning 4099 (equivalent of mismatched-tags) is disabled (bug 780474)
+        ## for the same reasons as above.
+        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -wd4099"
+    esac
+fi
+
 if test "$GNU_CC"; then
     CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
     CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fno-exceptions"
 fi
 
 dnl ========================================================
 dnl = Identical Code Folding
 dnl ========================================================
--- a/configure.in
+++ b/configure.in
@@ -2152,18 +2152,19 @@ ia64*-hpux*)
         # name of the enum itself.  This behavior is allowed in C++11, and the
         # warning has been removed in VS2012.
         # MSVC warning C4800 warns when a value is implicitly cast to bool,
         # because this also forces narrowing to a single byte, which can be a
         # perf hit.  But this matters so little in practice (and often we want
         # that behavior) that it's better to turn it off.
         # MSVC warning C4819 warns some UTF-8 characters (e.g. copyright sign)
         # on non-Western system locales even if it is in a comment.
+        # khuey says we can safely ignore MSVC warning C4251
         CFLAGS="$CFLAGS -wd4819"
-        CXXFLAGS="$CXXFLAGS -wd4345 -wd4351 -wd4482 -wd4800 -wd4819"
+        CXXFLAGS="$CXXFLAGS -wd4251 -wd4345 -wd4351 -wd4482 -wd4800 -wd4819"
         # make 'foo == bar;' error out
         CFLAGS="$CFLAGS -we4553"
         CXXFLAGS="$CXXFLAGS -we4553"
         LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib secur32.lib netapi32.lib"
         MOZ_DEBUG_FLAGS='-Zi'
         MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
         WARNINGS_AS_ERRORS='-WX'
         MOZ_OPTIMIZE_FLAGS='-O1'
@@ -8960,30 +8961,33 @@ case "$host" in
 *-apple-darwin11*)
     FIXED_EGREP="env ARCHPREFERENCE=i386,x86_64 arch egrep"
     ;;
 *)
     FIXED_EGREP="egrep"
     ;;
 esac
 
-# target_arch is from {ia32|x64|arm}
+# target_arch is from {ia32|x64|arm|ppc}
 case "$CPU_ARCH" in
 x86_64 | ia64)
     WEBRTC_TARGET_ARCH=x64
     ;;
 
 arm*)
     WEBRTC_TARGET_ARCH=arm
     ;;
 
 x86)
     WEBRTC_TARGET_ARCH=ia32
     ;;
 
+ppc*)
+    WEBRTC_TARGET_ARCH=ppc
+    ;;
 *)
 # unsupported arch for webrtc
     WEBRTC_TARGET_ARCH=unknown
     MOZ_WEBRTC=
     ;;
 
 esac
 
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -81,17 +81,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "nsIAppsService.h"
 #include "sampler.h"
 
 #include "jsapi.h"
-#include "nsHTMLIFrameElement.h"
+#include "mozilla/dom/HTMLIFrameElement.h"
 #include "nsSandboxFlags.h"
 
 #include "mozilla/dom/StructuredCloneUtils.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
@@ -445,18 +445,18 @@ nsFrameLoader::ReallyStartLoadingInterna
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
 
   // Is this an <iframe> with a sandbox attribute or a parent which is
   // sandboxed ?
-  nsHTMLIFrameElement* iframe =
-    nsHTMLIFrameElement::FromContent(mOwnerContent);
+  HTMLIFrameElement* iframe =
+    HTMLIFrameElement::FromContent(mOwnerContent);
 
   uint32_t sandboxFlags = 0;
 
   if (iframe) {
     sandboxFlags = iframe->GetSandboxFlags();
 
     uint32_t parentSandboxFlags = iframe->OwnerDoc()->GetSandboxFlags();
 
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -1020,17 +1020,18 @@ nsScriptLoader::ConvertToUTF16(nsIChanne
     // the BOM for endianness. Both the UTF-16 and the UTF-8 decoder will
     // take care of swallowing the BOM.
     charsetConv->GetUnicodeDecoderRaw(charset.get(),
                                       getter_AddRefs(unicodeDecoder));
   }
 
   if (!unicodeDecoder &&
       aChannel &&
-      NS_SUCCEEDED(aChannel->GetContentCharset(charset))) {
+      NS_SUCCEEDED(aChannel->GetContentCharset(charset)) &&
+      !charset.IsEmpty()) {
     charsetConv->GetUnicodeDecoder(charset.get(),
                                    getter_AddRefs(unicodeDecoder));
   }
 
   if (!unicodeDecoder && !aHintCharset.IsEmpty()) {
     CopyUTF16toUTF8(aHintCharset, charset);
     charsetConv->GetUnicodeDecoder(charset.get(),
                                    getter_AddRefs(unicodeDecoder));
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -3366,16 +3366,18 @@ void
 nsXMLHttpRequest::SetMultipart(bool aMultipart, nsresult& aRv)
 {
   if (!(mState & XML_HTTP_REQUEST_UNSENT)) {
     // Can't change this while we're in the middle of something.
     aRv = NS_ERROR_IN_PROGRESS;
     return;
   }
 
+  LogMessage("MultipartXHRWarning", GetOwner());
+
   if (aMultipart) {
     mState |= XML_HTTP_REQUEST_MULTIPART;
   } else {
     mState &= ~XML_HTTP_REQUEST_MULTIPART;
   }
 }
 
 /* attribute boolean mozBackgroundRequest; */
--- a/content/base/test/test_XHR_anon.html
+++ b/content/base/test/test_XHR_anon.html
@@ -19,20 +19,18 @@
 // An XHR with the anon flag set will not send cookie and auth information.
 const TEST_URL = "http://example.com/tests/content/base/test/file_XHR_anon.sjs";
 document.cookie = "foo=bar";
 
 let am = {
   authMgr: null,
 
   init: function() {
-    const {classes: Cc, interfaces: Ci} = SpecialPowers.wrap(Components);
-
-    this.authMgr = Cc["@mozilla.org/network/http-auth-manager;1"]
-                     .getService(Components.interfaces.nsIHttpAuthManager)
+    this.authMgr = SpecialPowers.Cc["@mozilla.org/network/http-auth-manager;1"]
+                                .getService(SpecialPowers.Ci.nsIHttpAuthManager)
   },
 
   addIdentity: function() {
     this.authMgr.setAuthIdentity("http", "example.com", -1, "basic", "testrealm",
                                  "", "example.com", "user1", "password1");
   },
 
   tearDown: function() {
--- a/content/base/test/test_bug425013.html
+++ b/content/base/test/test_bug425013.html
@@ -10,17 +10,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body onload="runtests();">
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=425013">Mozilla Bug 425013</a>
 <br>
 
 <script type="text/javascript;version=1.7">
 var missingPlugins = new Array();
-var OBJLC = Components.interfaces.nsIObjectLoadingContent;
+var OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
 
 function pluginBinding(event)
 {
   var plugin = event.target;
   plugin instanceof OBJLC;
   if (SpecialPowers.wrap(plugin).pluginFallbackType == OBJLC.PLUGIN_UNSUPPORTED)
     missingPlugins.push(plugin);
 }
--- a/content/base/test/test_bug429157.html
+++ b/content/base/test/test_bug429157.html
@@ -10,17 +10,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body onload="runtests();">
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=429157">Mozilla Bug 429157</a>
 <br>
 
 <script>
 var missingPlugins = new Array();
-const OBJLC = Components.interfaces.nsIObjectLoadingContent;
+const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
 
 function pluginBindingAttached(event)
 {
   var plugin = event.target;
   plugin instanceof OBJLC;
   if (SpecialPowers.wrap(plugin).pluginFallbackType == OBJLC.PLUGIN_UNSUPPORTED)
     missingPlugins.push(plugin);
 }
--- a/content/base/test/test_bug810494.html
+++ b/content/base/test/test_bug810494.html
@@ -14,17 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=810494">Mozilla Bug 810494</a>
 <pre id="test">
 <script type="application/javascript;version=1.8">
 
 function test(tag, type) {
   "use strict";
   info("testing " + tag + " tag with type " + type);
 
-  const OBJLC = Components.interfaces.nsIObjectLoadingContent;
+  const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
   let obj = document.createElement(tag);
   obj.type = type;
   document.body.appendChild(obj);
 
   obj instanceof OBJLC;
   obj = SpecialPowers.wrap(obj);
 
   // We expect this tag to simply go to alternate content, not get a
--- a/content/base/test/test_child_process_shutdown_message.html
+++ b/content/base/test/test_child_process_shutdown_message.html
@@ -11,24 +11,22 @@
 <p id="display">
 </p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="application/javascript;version=1.8">
 
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = SpecialPowers.wrap(Components);
-
 const APP_URL = "http://example.org";
 const APP_MANIFEST = "http://example.org/manifest.webapp";
 const CHILD_PROCESS_SHUTDOWN_MESSAGE = "child-process-shutdown";
 
-let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
-             .getService(Ci.nsIMessageBroadcaster);
+let ppmm = SpecialPowers.Cc["@mozilla.org/parentprocessmessagemanager;1"]
+                        .getService(SpecialPowers.Ci.nsIMessageBroadcaster);
 
 /**
  * Load the example.org site in an <iframe mozbrowser>
  *
  * @param isApp
  *        If true, the example.org site will be loaded as an app.
  */
 function loadBrowser(isApp, callback) {
--- a/content/base/test/test_messagemanager_assertpermission.html
+++ b/content/base/test/test_messagemanager_assertpermission.html
@@ -10,28 +10,26 @@
 <p id="display">
 </p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="application/javascript;version=1.8">
 
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = SpecialPowers.wrap(Components);
-
 const APP_URL = "http://example.org";
 const APP_MANIFEST = "http://example.org/manifest.webapp";
 const CHILD_PROCESS_SHUTDOWN_MESSAGE = "child-process-shutdown";
 
-let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
-             .getService(Ci.nsIMessageBroadcaster);
-let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
-             .getService(Ci.nsISyncMessageSender);
-let gAppsService = Cc["@mozilla.org/AppsService;1"]
-                     .getService(Ci.nsIAppsService);
+let ppmm = SpecialPowers.Cc["@mozilla.org/parentprocessmessagemanager;1"]
+                        .getService(SpecialPowers.Ci.nsIMessageBroadcaster);
+let cpmm = SpecialPowers.Cc["@mozilla.org/childprocessmessagemanager;1"]
+                        .getService(SpecialPowers.Ci.nsISyncMessageSender);
+let gAppsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"]
+                     .getService(SpecialPowers.Ci.nsIAppsService);
 
 function setUp() {
   SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
   SpecialPowers.setBoolPref("dom.ipc.browser_frames.oop_by_default", true);
   SpecialPowers.addPermission("browser", true, window.document);
   SpecialPowers.addPermission("embed-apps", true, window.document);
 
   let appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
--- a/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
+++ b/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
@@ -40,18 +40,18 @@ var OPTIONS = {
       throw error;
     }
     return request.responseText;
   };
 
 SimpleTest.waitForExplicitFinish();
 
 function detectDriverType() {
-  const Cc = SpecialPowers.wrap(Components).classes;
-  const Ci = SpecialPowers.wrap(Components).interfaces;
+  const Cc = SpecialPowers.Cc;
+  const Ci = SpecialPowers.Ci;
   var doc = Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser).parseFromString("<html/>", "text/html");
 
   var canvas = doc.createElement("canvas");
   canvas.width = 1;
   canvas.height = 1;
 
   var type = "";
   var gl;
@@ -100,25 +100,25 @@ function start() {
   // Set kMacVersion to the OS X version for Mac, and 0 otherwise.
   var osxmatch = /Mac OS X (\d+.\d+)/.exec(navigator.userAgent);
   var kMacVersion = osxmatch ? parseFloat(osxmatch[1]) : 0;
 
   var kIsWindowsVistaOrHigher = false;
   if (kIsWindows) {
     // code borrowed from browser/modules/test/browser_taskbar_preview.js
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var version = Components.classes["@mozilla.org/system-info;1"]
-                            .getService(Components.interfaces.nsIPropertyBag2)
+    var version = SpecialPowers.Cc["@mozilla.org/system-info;1"]
+                            .getService(SpecialPowers.Ci.nsIPropertyBag2)
                             .getProperty("version");
     kIsWindowsVistaOrHigher = (parseFloat(version) >= 6.0);
   }
 
   function getEnv(env) {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var envsvc = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment);
+    var envsvc = SpecialPowers.Cc["@mozilla.org/process/environment;1"].getService(SpecialPowers.Ci.nsIEnvironment);
     var val = envsvc.get(env);
     if (val == "")
       return null;
     return val;
   }
 
   var reportType = WebGLTestHarnessModule.TestHarness.reportType;
 
rename from content/html/content/src/nsHTMLIFrameElement.cpp
rename to content/html/content/src/HTMLIFrameElement.cpp
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/HTMLIFrameElement.cpp
@@ -1,104 +1,104 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "mozilla/Util.h"
 
-#include "nsHTMLIFrameElement.h"
+#include "mozilla/dom/HTMLIFrameElement.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "nsError.h"
 #include "nsRuleData.h"
 #include "nsStyleConsts.h"
 #include "nsContentUtils.h"
 
-using namespace mozilla;
-using namespace mozilla::dom;
-
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
 
-nsHTMLIFrameElement::nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
-                                         FromParser aFromParser)
+DOMCI_NODE_DATA(HTMLIFrameElement, mozilla::dom::HTMLIFrameElement)
+
+namespace mozilla {
+namespace dom {
+
+HTMLIFrameElement::HTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                                     FromParser aFromParser)
   : nsGenericHTMLFrameElement(aNodeInfo, aFromParser)
 {
 }
 
-nsHTMLIFrameElement::~nsHTMLIFrameElement()
+HTMLIFrameElement::~HTMLIFrameElement()
 {
 }
 
-NS_IMPL_ADDREF_INHERITED(nsHTMLIFrameElement, Element)
-NS_IMPL_RELEASE_INHERITED(nsHTMLIFrameElement, Element)
-
-DOMCI_NODE_DATA(HTMLIFrameElement, nsHTMLIFrameElement)
+NS_IMPL_ADDREF_INHERITED(HTMLIFrameElement, Element)
+NS_IMPL_RELEASE_INHERITED(HTMLIFrameElement, Element)
 
-// QueryInterface implementation for nsHTMLIFrameElement
-NS_INTERFACE_TABLE_HEAD(nsHTMLIFrameElement)
-  NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(nsHTMLIFrameElement)
-    NS_INTERFACE_TABLE_ENTRY(nsHTMLIFrameElement, nsIDOMHTMLIFrameElement)
-    NS_INTERFACE_TABLE_ENTRY(nsHTMLIFrameElement, nsIDOMGetSVGDocument)
+// QueryInterface implementation for HTMLIFrameElement
+NS_INTERFACE_TABLE_HEAD(HTMLIFrameElement)
+  NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(HTMLIFrameElement)
+    NS_INTERFACE_TABLE_ENTRY(HTMLIFrameElement, nsIDOMHTMLIFrameElement)
+    NS_INTERFACE_TABLE_ENTRY(HTMLIFrameElement, nsIDOMGetSVGDocument)
   NS_OFFSET_AND_INTERFACE_TABLE_END
-  NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLIFrameElement,
+  NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(HTMLIFrameElement,
                                                nsGenericHTMLFrameElement)
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLIFrameElement)
 
-NS_IMPL_ELEMENT_CLONE(nsHTMLIFrameElement)
+NS_IMPL_ELEMENT_CLONE(HTMLIFrameElement)
 
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Align, align)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, FrameBorder, frameborder)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Height, height)
-NS_IMPL_URI_ATTR(nsHTMLIFrameElement, LongDesc, longdesc)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, MarginHeight, marginheight)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, MarginWidth, marginwidth)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Name, name)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Scrolling, scrolling)
-NS_IMPL_URI_ATTR(nsHTMLIFrameElement, Src, src)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Width, width)
-NS_IMPL_BOOL_ATTR(nsHTMLIFrameElement, Allowfullscreen, allowfullscreen)
-NS_IMPL_STRING_ATTR(nsHTMLIFrameElement, Sandbox, sandbox)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, Align, align)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, FrameBorder, frameborder)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, Height, height)
+NS_IMPL_URI_ATTR(HTMLIFrameElement, LongDesc, longdesc)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, MarginHeight, marginheight)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, MarginWidth, marginwidth)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, Name, name)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, Scrolling, scrolling)
+NS_IMPL_URI_ATTR(HTMLIFrameElement, Src, src)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, Width, width)
+NS_IMPL_BOOL_ATTR(HTMLIFrameElement, Allowfullscreen, allowfullscreen)
+NS_IMPL_STRING_ATTR(HTMLIFrameElement, Sandbox, sandbox)
 
 void
-nsHTMLIFrameElement::GetItemValueText(nsAString& aValue)
+HTMLIFrameElement::GetItemValueText(nsAString& aValue)
 {
   GetSrc(aValue);
 }
 
 void
-nsHTMLIFrameElement::SetItemValueText(const nsAString& aValue)
+HTMLIFrameElement::SetItemValueText(const nsAString& aValue)
 {
   SetSrc(aValue);
 }
 
 NS_IMETHODIMP
-nsHTMLIFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
+HTMLIFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
 {
   return nsGenericHTMLFrameElement::GetContentDocument(aContentDocument);
 }
 
 NS_IMETHODIMP
-nsHTMLIFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
+HTMLIFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
 {
   return nsGenericHTMLFrameElement::GetContentWindow(aContentWindow);
 }
 
 NS_IMETHODIMP
-nsHTMLIFrameElement::GetSVGDocument(nsIDOMDocument **aResult)
+HTMLIFrameElement::GetSVGDocument(nsIDOMDocument **aResult)
 {
   return GetContentDocument(aResult);
 }
 
 bool
-nsHTMLIFrameElement::ParseAttribute(int32_t aNamespaceID,
-                                    nsIAtom* aAttribute,
-                                    const nsAString& aValue,
-                                    nsAttrValue& aResult)
+HTMLIFrameElement::ParseAttribute(int32_t aNamespaceID,
+                                  nsIAtom* aAttribute,
+                                  const nsAString& aValue,
+                                  nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::marginwidth) {
       return aResult.ParseSpecialIntValue(aValue);
     }
     if (aAttribute == nsGkAtoms::marginheight) {
       return aResult.ParseSpecialIntValue(aValue);
     }
@@ -175,17 +175,17 @@ MapAttributesIntoRule(const nsMappedAttr
   }
 
   nsGenericHTMLElement::MapScrollingAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
   nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
 }
 
 NS_IMETHODIMP_(bool)
-nsHTMLIFrameElement::IsAttributeMapped(const nsIAtom* aAttribute) const
+HTMLIFrameElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
   static const MappedAttributeEntry attributes[] = {
     { &nsGkAtoms::width },
     { &nsGkAtoms::height },
     { &nsGkAtoms::frameborder },
     { nullptr },
   };
 
@@ -197,25 +197,25 @@ nsHTMLIFrameElement::IsAttributeMapped(c
   };
   
   return FindAttributeDependence(aAttribute, map);
 }
 
 
 
 nsMapRuleToAttributesFunc
-nsHTMLIFrameElement::GetAttributeMappingFunction() const
+HTMLIFrameElement::GetAttributeMappingFunction() const
 {
   return &MapAttributesIntoRule;
 }
 
 nsresult
-nsHTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                                  const nsAttrValue* aValue,
-                                  bool aNotify)
+HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+                                const nsAttrValue* aValue,
+                                bool aNotify)
 {
   if (aName == nsGkAtoms::sandbox && aNameSpaceID == kNameSpaceID_None) {
     // Parse the new value of the sandbox attribute, and if we have a docshell
     // set its sandbox flags appropriately.
     if (mFrameLoader) {
       nsCOMPtr<nsIDocShell> docshell = mFrameLoader->GetExistingDocShell();
 
       if (docshell) {
@@ -232,19 +232,22 @@ nsHTMLIFrameElement::AfterSetAttr(int32_
       }
     }
   }
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                             aNotify);
 }
 
 uint32_t
-nsHTMLIFrameElement::GetSandboxFlags()
+HTMLIFrameElement::GetSandboxFlags()
 {
   nsAutoString sandboxAttr;
 
   if (GetAttr(kNameSpaceID_None, nsGkAtoms::sandbox, sandboxAttr)) {
     return nsContentUtils::ParseSandboxAttributeToFlags(sandboxAttr);
   }
 
   // No sandbox attribute, no sandbox flags.
   return 0;
 }
+
+} // namespace dom
+} // namespace mozilla
rename from content/html/content/src/nsHTMLIFrameElement.h
rename to content/html/content/src/HTMLIFrameElement.h
--- a/content/html/content/src/nsHTMLIFrameElement.h
+++ b/content/html/content/src/HTMLIFrameElement.h
@@ -1,27 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef mozilla_dom_HTMLIFrameElement_h
+#define mozilla_dom_HTMLIFrameElement_h
+
 #include "nsGenericHTMLFrameElement.h"
 #include "nsIDOMHTMLIFrameElement.h"
 #include "nsIDOMGetSVGDocument.h"
 
-class nsHTMLIFrameElement : public nsGenericHTMLFrameElement
-                          , public nsIDOMHTMLIFrameElement
-                          , public nsIDOMGetSVGDocument
+namespace mozilla {
+namespace dom {
+
+class HTMLIFrameElement MOZ_FINAL : public nsGenericHTMLFrameElement
+                                  , public nsIDOMHTMLIFrameElement
+                                  , public nsIDOMGetSVGDocument
 {
 public:
-  nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
-                      mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
-  virtual ~nsHTMLIFrameElement();
+  HTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                    FromParser aFromParser = NOT_FROM_PARSER);
+  virtual ~HTMLIFrameElement();
 
-  NS_IMPL_FROMCONTENT_HTML_WITH_TAG(nsHTMLIFrameElement, iframe)
+  NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLIFrameElement, iframe)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
   // nsIDOMElement
@@ -53,8 +59,13 @@ public:
                                 bool aNotify);
 
   uint32_t GetSandboxFlags();
 
 protected:
   virtual void GetItemValueText(nsAString& text);
   virtual void SetItemValueText(const nsAString& text);
 };
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -16,17 +16,16 @@ LIBXUL_LIBRARY	= 1
 ifndef _MSC_VER
 FAIL_ON_WARNINGS = 1
 endif # !_MSC_VER
 
 
 EXPORTS		= \
 		HTMLPropertiesCollection.h \
 		nsGenericHTMLElement.h \
-		nsHTMLIFrameElement.h \
 		nsClientRect.h \
 		nsHTMLDNSPrefetch.h \
 		nsTimeRanges.h \
 		$(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom
 
 EXPORTS_mozilla/dom = \
@@ -38,16 +37,17 @@ EXPORTS_mozilla/dom = \
 		HTMLDataListElement.h \
 		HTMLDivElement.h \
 		HTMLFieldSetElement.h \
 		HTMLFontElement.h \
 		HTMLFrameElement.h \
 		HTMLFrameSetElement.h \
 		HTMLHeadingElement.h \
 		HTMLHRElement.h \
+		HTMLIFrameElement.h \
 		HTMLImageElement.h \
 		HTMLLabelElement.h \
 		HTMLLegendElement.h \
 		HTMLLIElement.h \
 		HTMLLinkElement.h \
 		HTMLMapElement.h \
 		HTMLMenuElement.h \
 		HTMLMenuItemElement.h \
@@ -98,17 +98,17 @@ CPPSRCS		= \
 		HTMLDivElement.cpp \
 		HTMLFieldSetElement.cpp \
 		HTMLFontElement.cpp \
 		nsHTMLFormElement.cpp \
 		HTMLFrameElement.cpp \
 		HTMLFrameSetElement.cpp \
 		HTMLHRElement.cpp \
 		HTMLHeadingElement.cpp \
-		nsHTMLIFrameElement.cpp \
+		HTMLIFrameElement.cpp \
 		HTMLImageElement.cpp \
 		nsHTMLInputElement.cpp \
 		HTMLLIElement.cpp \
 		HTMLLabelElement.cpp \
 		HTMLLegendElement.cpp \
 		HTMLLinkElement.cpp \
 		HTMLMapElement.cpp \
 		HTMLMenuElement.cpp \
--- a/content/xbl/test/test_bug397934.xhtml
+++ b/content/xbl/test/test_bug397934.xhtml
@@ -73,17 +73,17 @@ addLoadEvent(function() {
      "test1" + ": First field wins even if undefined");
   is(typeof(d.emptyTest1), "undefined",
      "test1" + ": First field wins even if undefined, double-check");
   is(d.emptyTest2, "empty2",
      "test1" + ": First field wins");
   is(d.testAncestor, "ancestor",
      "test1" + ": Empty field should not override ancestor binding");
 
-  var win = XPCNativeWrapper.unwrap(window);
+  var win = window;
   win.counter = 0;
   d.testEvalOnce;
   d.testEvalOnce;
   is(win.counter, 1, "Field should have evaluated once and only once");
 
   d = $("display2");
   is(d.storage, undefined,
      "test2" +
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -130,16 +130,24 @@ AudioChannelService::UnregisterType(Audi
   // The array may contain multiple occurrence of this appId but
   // this should remove only the first one.
   AudioChannelInternalType type = GetInternalType(aType, aElementHidden);
   mChannelCounters[type].RemoveElement(aChildID);
 
   // In order to avoid race conditions, it's safer to notify any existing
   // agent any time a new one is registered.
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
+    // We only remove ChildID when it is in the foreground.
+    // If in the background, we kept ChildID for allowing it to play next song.
+    if (aType == AUDIO_CHANNEL_CONTENT &&
+        mActiveContentChildIDs.Contains(aChildID) &&
+        (!aElementHidden &&
+         !mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].Contains(aChildID))) {
+      mActiveContentChildIDs.RemoveElement(aChildID);
+    }
     SendAudioChannelChangedNotification();
     Notify();
   }
 }
 
 bool
 AudioChannelService::GetMuted(AudioChannelAgent* aAgent, bool aElementHidden)
 {
@@ -170,33 +178,41 @@ AudioChannelService::GetMutedInternal(Au
 
   if (newType != oldType) {
     mChannelCounters[newType].AppendElement(aChildID);
     mChannelCounters[oldType].RemoveElement(aChildID);
   }
 
   // If the audio content channel is visible, let's remember this ChildID.
   if (newType == AUDIO_CHANNEL_INT_CONTENT &&
-      oldType == AUDIO_CHANNEL_INT_CONTENT_HIDDEN &&
-      !mActiveContentChildIDs.Contains(aChildID)) {
+      oldType == AUDIO_CHANNEL_INT_CONTENT_HIDDEN) {
 
     if (mActiveContentChildIDsFrozen) {
       mActiveContentChildIDsFrozen = false;
       mActiveContentChildIDs.Clear();
     }
 
-    mActiveContentChildIDs.AppendElement(aChildID);
+    if (!mActiveContentChildIDs.Contains(aChildID)) {
+      mActiveContentChildIDs.AppendElement(aChildID);
+    }
   }
 
-  // If nothing is visible, the list has to been frozen.
   else if (newType == AUDIO_CHANNEL_INT_CONTENT_HIDDEN &&
            oldType == AUDIO_CHANNEL_INT_CONTENT &&
-           !mActiveContentChildIDsFrozen &&
-           mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].IsEmpty()) {
-    mActiveContentChildIDsFrozen = true;
+           !mActiveContentChildIDsFrozen) {
+    // If nothing is visible, the list has to been frozen.
+    // Or if there is still any one with other ChildID in foreground then
+    // it should be removed from list and left other ChildIDs in the foreground
+    // to keep playing. Finally only last one childID which go to background
+    // will be in list.
+    if (mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].IsEmpty()) {
+      mActiveContentChildIDsFrozen = true;
+    } else if (!mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].Contains(aChildID)) {
+      mActiveContentChildIDs.RemoveElement(aChildID);
+    }
   }
 
   if (newType != oldType && aType == AUDIO_CHANNEL_CONTENT) {
     Notify();
   }
 
   // Let play any visible audio channel.
   if (!aElementHidden) {
@@ -286,18 +302,22 @@ AudioChannelService::SendAudioChannelCha
     else if (!mChannelCounters[AUDIO_CHANNEL_INT_ALARM_HIDDEN].IsEmpty()) {
       higher = AUDIO_CHANNEL_ALARM;
     }
 
     else if (!mChannelCounters[AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN].IsEmpty()) {
       higher = AUDIO_CHANNEL_NOTIFICATION;
     }
 
-    // Content channels play in background if just one is active.
-    else if (!mActiveContentChildIDs.IsEmpty()) {
+    // There is only one Child can play content channel in the background.
+    // And need to check whether there is any content channels under playing
+    // now.
+    else if (!mActiveContentChildIDs.IsEmpty() &&
+             mChannelCounters[AUDIO_CHANNEL_INT_CONTENT_HIDDEN].Contains(
+             mActiveContentChildIDs[0])) {
       higher = AUDIO_CHANNEL_CONTENT;
     }
   }
 
   if (higher != mCurrentHigherChannel) {
     mCurrentHigherChannel = higher;
 
     nsString channelName;
--- a/dom/audiochannel/tests/TestAudioChannelService.cpp
+++ b/dom/audiochannel/tests/TestAudioChannelService.cpp
@@ -1,11 +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/. */
+#ifdef XP_WIN
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
 
 #include "TestHarness.h"
 
 #include "AudioChannelService.h"
 #include "AudioChannelAgent.h"
 
 #define TEST_ENSURE_BASE(_test, _msg)       \
   PR_BEGIN_MACRO                            \
@@ -14,29 +19,35 @@
       return NS_ERROR_FAILURE;              \
     } else {                                \
       passed(_msg);                         \
     }                                       \
   PR_END_MACRO
 
 using namespace mozilla::dom;
 
-class Agent
+class Agent : public nsIAudioChannelAgentCallback
 {
 public:
+  NS_DECL_ISUPPORTS
+
   Agent(AudioChannelType aType)
   : mType(aType)
+  , mWaitCallback(false)
   , mRegistered(false)
+  , mCanPlay(false)
   {
     mAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
   }
 
+  virtual ~Agent() {}
+
   nsresult Init()
   {
-    nsresult rv = mAgent->Init(mType, nullptr);
+    nsresult rv = mAgent->Init(mType, this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return mAgent->SetVisibilityState(false);
   }
 
   nsresult StartPlaying(bool *_ret)
   {
     if (mRegistered)
@@ -45,310 +56,375 @@ public:
     nsresult rv = mAgent->StartPlaying(_ret);
     mRegistered = true;
     return rv;
   }
 
   nsresult StopPlaying()
   {
     mRegistered = false;
+    int loop = 0;
+    while (mWaitCallback) {
+      #ifdef XP_WIN
+      Sleep(1000);
+      #else
+      sleep(1);
+      #endif
+      if (loop++ == 5) {
+        TEST_ENSURE_BASE(false, "StopPlaying timeout");
+      }
+    }
     return mAgent->StopPlaying();
   }
 
+  nsresult SetVisibilityState(bool visible)
+  {
+    if (mRegistered) {
+      mWaitCallback = true;
+    }
+    return mAgent->SetVisibilityState(visible);
+  }
+
+  NS_IMETHODIMP CanPlayChanged(bool canPlay)
+  {
+    mCanPlay = canPlay;
+    mWaitCallback = false;
+    return NS_OK;
+  }
+
+  nsresult GetCanPlay(bool *_ret)
+  {
+    int loop = 0;
+    while (mWaitCallback) {
+      #ifdef XP_WIN
+      Sleep(1000);
+      #else
+      sleep(1);
+      #endif
+      if (loop++ == 5) {
+        TEST_ENSURE_BASE(false, "GetCanPlay timeout");
+      }
+    }
+    *_ret = mCanPlay;
+    return NS_OK;
+  }
+
   nsCOMPtr<AudioChannelAgent> mAgent;
   AudioChannelType mType;
+  bool mWaitCallback;
   bool mRegistered;
+  bool mCanPlay;
 };
 
+NS_IMPL_ISUPPORTS1(Agent, nsIAudioChannelAgentCallback)
+
 nsresult
 TestDoubleStartPlaying()
 {
-  Agent agent(AUDIO_CHANNEL_NORMAL);
-  nsresult rv = agent.Init();
+  nsCOMPtr<Agent> agent = new Agent(AUDIO_CHANNEL_NORMAL);
+
+  nsresult rv = agent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool playing;
-  rv = agent.mAgent->StartPlaying(&playing);
+  rv = agent->mAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent.mAgent->StartPlaying(&playing);
+  rv = agent->mAgent->StartPlaying(&playing);
   TEST_ENSURE_BASE(NS_FAILED(rv), "Test0: StartPlaying calling twice should return error");
 
   return NS_OK;
 }
 
 nsresult
 TestOneNormalChannel()
 {
-  Agent agent(AUDIO_CHANNEL_NORMAL);
-  nsresult rv = agent.Init();
+  nsCOMPtr<Agent> agent = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsresult rv = agent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool playing;
-  rv = agent.StartPlaying(&playing);
+  rv = agent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test1: A normal channel unvisible agent must not be playing");
 
-  rv = agent.mAgent->SetVisibilityState(true);
+  rv = agent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent.StartPlaying(&playing);
+  rv = agent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test1: A normal channel visible agent should be playing");
 
   return rv;
 }
 
 nsresult
 TestTwoNormalChannels()
 {
-  Agent agent1(AUDIO_CHANNEL_NORMAL);
-  nsresult rv = agent1.Init();
+  nsCOMPtr<Agent> agent1 = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsresult rv = agent1->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent agent2(AUDIO_CHANNEL_NORMAL);
-  rv = agent2.Init();
+  nsCOMPtr<Agent> agent2 = new Agent(AUDIO_CHANNEL_NORMAL);
+  rv = agent2->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool playing;
-  rv = agent1.StartPlaying(&playing);
+  rv = agent1->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test2: A normal channel unvisible agent1 must not be playing");
 
-  rv = agent2.StartPlaying(&playing);
+  rv = agent2->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test2: A normal channel unvisible agent2 must not be playing");
 
-  rv = agent1.mAgent->SetVisibilityState(true);
+  rv = agent1->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent2.mAgent->SetVisibilityState(true);
+  rv = agent2->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent1.StartPlaying(&playing);
+  rv = agent1->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test2: A normal channel visible agent1 should be playing");
 
-  rv = agent2.StartPlaying(&playing);
+  rv = agent2->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test2: A normal channel visible agent2 should be playing");
 
   return rv;
 }
 
 nsresult
 TestContentChannels()
 {
-  Agent agent1(AUDIO_CHANNEL_CONTENT);
-  nsresult rv = agent1.Init();
+  nsCOMPtr<Agent> agent1 = new Agent(AUDIO_CHANNEL_CONTENT);
+  nsresult rv = agent1->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent agent2(AUDIO_CHANNEL_CONTENT);
-  rv = agent2.Init();
+  nsCOMPtr<Agent> agent2 = new Agent(AUDIO_CHANNEL_CONTENT);
+  rv = agent2->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent1.mAgent->SetVisibilityState(true);
+  /* All content channels in the foreground can be allowed to play */
+  rv = agent1->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent2.mAgent->SetVisibilityState(true);
+  rv = agent2->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool playing;
-  rv = agent1.StartPlaying(&playing);
-  NS_ENSURE_SUCCESS(rv, rv);
-  TEST_ENSURE_BASE(playing, "Test3: A content channel unvisible agent1 should be playing");
-
-  rv = agent2.StartPlaying(&playing);
-  NS_ENSURE_SUCCESS(rv, rv);
-  TEST_ENSURE_BASE(playing, "Test3: A content channel unvisible agent2 should be playing");
-
-  rv = agent1.mAgent->SetVisibilityState(true);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = agent2.mAgent->SetVisibilityState(false);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = agent1.StartPlaying(&playing);
+  rv = agent1->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test3: A content channel visible agent1 should be playing");
 
-  rv = agent2.StartPlaying(&playing);
+  rv = agent2->StartPlaying(&playing);
+  NS_ENSURE_SUCCESS(rv, rv);
+  TEST_ENSURE_BASE(playing, "Test3: A content channel visible agent2 should be playing");
+
+  /* Test the transition state of one content channel tried to set non-visible
+   * state first when app is going to background. */
+  rv = agent1->SetVisibilityState(false);
   NS_ENSURE_SUCCESS(rv, rv);
-  TEST_ENSURE_BASE(playing, "Test3: A content channel unvisible agent2 should be playing");
 
-  rv = agent1.mAgent->SetVisibilityState(true);
+  rv = agent1->GetCanPlay(&playing);
+  NS_ENSURE_SUCCESS(rv, rv);
+  TEST_ENSURE_BASE(playing, "Test3: A content channel unvisible agent1 should be playing from foreground to background");
+
+  /* Test all content channels set non-visible already */
+  rv = agent2->SetVisibilityState(false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent2.mAgent->SetVisibilityState(true);
+  rv = agent2->GetCanPlay(&playing);
+  NS_ENSURE_SUCCESS(rv, rv);
+  TEST_ENSURE_BASE(playing, "Test3: A content channel unvisible agent2 should be playing from foreground to background");
+
+  /* Clear the content channels & mActiveContentChildIDs in AudioChannelService.
+   * If agent stop playing in the background, we will reserve it's childID in
+   * mActiveContentChildIDs, then it can allow to play next song. So we set agents
+   * to foreground first then stopping to play */
+  rv = agent1->SetVisibilityState(true);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = agent2->SetVisibilityState(true);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = agent1->StopPlaying();
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = agent2->StopPlaying();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent1.StartPlaying(&playing);
+  /* Test that content channels can't be allow to play when they starts from the background state */
+  rv = agent1->SetVisibilityState(false);
   NS_ENSURE_SUCCESS(rv, rv);
-  TEST_ENSURE_BASE(playing, "Test3: A content channel visible agent1 should be playing");
+  rv = agent2->SetVisibilityState(false);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = agent2.StartPlaying(&playing);
+  rv = agent1->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
-  TEST_ENSURE_BASE(playing, "Test3: A content channel visible agent2 should be playing");
+  TEST_ENSURE_BASE(!playing, "Test3: A content channel unvisible agent1 must not be playing from background state");
+
+  rv = agent2->StartPlaying(&playing);
+  NS_ENSURE_SUCCESS(rv, rv);
+  TEST_ENSURE_BASE(!playing, "Test3: A content channel unvisible agent2 must not be playing from background state");
 
   return rv;
 }
 
 nsresult
 TestPriorities()
 {
-  Agent normalAgent(AUDIO_CHANNEL_NORMAL);
-  nsresult rv = normalAgent.Init();
+  nsCOMPtr<Agent> normalAgent = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsresult rv = normalAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent contentAgent(AUDIO_CHANNEL_CONTENT);
-  rv = contentAgent.Init();
+  nsCOMPtr<Agent> contentAgent = new Agent(AUDIO_CHANNEL_CONTENT);
+  rv = contentAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent notificationAgent(AUDIO_CHANNEL_NOTIFICATION);
-  rv = notificationAgent.Init();
+  nsCOMPtr<Agent> notificationAgent = new Agent(AUDIO_CHANNEL_NOTIFICATION);
+  rv = notificationAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent alarmAgent(AUDIO_CHANNEL_ALARM);
-  rv = alarmAgent.Init();
+  nsCOMPtr<Agent> alarmAgent = new Agent(AUDIO_CHANNEL_ALARM);
+  rv = alarmAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent telephonyAgent(AUDIO_CHANNEL_TELEPHONY);
-  rv = telephonyAgent.Init();
+  nsCOMPtr<Agent> telephonyAgent = new Agent(AUDIO_CHANNEL_TELEPHONY);
+  rv = telephonyAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent ringerAgent(AUDIO_CHANNEL_RINGER);
-  rv = ringerAgent.Init();
+  nsCOMPtr<Agent> ringerAgent = new Agent(AUDIO_CHANNEL_RINGER);
+  rv = ringerAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  Agent pNotificationAgent(AUDIO_CHANNEL_PUBLICNOTIFICATION);
-  rv = pNotificationAgent.Init();
+  nsCOMPtr<Agent> pNotificationAgent = new Agent(AUDIO_CHANNEL_PUBLICNOTIFICATION);
+  rv = pNotificationAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool playing;
 
   // Normal should not be playing because not visible.
-  rv = normalAgent.StartPlaying(&playing);
+  rv = normalAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
-  TEST_ENSURE_BASE(!playing, "Test4: A normal channel unvisible agent should not be playing");
+  TEST_ENSURE_BASE(!playing, "Test4: A normal channel unvisible agent must not be playing");
 
   // Content should be playing.
-  rv = contentAgent.StartPlaying(&playing);
+  rv = contentAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
-  TEST_ENSURE_BASE(playing, "Test4: A content channel unvisible agent should be playing");
+  TEST_ENSURE_BASE(!playing, "Test4: A content channel unvisible agent must not be playing from background state");
 
   // Notification should be playing.
-  rv = notificationAgent.StartPlaying(&playing);
+  rv = notificationAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: An notification channel unvisible agent should be playing");
 
   // Now content should be not playing because of the notification playing.
-  rv = contentAgent.StartPlaying(&playing);
+  rv = contentAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test4: A content channel unvisible agent should not be playing when notification channel is playing");
 
   // Adding an alarm.
-  rv = alarmAgent.StartPlaying(&playing);
+  rv = alarmAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: An alarm channel unvisible agent should be playing");
 
   // Now notification should be not playing because of the alarm playing.
-  rv = notificationAgent.StartPlaying(&playing);
+  rv = notificationAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test4: A notification channel unvisible agent should not be playing when an alarm is playing");
 
   // Adding an telephony.
-  rv = telephonyAgent.StartPlaying(&playing);
+  rv = telephonyAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: An telephony channel unvisible agent should be playing");
 
   // Now alarm should be not playing because of the telephony playing.
-  rv = alarmAgent.StartPlaying(&playing);
+  rv = alarmAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test4: A alarm channel unvisible agent should not be playing when a telephony is playing");
 
   // Adding an ringer.
-  rv = ringerAgent.StartPlaying(&playing);
+  rv = ringerAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: An ringer channel unvisible agent should be playing");
 
   // Now telephony should be not playing because of the ringer playing.
-  rv = telephonyAgent.StartPlaying(&playing);
+  rv = telephonyAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test4: A telephony channel unvisible agent should not be playing when a riger is playing");
 
   // Adding an pNotification.
-  rv = pNotificationAgent.StartPlaying(&playing);
+  rv = pNotificationAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: An pNotification channel unvisible agent should be playing");
 
   // Now ringer should be not playing because of the public notification playing.
-  rv = ringerAgent.StartPlaying(&playing);
+  rv = ringerAgent->StartPlaying(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(!playing, "Test4: A ringer channel unvisible agent should not be playing when a public notification is playing");
 
   // Settings visible the normal channel.
-  rv = normalAgent.mAgent->SetVisibilityState(true);
+  rv = normalAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Normal should be playing because visible.
-  rv = normalAgent.StartPlaying(&playing);
+  rv = normalAgent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: A normal channel visible agent should be playing");
 
   // Settings visible the content channel.
-  rv = contentAgent.mAgent->SetVisibilityState(true);
+  rv = contentAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Content should be playing because visible.
-  rv = contentAgent.StartPlaying(&playing);
+  rv = contentAgent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: A content channel visible agent should be playing");
 
   // Settings visible the notification channel.
-  rv = notificationAgent.mAgent->SetVisibilityState(true);
+  rv = notificationAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Notification should be playing because visible.
-  rv = notificationAgent.StartPlaying(&playing);
+  rv = notificationAgent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: A notification channel visible agent should be playing");
 
   // Settings visible the alarm channel.
-  rv = alarmAgent.mAgent->SetVisibilityState(true);
+  rv = alarmAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Alarm should be playing because visible.
-  rv = alarmAgent.StartPlaying(&playing);
+  rv = alarmAgent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: A alarm channel visible agent should be playing");
 
   // Settings visible the telephony channel.
-  rv = telephonyAgent.mAgent->SetVisibilityState(true);
+  rv = telephonyAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Telephony should be playing because visible.
-  rv = telephonyAgent.StartPlaying(&playing);
+  rv = telephonyAgent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: A telephony channel visible agent should be playing");
 
   // Settings visible the ringer channel.
-  rv = ringerAgent.mAgent->SetVisibilityState(true);
+  rv = ringerAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Ringer should be playing because visible.
-  rv = ringerAgent.StartPlaying(&playing);
+  rv = ringerAgent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: A ringer channel visible agent should be playing");
 
   // Settings visible the pNotification channel.
-  rv = pNotificationAgent.mAgent->SetVisibilityState(true);
+  rv = pNotificationAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // pNotification should be playing because visible.
-  rv = pNotificationAgent.StartPlaying(&playing);
+  rv = pNotificationAgent->GetCanPlay(&playing);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playing, "Test4: A pNotification channel visible agent should be playing");
 
   return rv;
 }
 
 int main(int argc, char** argv)
 {
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/844559.html
@@ -0,0 +1,3 @@
+<script>
+Components.lookupMethod(Image, "x")
+</script>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -34,8 +34,9 @@ load 693894.html
 load 693811-1.html
 load 693811-2.html
 load 693811-3.html
 load 695867.html
 load 697643.html
 load 706283-1.html
 load 708405-1.html
 load 745495.html
+load 844559.html
--- a/dom/bindings/BindingGen.py
+++ b/dom/bindings/BindingGen.py
@@ -1,66 +1,73 @@
 # 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/.
 
 import os
 import cPickle
 from Configuration import Configuration
-from Codegen import CGBindingRoot, replaceFileIfChanged
+from Codegen import CGBindingRoot
 
-def generate_binding_header(config, outputprefix, webidlfile):
+def generate_binding_header(config, outputprefix, srcprefix, webidlfile):
     """
     |config| Is the configuration object.
     |outputprefix| is a prefix to use for the header guards and filename.
     """
 
     filename = outputprefix + ".h"
+    depsname = ".deps/" + filename + ".pp"
     root = CGBindingRoot(config, outputprefix, webidlfile)
-    if replaceFileIfChanged(filename, root.declare()):
-        print "Generating binding header: %s" % (filename)
+    with open(filename, 'wb') as f:
+        f.write(root.declare())
+    with open(depsname, 'wb') as f:
+        f.write("\n".join(filename + ": " + os.path.join(srcprefix, x) for x in root.deps()))
 
-def generate_binding_cpp(config, outputprefix, webidlfile):
+def generate_binding_cpp(config, outputprefix, srcprefix, webidlfile):
     """
     |config| Is the configuration object.
     |outputprefix| is a prefix to use for the header guards and filename.
     """
 
     filename = outputprefix + ".cpp"
+    depsname = ".deps/" + filename + ".pp"
     root = CGBindingRoot(config, outputprefix, webidlfile)
-    if replaceFileIfChanged(filename, root.define()):
-        print "Generating binding implementation: %s" % (filename)
+    with open(filename, 'wb') as f:
+        f.write(root.define())
+    with open(depsname, 'wb') as f:
+        f.write("\n".join(filename + ": " + os.path.join(srcprefix, x) for x in root.deps()))
 
 def main():
 
     # Parse arguments.
     from optparse import OptionParser
-    usagestring = "usage: %prog [header|cpp] configFile outputPrefix webIDLFile"
+    usagestring = "usage: %prog [header|cpp] configFile outputPrefix srcPrefix webIDLFile"
     o = OptionParser(usage=usagestring)
     o.add_option("--verbose-errors", action='store_true', default=False,
                  help="When an error happens, display the Python traceback.")
     (options, args) = o.parse_args()
 
-    if len(args) != 4 or (args[0] != "header" and args[0] != "cpp"):
+    if len(args) != 5 or (args[0] != "header" and args[0] != "cpp"):
         o.error(usagestring)
     buildTarget = args[0]
     configFile = os.path.normpath(args[1])
     outputPrefix = args[2]
-    webIDLFile = os.path.normpath(args[3])
+    srcPrefix = os.path.normpath(args[3])
+    webIDLFile = os.path.normpath(args[4])
 
     # Load the parsing results
     f = open('ParserResults.pkl', 'rb')
     parserData = cPickle.load(f)
     f.close()
 
     # Create the configuration data.
     config = Configuration(configFile, parserData)
 
     # Generate the prototype classes.
     if buildTarget == "header":
-        generate_binding_header(config, outputPrefix, webIDLFile);
+        generate_binding_header(config, outputPrefix, srcPrefix, webIDLFile);
     elif buildTarget == "cpp":
-        generate_binding_cpp(config, outputPrefix, webIDLFile);
+        generate_binding_cpp(config, outputPrefix, srcPrefix, webIDLFile);
     else:
         assert False # not reached
 
 if __name__ == '__main__':
     main()
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -54,16 +54,19 @@ class CGThing():
     def __init__(self):
         pass # Nothing for now
     def declare(self):
         """Produce code for a header file."""
         assert(False)  # Override me!
     def define(self):
         """Produce code for a cpp file."""
         assert(False) # Override me!
+    def deps(self):
+        """Produce the deps for a pp file"""
+        assert(False) # Override me!
 
 class CGNativePropertyHooks(CGThing):
     """
     Generate a NativePropertyHooks for a given descriptor
     """
     def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
@@ -304,29 +307,38 @@ class CGList(CGThing):
     def prepend(self, child):
         self.children.insert(0, child)
     def join(self, generator):
         return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
     def declare(self):
         return self.join(child.declare() for child in self.children if child is not None)
     def define(self):
         return self.join(child.define() for child in self.children if child is not None)
+    def deps(self):
+        deps = set()
+        for child in self.children:
+            if child is None:
+                continue
+            deps = deps.union(child.deps())
+        return deps
 
 class CGGeneric(CGThing):
     """
     A class that spits out a fixed string into the codegen.  Can spit out a
     separate string for the declaration too.
     """
     def __init__(self, define="", declare=""):
         self.declareText = declare
         self.defineText = define
     def declare(self):
         return self.declareText
     def define(self):
         return self.defineText
+    def deps(self):
+        return set()
 
 # We'll want to insert the indent at the beginnings of lines, but we
 # don't want to indent empty lines.  So only indent lines that have a
 # non-newline character on them.
 lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
 class CGIndenter(CGThing):
     """
     A class that takes another CGThing and generates code that indents that
@@ -382,16 +394,19 @@ class CGWrapper(CGThing):
         defn = self.child.define()
         if self.reindent:
             # We don't use lineStartDetector because we don't want to
             # insert whitespace at the beginning of our _first_ line.
             defn = stripTrailingWhitespace(
                 defn.replace("\n", "\n" + (" " * len(self.definePre))))
         return self.definePre + defn + self.definePost
 
+    def deps(self):
+        return self.child.deps()
+
 class CGIfWrapper(CGWrapper):
     def __init__(self, child, condition):
         pre = CGWrapper(CGGeneric(condition), pre="if (", post=") {\n",
                         reindent=True)
         CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
                            post="\n}")
 
 class CGNamespace(CGWrapper):
@@ -980,24 +995,40 @@ class CGNamedConstructors(CGThing):
     def __init__(self, descriptor):
         self.descriptor = descriptor
         CGThing.__init__(self)
     def declare(self):
         return ""
     def define(self):
         if len(self.descriptor.interface.namedConstructors) == 0:
             return ""
+
+        constructorID = "constructors::id::"
+        if self.descriptor.interface.hasInterfaceObject():
+            constructorID += self.descriptor.name
+        else:
+            constructorID += "_ID_Count"
+        nativePropertyHooks = """const NativePropertyHooks sNamedConstructorNativePropertyHooks = {
+    nullptr,
+    nullptr,
+    { nullptr, nullptr },
+    prototypes::id::%s,
+    %s,
+    nullptr
+};
+
+""" % (self.descriptor.name, constructorID)
         namedConstructors = CGList([], ",\n")
         for n in self.descriptor.interface.namedConstructors:
-            namedConstructors.append(CGGeneric("{ \"%s\", { %s, nullptr }, %i }" % (n.identifier.name, NamedConstructorName(n), methodLength(n))))
+            namedConstructors.append(CGGeneric("{ \"%s\", { %s, &sNamedConstructorNativePropertyHooks }, %i }" % (n.identifier.name, NamedConstructorName(n), methodLength(n))))
         namedConstructors.append(CGGeneric("{ nullptr, { nullptr, nullptr }, 0 }"))
         namedConstructors = CGWrapper(CGIndenter(namedConstructors),
                                       pre="static const NamedConstructor namedConstructors[] = {\n",
                                       post="\n};\n")
-        return namedConstructors.define()
+        return nativePropertyHooks + namedConstructors.define()
 
 class CGClassHasInstanceHook(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
                 Argument('JSMutableHandleValue', 'vp'), Argument('JSBool*', 'bp')]
         CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
                                         'JSBool', args)
 
@@ -4848,16 +4879,19 @@ class CGEnum(CGThing):
         return """
   const EnumEntry strings[%d] = {
     %s,
     { NULL, 0 }
   };
 """ % (len(self.enum.values()) + 1,
        ",\n    ".join(['{"' + val + '", ' + str(len(val)) + '}' for val in self.enum.values()]))
 
+    def deps(self):
+        return self.enum.getDeps()
+
 def getUnionAccessorSignatureType(type, descriptorProvider):
     """
     Returns the types that are used in the getter and setter signatures for
     union types
     """
     if type.isArray():
         raise TypeError("Can't handle array arguments yet")
 
@@ -5738,39 +5772,45 @@ class CGPrototypeTraitsClass(CGClass):
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
                            [descriptor.interface.inheritanceDepth()])]
         typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
         CGClass.__init__(self, 'PrototypeTraits', indent=indent,
                          templateArgs=templateArgs,
                          templateSpecialization=templateSpecialization,
                          enums=enums, typedefs=typedefs, isStruct=True)
+    def deps(self):
+        return set()
 
 class CGPrototypeIDMapClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('class', 'ConcreteClass')]
         templateSpecialization = [descriptor.nativeType]
         enums = [ClassEnum('', ['PrototypeID'],
                            ['prototypes::id::' + descriptor.name])]
         CGClass.__init__(self, 'PrototypeIDMap', indent=indent,
                          templateArgs=templateArgs,
                          templateSpecialization=templateSpecialization,
                          enums=enums, isStruct=True)
+    def deps(self):
+        return set()
 
 class CGClassForwardDeclare(CGThing):
     def __init__(self, name, isStruct=False):
         CGThing.__init__(self)
         self.name = name
         self.isStruct = isStruct
     def declare(self):
         type = 'struct' if self.isStruct else 'class'
         return '%s %s;\n' % (type, self.name)
     def define(self):
         # Header only
         return ''
+    def deps(self):
+        return set()
 
 class CGProxySpecialOperation(CGPerSignatureCall):
     """
     Base class for classes for calling an indexed or named special operation
     (don't use this directly, use the derived classes below).
     """
     def __init__(self, descriptor, operation):
         nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
@@ -6437,16 +6477,18 @@ def stripTrailingWhitespace(text):
     return '\n'.join(lines) + tail
 
 class CGDescriptor(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
 
         assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
 
+        self._deps = descriptor.interface.getDeps()
+
         cgThings = []
         # These are set to true if at least one non-static
         # method/getter/setter exist on the interface.
         (hasMethod, hasGetter, hasLenientGetter,
          hasSetter, hasLenientSetter) = False, False, False, False, False
         for n in descriptor.interface.namedConstructors:
             cgThings.append(CGClassConstructor(descriptor, n,
                                                NamedConstructorName(n)))
@@ -6573,16 +6615,18 @@ class CGDescriptor(CGThing):
         self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
                                             cgThings),
                                 post='\n')
 
     def declare(self):
         return self.cgRoot.declare()
     def define(self):
         return self.cgRoot.define()
+    def deps(self):
+        return self._deps
 
 class CGNamespacedEnum(CGThing):
     def __init__(self, namespace, enumName, names, values, comment=""):
 
         if not values:
             values = []
 
         # Account for explicit enum values.
@@ -6777,16 +6821,19 @@ class CGDictionary(CGThing):
                 "initMembers": "\n\n".join(memberInits),
                 "idInit": CGIndenter(idinit).define(),
                 "isMainThread": toStringBool(not self.workers),
                 "toObjectParent": CGIndenter(CGGeneric(toObjectParent)).define(),
                 "ensureObject": CGIndenter(CGGeneric(ensureObject)).define(),
                 "defineMembers": "\n\n".join(memberDefines)
                 })
 
+    def deps(self):
+        return self.dictionary.getDeps()
+
     @staticmethod
     def makeDictionaryName(dictionary, workers):
         suffix = "Workers" if workers else ""
         return dictionary.identifier.name + suffix
 
     def makeClassName(self, dictionary):
         return self.makeDictionaryName(dictionary, self.workers)
 
@@ -7198,16 +7245,19 @@ class CGBindingRoot(CGThing):
         # Store the final result.
         self.root = curr
 
     def declare(self):
         return stripTrailingWhitespace(self.root.declare())
     def define(self):
         return stripTrailingWhitespace(self.root.define())
 
+    def deps(self):
+        return self.root.deps()
+
 class CGNativeMember(ClassMethod):
     def __init__(self, descriptor, member, name, signature, extendedAttrs,
                  breakAfter=True, passCxAsNeeded=True, visibility="public",
                  jsObjectsArePtr=False, variadicIsSequence=False):
         """
         If jsObjectsArePtr is true, typed arrays and "object" will be
         passed as JSObject*
         """
@@ -7773,16 +7823,17 @@ class CGExampleRoot(CGThing):
 
     def define(self):
         return self.root.define()
 
 class CGCallback(CGClass):
     def __init__(self, idlObject, descriptorProvider, baseName, methods,
                  getters=[], setters=[]):
         self.baseName = baseName
+        self._deps = idlObject.getDeps()
         name = idlObject.identifier.name
         if descriptorProvider.workers:
             name += "Workers"
         # For our public methods that needThisHandling we want most of the
         # same args and the same return type as what CallbackMember
         # generates.  So we want to take advantage of all its
         # CGNativeMember infrastructure, but that infrastructure can't deal
         # with templates and most especially template arguments.  So just
@@ -7862,16 +7913,19 @@ class CGCallback(CGClass):
                             bodyInHeader=True,
                             templateArgs=["typename T"],
                             body=bodyWithThis),
                 ClassMethod(method.name, method.returnType, argsWithoutThis,
                             bodyInHeader=True,
                             body=bodyWithoutThis),
                 method]
 
+    def deps(self):
+        return self._deps
+
 class CGCallbackFunction(CGCallback):
     def __init__(self, callback, descriptorProvider):
         CGCallback.__init__(self, callback, descriptorProvider,
                             "CallbackFunction",
                             methods=[CallCallback(callback, descriptorProvider)])
 
     def getConstructors(self):
         return CGCallback.getConstructors(self) + [
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -60,22 +60,24 @@ class Configuration:
                 d.nativeType != descriptor.nativeType or d == descriptor
                 for d in self.descriptors)
 
         self.enums = [e for e in parseData if e.isEnum()]
 
         # Figure out what our main-thread and worker dictionaries and callbacks
         # are.
         mainTypes = set()
-        for descriptor in self.getDescriptors(workers=False, isExternal=False):
+        for descriptor in ([self.getDescriptor("DummyInterface", workers=False)] +
+                           self.getDescriptors(workers=False, isExternal=False, skipGen=False)):
             mainTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
         (mainCallbacks, mainDictionaries) = findCallbacksAndDictionaries(mainTypes)
 
         workerTypes = set();
-        for descriptor in self.getDescriptors(workers=True, isExternal=False):
+        for descriptor in ([self.getDescriptor("DummyInterfaceWorkers", workers=True)] +
+                           self.getDescriptors(workers=True, isExternal=False, skipGen=False)):
             workerTypes |= set(getFlatTypes(getTypesFromDescriptor(descriptor)))
         (workerCallbacks, workerDictionaries) = findCallbacksAndDictionaries(workerTypes)
 
         self.dictionaries = [d for d in parseData if d.isDictionary()]
         self.callbacks = [c for c in parseData if
                           c.isCallback() and not c.isInterface()]
 
         def flagWorkerOrMainThread(items, main, worker):
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -70,17 +70,16 @@ EXPORTS_$(binding_include_path) = \
   NonRefcountedDOMObject.h \
   Nullable.h \
   PrimitiveConversions.h \
   PrototypeList.h \
   RegisterBindings.h \
   TypedArray.h \
   UnionConversions.h \
   UnionTypes.h \
-  $(exported_binding_headers) \
   $(NULL)
 
 LOCAL_INCLUDES += -I$(topsrcdir)/js/xpconnect/src \
   -I$(topsrcdir)/js/xpconnect/wrappers \
   -I$(topsrcdir)/content/canvas/src \
   -I$(topsrcdir)/content/html/content/src \
   -I$(topsrcdir)/media/webrtc/signaling/src/peerconnection \
   -I$(topsrcdir)/dom/base \
@@ -92,27 +91,52 @@ LOCAL_INCLUDES += -I$(topsrcdir)/js/xpco
   $(NULL)
 
 ifdef MOZ_AUDIO_CHANNEL_MANAGER
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/dom/system/gonk \
   $(NULL)
 endif
 
+# XXXkhuey this is a terrible hack to avoid blowing out the command line
+ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS)))
+$(shell echo "$(addsuffix .pp,$(binding_header_files))" > pp.list)
+$(shell echo "$(addsuffix .pp,$(binding_cpp_files))" >> pp.list)
+
+# The script mddepend.pl checks the dependencies and writes to stdout
+# one rule to force out-of-date objects. For example,
+#   foo.o boo.o: FORCE
+# The script has an advantage over including the *.pp files directly
+# because it handles the case when header files are removed from the build.
+# 'make' would complain that there is no way to build missing headers.
+ALL_PP_RESULTS = $(shell cat pp.list | $(PERL) $(BUILD_TOOLS)/mddepend.pl)
+$(eval $(ALL_PP_RESULTS))
+
+endif
+
+EXPORTS_GENERATED_FILES := $(exported_binding_headers)
+EXPORTS_GENERATED_DEST := $(DIST)/include/$(binding_include_path)
+EXPORTS_GENERATED_TARGET := webidl-export
+INSTALL_TARGETS += EXPORTS_GENERATED
+
 include $(topsrcdir)/config/rules.mk
 
+# We need to create a separate target so we can ensure that the pickle is
+# done before generating headers.
+export:: ParserResults.pkl
+	$(MAKE) webidl-export
+
 # If you change bindinggen_dependencies here, change it in
 # dom/bindings/test/Makefile.in too.
 bindinggen_dependencies := \
   BindingGen.py \
   Bindings.conf \
   Configuration.py \
   Codegen.py \
   parser/WebIDL.py \
-  ParserResults.pkl \
   $(GLOBAL_DEPS) \
   $(NULL)
 
 CSS2Properties.webidl: $(topsrcdir)/layout/style/nsCSSPropList.h \
                        $(topsrcdir)/layout/style/nsCSSPropAliasList.h \
                        $(webidl_base)/CSS2Properties.webidl.in \
                        $(webidl_base)/CSS2PropertiesProps.h \
                        $(srcdir)/GenerateCSS2PropertiesWebIDL.py \
@@ -124,30 +148,36 @@ CSS2Properties.webidl: $(topsrcdir)/layo
 $(webidl_files): %: $(webidl_base)/%
 	$(INSTALL) $(IFLAGS1) $(webidl_base)/$* .
 
 $(test_webidl_files): %: $(srcdir)/test/%
 	$(INSTALL) $(IFLAGS1) $(srcdir)/test/$* .
 
 $(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
                                      %.webidl \
+                                     $(call mkdir_deps,$(MDDEPDIR)) \
                                      $(NULL)
 	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) -I$(srcdir)/parser \
 	  $(srcdir)/BindingGen.py header \
-	  $(srcdir)/Bindings.conf $*Binding \
+	  $(srcdir)/Bindings.conf \
+	  $*Binding \
+	  $(topsrcdir)/dom/webidl/ \
 	  $*.webidl
 
 $(binding_cpp_files): %Binding.cpp: $(bindinggen_dependencies) \
                                     %.webidl \
+                                    $(call mkdir_deps,$(MDDEPDIR)) \
                                     $(NULL)
 	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) -I$(srcdir)/parser \
 	  $(srcdir)/BindingGen.py cpp \
-	  $(srcdir)/Bindings.conf $*Binding \
+	  $(srcdir)/Bindings.conf \
+	  $*Binding \
+	  $(topsrcdir)/dom/webidl/ \
 	  $*.webidl
 
 $(globalgen_targets): ParserResults.pkl
 
 %-example: $(bindinggen_dependencies) \
            $(all_webidl_files) \
            $(NULL)
 	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
@@ -190,9 +220,11 @@ GARBAGE += \
   $(wildcard *-example.h) \
   $(wildcard *-example.cpp) \
   $(NULL)
 
 # Make sure all binding header files are created during the export stage, so we
 # don't have issues with .cpp files being compiled before we've generated the
 # headers they depend on.  This is really only needed for the test files, since
 # the non-test headers are all exported above anyway.
-export:: $(binding_header_files)
+webidl-export:: $(binding_header_files)
+
+.PHONY: webidl-export
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -169,16 +169,48 @@ class IDLObject(object):
         self.userData[key] = value
 
     def addExtendedAttributes(self, attrs):
         assert False # Override me!
 
     def handleExtendedAttribute(self, attr):
         assert False # Override me!
 
+    def _getDependentObjects(self):
+        assert False # Override me!
+
+    def getDeps(self, visited=None):
+        """ Return a set of files that this object depends on.  If any of
+            these files are changed the parser needs to be rerun to regenerate
+            a new IDLObject.
+
+            The visited argument is a set of all the objects already visited.
+            We must test to see if we are in it, and if so, do nothing.  This
+            prevents infinite recursion."""
+
+        # NB: We can't use visited=set() above because the default value is
+        # evaluated when the def statement is evaluated, not when the function
+        # is executed, so there would be one set for all invocations.
+        if visited == None:
+            visited = set()
+
+        if self in visited:
+            return set()
+
+        visited.add(self)
+
+        deps = set()
+        if self.filename() != "<builtin>":
+            deps.add(self.filename())
+
+        for d in self._getDependentObjects():
+            deps = deps.union(d.getDeps(visited))
+
+        return deps
+
 class IDLScope(IDLObject):
     def __init__(self, location, parentScope, identifier):
         IDLObject.__init__(self, location)
 
         self.parentScope = parentScope
         if identifier:
             assert isinstance(identifier, IDLIdentifier)
             self._name = identifier
@@ -438,16 +470,19 @@ class IDLExternalInterface(IDLObjectWith
         return False
 
     def addExtendedAttributes(self, attrs):
         assert len(attrs) == 0
 
     def resolve(self, parentScope):
         pass
 
+    def _getDependentObjects(self):
+        return set()
+
 class IDLInterface(IDLObjectWithScope):
     def __init__(self, location, parentScope, name, parent, members,
                  isPartial):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(name, IDLUnresolvedIdentifier)
         assert not isPartial or not parent
 
         self.parent = None
@@ -911,16 +946,23 @@ class IDLInterface(IDLObjectWithScope):
         # Now make it look like we were parsed at this new location, since
         # that's the place where the interface is "really" defined
         self.location = location
         assert not self.parent
         self.parent = parent
         # Put the new members at the beginning
         self.members = members + self.members
 
+    def _getDependentObjects(self):
+        deps = set(self.members)
+        deps.union(self.implementedInterfaces)
+        if self.parent:
+            deps.add(self.parent)
+        return deps
+
 class IDLDictionary(IDLObjectWithScope):
     def __init__(self, location, parentScope, name, parent, members):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(name, IDLUnresolvedIdentifier)
         assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
 
         self.parent = parent
         self._finished = False
@@ -981,16 +1023,21 @@ class IDLDictionary(IDLObjectWithScope):
                                       [member.location, inheritedMember.location])
 
     def validate(self):
         pass
 
     def addExtendedAttributes(self, attrs):
         assert len(attrs) == 0
 
+    def _getDependentObjects(self):
+        deps = set(self.members)
+        if (self.parent):
+            deps.add(self.parent)
+        return deps
 
 class IDLEnum(IDLObjectWithIdentifier):
     def __init__(self, location, parentScope, name, values):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(name, IDLUnresolvedIdentifier)
 
         if len(values) != len(set(values)):
             raise WebIDLError("Enum %s has multiple identical strings" % name.name,
@@ -1009,16 +1056,19 @@ class IDLEnum(IDLObjectWithIdentifier):
         pass
 
     def isEnum(self):
         return True
 
     def addExtendedAttributes(self, attrs):
         assert len(attrs) == 0
 
+    def _getDependentObjects(self):
+        return set()
+
 class IDLType(IDLObject):
     Tags = enum(
         # The integer types
         'int8',
         'uint8',
         'int16',
         'uint16',
         'int32',
@@ -1298,16 +1348,19 @@ class IDLNullableType(IDLType):
 
     def isDistinguishableFrom(self, other):
         if (other.nullable() or (other.isUnion() and other.hasNullableType) or
             other.isDictionary()):
             # Can't tell which type null should become
             return False
         return self.inner.isDistinguishableFrom(other)
 
+    def _getDependentObjects(self):
+        return self.inner._getDependentObjects()
+
 class IDLSequenceType(IDLType):
     def __init__(self, location, parameterType):
         assert not parameterType.isVoid()
 
         IDLType.__init__(self, location, parameterType.name)
         self.inner = parameterType
         self.builtin = False
 
@@ -1368,16 +1421,19 @@ class IDLSequenceType(IDLType):
 
     def isDistinguishableFrom(self, other):
         if other.isUnion():
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isDate() or other.isNonCallbackInterface())
 
+    def _getDependentObjects(self):
+        return self.inner._getDependentObjects()
+
 class IDLUnionType(IDLType):
     def __init__(self, location, memberTypes):
         IDLType.__init__(self, location, "")
         self.memberTypes = memberTypes
         self.hasNullableType = False
         self.hasDictionaryType = False
         self.flatMemberTypes = None
         self.builtin = False
@@ -1471,16 +1527,19 @@ class IDLUnionType(IDLType):
             otherTypes = [other]
         # For every type in otherTypes, check that it's distinguishable from
         # every type in our types
         for u in otherTypes:
             if any(not t.isDistinguishableFrom(u) for t in self.memberTypes):
                 return False
         return True
 
+    def _getDependentObjects(self):
+        return set(self.memberTypes)
+
 class IDLArrayType(IDLType):
     def __init__(self, location, parameterType):
         assert not parameterType.isVoid()
         if parameterType.isSequence():
             raise WebIDLError("Array type cannot parameterize over a sequence type",
                               [location])
         if parameterType.isDictionary():
             raise WebIDLError("Array type cannot parameterize over a dictionary type",
@@ -1546,16 +1605,19 @@ class IDLArrayType(IDLType):
 
     def isDistinguishableFrom(self, other):
         if other.isUnion():
             # Just forward to the union; it'll deal
             return other.isDistinguishableFrom(self)
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isDate() or other.isNonCallbackInterface())
 
+    def _getDependentObjects(self):
+        return self.inner._getDependentObjects()
+
 class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
     def __init__(self, location, innerType, name):
         IDLType.__init__(self, location, innerType.name)
 
         identifier = IDLUnresolvedIdentifier(location, name)
 
         IDLObjectWithIdentifier.__init__(self, location, None, identifier)
 
@@ -1633,16 +1695,19 @@ class IDLTypedefType(IDLType, IDLObjectW
         return self.inner.tag()
 
     def unroll(self):
         return self.inner.unroll()
 
     def isDistinguishableFrom(self, other):
         return self.inner.isDistinguishableFrom(other)
 
+    def _getDependentObjects(self):
+        return self.inner._getDependentObjects()
+
 class IDLWrapperType(IDLType):
     def __init__(self, location, inner):
         IDLType.__init__(self, location, inner.identifier.name)
         self.inner = inner
         self._identifier = inner.identifier
         self.builtin = False
 
     def __eq__(self, other):
@@ -1736,16 +1801,33 @@ class IDLWrapperType(IDLType):
         if (other.isDictionary() or other.isCallback() or
             other.isSequence() or other.isArray()):
             return self.isNonCallbackInterface()
 
         # Not much else |other| can be
         assert other.isObject()
         return False
 
+    def _getDependentObjects(self):
+        # NB: The codegen for an interface type depends on
+        #  a) That the identifier is in fact an interface (as opposed to
+        #     a dictionary or something else).
+        #  b) The native type of the interface.
+        #  If we depend on the interface object we will also depend on
+        #  anything the interface depends on which is undesirable.  We
+        #  considered implementing a dependency just on the interface type
+        #  file, but then every modification to an interface would cause this
+        #  to be regenerated which is still undesirable.  We decided not to
+        #  depend on anything, reasoning that:
+        #  1) Changing the concrete type of the interface requires modifying
+        #     Bindings.conf, which is still a global dependency.
+        #  2) Changing an interface to a dictionary (or vice versa) with the
+        #     same identifier should be incredibly rare.
+        return set()
+
 class IDLBuiltinType(IDLType):
 
     Types = enum(
         # The integer types
         'byte',
         'octet',
         'short',
         'unsigned_short',
@@ -1901,16 +1983,19 @@ class IDLBuiltinType(IDLType):
                  (self.isArrayBufferView() and not other.isArrayBufferView() and
                   not other.isTypedArray()) or
                  # Typed arrays are distinguishable from everything
                  # except ArrayBufferView and the same type of typed
                  # array
                  (self.isTypedArray() and not other.isArrayBufferView() and not
                   (other.isTypedArray() and other.name == self.name)))))
 
+    def _getDependentObjects(self):
+        return set()
+
 BuiltinTypes = {
       IDLBuiltinType.Types.byte:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
                          IDLBuiltinType.Types.byte),
       IDLBuiltinType.Types.octet:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Octet",
                          IDLBuiltinType.Types.octet),
       IDLBuiltinType.Types.short:
@@ -2059,16 +2144,19 @@ class IDLValue(IDLObject):
                 raise WebIDLError("'%s' is not a valid default value for enum %s"
                                   % (self.value, type.inner.identifier.name),
                                   [location, type.inner.location])
             return self
         else:
             raise WebIDLError("Cannot coerce type %s to type %s." %
                               (self.type, type), [location])
 
+    def _getDependentObjects(self):
+        return set()
+
 class IDLNullValue(IDLObject):
     def __init__(self, location):
         IDLObject.__init__(self, location)
         self.type = None
         self.value = None
 
     def coerceToType(self, type, location):
         if (not isinstance(type, IDLNullableType) and
@@ -2076,17 +2164,20 @@ class IDLNullValue(IDLObject):
             not type.isDictionary() and
             not type.isAny()):
             raise WebIDLError("Cannot coerce null value to type %s." % type,
                               [location])
 
         nullValue = IDLNullValue(self.location)
         nullValue.type = type
         return nullValue
-        
+
+    def _getDependentObjects(self):
+        return set()
+  
 
 class IDLInterfaceMember(IDLObjectWithIdentifier):
 
     Tags = enum(
         'Const',
         'Attr',
         'Method'
     )
@@ -2157,16 +2248,19 @@ class IDLConst(IDLInterfaceMember):
         coercedValue = self.value.coerceToType(self.type, self.location)
         assert coercedValue
 
         self.value = coercedValue
 
     def validate(self):
         pass
 
+    def _getDependentObjects(self):
+        return set([self.type, self.value])
+
 class IDLAttribute(IDLInterfaceMember):
     def __init__(self, location, identifier, type, readonly, inherit=False,
                  static=False, stringifier=False):
         IDLInterfaceMember.__init__(self, location, identifier,
                                     IDLInterfaceMember.Tags.Attr)
 
         assert isinstance(type, IDLType)
         self.type = type
@@ -2302,16 +2396,19 @@ class IDLAttribute(IDLInterfaceMember):
         IDLInterfaceMember.addExtendedAttributes(self, attrs)
 
     def hasLenientThis(self):
         return self.lenientThis
 
     def isUnforgeable(self):
         return self._unforgeable
 
+    def _getDependentObjects(self):
+        return set([self.type])
+
 class IDLArgument(IDLObjectWithIdentifier):
     def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False):
         IDLObjectWithIdentifier.__init__(self, location, None, identifier)
 
         assert isinstance(type, IDLType)
         self.type = type
 
         self.optional = optional
@@ -2374,16 +2471,22 @@ class IDLArgument(IDLObjectWithIdentifie
 
         # Now do the coercing thing; this needs to happen after the
         # above creation of a default value.
         if self.defaultValue:
             self.defaultValue = self.defaultValue.coerceToType(self.type,
                                                                self.location)
             assert self.defaultValue
 
+    def _getDependentObjects(self):
+        deps = set([self.type])
+        if self.defaultValue:
+            deps.add(self.defaultValue)
+        return deps
+
 class IDLCallbackType(IDLType, IDLObjectWithScope):
     def __init__(self, location, parentScope, identifier, returnType, arguments):
         assert isinstance(returnType, IDLType)
 
         IDLType.__init__(self, location, identifier.name)
 
         self._returnType = returnType
         # Clone the list
@@ -2441,31 +2544,39 @@ class IDLCallbackType(IDLType, IDLObject
         for attr in attrs:
             if attr.identifier() == "TreatNonCallableAsNull":
                 self._treatNonCallableAsNull = True
             else:
                 unhandledAttrs.append(attr)
         if len(unhandledAttrs) != 0:
             IDLType.addExtendedAttributes(self, unhandledAttrs)
 
+    def _getDependentObjects(self):
+        return set([self._returnType] + self._arguments)
+
 class IDLMethodOverload:
     """
     A class that represents a single overload of a WebIDL method.  This is not
     quite the same as an element of the "effective overload set" in the spec,
     because separate IDLMethodOverloads are not created based on arguments being
     optional.  Rather, when multiple methods have the same name, there is an
     IDLMethodOverload for each one, all hanging off an IDLMethod representing
     the full set of overloads.
     """
     def __init__(self, returnType, arguments, location):
         self.returnType = returnType
         # Clone the list of arguments, just in case
         self.arguments = list(arguments)
         self.location = location
 
+    def _getDependentObjects(self):
+        deps = set(self.arguments)
+        deps.add(self.returnType)
+        return deps
+
 class IDLMethod(IDLInterfaceMember, IDLScope):
 
     Special = enum(
         'Getter',
         'Setter',
         'Creator',
         'Deleter',
         'LegacyCaller',
@@ -2803,16 +2914,22 @@ class IDLMethod(IDLInterfaceMember, IDLS
                 raise WebIDLError("[LenientFloat] used on a non-void method",
                                   [attr.location, self.location])
             if not any(arg.type.includesRestrictedFloat() for arg in sig[1]):
                 raise WebIDLError("[LenientFloat] used on an operation with no "
                                   "restricted float type arguments",
                                   [attr.location, self.location])
         IDLInterfaceMember.handleExtendedAttribute(self, attr)
 
+    def _getDependentObjects(self):
+        deps = set()
+        for overload in self._overloads:
+            deps.union(overload._getDependentObjects())
+        return deps
+
 class IDLImplementsStatement(IDLObject):
     def __init__(self, location, implementor, implementee):
         IDLObject.__init__(self, location)
         self.implementor = implementor;
         self.implementee = implementee
 
     def finish(self, scope):
         assert(isinstance(self.implementor, IDLIdentifierPlaceholder))
--- a/dom/bindings/parser/tests/test_nullable_equivalency.py
+++ b/dom/bindings/parser/tests/test_nullable_equivalency.py
@@ -85,17 +85,17 @@ def checkEquivalent(iface, harness):
     #  - names beginning with '_',
     #  - functions which throw when called with no args, and
     #  - class-level non-callables ("static variables").
     #
     # Yes, this is an ugly, fragile hack.  But it finds bugs...
     for attr in dir(type1):
         if attr.startswith('_') or \
            attr in ['nullable', 'builtin', 'filename', 'location',
-                    'inner', 'QName'] or \
+                    'inner', 'QName', 'getDeps'] or \
            (hasattr(type(type1), attr) and not callable(getattr(type1, attr))):
             continue
 
         a1 = getattr(type1, attr)
 
         if callable(a1):
             try:
                 v1 = a1()
--- a/dom/bindings/test/Makefile.in
+++ b/dom/bindings/test/Makefile.in
@@ -39,17 +39,16 @@ LOCAL_INCLUDES += \
 # dom/bindings/Makefile.in too.  But note that we include ../Makefile
 # here manually, since $(GLOBAL_DEPS) won't cover it.
 bindinggen_dependencies := \
   ../BindingGen.py \
   ../Bindings.conf \
   ../Configuration.py \
   ../Codegen.py \
   ../parser/WebIDL.py \
-  ../ParserResults.pkl \
   ../Makefile \
   $(GLOBAL_DEPS) \
   $(NULL)
 
 MOCHITEST_FILES := \
   test_bug773326.html \
   test_enums.html \
   test_integers.html \
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -8,47 +8,48 @@
 //   #define CreateEvent CreateEventW
 // That messes up our call to nsEventDispatcher::CreateEvent below.
 
 #ifdef CreateEvent
 #undef CreateEvent
 #endif
 
 #include "BrowserElementParent.h"
-#include "nsHTMLIFrameElement.h"
+#include "mozilla/dom/HTMLIFrameElement.h"
 #include "nsOpenWindowEventDetail.h"
 #include "nsEventDispatcher.h"
 #include "nsIDOMCustomEvent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsVariant.h"
 #include "nsAsyncScrollEventDetail.h"
 
 using mozilla::dom::Element;
+using mozilla::dom::HTMLIFrameElement;
 using mozilla::dom::TabParent;
 
 namespace {
 
 /**
  * Create an <iframe mozbrowser> owned by the same document as
  * aOpenerFrameElement.
  */
-already_AddRefed<nsHTMLIFrameElement>
+already_AddRefed<HTMLIFrameElement>
 CreateIframe(Element* aOpenerFrameElement, const nsAString& aName, bool aRemote)
 {
   nsNodeInfoManager *nodeInfoManager =
     aOpenerFrameElement->OwnerDoc()->NodeInfoManager();
 
   nsCOMPtr<nsINodeInfo> nodeInfo =
     nodeInfoManager->GetNodeInfo(nsGkAtoms::iframe,
                                  /* aPrefix = */ nullptr,
                                  kNameSpaceID_XHTML,
                                  nsIDOMNode::ELEMENT_NODE);
 
-  nsRefPtr<nsHTMLIFrameElement> popupFrameElement =
-    static_cast<nsHTMLIFrameElement*>(
+  nsRefPtr<HTMLIFrameElement> popupFrameElement =
+    static_cast<HTMLIFrameElement*>(
       NS_NewHTMLIFrameElement(nodeInfo.forget(), mozilla::dom::NOT_FROM_PARSER));
 
   popupFrameElement->SetMozbrowser(true);
 
   // Copy the opener frame's mozapp attribute to the popup frame.
   if (aOpenerFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)) {
     nsAutoString mozapp;
     aOpenerFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, mozapp);
@@ -146,17 +147,17 @@ BrowserElementParent::OpenWindowOOP(TabP
                                     const nsAString& aURL,
                                     const nsAString& aName,
                                     const nsAString& aFeatures)
 {
   // Create an iframe owned by the same document which owns openerFrameElement.
   nsCOMPtr<Element> openerFrameElement =
     do_QueryInterface(aOpenerTabParent->GetOwnerElement());
   NS_ENSURE_TRUE(openerFrameElement, false);
-  nsRefPtr<nsHTMLIFrameElement> popupFrameElement =
+  nsRefPtr<HTMLIFrameElement> popupFrameElement =
     CreateIframe(openerFrameElement, aName, /* aRemote = */ true);
 
   // Normally an <iframe> element will try to create a frameLoader when the
   // page touches iframe.contentWindow or sets iframe.src.
   //
   // But in our case, we want to delay the creation of the frameLoader until
   // we've verified that the popup has gone through successfully.  If the popup
   // is "blocked" by the embedder, we don't want to load the popup's url.
@@ -204,17 +205,17 @@ BrowserElementParent::OpenWindowInProces
 
   nsCOMPtr<nsIDOMElement> openerFrameDOMElement;
   topWindow->GetFrameElement(getter_AddRefs(openerFrameDOMElement));
   NS_ENSURE_TRUE(openerFrameDOMElement, false);
 
   nsCOMPtr<Element> openerFrameElement =
     do_QueryInterface(openerFrameDOMElement);
 
-  nsRefPtr<nsHTMLIFrameElement> popupFrameElement =
+  nsRefPtr<HTMLIFrameElement> popupFrameElement =
     CreateIframe(openerFrameElement, aName, /* aRemote = */ false);
   NS_ENSURE_TRUE(popupFrameElement, false);
 
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
   bool dispatchSucceeded =
--- a/dom/browser-element/mochitest/browserElement_AppFramePermission.js
+++ b/dom/browser-element/mochitest/browserElement_AppFramePermission.js
@@ -3,17 +3,17 @@
 
 // Bug 777384 - Test mozapp permission.
 "use strict";
 
 SimpleTest.waitForExplicitFinish();
 
 function makeAllAppsLaunchable() {
   var Webapps = {};
-  SpecialPowers.wrap(Components).utils.import("resource://gre/modules/Webapps.jsm", Webapps);
+  SpecialPowers.Cu.import("resource://gre/modules/Webapps.jsm", Webapps);
   var appRegistry = SpecialPowers.wrap(Webapps.DOMApplicationRegistry);
 
   var originalValue = appRegistry.allAppsLaunchable;
   appRegistry.allAppsLaunchable = true;
 
   // Clean up after ourselves once tests are done so the test page is unloaded.
   window.addEventListener("unload", function restoreAllAppsLaunchable(event) {
     if (event.target == window.document) {
--- a/dom/contacts/tests/test_contacts_blobs.html
+++ b/dom/contacts/tests/test_contacts_blobs.html
@@ -49,17 +49,17 @@ function getRandomView(size)
  for (var i = 0; i < size; i++) {
    view[i] = parseInt(Math.random() * 255)
  }
  return view;
 }
 
 function getBlob(type, view)
 {
-  return utils.getBlob([view], {type: type});
+  return SpecialPowers.unwrap(utils.getBlob([view], {type: type}));
 }
 
 function getRandomBlob(size)
 {
   return getBlob("binary/random", getRandomView(size));
 }
 
 function compareBuffers(buffer1, buffer2)
--- a/dom/file/test/helpers.js
+++ b/dom/file/test/helpers.js
@@ -174,20 +174,20 @@ function compareBuffers(buffer1, buffer2
       return false;
     }
   }
   return true;
 }
 
 function getBlob(type, buffer)
 {
-  return utils.getBlob([buffer], {type: type});
+  return SpecialPowers.unwrap(utils.getBlob([buffer], {type: type}));
 }
 
 function getRandomBlob(size)
 {
   return getBlob("binary/random", getRandomBuffer(size));
 }
 
 function getFileId(blob)
 {
-  return utils.getFileId(blob);
+  return SpecialPowers.unwrap(utils.getFileId(blob));
 }
--- a/dom/file/test/test_archivereader_nonUnicode.html
+++ b/dom/file/test/test_archivereader_nonUnicode.html
@@ -6,18 +6,18 @@
 <head>
   <title>Archive Reader Non-Unicode Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function createNonUnicodeData() {
-    const Cc = SpecialPowers.wrap(Components).classes;
-    const Ci = SpecialPowers.wrap(Components).interfaces;
+    const Cc = SpecialPowers.Cc;
+    const Ci = SpecialPowers.Ci;
 
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
     var testFile = dirSvc.get("ProfD", Ci.nsIFile);
     testFile.append("fileArchiveReader_nonUnicode.zip");
     var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
     outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
                    0666, 0);
 
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -44,22 +44,22 @@ function compareBuffers(buffer1, buffer2
       return false;
     }
   }
   return true;
 }
 
 function getBlob(type, view)
 {
-  return utils.getBlob([view], {type: type});
+  return SpecialPowers.unwrap(utils.getBlob([view], {type: type}));
 }
 
 function getFile(name, type, view)
 {
-  return utils.getFile(name, [view], {type: type});
+  return SpecialPowers.unwrap(utils.getFile(name, [view], {type: type}));
 }
 
 function getRandomBlob(size)
 {
   return getBlob("binary/random", getRandomView(size));
 }
 
 function getRandomFile(name, size)
--- a/dom/indexedDB/test/helpers.js
+++ b/dom/indexedDB/test/helpers.js
@@ -5,17 +5,17 @@
 
 var testGenerator = testSteps();
 var archiveReaderEnabled = false;
 
 // The test js is shared between xpcshell (which has no SpecialPowers object)
 // and content mochitests (where the |Components| object is accessible only as
 // SpecialPowers.Components). Expose Components if necessary here to make things
 // work everywhere.
-if (typeof Components === 'undefined')
+if (typeof Components === 'undefined' && typeof SpecialPowers === 'object')
   Components = SpecialPowers.Components;
 
 function executeSoon(aFun)
 {
   let comp = SpecialPowers.wrap(Components);
 
   let thread = comp.classes["@mozilla.org/thread-manager;1"]
                    .getService(comp.interfaces.nsIThreadManager)
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -79,16 +79,17 @@ FullScreenDeniedMovedDocument=Request fo
 FullScreenDeniedLostWindow=Request for full-screen was denied because we no longer have a window.
 FullScreenDeniedSubDocFullScreen=Request for full-screen was denied because a subdocument of the document requesting full-screen is already full-screen.
 FullScreenDeniedNotDescendant=Request for full-screen was denied because requesting element is not a descendant of the current full-screen element.
 FullScreenDeniedNotFocusedTab=Request for full-screen was denied because requesting element is not in the currently focused tab.
 RemovedFullScreenElement=Exited full-screen because full-screen element was removed from document.
 FocusedWindowedPluginWhileFullScreen=Exited full-screen because windowed plugin was focused.
 HTMLMultipartXHRWarning=HTML parsing in XMLHttpRequest is not supported for multipart responses.
 HTMLSyncXHRWarning=HTML parsing in XMLHttpRequest is not supported in the synchronous mode.
+MultipartXHRWarning=Support for multipart responses in XMLHttpRequest is going to be removed in an upcoming version. Please migrate to chunked responses or to Web Sockets.
 InvalidRedirectChannelWarning=Unable to redirect to %S because the channel doesn't implement nsIWritablePropertyBag2.
 ReportOnlyCSPIgnored=Report-only CSP policy will be ignored because there are other non-report-only CSP policies applied.
 ResponseTypeSyncXHRWarning=Use of XMLHttpRequest's responseType attribute is no longer supported in the synchronous mode in window context.
 WithCredentialsSyncXHRWarning=Use of XMLHttpRequest's withCredentials attribute is no longer supported in the synchronous mode in window context.
 TimeoutSyncXHRWarning=Use of XMLHttpRequest's timeout attribute is not supported in the synchronous mode in window context.
 JSONCharsetWarning=An attempt was made to declare a non-UTF-8 encoding for JSON retrieved using XMLHttpRequest. Only UTF-8 is supported for decoding JSON.
 # LOCALIZATION NOTE: Do not translate decodeAudioData.
 MediaDecodeAudioDataUnknownContentType=The buffer passed to decodeAudioData contains an unknown content type.
--- a/dom/locales/en-US/chrome/mathml/mathml.properties
+++ b/dom/locales/en-US/chrome/mathml/mathml.properties
@@ -1,15 +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/.
 
 ChildCountIncorrect=Invalid markup: Incorrect number of children for <%1$S/> tag.
 DuplicateMprescripts=Invalid markup: More than one <mprescripts/> in <mmultiscripts/>.
-NoSubSup=Invalid markup: Expected at least one subscript/superscript pair in <mmultiscripts/>.  Found none.
+# LOCALIZATION NOTE:  The first child of <mmultiscript/> is the base, that is the element to which scripts are attached.
+NoBase=Invalid markup: Expected exactly one Base element in <mmultiscripts/>.  Found none.
 SubSupMismatch=Invalid markup: Incomplete subscript/superscript pair in <mmultiscripts/>.
 
 # LOCALIZATION NOTE:  When localizing the single quotes ('), follow the conventions in css.properties for your target locale.
 AttributeParsingError=Error in parsing the value '%1$S' for '%2$S' attribute of <%3$S/>.  Attribute ignored.
 AttributeParsingErrorNoTag=Error in parsing the value '%1$S' for '%2$S' attribute.  Attribute ignored.
 LengthParsingError=Error in parsing MathML attribute value '%1$S' as length.  Attribute ignored.
 DeprecatedSupersededBy='%1$S' is deprecated in MathML 3, superseded by '%2$S'.
 UnitlessValuesAreDeprecated=Unitless values are deprecated in MathML 3.
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -907,17 +907,17 @@ MediaManager::GetUserMedia(bool aPrivile
       nsCOMPtr<nsIPopupWindowManager> pm =
         do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
       if (!pm) {
         return NS_OK;
       }
       uint32_t permission;
       nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
       pm->TestPermission(doc->NodePrincipal(), &permission);
-      if ((permission == nsIPopupWindowManager::DENY_POPUP)) {
+      if (permission == nsIPopupWindowManager::DENY_POPUP) {
         nsCOMPtr<nsIDOMDocument> domDoc = aWindow->GetExtantDocument();
         nsGlobalWindow::FirePopupBlockedEvent(
           domDoc, aWindow, nullptr, EmptyString(), EmptyString()
         );
         return NS_OK;
       }
     }
   }
--- a/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl
+++ b/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl
@@ -1,33 +1,45 @@
 /* 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 "domstubs.idl"
 #include "nsISupports.idl"
 #include "nsIMobileMessageDatabaseService.idl"
 
-interface nsIDOMMozSmsMessage;
-
-[scriptable, function, uuid(9cd80750-6a08-11e2-ac93-bf895e53f40e)]
+[scriptable, function, uuid(0bffae74-71db-11e2-962a-73cf64d6393e)]
 interface nsIRilMobileMessageDatabaseCallback : nsISupports
 {
-  void notify(in nsresult aRv, in nsIDOMMozSmsMessage aSms);
+  /**
+   * |aRecord| Object: the mobile-message database record
+   */
+  void notify(in nsresult aRv, in jsval aRecord);
 };
 
-[scriptable, uuid(89528354-6a08-11e2-8243-af4cf90404a9)]
+[scriptable, uuid(3592525a-71d6-11e2-82ca-f75ae6e08ee2)]
 interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
 {
-  long saveReceivedMessage(in DOMString aSender,
-                           in DOMString aBody,
-                           in DOMString aMessageClass,
-                           in unsigned long long aDate,
+  /**
+   * |aMessage| Object: should contain the following properties for internal use:
+   *   - |type| DOMString: "sms" or "mms"
+   *   - |sender| DOMString: the phone number of sender
+   *   - |timestamp| Number: the timestamp of received message
+   *   - |messageClass| DOMString: the message class of received message
+   */
+  long saveReceivedMessage(in jsval aMessage,
                 [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
-  long saveSendingMessage(in DOMString aReceiver,
-                          in DOMString aBody,
-                          in DOMString aDeliveryStatus,
-                          in unsigned long long aDate,
+
+  /**
+   * |aMessage| Object: should contain the following properties for internal use:
+   *   - |type| DOMString: "sms" or "mms"
+   *   - |receiver| DOMString: the phone number of receiver
+   *   - |timestamp| Number: the timestamp of sending message
+   *   - |deliveryStatus| DOMString: the delivery status of sending message
+   */
+  long saveSendingMessage(in jsval aMessage,
                [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
+
   void setMessageDelivery(in long aMessageId,
                           in DOMString aDelivery,
                           in DOMString aDeliveryStatus,
                [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
 };
--- a/dom/mobilemessage/src/ril/MobileMessageDatabaseService.js
+++ b/dom/mobilemessage/src/ril/MobileMessageDatabaseService.js
@@ -408,18 +408,18 @@ MobileMessageDatabaseService.prototype =
         [record.receiver, timestamp]
       ];
       record.readIndex = [record.read, timestamp];
       cursor.update(record);
       cursor.continue();
     };
   },
 
-  createMessageFromRecord: function createMessageFromRecord(aRecord) {
-    if (DEBUG) debug("createMessageFromRecord: " + JSON.stringify(aRecord));
+  createSmsMessageFromRecord: function createSmsMessageFromRecord(aRecord) {
+    if (DEBUG) debug("createSmsMessageFromRecord: " + JSON.stringify(aRecord));
     return gSmsService.createSmsMessage(aRecord.id,
                                         aRecord.delivery,
                                         aRecord.deliveryStatus,
                                         aRecord.sender,
                                         aRecord.receiver,
                                         aRecord.body,
                                         aRecord.messageClass,
                                         aRecord.timestamp,
@@ -477,17 +477,17 @@ MobileMessageDatabaseService.prototype =
     }
 
     let firstMessageId = aMessageList.results.shift();
     if (DEBUG) debug ("Fetching message " + firstMessageId);
 
     let getRequest = aObjectStore.get(firstMessageId);
     let self = this;
     getRequest.onsuccess = function onsuccess(event) {
-      let sms = self.createMessageFromRecord(event.target.result);
+      let sms = self.createSmsMessageFromRecord(event.target.result);
       if (aMessageList.listId >= 0) {
         if (DEBUG) {
           debug("notifyNextMessageInListGot - listId: "
                 + aMessageList.listId + ", messageId: " + firstMessageId);
         }
         smsRequest.notifyNextMessageInListGot(sms);
       } else {
         self.lastMessageListId += 1;
@@ -652,18 +652,17 @@ MobileMessageDatabaseService.prototype =
     aRecord.id = this.lastKey;
     if (DEBUG) debug("Going to store " + JSON.stringify(aRecord));
 
     let self = this;
     function notifyResult(rv) {
       if (!aCallback) {
         return;
       }
-      let sms = self.createMessageFromRecord(aRecord);
-      aCallback.notify(rv, sms);
+      aCallback.notify(rv, aRecord);
     }
 
     this.newTxn(READ_WRITE, function(error, txn, stores) {
       if (error) {
         // TODO bug 832140 check event.target.errorCode
         notifyResult(Cr.NS_ERROR_FAILURE);
         return;
       }
@@ -673,19 +672,18 @@ MobileMessageDatabaseService.prototype =
       txn.onabort = function onabort(event) {
         // TODO bug 832140 check event.target.errorCode
         notifyResult(Cr.NS_ERROR_FAILURE);
       };
 
       // First add to main objectStore.
       stores[0].put(aRecord);
 
+      // Next update the other objectStore.
       let number = getNumberFromRecord(aRecord);
-
-      // Next update the other objectStore.
       stores[1].get(number).onsuccess = function onsuccess(event) {
         let mostRecentEntry = event.target.result;
         if (mostRecentEntry) {
           let needsUpdate = false;
 
           if (mostRecentEntry.timestamp <= aRecord.timestamp) {
             mostRecentEntry.timestamp = aRecord.timestamp;
             mostRecentEntry.body = aRecord.body;
@@ -708,130 +706,122 @@ MobileMessageDatabaseService.prototype =
                                     unreadCount: aRecord.read ? 0 : 1 });
         }
       };
     }, [STORE_NAME, MOST_RECENT_STORE_NAME]);
     // We return the key that we expect to store in the db
     return aRecord.id;
   },
 
+  getRilIccInfoMsisdn: function getRilIccInfoMsisdn() {
+    let iccInfo = this.mRIL.rilContext.iccInfo;
+    let number = iccInfo ? iccInfo.msisdn : null;
+
+    // Workaround an xpconnect issue with undefined string objects.
+    // See bug 808220
+    if (number === undefined || number === "undefined") {
+      return null;
+    }
+    return number;
+  },
+
+  makePhoneNumberInternational: function makePhoneNumberInternational(aNumber) {
+    if (!aNumber) {
+      return aNumber;
+    }
+    let parsedNumber = PhoneNumberUtils.parse(aNumber.toString());
+    if (!parsedNumber || !parsedNumber.internationalNumber) {
+      return aNumber;
+    }
+    return parsedNumber.internationalNumber;
+  },
 
   /**
    * nsIRilMobileMessageDatabaseService API
    */
 
-  saveReceivedMessage: function saveReceivedMessage(
-      aSender, aBody, aMessageClass, aDate, aCallback) {
-    let iccInfo = this.mRIL.rilContext.iccInfo;
-    let receiver = iccInfo ? iccInfo.msisdn : null;
-
-    // Workaround an xpconnect issue with undefined string objects.
-    // See bug 808220
-    if (receiver === undefined || receiver === "undefined") {
-      receiver = null;
-    }
-
-    if (receiver) {
-      let parsedNumber = PhoneNumberUtils.parse(receiver);
-      receiver = (parsedNumber && parsedNumber.internationalNumber)
-                 ? parsedNumber.internationalNumber
-                 : receiver;
+  saveReceivedMessage: function saveReceivedMessage(aMessage, aCallback) {
+    if (aMessage.type === undefined ||
+        aMessage.sender === undefined ||
+        aMessage.messageClass === undefined ||
+        aMessage.timestamp === undefined) {
+      if (aCallback) {
+        aCallback.notify(Cr.NS_ERROR_FAILURE, null);
+      }
+      return;
     }
 
-    let sender = aSender;
-    if (sender) {
-      let parsedNumber = PhoneNumberUtils.parse(sender);
-      sender = (parsedNumber && parsedNumber.internationalNumber)
-               ? parsedNumber.internationalNumber
-               : sender;
-    }
+    let receiver = this.getRilIccInfoMsisdn();
+    receiver = this.makePhoneNumberInternational(receiver);
+
+    let sender = aMessage.sender =
+      this.makePhoneNumberInternational(aMessage.sender);
+
+    let timestamp = aMessage.timestamp;
 
-    let record = {
-      deliveryIndex:  [DELIVERY_RECEIVED, aDate],
-      numberIndex:    [[sender, aDate], [receiver, aDate]],
-      readIndex:      [FILTER_READ_UNREAD, aDate],
+    // Adding needed indexes and extra attributes for internal use.
+    aMessage.deliveryIndex = [DELIVERY_RECEIVED, timestamp];
+    aMessage.numberIndex = [[sender, timestamp], [receiver, timestamp]];
+    aMessage.readIndex = [FILTER_READ_UNREAD, timestamp];
+    aMessage.delivery = DELIVERY_RECEIVED;
+    aMessage.deliveryStatus = DELIVERY_STATUS_SUCCESS;
+    aMessage.receiver = receiver;
+    aMessage.read = FILTER_READ_UNREAD;
 
-      delivery:       DELIVERY_RECEIVED,
-      deliveryStatus: DELIVERY_STATUS_SUCCESS,
-      sender:         sender,
-      receiver:       receiver,
-      body:           aBody,
-      messageClass:   aMessageClass,
-      timestamp:      aDate,
-      read:           FILTER_READ_UNREAD
-    };
-    return this.saveRecord(record, aCallback);
+    return this.saveRecord(aMessage, aCallback);
   },
 
-  saveSendingMessage: function saveSendingMessage(
-      aReceiver, aBody, aDeliveryStatus, aDate, aCallback) {
-    let rilContext = this.mRIL.rilContext;
-    let sender = rilContext.iccInfo
-               ? rilContext.iccInfo.msisdn
-               : null;
-
-    // Workaround an xpconnect issue with undefined string objects.
-    // See bug 808220
-    if (sender === undefined || sender === "undefined") {
-      sender = null;
+  saveSendingMessage: function saveSendingMessage(aMessage, aCallback) {
+    if (aMessage.type === undefined ||
+        aMessage.receiver === undefined ||
+        aMessage.deliveryStatus === undefined ||
+        aMessage.timestamp === undefined) {
+      if (aCallback) {
+        aCallback.notify(Cr.NS_ERROR_FAILURE, null);
+      }
+      return;
     }
 
-    let receiver = aReceiver;
+    let sender = this.getRilIccInfoMsisdn();
+    let receiver = aMessage.receiver;
 
+    let rilContext = this.mRIL.rilContext;
     if (rilContext.voice.network.mcc === rilContext.iccInfo.mcc) {
-      if (receiver) {
-        let parsedNumber = PhoneNumberUtils.parse(receiver.toString());
-        receiver = (parsedNumber && parsedNumber.internationalNumber)
-                   ? parsedNumber.internationalNumber
-                   : receiver;
-      }
-
-      if (sender) {
-        let parsedNumber = PhoneNumberUtils.parse(sender.toString());
-        sender = (parsedNumber && parsedNumber.internationalNumber)
-                 ? parsedNumber.internationalNumber
-                 : sender;
-      }
+      receiver = aMessage.receiver = this.makePhoneNumberInternational(receiver);
+      sender = this.makePhoneNumberInternational(sender);
     }
 
-    let record = {
-      deliveryIndex:  [DELIVERY_SENDING, aDate],
-      numberIndex:    [[sender, aDate], [receiver, aDate]],
-      readIndex:      [FILTER_READ_READ, aDate],
+    let timestamp = aMessage.timestamp;
 
-      delivery:       DELIVERY_SENDING,
-      deliveryStatus: aDeliveryStatus,
-      sender:         sender,
-      receiver:       receiver,
-      body:           aBody,
-      messageClass:   MESSAGE_CLASS_NORMAL,
-      timestamp:      aDate,
-      read:           FILTER_READ_READ
-    };
-    return this.saveRecord(record, aCallback);
+    // Adding needed indexes and extra attributes for internal use.
+    aMessage.deliveryIndex = [DELIVERY_SENDING, timestamp];
+    aMessage.numberIndex = [[sender, timestamp], [receiver, timestamp]];
+    aMessage.readIndex = [FILTER_READ_READ, timestamp];
+    aMessage.delivery = DELIVERY_SENDING;
+    aMessage.sender = sender;
+    aMessage.messageClass = MESSAGE_CLASS_NORMAL;
+    aMessage.read = FILTER_READ_READ;
+
+    return this.saveRecord(aMessage, aCallback);
   },
 
   setMessageDelivery: function setMessageDelivery(
       messageId, delivery, deliveryStatus, callback) {
     if (DEBUG) {
       debug("Setting message " + messageId + " delivery to " + delivery
             + ", and deliveryStatus to " + deliveryStatus);
     }
 
     let self = this;
     let record;
     function notifyResult(rv) {
       if (!callback) {
         return;
       }
-      let sms = null;
-      if (record) {
-        sms = self.createMessageFromRecord(record);
-      }
-      callback.notify(rv, sms);
+      callback.notify(rv, record);
     }
 
     this.newTxn(READ_WRITE, function (error, txn, store) {
       if (error) {
         // TODO bug 832140 check event.target.errorCode
         notifyResult(Cr.NS_ERROR_FAILURE);
         return;
       }
@@ -909,17 +899,17 @@ MobileMessageDatabaseService.prototype =
         if (record.id != messageId) {
           if (DEBUG) {
             debug("Requested message ID (" + messageId + ") is " +
                   "different from the one we got");
           }
           aRequest.notifyGetMessageFailed(Ci.nsISmsRequest.UNKNOWN_ERROR);
           return;
         }
-        let sms = self.createMessageFromRecord(record);
+        let sms = self.createSmsMessageFromRecord(record);
         aRequest.notifyMessageGot(sms);
       };
 
       txn.onerror = function onerror(event) {
         if (DEBUG) {
           if (event.target)
             debug("Caught error on transaction", event.target.errorCode);
         }
@@ -1215,17 +1205,17 @@ MobileMessageDatabaseService.prototype =
             messageList.numberQueues = [{
               // For timestamp.
               processing: 1,
               results: []
             }, {
               // For all numbers.
               processing: filter.numbers.length,
               results: []
-	    }];
+            }];
 
             let timeRange = null;
             if (filter.startDate != null && filter.endDate != null) {
               timeRange = IDBKeyRange.bound(filter.startDate.getTime(),
                                             filter.endDate.getTime());
             } else if (filter.startDate != null) {
               timeRange = IDBKeyRange.lowerBound(filter.startDate.getTime());
             } else if (filter.endDate != null) {
@@ -1322,17 +1312,17 @@ MobileMessageDatabaseService.prototype =
       };
 
       txn.oncomplete = function oncomplete(event) {
         if (DEBUG) debug("Transaction " + txn + " completed.");
         if (!record) {
           if (DEBUG) debug("Could not get message id " + messageId);
           aRequest.notifyReadMessageListFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR);
         }
-        let sms = self.createMessageFromRecord(record);
+        let sms = self.createSmsMessageFromRecord(record);
         aRequest.notifyNextMessageInListGot(sms);
       };
 
       txn.onerror = function onerror(event) {
         //TODO check event.target.errorCode
         if (DEBUG) {
           debug("Error retrieving message id: " + messageId +
                 ". Error code: " + event.target.errorCode);
--- a/dom/permission/tests/test_permission_basics.html
+++ b/dom/permission/tests/test_permission_basics.html
@@ -25,23 +25,22 @@ var testPrivApp = {
   'manifestURL' : 'https://aprivileged.com/manifest.webapp'
 };
 
 var testCertApp = {
   'manifestURL' : 'https://acertified.com/manifest.webapp'
 };
 
 SpecialPowers.addPermission("permissions", true, document);
-var comp = SpecialPowers.wrap(Components);
 SpecialPowers.pushPrefEnv({ "set": [["dom.mozPermissionSettings.enabled", true]] },
                           function() {
                             SpecialPowers.removePermission("permissions", document);
                           });
 
-comp.utils.import("resource://gre/modules/PermissionSettings.jsm");
+SpecialPowers.Cu.import("resource://gre/modules/PermissionSettings.jsm");
 var mozPermissions = window.navigator.mozPermissionSettings;
 
 function permissionTest() {
   // Any permission explicit for privileged and implicit for certified serves
   var testPerm = "contacts-read";
   // Any permission explicit for privileged and certified apps
   var explicitPerm = "geolocation";
 
--- a/dom/settings/tests/test_settings_onsettingchange.html
+++ b/dom/settings/tests/test_settings_onsettingchange.html
@@ -16,18 +16,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 "use strict";
 
-var comp = SpecialPowers.wrap(Components);
-comp.utils.import("resource://gre/modules/SettingsChangeNotifier.jsm");
+SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
 SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
 SpecialPowers.addPermission("settings-write", true, document);
 SpecialPowers.addPermission("settings-read", true, document);
 
 var screenBright = {"screen.brightness": 0.7};
 
 function onFailure() {
   ok(false, "in on Failure!");
--- a/dom/sms/tests/test_smsdatabaseservice.xul
+++ b/dom/sms/tests/test_smsdatabaseservice.xul
@@ -172,43 +172,47 @@ function checkDB(callback) {
 }
 
 function newRandomId() {
   return Math.floor(Math.random() * LONG_MAX);
 };
 
 let sms = [
   {
+    type: "sms",
     sender: "+34666000000",
     receiver: "+34666111000",
     body: "message 0",
+    messageClass: "normal",
     timestamp: 1329999861762
   },
   {
+    type: "sms",
     sender: "+34666000111",
     receiver: "+34666111111",
     body: "message 1",
+    messageClass: "normal",
     timestamp: 1329999861763
   },
   {
+    type: "sms",
     sender: "+34666000222",
     receiver: "+34666111222",
     body: "message 2",
+    messageClass: "normal",
     timestamp: 1329999861764
   },
 ];
 
 /**
  * nsIMobileMessageDatabaseService.saveReceivedMessage
  */
 add_test(function test_saveReceivedMessage() {
   info("test_saveReceivedMessage");
-  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[0].sender,
-                                                                    sms[0].body,
-                                                                    sms[0].timestamp);
+  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[0]);
   checkDB(function (store) {
     let request = store.get(messageId);
     request.onsuccess = function onsuccess() {
       let data = request.result;
       isnot(data, null);
       is(data.id,        messageId);
       is(data.sender,    sms[0].sender);
       is(data.receiver,  null);
@@ -257,19 +261,17 @@ add_test(function test_getMessage_succes
       is(message.delivery, "received");
       is(message.sender,   sms[2].sender);
       is(message.receiver, null);
       is(message.body,     sms[2].body);
       is(message.read,     false);
       run_next_test();
     }
   });
-  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[2].sender,
-                                                                    sms[2].body,
-                                                                    sms[2].timestamp);
+  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[2]);
   SimpleTest.executeSoon(function () {
     gMobileMessageDatabaseService.getMessage(messageId, fakeRequestId);
   });
 });
 
 add_test(function test_getMessage_failed() {
   info("test_getMessage_failed");
   let fakeRequestId = newRandomId();
@@ -816,19 +818,17 @@ add_test(function test_deleteMessage_suc
   let fakeRequestId = newRandomId();
   fakeSmsRequestManager({
     notifySmsDeleted: function notifySmsDeleted(requestId, deleted) {
       is(requestId, fakeRequestId);
       ok(deleted);
       run_next_test();
     }
   });
-  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[0].sender,
-                                                                    sms[0].body,
-                                                                    sms[0].timestamp);
+  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[0]);
   SimpleTest.executeSoon(function () {
     gMobileMessageDatabaseService.deleteMessage(messageId, fakeRequestId);
   });
 });
 
 add_test(function test_deleteMessage_failed() {
   info("test_deleteMessage_failed");
   let fakeRequestId = newRandomId();
@@ -847,19 +847,17 @@ add_test(function test_markMessageRead_s
   let fakeRequestId = newRandomId();
   fakeSmsRequestManager({
     notifyMarkedMessageRead: function notifyMarkedMessageRead(requestId, read) {
       is(requestId, fakeRequestId);
       is(read, true);
       run_next_test();
     }
   });
-  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[2].sender,
-                                                                    sms[2].body,
-                                                                    sms[2].timestamp); 
+  let messageId = gMobileMessageDatabaseService.saveReceivedMessage(sms[2]); 
   SimpleTest.executeSoon(function () {
     gMobileMessageDatabaseService.markMessageRead(messageId, true, fakeRequestId);
   });
 });
 
 add_test(function test_markMessageRead_failed() {
   info("test_markMessageRead_failed");
   let fakeRequestId = newRandomId();
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1471,16 +1471,28 @@ RadioInterfaceLayer.prototype = {
       sourcePort: message.header.originatorPort,
       destinationAddress: this.rilContext.iccInfo.msisdn,
       destinationPort: message.header.destinationPort,
     };
     WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length,
                                      0, options);
   },
 
+  createSmsMessageFromRecord: function createSmsMessageFromRecord(aRecord) {
+    return gSmsService.createSmsMessage(aRecord.id,
+                                        aRecord.delivery,
+                                        aRecord.deliveryStatus,
+                                        aRecord.sender,
+                                        aRecord.receiver,
+                                        aRecord.body,
+                                        aRecord.messageClass,
+                                        aRecord.timestamp,
+                                        aRecord.read);
+  },
+
   portAddressedSmsApps: null,
   handleSmsReceived: function handleSmsReceived(message) {
     debug("handleSmsReceived: " + JSON.stringify(message));
 
     // FIXME: Bug 737202 - Typed arrays become normal arrays when sent to/from workers
     if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
       message.fullData = new Uint8Array(message.fullData);
     }
@@ -1496,30 +1508,36 @@ RadioInterfaceLayer.prototype = {
       return true;
     }
 
     if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
       // Don't know how to handle binary data yet.
       return true;
     }
 
+    message.type = "sms";
+    message.sender = message.sender || null;
+    message.receiver = message.receiver || null;
+    message.body = message.fullBody = message.fullBody || null;
+
     // TODO: Bug #768441
     // For now we don't store indicators persistently. When the mwi.discard
     // flag is false, we'll need to persist the indicator to EFmwis.
     // See TS 23.040 9.2.3.24.2
 
     let mwi = message.mwi;
     if (mwi) {
-      mwi.returnNumber = message.sender || null;
-      mwi.returnMessage = message.fullBody || null;
+      mwi.returnNumber = message.sender;
+      mwi.returnMessage = message.fullBody;
       this._sendTargetMessage("voicemail", "RIL:VoicemailNotification", mwi);
       return true;
     }
 
-    let notifyReceived = function notifyReceived(rv, sms) {
+    let notifyReceived = function notifyReceived(rv, record) {
+      let sms = this.createSmsMessageFromRecord(record);
       let success = Components.isSuccessCode(rv);
 
       // Acknowledge the reception of the SMS.
       message.rilMessageType = "ackSMS";
       if (!success) {
         message.result = RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED;
       }
       this.worker.postMessage(message);
@@ -1527,48 +1545,40 @@ RadioInterfaceLayer.prototype = {
       if (!success) {
         // At this point we could send a message to content to notify the user
         // that storing an incoming SMS failed, most likely due to a full disk.
         debug("Could not store SMS " + message.id + ", error code " + rv);
         return;
       }
 
       gSystemMessenger.broadcastMessage("sms-received", {
-          id: message.id,
-          delivery: DOM_SMS_DELIVERY_RECEIVED,
-          deliveryStatus: RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS,
-          sender: message.sender || null,
-          receiver: message.receiver || null,
-          body: message.fullBody || null,
-          messageClass: message.messageClass,
-          timestamp: message.timestamp,
-          read: false
+        id: message.id,
+        delivery: DOM_SMS_DELIVERY_RECEIVED,
+        deliveryStatus: RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS,
+        sender: message.sender,
+        receiver: message.receiver,
+        body: message.fullBody,
+        messageClass: message.messageClass,
+        timestamp: message.timestamp,
+        read: false
       });
+
       Services.obs.notifyObservers(sms, kSmsReceivedObserverTopic, null);
     }.bind(this);
 
     if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
-      message.id = gMobileMessageDatabaseService.saveReceivedMessage(
-        message.sender || null,
-        message.fullBody || null,
-        message.messageClass,
-        message.timestamp,
-        notifyReceived);
+      message.id = gMobileMessageDatabaseService.saveReceivedMessage(message,
+                                                                     notifyReceived);
     } else {
       message.id = -1;
-      let sms = gSmsService.createSmsMessage(message.id,
-                                             DOM_SMS_DELIVERY_RECEIVED,
-                                             RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS,
-                                             message.sender || null,
-                                             message.receiver || null,
-                                             message.fullBody || null,
-                                             message.messageClass,
-                                             message.timestamp,
-                                             false);
-      notifyReceived(Cr.NS_OK, sms);
+      message.delivery = DOM_SMS_DELIVERY_RECEIVED;
+      message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS;
+      message.read = false;
+
+      notifyReceived(Cr.NS_OK, message);
     }
 
     // SMS ACK will be sent in notifyReceived. Return false here.
     return false;
   },
 
   /**
    * Local storage for sent SMS messages.
@@ -1591,17 +1601,18 @@ RadioInterfaceLayer.prototype = {
     let options = this._sentSmsEnvelopes[message.envelopeId];
     if (!options) {
       return;
     }
 
     gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
                                                      DOM_SMS_DELIVERY_SENT,
                                                      options.sms.deliveryStatus,
-                                                     function notifyResult(rv, sms) {
+                                                     function notifyResult(rv, record) {
+      let sms = this.createSmsMessageFromRecord(record);
       //TODO bug 832140 handle !Components.isSuccessCode(rv)
       gSystemMessenger.broadcastMessage("sms-sent",
                                         {id: options.sms.id,
                                          delivery: DOM_SMS_DELIVERY_SENT,
                                          deliveryStatus: options.sms.deliveryStatus,
                                          sender: message.sender || null,
                                          receiver: options.sms.receiver,
                                          body: options.sms.body,
@@ -1629,23 +1640,24 @@ RadioInterfaceLayer.prototype = {
     if (!options) {
       return;
     }
     delete this._sentSmsEnvelopes[message.envelopeId];
 
     gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
                                                      options.sms.delivery,
                                                      message.deliveryStatus,
-                                                     function notifyResult(rv, sms) {
+                                                     function notifyResult(rv, record) {
+      let sms = this.createSmsMessageFromRecord(record);
       //TODO bug 832140 handle !Components.isSuccessCode(rv)
       let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
                   ? kSmsDeliverySuccessObserverTopic
                   : kSmsDeliveryErrorObserverTopic;
       Services.obs.notifyObservers(sms, topic, null);
-    });
+    }.bind(this));
   },
 
   handleSmsSendFailed: function handleSmsSendFailed(message) {
     debug("handleSmsSendFailed: " + JSON.stringify(message));
 
     let options = this._sentSmsEnvelopes[message.envelopeId];
     if (!options) {
       return;
@@ -1657,21 +1669,22 @@ RadioInterfaceLayer.prototype = {
       case RIL.ERROR_RADIO_NOT_AVAILABLE:
         error = Ci.nsISmsRequest.NO_SIGNAL_ERROR;
         break;
     }
 
     gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
                                                      DOM_SMS_DELIVERY_ERROR,
                                                      RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
-                                                     function notifyResult(rv, sms) {
+                                                     function notifyResult(rv, record) {
+      let sms = this.createSmsMessageFromRecord(record);
       //TODO bug 832140 handle !Components.isSuccessCode(rv)
       options.request.notifySendMessageFailed(error);
       Services.obs.notifyObservers(sms, kSmsFailedObserverTopic, null);
-    });
+    }.bind(this));
   },
 
   /**
    * Handle data call state changes.
    */
   handleDataCallState: function handleDataCallState(datacall) {
     let data = this.rilContext.data;
 
@@ -2640,18 +2653,27 @@ RadioInterfaceLayer.prototype = {
       options.segmentRef16Bit = this.segmentRef16Bit;
       options.segmentRef = this.nextSegmentRef;
     }
 
     let timestamp = Date.now();
     let deliveryStatus = options.requestStatusReport
                        ? RIL.GECKO_SMS_DELIVERY_STATUS_PENDING
                        : RIL.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE;
-    let id = gMobileMessageDatabaseService.saveSendingMessage(number, message, deliveryStatus, timestamp,
-                                                              function notifyResult(rv, sms) {
+    let sendingMessage = {
+      type: "sms",
+      receiver: number,
+      body: message,
+      deliveryStatus: deliveryStatus,
+      timestamp: timestamp
+    };
+
+    let id = gMobileMessageDatabaseService.saveSendingMessage(sendingMessage,
+                                                              function notifyResult(rv, record) {
+      let sms = this.createSmsMessageFromRecord(record);
       //TODO bug 832140 handle !Components.isSuccessCode(rv)
       Services.obs.notifyObservers(sms, kSmsSendingObserverTopic, null);
 
       // Keep current SMS message info for sent/delivered notifications
       options.envelopeId = this.createSmsEnvelope({
           request: request,
           sms: sms,
           requestStatusReport: options.requestStatusReport
--- a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
+++ b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul
@@ -45,16 +45,23 @@ https://bugzilla.mozilla.org/show_bug.cg
         var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype", sandbox);
         ok(xhr, "'XMLHttpRequest.prototype' in a sandbox should return the XMLHttpRequest interface prototype object");
         ok(isXrayWrapper(xhr), "Getting an interface prototype object on an Xray wrapper should return an Xray wrapper");
         ok(isXrayWrapper(xhr.constructor), "Getting the constructor property on an Xray wrapper of an interface prototype object should return an Xray wrapper");
       } catch (e) {
         ok(false, "'XMLHttpRequest.prototype' shouldn't throw in a sandbox");
       }
       try {
+        var img = Components.utils.evalInSandbox("Image.prototype", sandbox);
+        ok(img, "'Image.prototype' in a sandbox should return the interface prototype object");
+        ok(isXrayWrapper(img), "Getting an interface prototype object on an Xray wrapper should return an Xray wrapper");
+      } catch (e) {
+        ok(false, "'Image.prototype' shouldn't throw in a sandbox");
+      }
+      try {
         var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox);
         xhr.prototype = false;
       } catch (e) {
         ok(true, "'XMLHttpRequest.prototype' should be readonly");
       }
       try {
         var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox);
         delete xhr.prototype;
--- a/dom/tests/mochitest/general/test_domWindowUtils.html
+++ b/dom/tests/mochitest/general/test_domWindowUtils.html
@@ -80,17 +80,18 @@ function testElementFromPoint() {
     
     if (moveData) {
       let moveEl = moveData[1];
       let [moveX, moveY] = moveData[0];
 
       moveEl.style.left = moveX + "px";
       moveEl.style.top = moveY + "px";
     }
-    let found = domWindowUtils.elementFromPoint(x, y, ignoreScroll, flushLayout);
+    let found = SpecialPowers.unwrap(domWindowUtils.elementFromPoint(
+                                     x, y, ignoreScroll, flushLayout));
     is(found, expected, "at index " + i + " for data " + testData[i][0].toSource());
   }
 
   SimpleTest.executeSoon(function() {
     next();
   });
 },
 
--- a/dom/tests/mochitest/webapps/file_bug_779982.js
+++ b/dom/tests/mochitest/webapps/file_bug_779982.js
@@ -1,11 +1,11 @@
 function makeAllAppsLaunchable() {
   var Webapps = {};
-  SpecialPowers.wrap(Components).utils.import("resource://gre/modules/Webapps.jsm", Webapps);
+  SpecialPowers.Cu.import("resource://gre/modules/Webapps.jsm", Webapps);
   var appRegistry = SpecialPowers.wrap(Webapps.DOMApplicationRegistry);
 
   var originalValue = appRegistry.allAppsLaunchable;
   appRegistry.allAppsLaunchable = true;
 
   // Clean up after ourselves once tests are done so the test page is unloaded.
   window.addEventListener("unload", function restoreAllAppsLaunchable(event) {
     if (event.target == window.document) {
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -1484,16 +1484,24 @@ void AsyncPanZoomController::SetZoomAndR
 void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,
                                                    float aMinZoom,
                                                    float aMaxZoom) {
   mAllowZoom = aAllowZoom;
   mMinZoom = aMinZoom;
   mMaxZoom = aMaxZoom;
 }
 
+void AsyncPanZoomController::PostDelayedTask(Task* aTask, int aDelayMs) {
+  if (!mGeckoContentController) {
+    return;
+  }
+
+  mGeckoContentController->PostDelayedTask(aTask, aDelayMs);
+}
+
 void AsyncPanZoomController::SendAsyncScrollEvent() {
   if (!mGeckoContentController) {
     return;
   }
 
   gfx::Rect contentRect;
   gfx::Size scrollableSize;
   {
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -146,16 +146,22 @@ public:
 
   /**
    * Updates any zoom constraints contained in the <meta name="viewport"> tag.
    * We try to obey everything it asks us elsewhere, but here we only handle
    * minimum-scale, maximum-scale, and user-scalable.
    */
   void UpdateZoomConstraints(bool aAllowZoom, float aMinScale, float aMaxScale);
 
+  /**
+   * Schedules a runnable to run on the controller/UI thread at some time
+   * in the future.
+   */
+  void PostDelayedTask(Task* aTask, int aDelayMs);
+
   // --------------------------------------------------------------------------
   // These methods must only be called on the compositor thread.
   //
 
   /**
    * The compositor calls this when it's about to draw pannable/zoomable content
    * and is setting up transforms for compositing the layer tree. This is not
    * idempotent. For example, a fling transform can be applied each time this is
--- a/gfx/layers/ipc/GeckoContentController.h
+++ b/gfx/layers/ipc/GeckoContentController.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_GeckoContentController_h
 #define mozilla_layers_GeckoContentController_h
 
 #include "FrameMetrics.h"
 #include "nsISupportsImpl.h"
 
+class Task;
+
 namespace mozilla {
 namespace layers {
 
 class GeckoContentController {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoContentController)
 
   /**
@@ -47,16 +49,22 @@ public:
   /**
    * Requests sending a mozbrowserasyncscroll domevent to embedder.
    * |aContentRect| is in CSS pixels, relative to the current cssPage.
    * |aScrollableSize| is the current content width/height in CSS pixels.
    */
   virtual void SendAsyncScrollDOMEvent(const gfx::Rect &aContentRect,
                                        const gfx::Size &aScrollableSize) = 0;
 
+  /**
+   * Schedules a runnable to run on the controller/UI thread at some time
+   * in the future.
+   */
+  virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0;
+
   GeckoContentController() {}
   virtual ~GeckoContentController() {}
 };
 
 }
 }
 
 #endif // mozilla_layers_GeckoContentController_h
--- a/gfx/layers/ipc/GestureEventListener.cpp
+++ b/gfx/layers/ipc/GestureEventListener.cpp
@@ -83,18 +83,17 @@ nsEventStatus GestureEventListener::Hand
       mTapStartTime = event.mTime;
       mTouchStartPosition = event.mTouches[0].mScreenPoint;
       if (mState == GESTURE_NONE) {
         mState = GESTURE_WAITING_SINGLE_TAP;
 
         mLongTapTimeoutTask =
           NewRunnableMethod(this, &GestureEventListener::TimeoutLongTap);
 
-        MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
+        mAsyncPanZoomController->PostDelayedTask(
           mLongTapTimeoutTask,
           Preferences::GetInt("ui.click_hold_context_menus.delay", 500));
       }
     } else if (length == 2) {
       // Another finger has been added; it can't be a tap anymore.
       HandleTapCancel(event);
     }
 
@@ -164,18 +163,17 @@ nsEventStatus GestureEventListener::Hand
         // We were not waiting for anything but a single tap has happened that
         // may turn into a double tap. Wait a while and if it doesn't turn into
         // a double tap, send a single tap instead.
         mState = GESTURE_WAITING_DOUBLE_TAP;
 
         mDoubleTapTimeoutTask =
           NewRunnableMethod(this, &GestureEventListener::TimeoutDoubleTap);
 
-        MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
+        mAsyncPanZoomController->PostDelayedTask(
           mDoubleTapTimeoutTask,
           MAX_TAP_TIME);
       }
 
       mLastTapEndTime = event.mTime;
     }
 
     if (mState == GESTURE_WAITING_SINGLE_TAP) {
--- a/gfx/layers/ipc/GestureEventListener.h
+++ b/gfx/layers/ipc/GestureEventListener.h
@@ -1,9 +1,12 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=4 ts=8 et 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
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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/. */
 
 #ifndef mozilla_layers_GestureEventListener_h
 #define mozilla_layers_GestureEventListener_h
 
 #include "mozilla/RefPtr.h"
 #include "InputData.h"
 #include "Axis.h"
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -116,17 +116,17 @@ CanvasLayerOGL::Initialize(const Data& a
   if (aData.mDrawTarget &&
       aData.mDrawTarget->GetNativeSurface(gfx::NATIVE_SURFACE_CGCONTEXT_ACCELERATED)) {
     mDrawTarget = aData.mDrawTarget;
     mNeedsYFlip = false;
     mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
     return;
   } else if (aData.mDrawTarget) {
     mDrawTarget = aData.mDrawTarget;
-    mCanvasSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
+    mCanvasSurface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget);
     mNeedsYFlip = false;
   } else if (aData.mSurface) {
     mCanvasSurface = aData.mSurface;
     mNeedsYFlip = false;
 #if defined(GL_PROVIDER_GLX)
     if (aData.mSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
         gfxXlibSurface *xsurf = static_cast<gfxXlibSurface*>(aData.mSurface);
         mPixmap = xsurf->GetGLXPixmap();
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -297,16 +297,17 @@ VectorImage::VectorImage(imgStatusTracke
   mIsDrawing(false),
   mHaveAnimations(false),
   mHaveRestrictedRegion(false)
 {
 }
 
 VectorImage::~VectorImage()
 {
+  CancelAllListeners();
 }
 
 //------------------------------------------------------------------------------
 // Methods inherited from Image.h
 
 nsresult
 VectorImage::Init(const char* aMimeType,
                   uint32_t aFlags)
@@ -894,19 +895,16 @@ VectorImage::OnSVGDocumentParsed()
     // notified that the SVG finished loading, so we need to treat this as an error.
     OnSVGDocumentError();
   }
 }
 
 void
 VectorImage::CancelAllListeners()
 {
-  NS_ABORT_IF_FALSE(mParseCompleteListener, "Should have the parse complete listener");
-  NS_ABORT_IF_FALSE(mLoadEventListener, "Should have the load event listener");
-
   if (mParseCompleteListener) {
     mParseCompleteListener->Cancel();
     mParseCompleteListener = nullptr;
   }
   if (mLoadEventListener) {
     mLoadEventListener->Cancel();
     mLoadEventListener = nullptr;
   }
--- a/image/test/crashtests/ownerdiscard.html
+++ b/image/test/crashtests/ownerdiscard.html
@@ -1,18 +1,18 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
 <body>
   <div id=tCF0>
     <img id=victim src=ie.png>
     <iframe src=discardframe.htm></iframe>
   </div>
   <script>
-    const Ci = Components.interfaces;
-    const Cc = SpecialPowers.wrap(Components).classes;
+    const Ci = SpecialPowers.Ci;
+    const Cc = SpecialPowers.Cc;
 
     function ImageDecoderObserverStub()
     {
       this.sizeAvailable = function sizeAvailable(aRequest)   {}
       this.frameComplete = function frameComplete(aRequest)   {}
       this.decodeComplete = function decodeComplete(aRequest) {}
       this.loadComplete = function loadComplete(aRequest)     {}
       this.frameUpdate = function frameUpdate(aRequest)       {}
--- a/js/ipc/ObjectWrapperChild.cpp
+++ b/js/ipc/ObjectWrapperChild.cpp
@@ -475,17 +475,17 @@ ObjectWrapperChild::AnswerNewEnumerateNe
 
     if (!strIds)
         return false;
 
     jsval v = JS_GetReservedSlot(state, sNextIdIndexSlot);
 
     int32_t i = JSVAL_TO_INT(v);
     NS_ASSERTION(i >= 0, "Index of next jsid negative?");
-    NS_ASSERTION(i <= strIds->Length(), "Index of next jsid too large?");
+    NS_ASSERTION(size_t(i) <= strIds->Length(), "Index of next jsid too large?");
 
     if (size_t(i) == strIds->Length()) {
         *status = JS_TRUE;
         return JSObject_to_JSVariant(cx, NULL, statep);
     }
 
     *idp = strIds->ElementAt(i);
     JS_SetReservedSlot(state, sNextIdIndexSlot, INT_TO_JSVAL(i + 1));
--- a/js/src/build/autoconf/compiler-opts.m4
+++ b/js/src/build/autoconf/compiler-opts.m4
@@ -89,16 +89,25 @@ if test "$CLANG_CXX"; then
     ## from C.
     ##
     ## mismatched-tags is disabled (bug 780474) mostly because it's useless.
     ## Worse, it's not supported by gcc, so it will cause tryserver bustage
     ## without any easy way for non-Clang users to check for it.
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage -Wno-mismatched-tags"
 fi
 
+if test -z "$GNU_CC"; then
+    case "$target" in
+    *-mingw*)
+        ## Warning 4099 (equivalent of mismatched-tags) is disabled (bug 780474)
+        ## for the same reasons as above.
+        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -wd4099"
+    esac
+fi
+
 if test "$GNU_CC"; then
     CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
     CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections -fno-exceptions"
 fi
 
 dnl ========================================================
 dnl = Identical Code Folding
 dnl ========================================================
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1679,17 +1679,18 @@ ia64*-hpux*)
         MKSHLIB_UNFORCE_ALL=
         DSO_LDOPTS=-SUBSYSTEM:WINDOWS
         _USE_CPP_INCLUDE_FLAG=1
         _DEFINES_CFLAGS='-FI $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT'
         _DEFINES_CXXFLAGS='-FI $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT'
         CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         # MSVC warning C4244 is ubiquitous, useless, and annoying.
-        CXXFLAGS="$CXXFLAGS -wd4244"
+        # khuey says we can safely ignore MSVC warning C4251
+        CXXFLAGS="$CXXFLAGS -wd4244 -wd4251"
         # make 'foo == bar;' error out
         CFLAGS="$CFLAGS -we4553"
         CXXFLAGS="$CXXFLAGS -we4553"
         LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib psapi.lib"
         MOZ_DEBUG_FLAGS='-Zi'
         MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
         WARNINGS_AS_ERRORS='-WX'
         MOZ_OPTIMIZE_FLAGS="-O2"
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1467,18 +1467,17 @@ ion::CanEnterAtBranch(JSContext *cx, JSS
 
     if (script->ion && script->ion->osrPc() != pc)
         return Method_Skipped;
 
     return Method_Compiled;
 }
 
 MethodStatus
-ion::CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp,
-              bool isConstructing, bool newType)
+ion::CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp, bool isConstructing)
 {
     JS_ASSERT(ion::IsEnabled(cx));
 
     // Skip if the script has been disabled.
     if (script->ion == ION_DISABLED_SCRIPT)
         return Method_Skipped;
 
     // Skip if the script is being compiled off thread.
@@ -1490,18 +1489,18 @@ ion::CanEnter(JSContext *cx, JSScript *s
         return Method_Skipped;
 
     // If constructing, allocate a new |this| object before building Ion.
     // Creating |this| is done before building Ion because it may change the
     // type information and invalidate compilation results.
     if (isConstructing && fp.thisValue().isPrimitive()) {
         RootedScript scriptRoot(cx, script);
         RootedObject callee(cx, &fp.callee());
-        RootedObject obj(cx, CreateThisForFunction(cx, callee, newType));
-        if (!obj)
+        RootedObject obj(cx, CreateThisForFunction(cx, callee, fp.useNewType()));
+        if (!obj || !ion::IsEnabled(cx)) // Note: OOM under CreateThis can disable TI.
             return Method_Skipped;
         fp.thisValue().setObject(*obj);
         script = scriptRoot;
     }
 
     // Mark as forbidden if frame can't be handled.
     if (!CheckFrame(fp)) {
         ForbidCompilation(cx, script);
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -256,18 +256,17 @@ bool InitializeIon();
 
 // Get and set the current Ion context.
 IonContext *GetIonContext();
 
 bool SetIonContext(IonContext *ctx);
 
 MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
                               AbstractFramePtr fp, jsbytecode *pc, bool isConstructing);
-MethodStatus CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp,
-                      bool isConstructing, bool newType);
+MethodStatus CanEnter(JSContext *cx, JSScript *script, AbstractFramePtr fp, bool isConstructing);
 MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);
 
 enum IonExecStatus
 {
     // The method call had to be aborted due to a stack limit check. This
     // error indicates that Ion never attempted to clean up frames.
     IonExec_Aborted,
 
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -4483,25 +4483,24 @@ IonBuilder::jsop_eval(uint32_t argc)
     if (IsBuiltinEvalForScope(&script()->global(), ObjectValue(*singleton))) {
         if (argc != 1)
             return abort("Direct eval with more than one argument");
 
         if (!info().fun())
             return abort("Direct eval in global code");
 
         types::StackTypeSet *thisTypes = oracle->thisTypeSet(script());
-        if (!thisTypes) {
-            // The 'this' value for the outer and eval scripts must be the
-            // same. This is not guaranteed if a primitive string/number/etc.
-            // is passed through to the eval invoke as the primitive may be
-            // boxed into different objects if accessed via 'this'.
-            JSValueType type = thisTypes->getKnownTypeTag();
-            if (type != JSVAL_TYPE_OBJECT && type != JSVAL_TYPE_NULL && type != JSVAL_TYPE_UNDEFINED)
-                return abort("Direct eval from script with maybe-primitive 'this'");
-        }
+
+        // The 'this' value for the outer and eval scripts must be the
+        // same. This is not guaranteed if a primitive string/number/etc.
+        // is passed through to the eval invoke as the primitive may be
+        // boxed into different objects if accessed via 'this'.
+        JSValueType type = thisTypes->getKnownTypeTag();
+        if (type != JSVAL_TYPE_OBJECT && type != JSVAL_TYPE_NULL && type != JSVAL_TYPE_UNDEFINED)
+            return abort("Direct eval from script with maybe-primitive 'this'");
 
         CallInfo callInfo(cx, /* constructing = */ false);
         if (!callInfo.init(current, argc))
             return false;
         callInfo.unwrapArgs();
 
         MDefinition *scopeChain = current->scopeChain();
         MDefinition *string = callInfo.getArg(0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-01.js
@@ -0,0 +1,19 @@
+// getColumnOffsets correctly places the various parts of a ForStatement.
+
+var global = newGlobal('new-compartment');
+Debugger(global).onDebuggerStatement = function (frame) {
+    var script = frame.eval("f").return.script;
+    script.getAllColumnOffsets().forEach(function (offset) {
+        script.setBreakpoint(offset.offset, {
+            hit: function (frame) {
+                assertEq(offset.lineNumber, 17);
+                global.log += offset.columnNumber + " ";
+            }
+        });
+    });
+};
+
+global.log = '';
+global.eval("function f(n) { for (var i = 0; i < n; ++i) log += '. '; log += '! '; } debugger;");
+global.f(3);
+assertEq(global.log, "21 32 44 . 39 32 44 . 39 32 44 . 39 32 57 ! 69 ");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug844364.js
@@ -0,0 +1,6 @@
+
+function f() {
+  eval("this")
+}
+f()
+f()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug844459.js
@@ -0,0 +1,7 @@
+
+
+function testEvalThrow(x, y) {
+  eval("");
+}
+for (var i = 0; i < 5; i++)
+  testEvalThrow.call("");
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -74,18 +74,18 @@ MSG_DEF(JSMSG_BAD_FORMAL,              2
 MSG_DEF(JSMSG_CANT_DELETE,             21, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
 MSG_DEF(JSMSG_NOT_FUNCTION,            22, 1, JSEXN_TYPEERR, "{0} is not a function")
 MSG_DEF(JSMSG_NOT_CONSTRUCTOR,         23, 1, JSEXN_TYPEERR, "{0} is not a constructor")
 MSG_DEF(JSMSG_INVALID_DATE,            24, 0, JSEXN_RANGEERR, "invalid date")
 MSG_DEF(JSMSG_TOO_DEEP,                25, 1, JSEXN_INTERNALERR, "{0} nested too deeply")
 MSG_DEF(JSMSG_OVER_RECURSED,           26, 0, JSEXN_INTERNALERR, "too much recursion")
 MSG_DEF(JSMSG_IN_NOT_OBJECT,           27, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
 MSG_DEF(JSMSG_BAD_NEW_RESULT,          28, 1, JSEXN_TYPEERR, "invalid new expression result {0}")
-MSG_DEF(JSMSG_UNUSED29,                29, 0, JSEXN_NONE, "")
-MSG_DEF(JSMSG_UNUSED30,                30, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED,    29, 0, JSEXN_ERR, "Permission denied to access object")
+MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED,  30, 1, JSEXN_ERR, "Permission denied to access property '{0}'")
 MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS,      31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
 MSG_DEF(JSMSG_BAD_BYTECODE,            32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
 MSG_DEF(JSMSG_BAD_RADIX,               33, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36")
 MSG_DEF(JSMSG_PAREN_BEFORE_LET,        34, 0, JSEXN_SYNTAXERR, "missing ( before let head")
 MSG_DEF(JSMSG_CANT_CONVERT,            35, 1, JSEXN_ERR, "can't convert {0} to an integer")
 MSG_DEF(JSMSG_CYCLIC_VALUE,            36, 1, JSEXN_TYPEERR, "cyclic {0} value")
 MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT,   37, 0, JSEXN_TYPEERR, "can't compile over a script that is currently executing")
 MSG_DEF(JSMSG_CANT_CONVERT_TO,         38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -876,16 +876,19 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     jitHardening(false),
     ionPcScriptCache(NULL),
     threadPool(this),
     ctypesActivityCallback(NULL),
     parallelWarmup(0),
     ionReturnOverride_(MagicValue(JS_ARG_POISON)),
     useHelperThreads_(useHelperThreads),
     requestedHelperThreadCount(-1),
+#ifdef DEBUG
+    enteredPolicy(NULL),
+#endif
     rngNonce(0)
 {
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&onNewGlobalObjectWatchers);
 
     PodZero(&debugHooks);
     PodZero(&atomState);
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -564,17 +564,17 @@ struct MallocProvider
     }
 
     JS_DECLARE_NEW_METHODS(new_, malloc_, JS_ALWAYS_INLINE)
 };
 
 namespace gc {
 class MarkingValidator;
 } // namespace gc
-
+class AutoEnterPolicy;
 } // namespace js
 
 struct JSRuntime : js::RuntimeFriendFields,
                    public js::MallocProvider<JSRuntime>
 {
     /*
      * Per-thread data for the main thread that is associated with
      * this JSRuntime, as opposed to any worker threads used in
@@ -1296,17 +1296,21 @@ struct JSRuntime : js::RuntimeFriendFiel
 #ifdef JS_THREADSAFE
         if (requestedHelperThreadCount < 0)
             return js::GetCPUCount() - 1;
         return requestedHelperThreadCount;
 #else
         return 0;
 #endif
     }
+#ifdef DEBUG
+  public:
+    js::AutoEnterPolicy *enteredPolicy;
 
+#endif
   private:
     /*
      * Used to ensure that compartments created at the same time get different
      * random number sequences. See js::InitRandom.
      */
     uint64_t rngNonce;
 
   public:
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -427,16 +427,17 @@ JSCompartment::wrap(JSContext *cx, JSObj
         return false;
     *objp = &value.get().toObject();
     return true;
 }
 
 bool
 JSCompartment::wrapId(JSContext *cx, jsid *idp)
 {
+    MOZ_ASSERT(*idp != JSID_VOID, "JSID_VOID is an out-of-band sentinel value");
     if (JSID_IS_INT(*idp))
         return true;
     RootedValue value(cx, IdToValue(*idp));
     if (!wrap(cx, &value))
         return false;
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, value.get(), &id))
         return false;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1411,11 +1411,18 @@ class JS_FRIEND_API(AutoCTypesActivityCa
     void DoEndCallback() {
         if (callback) {
             callback(cx, endType);
             callback = NULL;
         }
     }
 };
 
+#ifdef DEBUG
+extern JS_FRIEND_API(void)
+assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id);
+#else
+inline JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id) {};
+#endif
+
 } /* namespace js */
 
 #endif /* jsfriendapi_h___ */
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -271,16 +271,32 @@ js::RunScript(JSContext *cx, StackFrame 
     JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->regs().pc == script->code);
     JS_ASSERT_IF(fp->isEvalFrame(), script->isActiveEval);
 #ifdef JS_METHODJIT_SPEW
     JMCheckLogging();
 #endif
 
     JS_CHECK_RECURSION(cx, return false);
 
+    // Check to see if useNewType flag should be set for this frame.
+    if (fp->isFunctionFrame() && fp->isConstructing() && !fp->isGeneratorFrame() &&
+        cx->typeInferenceEnabled())
+    {
+        StackIter iter(cx);
+        if (!iter.done()) {
+            ++iter;
+            if (iter.isScript()) {
+                RawScript script = iter.script();
+                jsbytecode *pc = iter.pc();
+                if (UseNewType(cx, script, pc))
+                    fp->setUseNewType();
+            }
+        }
+    }
+
 #ifdef DEBUG
     struct CheckStackBalance {
         JSContext *cx;
         StackFrame *fp;
         CheckStackBalance(JSContext *cx)
           : cx(cx), fp(cx->fp())
         {}
         ~CheckStackBalance() {
@@ -289,17 +305,17 @@ js::RunScript(JSContext *cx, StackFrame 
     } check(cx);
 #endif
 
     SPSEntryMarker marker(cx->runtime);
 
 #ifdef JS_ION
     if (ion::IsEnabled(cx)) {
         ion::MethodStatus status = ion::CanEnter(cx, script, AbstractFramePtr(fp),
-                                                 fp->isConstructing(), false);
+                                                 fp->isConstructing());
         if (status == ion::Method_Error)
             return false;
         if (status == ion::Method_Compiled) {
             ion::IonExecStatus status = ion::Cannon(cx, fp);
 
             // Note that if we bailed out, new inline frames may have been
             // pushed, so we interpret with the current fp.
             if (status == ion::IonExec_Bailout)
@@ -1154,17 +1170,17 @@ js::Interpret(JSContext *cx, StackFrame 
 
     /* State communicated between non-local jumps: */
     bool interpReturnOK;
 
     /* Don't call the script prologue if executing between Method and Trace JIT. */
     if (interpMode == JSINTERP_NORMAL) {
         StackFrame *fp = regs.fp();
         if (!fp->isGeneratorFrame()) {
-            if (!fp->prologue(cx, UseNewTypeAtEntry(cx, fp)))
+            if (!fp->prologue(cx))
                 goto error;
         } else {
             Probes::enterScript(cx, script, script->function(), fp);
         }
         if (cx->compartment->debugMode()) {
             JSTrapStatus status = ScriptDebugPrologue(cx, fp);
             switch (status) {
               case JSTRAP_CONTINUE:
@@ -2356,26 +2372,29 @@ BEGIN_CASE(JSOP_FUNCALL)
     if (!TypeMonitorCall(cx, args, construct))
         goto error;
 
     InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
     bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
     funScript = fun->nonLazyScript();
     if (!cx->stack.pushInlineFrame(cx, regs, args, fun, funScript, initial))
         goto error;
+ 
+    if (newType)
+        regs.fp()->setUseNewType();
 
     SET_SCRIPT(regs.fp()->script());
 #ifdef JS_METHODJIT
     script->resetLoopCount();
 #endif
 
 #ifdef JS_ION
     if (!newType && ion::IsEnabled(cx)) {
         ion::MethodStatus status = ion::CanEnter(cx, script, AbstractFramePtr(regs.fp()),
-                                                 regs.fp()->isConstructing(), newType);
+                                                 regs.fp()->isConstructing());
         if (status == ion::Method_Error)
             goto error;
         if (status == ion::Method_Compiled) {
             ion::IonExecStatus exec = ion::Cannon(cx, regs.fp());
             CHECK_BRANCH();
             if (exec == ion::IonExec_Bailout) {
                 SET_SCRIPT(regs.fp()->script());
                 op = JSOp(*regs.pc);
@@ -2400,17 +2419,17 @@ BEGIN_CASE(JSOP_FUNCALL)
             mjit::JaegerStatus status = mjit::JaegerShot(cx, true);
             CHECK_PARTIAL_METHODJIT(status);
             interpReturnOK = mjit::JaegerStatusToSuccess(status);
             goto jit_return;
         }
     }
 #endif
 
-    if (!regs.fp()->prologue(cx, newType))
+    if (!regs.fp()->prologue(cx))
         goto error;
     if (cx->compartment->debugMode()) {
         switch (ScriptDebugPrologue(cx, regs.fp())) {
           case JSTRAP_CONTINUE:
             break;
           case JSTRAP_RETURN:
             interpReturnOK = true;
             goto forced_return;
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -92,19 +92,21 @@ ComputeThis(JSContext *cx, AbstractFrame
     if (frame.isFunctionFrame()) {
         if (frame.fun()->strict() || frame.fun()->isSelfHostedBuiltin())
             return true;
         /*
          * Eval function frames have their own |this| slot, which is a copy of the function's
          * |this| slot. If we lazily wrap a primitive |this| in an eval function frame, the
          * eval's frame will get the wrapper, but the function's frame will not. To prevent
          * this, we always wrap a function's |this| before pushing an eval frame, and should
-         * thus never see an unwrapped primitive in a non-strict eval function frame.
+         * thus never see an unwrapped primitive in a non-strict eval function frame. Null
+         * and undefined |this| values will unwrap to the same object in the function and
+         * eval frames, so are not required to be wrapped.
          */
-        JS_ASSERT(!frame.isEvalFrame());
+        JS_ASSERT_IF(frame.isEvalFrame(), thisv.isUndefined() || thisv.isNull());
     }
     bool modified;
     if (!BoxNonStrictThis(cx, &thisv, &modified))
         return false;
 
     frame.thisValue() = thisv;
     return true;
 }
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1221,19 +1221,16 @@ ExpressionDecompiler::decompilePC(jsbyte
     JS_ASSERT(script->code <= pc && pc < script->code + script->length);
 
     PCStack pcstack;
     if (!pcstack.init(cx, script, pc))
         return false;
 
     JSOp op = (JSOp)*pc;
 
-    // None of these stack-writing ops generates novel values.
-    JS_ASSERT(op != JSOP_CASE && op != JSOP_DUP && op != JSOP_DUP2);
-
     if (const char *token = CodeToken[op]) {
         // Handle simple cases of binary and unary operators.
         switch (js_CodeSpec[op].nuses) {
           case 2: {
             jssrcnote *sn = js_GetSrcNote(cx, script, pc);
             if (!sn || SN_TYPE(sn) != SRC_ASSIGNOP)
                 return write("(") &&
                        decompilePC(pcstack[-2]) &&
@@ -2252,16 +2249,19 @@ GetPCCountJSON(JSContext *cx, const Scri
     AppendJSONProperty(buf, "text", NO_COMMA);
 
     JSString *str = JS_DecompileScript(cx, script, NULL, 0);
     if (!str || !(str = ValueToSource(cx, StringValue(str))))
         return false;
 
     buf.append(str);
 
+    AppendJSONProperty(buf, "line");
+    NumberValueToStringBuffer(cx, Int32Value(script->lineno), buf);
+
     AppendJSONProperty(buf, "opcodes");
     buf.append('[');
     bool comma = false;
 
     SrcNoteLineScanner scanner(script->notes(), script->lineno);
 
     for (jsbytecode *pc = script->code;
          pc < script->code + script->length;
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -44,53 +44,111 @@ GetConstruct(UnrootedObject proxy)
 static inline HeapSlot &
 GetFunctionProxyConstruct(UnrootedObject proxy)
 {
     JS_ASSERT(IsFunctionProxy(proxy));
     JS_ASSERT(proxy->slotSpan() > JSSLOT_PROXY_CONSTRUCT);
     return proxy->getSlotRef(JSSLOT_PROXY_CONSTRUCT);
 }
 
+void
+js::AutoEnterPolicy::reportError(JSContext *cx, jsid id)
+{
+    if (JSID_IS_VOID(id)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_OBJECT_ACCESS_DENIED);
+    } else {
+        JSString *str = IdToString(cx, id);
+        const jschar *prop = str ? str->getCharsZ(cx) : NULL;
+        JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
+                               JSMSG_PROPERTY_ACCESS_DENIED, prop);
+    }
+}
+
+#ifdef DEBUG
+void
+js::AutoEnterPolicy::recordEnter(JSContext *cx, JSObject *proxy, jsid id)
+{
+    if (allowed()) {
+        context = cx;
+        enteredProxy.construct(cx, proxy);
+        enteredId.construct(cx, id);
+        prev = cx->runtime->enteredPolicy;
+        cx->runtime->enteredPolicy = this;
+    }
+}
+
+void
+js::AutoEnterPolicy::recordLeave()
+{
+    if (!enteredProxy.empty()) {
+        JS_ASSERT(context->runtime->enteredPolicy == this);
+        context->runtime->enteredPolicy = prev;
+    }
+}
+
+JS_FRIEND_API(void)
+js::assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id)
+{
+    MOZ_ASSERT(proxy->isProxy());
+    MOZ_ASSERT(cx->runtime->enteredPolicy);
+    MOZ_ASSERT(cx->runtime->enteredPolicy->enteredProxy.ref().get() == proxy);
+    MOZ_ASSERT(cx->runtime->enteredPolicy->enteredId.ref().get() == id);
+}
+#endif
+
 BaseProxyHandler::BaseProxyHandler(void *family)
   : mFamily(family),
-    mHasPrototype(false)
+    mHasPrototype(false),
+    mHasPolicy(false)
 {
 }
 
 BaseProxyHandler::~BaseProxyHandler()
 {
 }
 
 bool
+BaseProxyHandler::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act,
+                        bool *bp)
+{
+    *bp = true;
+    return true;
+}
+
+bool
 BaseProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 {
+    assertEnteredPolicy(cx, proxy_, id_);
     RootedObject proxy(cx, proxy_);
     RootedId id(cx, id_);
     AutoPropertyDescriptorRooter desc(cx);
     if (!getPropertyDescriptor(cx, proxy, id, &desc, 0))
         return false;
     *bp = !!desc.obj;
     return true;
 }
 
 bool
 BaseProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 {
+    assertEnteredPolicy(cx, proxy_, id_);
     RootedObject proxy(cx, proxy_);
     RootedId id(cx, id_);
     AutoPropertyDescriptorRooter desc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0))
         return false;
     *bp = !!desc.obj;
     return true;
 }
 
 bool
 BaseProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_, jsid id_, Value *vp)
 {
+    assertEnteredPolicy(cx, proxy, id_);
     RootedObject receiver(cx, receiver_);
     RootedId id(cx, id_);
 
     AutoPropertyDescriptorRooter desc(cx);
     if (!getPropertyDescriptor(cx, proxy, id, &desc, 0))
         return false;
     if (!desc.obj) {
         vp->setUndefined();
@@ -122,32 +180,34 @@ bool
 BaseProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject *receiver_, uint32_t index, Value *vp, bool *present)
 {
     RootedObject proxy(cx, proxy_);
     RootedObject receiver(cx, receiver_);
 
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
+    assertEnteredPolicy(cx, proxy, id);
 
     if (!has(cx, proxy, id, present))
         return false;
 
     if (!*present) {
         Debug_SetValueRangeToCrashOnTouch(vp, 1);
         return true;
     }
 
     return get(cx, proxy, receiver, id, vp);
 }
 
 bool
 BaseProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, bool strict,
                       Value *vp)
 {
+    assertEnteredPolicy(cx, proxy_, id_);
     RootedObject proxy(cx, proxy_), receiver(cx, receiver_);
     RootedId id(cx, id_);
 
     AutoPropertyDescriptorRooter desc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, JSRESOLVE_ASSIGNING))
         return false;
     /* The control-flow here differs from ::get() because of the fall-through case below. */
     if (desc.obj) {
@@ -214,44 +274,47 @@ BaseProxyHandler::set(JSContext *cx, JSO
     desc.getter = NULL;
     desc.setter = NULL; // Pick up the class getter/setter.
     return defineProperty(cx, receiver, id, &desc);
 }
 
 bool
 BaseProxyHandler::keys(JSContext *cx, JSObject *proxyArg, AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, proxyArg, JSID_VOID);
     JS_ASSERT(props.length() == 0);
 
     RootedObject proxy(cx, proxyArg);
 
     if (!getOwnPropertyNames(cx, proxy, props))
         return false;
 
     /* Select only the enumerable properties through in-place iteration. */
     AutoPropertyDescriptorRooter desc(cx);
     size_t i = 0;
     for (size_t j = 0, len = props.length(); j < len; j++) {
         JS_ASSERT(i <= j);
         jsid id = props[j];
+        AutoWaivePolicy policy(cx, proxy, id);
         if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0))
             return false;
         if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
             props[i++] = id;
     }
 
     JS_ASSERT(i <= props.length());
     props.resize(i);
 
     return true;
 }
 
 bool
 BaseProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
 {
+    assertEnteredPolicy(cx, proxy_, JSID_VOID);
     RootedObject proxy(cx, proxy_);
 
     AutoIdVector props(cx);
     if ((flags & JSITER_OWNONLY)
         ? !keys(cx, proxy, props)
         : !enumerate(cx, proxy, props)) {
         return false;
     }
@@ -263,28 +326,30 @@ BaseProxyHandler::iterate(JSContext *cx,
     *vp = value;
     return true;
 }
 
 bool
 BaseProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
                        Value *vp)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     AutoValueRooter rval(cx);
     RootedValue call(cx, GetCall(proxy));
     JSBool ok = Invoke(cx, vp[1], call, argc, JS_ARGV(cx, vp), rval.addr());
     if (ok)
         JS_SET_RVAL(cx, vp, rval.value());
     return ok;
 }
 
 bool
 BaseProxyHandler::construct(JSContext *cx, JSObject *proxy_, unsigned argc,
                             Value *argv, Value *rval)
 {
+    assertEnteredPolicy(cx, proxy_, JSID_VOID);
     RootedObject proxy(cx, proxy_);
     RootedValue fval(cx, GetConstruct(proxy_));
     if (fval.isUndefined())
         fval = GetCall(proxy);
     return InvokeConstructor(cx, fval, argc, argv, rval);
 }
 
 JSString *
@@ -293,16 +358,17 @@ BaseProxyHandler::obj_toString(JSContext
     return JS_NewStringCopyZ(cx, IsFunctionProxy(proxy)
                                  ? "[object Function]"
                                  : "[object Object]");
 }
 
 JSString *
 BaseProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     Value fval = GetCall(proxy);
     if (IsFunctionProxy(proxy) &&
         (fval.isPrimitive() || !fval.toObject().isFunction())) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_PROTO,
                              js_Function_str, js_toString_str,
                              "object");
         return NULL;
@@ -338,16 +404,17 @@ BaseProxyHandler::nativeCall(JSContext *
 {
     ReportIncompatible(cx, args);
     return false;
 }
 
 bool
 BaseProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     RootedValue val(cx, ObjectValue(*proxy.get()));
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
                         JSDVG_SEARCH_STACK, val, NullPtr());
     return false;
 }
 
 bool
 BaseProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
@@ -374,16 +441,18 @@ BaseProxyHandler::getPrototypeOf(JSConte
     return true;
 }
 
 
 bool
 DirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy,
                                           jsid id, PropertyDescriptor *desc, unsigned flags)
 {
+    assertEnteredPolicy(cx, proxy, id);
+    JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     RootedObject target(cx, GetProxyTargetObject(proxy));
     return JS_GetPropertyDescriptorById(cx, target, id, 0, desc);
 }
 
 static bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, jsid id, unsigned flags,
                          JSPropertyDescriptor *desc)
 {
@@ -398,57 +467,63 @@ GetOwnPropertyDescriptor(JSContext *cx, 
         desc->obj = NULL;
     return true;
 }
 
 bool
 DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
                                              jsid id, PropertyDescriptor *desc, unsigned flags)
 {
+    assertEnteredPolicy(cx, proxy, id);
     RootedObject target(cx, GetProxyTargetObject(proxy));
     return GetOwnPropertyDescriptor(cx, target, id, 0, desc);
 }
 
 bool
 DirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
                                    PropertyDescriptor *desc)
 {
+    assertEnteredPolicy(cx, proxy, id_);
     RootedObject obj(cx, GetProxyTargetObject(proxy));
     Rooted<jsid> id(cx, id_);
     Rooted<Value> v(cx, desc->value);
     return CheckDefineProperty(cx, obj, id, v, desc->getter, desc->setter, desc->attrs) &&
            JS_DefinePropertyById(cx, obj, id, v, desc->getter, desc->setter, desc->attrs);
 }
 
 bool
 DirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy,
                                         AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     RootedObject target(cx, GetProxyTargetObject(proxy));
     return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props);
 }
 
 bool
 DirectProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 {
     RootedValue v(cx);
+    assertEnteredPolicy(cx, proxy, id);
     RootedObject target(cx, GetProxyTargetObject(proxy));
     if (!JS_DeletePropertyById2(cx, target, id, v.address()))
         return false;
     JSBool b;
     if (!JS_ValueToBoolean(cx, v, &b))
         return false;
     *bp = !!b;
     return true;
 }
 
 bool
 DirectProxyHandler::enumerate(JSContext *cx, JSObject *proxy,
                               AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
+    JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     RootedObject target(cx, GetProxyTargetObject(proxy));
     return GetPropertyNames(cx, target, 0, &props);
 }
 
 bool
 DirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                                CallArgs args)
 {
@@ -460,16 +535,17 @@ DirectProxyHandler::nativeCall(JSContext
 
     return CallNativeImpl(cx, impl, args);
 }
 
 bool
 DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
                                 bool *bp)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     JSBool b;
     RootedObject target(cx, GetProxyTargetObject(proxy));
     if (!JS_HasInstance(cx, target, v, &b))
         return false;
     *bp = !!b;
     return true;
 }
 
@@ -480,23 +556,25 @@ DirectProxyHandler::objectClassIs(JSObje
 {
     RootedObject obj(cx, GetProxyTargetObject(proxy));
     return ObjectClassIs(obj, classValue, cx);
 }
 
 JSString *
 DirectProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     return obj_toStringHelper(cx, GetProxyTargetObject(proxy));
 }
 
 JSString *
 DirectProxyHandler::fun_toString(JSContext *cx, JSObject *proxy,
                                  unsigned indent)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     RootedObject target(cx, GetProxyTargetObject(proxy));
     return fun_toStringHelper(cx, target, indent);
 }
 
 bool
 DirectProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy,
                                     RegExpGuard *g)
 {
@@ -522,75 +600,83 @@ DirectProxyHandler::weakmapKeyDelegate(J
 DirectProxyHandler::DirectProxyHandler(void *family)
   : BaseProxyHandler(family)
 {
 }
 
 bool
 DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 {
+    assertEnteredPolicy(cx, proxy, id);
+    JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     JSBool found;
     RootedObject target(cx, GetProxyTargetObject(proxy));
     if (!JS_HasPropertyById(cx, target, id, &found))
         return false;
     *bp = !!found;
     return true;
 }
 
 bool
 DirectProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 {
+    assertEnteredPolicy(cx, proxy, id);
     RootedObject target(cx, GetProxyTargetObject(proxy));
     AutoPropertyDescriptorRooter desc(cx);
     if (!JS_GetPropertyDescriptorById(cx, target, id, 0, &desc))
         return false;
     *bp = (desc.obj == target);
     return true;
 }
 
 bool
 DirectProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_,
                         jsid id_, Value *vp)
 {
+    assertEnteredPolicy(cx, proxy, id_);
     RootedObject receiver(cx, receiver_);
     RootedId id(cx, id_);
     RootedValue value(cx);
     RootedObject target(cx, GetProxyTargetObject(proxy));
     if (!JSObject::getGeneric(cx, target, receiver, id, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 bool
 DirectProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiverArg,
                         jsid id_, bool strict, Value *vp)
 {
+    assertEnteredPolicy(cx, proxy, id_);
     RootedId id(cx, id_);
     Rooted<JSObject*> receiver(cx, receiverArg);
     RootedValue value(cx, *vp);
     RootedObject target(cx, GetProxyTargetObject(proxy));
     if (!JSObject::setGeneric(cx, target, receiver, id, &value, strict))
         return false;
 
     *vp = value;
     return true;
 }
 
 bool
 DirectProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
     return GetPropertyNames(cx, GetProxyTargetObject(proxy), JSITER_OWNONLY, &props);
 }
 
 bool
 DirectProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags,
                             Value *vp)
 {
+    assertEnteredPolicy(cx, proxy, JSID_VOID);
+    JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
     RootedValue value(cx);
     if (!GetIterator(cx, target, flags, &value))
         return false;
 
     *vp = value;
     return true;
 }
@@ -2172,25 +2258,28 @@ ScriptedDirectProxyHandler ScriptedDirec
         if (!handler->getPrototypeOf(cx, proxy, proto.address()))            \
             return false;                                                    \
         if (!proto)                                                          \
             return true;                                                     \
         assertSameCompartment(cx, proxy, proto);                             \
         return protoCall;                                                    \
     JS_END_MACRO                                                             \
 
-
 bool
 Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, PropertyDescriptor *desc,
                              unsigned flags)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
     RootedId id(cx, id_);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
+    desc->obj = NULL; // default result if we refuse to perform this action
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     if (!handler->hasPrototype())
         return handler->getPropertyDescriptor(cx, proxy, id, desc, flags);
     if (!handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags))
         return false;
     if (desc->obj)
         return true;
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
                         JS_GetPropertyDescriptorById(cx, proto, id, 0, desc));
@@ -2213,17 +2302,22 @@ Proxy::getPropertyDescriptor(JSContext *
 }
 
 bool
 Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id, PropertyDescriptor *desc,
                                 unsigned flags)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
-    return GetProxyHandler(proxy)->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+    desc->obj = NULL; // default result if we refuse to perform this action
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
+    return handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
 }
 
 bool
 Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy_, unsigned flags, jsid id,
                                 Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
@@ -2237,17 +2331,21 @@ Proxy::getOwnPropertyDescriptor(JSContex
     *vp = value;
     return true;
 }
 
 bool
 Proxy::defineProperty(JSContext *cx, JSObject *proxy_, jsid id, PropertyDescriptor *desc)
 {
     JS_CHECK_RECURSION(cx, return false);
+    BaseProxyHandler *handler = GetProxyHandler(proxy_);
     RootedObject proxy(cx, proxy_);
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     return GetProxyHandler(proxy)->defineProperty(cx, proxy, id, desc);
 }
 
 bool
 Proxy::defineProperty(JSContext *cx, JSObject *proxy_, jsid id_, const Value &v)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
@@ -2256,25 +2354,34 @@ Proxy::defineProperty(JSContext *cx, JSO
     return ParsePropertyDescriptorObject(cx, proxy, v, &desc) &&
            Proxy::defineProperty(cx, proxy, id, &desc);
 }
 
 bool
 Proxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy_, AutoIdVector &props)
 {
     JS_CHECK_RECURSION(cx, return false);
+    BaseProxyHandler *handler = GetProxyHandler(proxy_);
     RootedObject proxy(cx, proxy_);
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     return GetProxyHandler(proxy)->getOwnPropertyNames(cx, proxy, props);
 }
 
 bool
 Proxy::delete_(JSContext *cx, JSObject *proxy_, jsid id, bool *bp)
 {
     JS_CHECK_RECURSION(cx, return false);
+    BaseProxyHandler *handler = GetProxyHandler(proxy_);
     RootedObject proxy(cx, proxy_);
+    *bp = true; // default result if we refuse to perform this action
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     return GetProxyHandler(proxy)->delete_(cx, proxy, id, bp);
 }
 
 JS_FRIEND_API(bool)
 js::AppendUnique(JSContext *cx, AutoIdVector &base, AutoIdVector &others)
 {
     AutoIdVector uniqueOthers(cx);
     if (!uniqueOthers.reserve(others.length()))
@@ -2294,16 +2401,19 @@ js::AppendUnique(JSContext *cx, AutoIdVe
 }
 
 bool
 Proxy::enumerate(JSContext *cx, JSObject *proxy_, AutoIdVector &props)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     if (!handler->hasPrototype())
         return GetProxyHandler(proxy)->enumerate(cx, proxy, props);
     if (!handler->keys(cx, proxy, props))
         return false;
     AutoIdVector protoProps(cx);
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
                         GetPropertyNames(cx, proto, 0, &protoProps) &&
                         AppendUnique(cx, props, protoProps));
@@ -2311,16 +2421,20 @@ Proxy::enumerate(JSContext *cx, JSObject
 
 bool
 Proxy::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
     RootedId id(cx, id_);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
+    *bp = false; // default result if we refuse to perform this action
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     if (!handler->hasPrototype())
         return handler->has(cx, proxy, id, bp);
     if (!handler->hasOwn(cx, proxy, id, bp))
         return false;
     if (*bp)
         return true;
     JSBool Bp;
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
@@ -2328,25 +2442,34 @@ Proxy::has(JSContext *cx, JSObject *prox
                         ((*bp = Bp) || true));
 }
 
 bool
 Proxy::hasOwn(JSContext *cx, JSObject *proxy_, jsid id, bool *bp)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
-    return GetProxyHandler(proxy)->hasOwn(cx, proxy, id, bp);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+    *bp = false; // default result if we refuse to perform this action
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
+    return handler->hasOwn(cx, proxy, id, bp);
 }
 
 bool
 Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
+    vp.setUndefined(); // default result if we refuse to perform this action
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     bool own;
     if (!handler->hasPrototype()) {
         own = true;
     } else {
         if (!handler->hasOwn(cx, proxy, id, &own))
             return false;
     }
     if (own)
@@ -2355,27 +2478,30 @@ Proxy::get(JSContext *cx, HandleObject p
 }
 
 bool
 Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index,
                            MutableHandleValue vp, bool *present)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    BaseProxyHandler *handler = GetProxyHandler(proxy);
-
-    if (!handler->hasPrototype()) {
-        return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver, index,
-                                                           vp.address(), present);
-    }
-
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
 
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
+
+    if (!handler->hasPrototype()) {
+        return handler->getElementIfPresent(cx, proxy, receiver, index,
+                                            vp.address(), present);
+    }
+
     bool hasOwn;
     if (!handler->hasOwn(cx, proxy, id, &hasOwn))
         return false;
 
     if (hasOwn) {
         *present = true;
         return GetProxyHandler(proxy)->get(cx, proxy, receiver, id, vp.address());
     }
@@ -2385,16 +2511,19 @@ Proxy::getElementIfPresent(JSContext *cx
 }
 
 bool
 Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
+    AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     if (handler->hasPrototype()) {
         // If we're using a prototype, we still want to use the proxy trap unless
         // we have a non-own property with a setter.
         bool hasOwn;
         if (!handler->hasOwn(cx, proxy, id, &hasOwn))
             return false;
         if (!hasOwn) {
             RootedObject proto(cx);
@@ -2412,88 +2541,152 @@ Proxy::set(JSContext *cx, HandleObject p
     return handler->set(cx, proxy, receiver, id, strict, vp.address());
 }
 
 bool
 Proxy::keys(JSContext *cx, JSObject *proxy_, AutoIdVector &props)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
-    return GetProxyHandler(proxy)->keys(cx, proxy, props);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
+    return handler->keys(cx, proxy, props);
 }
 
 bool
 Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
-    if (!handler->hasPrototype())
-        return GetProxyHandler(proxy)->iterate(cx, proxy, flags, vp.address());
+    vp.setUndefined(); // default result if we refuse to perform this action
+    if (!handler->hasPrototype()) {
+        AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID,
+                               BaseProxyHandler::GET, /* mayThrow = */ false);
+        // If the policy denies access but wants us to return true, we need
+        // to hand a valid (empty) iterator object to the caller.
+        if (!policy.allowed()) {
+            AutoIdVector props(cx);
+            return policy.returnValue() &&
+                   EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
+        }
+        return handler->iterate(cx, proxy, flags, vp.address());
+    }
     AutoIdVector props(cx);
     // The other Proxy::foo methods do the prototype-aware work for us here.
     if ((flags & JSITER_OWNONLY)
         ? !Proxy::keys(cx, proxy, props)
         : !Proxy::enumerate(cx, proxy, props)) {
         return false;
     }
     return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
 }
 
 bool
 Proxy::call(JSContext *cx, JSObject *proxy_, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
-    return GetProxyHandler(proxy)->call(cx, proxy, argc, vp);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+
+    // Because vp[0] is JS_CALLEE on the way in and JS_RVAL on the way out, we
+    // can only set our default value once we're sure that we're not calling the
+    // trap.
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID,
+                           BaseProxyHandler::CALL, true);
+    if (!policy.allowed()) {
+        vp->setUndefined();
+        return policy.returnValue();
+    }
+
+    return handler->call(cx, proxy, argc, vp);
 }
 
 bool
 Proxy::construct(JSContext *cx, JSObject *proxy_, unsigned argc, Value *argv, Value *rval)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
-    return GetProxyHandler(proxy)->construct(cx, proxy, argc, argv, rval);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+
+    // Because vp[0] is JS_CALLEE on the way in and JS_RVAL on the way out, we
+    // can only set our default value once we're sure that we're not calling the
+    // trap.
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID,
+                           BaseProxyHandler::CALL, true);
+    if (!policy.allowed()) {
+        rval->setUndefined();
+        return policy.returnValue();
+    }
+
+    return handler->construct(cx, proxy, argc, argv, rval);
 }
 
 bool
 Proxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
 {
     JS_CHECK_RECURSION(cx, return false);
     Rooted<JSObject*> proxy(cx, &args.thisv().toObject());
+    // Note - we don't enter a policy here because our security architecture
+    // guards against nativeCall by overriding the trap itself in the right
+    // circumstances.
     return GetProxyHandler(proxy)->nativeCall(cx, test, impl, args);
 }
 
 bool
 Proxy::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
 {
     JS_CHECK_RECURSION(cx, return false);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+    *bp = false; // default result if we refuse to perform this action
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID, BaseProxyHandler::GET, true);
+    if (!policy.allowed())
+        return policy.returnValue();
     return GetProxyHandler(proxy)->hasInstance(cx, proxy, v, bp);
 }
 
 bool
 Proxy::objectClassIs(JSObject *proxy_, ESClassValue classValue, JSContext *cx)
 {
     RootedObject proxy(cx, proxy_);
     return GetProxyHandler(proxy)->objectClassIs(proxy, classValue, cx);
 }
 
 JSString *
 Proxy::obj_toString(JSContext *cx, JSObject *proxy_)
 {
     JS_CHECK_RECURSION(cx, return NULL);
     RootedObject proxy(cx, proxy_);
-    return GetProxyHandler(proxy)->obj_toString(cx, proxy);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID,
+                           BaseProxyHandler::GET, /* mayThrow = */ false);
+    // Do the safe thing if the policy rejects.
+    if (!policy.allowed()) {
+        return handler->BaseProxyHandler::obj_toString(cx, proxy);
+    }
+    return handler->obj_toString(cx, proxy);
 }
 
 JSString *
 Proxy::fun_toString(JSContext *cx, JSObject *proxy_, unsigned indent)
 {
     JS_CHECK_RECURSION(cx, return NULL);
     RootedObject proxy(cx, proxy_);
-    return GetProxyHandler(proxy)->fun_toString(cx, proxy, indent);
+    BaseProxyHandler *handler = GetProxyHandler(proxy);
+    AutoEnterPolicy policy(cx, handler, proxy, JSID_VOID,
+                           BaseProxyHandler::GET, /* mayThrow = */ false);
+    // Do the safe thing if the policy rejects.
+    if (!policy.allowed()) {
+        if (proxy->isCallable())
+            return JS_NewStringCopyZ(cx, "function () {\n    [native code]\n}");
+        ReportIsNotFunction(cx, ObjectValue(*proxy));
+        return NULL;
+    }
+    return handler->fun_toString(cx, proxy, indent);
 }
 
 bool
 Proxy::regexp_toShared(JSContext *cx, JSObject *proxy_, RegExpGuard *g)
 {
     JS_CHECK_RECURSION(cx, return false);
     RootedObject proxy(cx, proxy_);
     return GetProxyHandler(proxy)->regexp_toShared(cx, proxy, g);
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -46,36 +46,60 @@ class JS_FRIEND_API(Wrapper);
  * any assumptions about the target. Consequently, it does not provide any
  * default implementation for the fundamental traps. It does, however, implement
  * the derived traps in terms of the fundamental ones. This allows consumers of
  * this class to define any custom behavior they want.
  */
 class JS_FRIEND_API(BaseProxyHandler) {
     void *mFamily;
     bool mHasPrototype;
+    bool mHasPolicy;
   protected:
     // Subclasses may set this in their constructor.
     void setHasPrototype(bool aHasPrototype) { mHasPrototype = aHasPrototype; }
+    void setHasPolicy(bool aHasPolicy) { mHasPolicy = aHasPolicy; }
 
   public:
     explicit BaseProxyHandler(void *family);
     virtual ~BaseProxyHandler();
 
     bool hasPrototype() {
         return mHasPrototype;
     }
 
+    bool hasPolicy() {
+        return mHasPolicy;
+    }
+
     inline void *family() {
         return mFamily;
     }
 
     virtual bool isOuterWindow() {
         return false;
     }
 
+    /* Policy enforcement traps.
+     *
+     * enter() allows the policy to specify whether the caller may perform |act|
+     * on the proxy's |id| property. In the case when |act| is CALL, |id| is
+     * generally JSID_VOID.
+     *
+     * The |act| parameter to enter() specifies the action being performed.
+     * If |bp| is false, the trap suggests that the caller throw (though it
+     * may still decide to squelch the error).
+     */
+    enum Action {
+        GET,
+        SET,
+        CALL
+    };
+    virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act,
+                       bool *bp);
+
     /* ES5 Harmony fundamental proxy traps. */
     virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
                                        PropertyDescriptor *desc, unsigned flags) = 0;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
                                           jsid id, PropertyDescriptor *desc, unsigned flags) = 0;
     virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id,
                                 PropertyDescriptor *desc) = 0;
     virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy,
@@ -314,14 +338,80 @@ SetProxyExtra(RawObject obj, size_t n, c
 JS_FRIEND_API(JSObject *)
 NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv,
                JSObject *proto, JSObject *parent,
                JSObject *call = NULL, JSObject *construct = NULL);
 
 JSObject *
 RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv);
 
+class JS_FRIEND_API(AutoEnterPolicy)
+{
+  public:
+    typedef BaseProxyHandler::Action Action;
+    AutoEnterPolicy(JSContext *cx, BaseProxyHandler *handler,
+                    JSObject *wrapper, jsid id, Action act, bool mayThrow)
+#ifdef DEBUG
+        : context(NULL)
+#endif
+    {
+        allow = handler->hasPolicy() ? handler->enter(cx, wrapper, id, act, &rv)
+                                     : true;
+        recordEnter(cx, wrapper, id);
+        if (!allow && !rv && mayThrow)
+            reportError(cx, id);
+    }
+
+    virtual ~AutoEnterPolicy() { recordLeave(); }
+    inline bool allowed() { return allow; }
+    inline bool returnValue() { JS_ASSERT(!allowed()); return rv; }
+
+  protected:
+    // no-op constructor for subclass
+    AutoEnterPolicy()
+#ifdef DEBUG
+        : context(NULL)
+#endif
+        {};
+    void reportError(JSContext *cx, jsid id);
+    bool allow;
+    bool rv;
+
+#ifdef DEBUG
+    JSContext *context;
+    mozilla::Maybe<RootedObject> enteredProxy;
+    mozilla::Maybe<RootedId> enteredId;
+    // NB: We explicitly don't track the entered action here, because sometimes
+    // SET traps do an implicit GET during their implementation, leading to
+    // spurious assertions.
+    AutoEnterPolicy *prev;
+    void recordEnter(JSContext *cx, JSObject *proxy, jsid id);
+    void recordLeave();
+
+    friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id);
+#else
+    inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id) {}
+    inline void recordLeave() {}
+#endif
+
+};
+
+#ifdef DEBUG
+class JS_FRIEND_API(AutoWaivePolicy) : public AutoEnterPolicy {
+public:
+    AutoWaivePolicy(JSContext *cx, JSObject *proxy, jsid id)
+    {
+        allow = true;
+        recordEnter(cx, proxy, id);
+    }
+};
+#else
+class JS_FRIEND_API(AutoWaivePolicy) {
+    public: AutoWaivePolicy(JSContext *cx, JSObject *proxy, jsid id) {};
+};
+#endif
+
 } /* namespace js */
 
 extern JS_FRIEND_API(JSObject *)
 js_InitProxyClass(JSContext *cx, JSHandleObject obj);
 
 #endif
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -65,23 +65,16 @@ Wrapper::wrapperHandler(RawObject wrappe
 
 JSObject *
 Wrapper::wrappedObject(RawObject wrapper)
 {
     JS_ASSERT(wrapper->isWrapper());
     return GetProxyTargetObject(wrapper);
 }
 
-bool
-Wrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp)
-{
-    *bp = true;
-    return true;
-}
-
 JS_FRIEND_API(JSObject *)
 js::UnwrapObject(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
 {
     unsigned flags = 0;
     while (wrapped->isWrapper() &&
            !JS_UNLIKELY(stopAtOuter && wrapped->getClass()->ext.innerObject)) {
         flags |= Wrapper::wrapperHandler(wrapped)->flags();
         wrapped = GetProxyPrivate(wrapped).toObjectOrNull();
@@ -117,94 +110,27 @@ js::UnwrapOneChecked(RawObject obj, bool
 
 bool
 js::IsCrossCompartmentWrapper(RawObject wrapper)
 {
     return wrapper->isWrapper() &&
            !!(Wrapper::wrapperHandler(wrapper)->flags() & Wrapper::CROSS_COMPARTMENT);
 }
 
-#define CHECKED(op, act)                                                     \
-    JS_BEGIN_MACRO                                                           \
-        bool status;                                                         \
-        if (!enter(cx, wrapper, id, act, &status))                           \
-            return status;                                                   \
-        return (op);                                                         \
-    JS_END_MACRO
-
-#define SET(action) CHECKED(action, SET)
-#define GET(action) CHECKED(action, GET)
-
 Wrapper::Wrapper(unsigned flags, bool hasPrototype) : DirectProxyHandler(&sWrapperFamily)
                                                     , mFlags(flags)
                                                     , mSafeToUnwrap(true)
 {
     setHasPrototype(hasPrototype);
 }
 
 Wrapper::~Wrapper()
 {
 }
 
-bool
-Wrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapperArg,
-                               jsid id, PropertyDescriptor *desc, unsigned flags)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
-    desc->obj = NULL; // default result if we refuse to perform this action
-    CHECKED(DirectProxyHandler::getPropertyDescriptor(cx, wrapper, id, desc, flags),
-            (flags & JSRESOLVE_ASSIGNING) ? SET : GET);
-}
-
-bool
-Wrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapperArg,
-                                  jsid id, PropertyDescriptor *desc, unsigned flags)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    desc->obj = NULL; // default result if we refuse to perform this action
-    CHECKED(DirectProxyHandler::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags), GET);
-}
-
-bool
-Wrapper::defineProperty(JSContext *cx, JSObject *wrapperArg, jsid id,
-                        PropertyDescriptor *desc)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    SET(DirectProxyHandler::defineProperty(cx, wrapper, id, desc));
-}
-
-bool
-Wrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapperArg,
-                             AutoIdVector &props)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    // if we refuse to perform this action, props remains empty
-    jsid id = JSID_VOID;
-    GET(DirectProxyHandler::getOwnPropertyNames(cx, wrapper, props));
-}
-
-bool
-Wrapper::delete_(JSContext *cx, JSObject *wrapperArg, jsid id, bool *bp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    *bp = true; // default result if we refuse to perform this action
-    SET(DirectProxyHandler::delete_(cx, wrapper, id, bp));
-}
-
-bool
-Wrapper::enumerate(JSContext *cx, JSObject *wrapperArg, AutoIdVector &props)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
-    // if we refuse to perform this action, props remains empty
-    static jsid id = JSID_VOID;
-    GET(DirectProxyHandler::enumerate(cx, wrapper, props));
-}
-
 /*
  * Ordinarily, the convert trap would require unwrapping. However, the default
  * implementation of convert, JS_ConvertStub, obtains a default value by calling
  * the toString/valueOf method on the wrapper, if any. Throwing if we can't unwrap
  * in this case would be overly conservative. To make matters worse, XPConnect sometimes
  * installs a custom convert trap that obtains a default value by calling the
  * toString method on the wrapper. Doing a puncture in this case would be overly
  * conservative as well. We deal with these anomalies by falling back to the DefaultValue
@@ -229,136 +155,16 @@ Wrapper::defaultValue(JSContext *cx, JSO
      * necessary because the DefaultValue algorithm above operates on the
      * wrapper, not the wrappee, so we want to delay the decision to switch
      * compartments until this point.
      */
     AutoCompartment call(cx, wrappedObject(wrapper));
     return DirectProxyHandler::defaultValue(cx, wrapper, hint, vp);
 }
 
-bool
-Wrapper::has(JSContext *cx, JSObject *wrapperArg, jsid id, bool *bp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
-    *bp = false; // default result if we refuse to perform this action
-    GET(DirectProxyHandler::has(cx, wrapper, id, bp));
-}
-
-bool
-Wrapper::hasOwn(JSContext *cx, JSObject *wrapperArg, jsid id, bool *bp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    *bp = false; // default result if we refuse to perform this action
-    GET(DirectProxyHandler::hasOwn(cx, wrapper, id, bp));
-}
-
-bool
-Wrapper::get(JSContext *cx, JSObject *wrapperArg, JSObject *receiver, jsid id, Value *vp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    vp->setUndefined(); // default result if we refuse to perform this action
-    GET(DirectProxyHandler::get(cx, wrapper, receiver, id, vp));
-}
-
-bool
-Wrapper::set(JSContext *cx, JSObject *wrapperArg, JSObject *receiver, jsid id, bool strict,
-             Value *vp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    SET(DirectProxyHandler::set(cx, wrapper, receiver, id, strict, vp));
-}
-
-bool
-Wrapper::keys(JSContext *cx, JSObject *wrapperArg, AutoIdVector &props)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    // if we refuse to perform this action, props remains empty
-    const jsid id = JSID_VOID;
-    GET(DirectProxyHandler::keys(cx, wrapper, props));
-}
-
-bool
-Wrapper::iterate(JSContext *cx, JSObject *wrapperArg, unsigned flags, Value *vp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    JS_ASSERT(!hasPrototype()); // Should never be called when there's a prototype.
-    vp->setUndefined(); // default result if we refuse to perform this action
-    const jsid id = JSID_VOID;
-    GET(DirectProxyHandler::iterate(cx, wrapper, flags, vp));
-}
-
-bool
-Wrapper::call(JSContext *cx, JSObject *wrapperArg, unsigned argc, Value *vp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    vp->setUndefined(); // default result if we refuse to perform this action
-    const jsid id = JSID_VOID;
-    CHECKED(DirectProxyHandler::call(cx, wrapper, argc, vp), CALL);
-}
-
-bool
-Wrapper::construct(JSContext *cx, JSObject *wrapperArg, unsigned argc, Value *argv, Value *vp)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    vp->setUndefined(); // default result if we refuse to perform this action
-    const jsid id = JSID_VOID;
-    CHECKED(DirectProxyHandler::construct(cx, wrapper, argc, argv, vp), CALL);
-}
-
-bool
-Wrapper::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
-{
-    const jsid id = JSID_VOID;
-    RootedObject wrapper(cx, &args.thisv().toObject());
-    CHECKED(DirectProxyHandler::nativeCall(cx, test, impl, args), CALL);
-}
-
-bool
-Wrapper::hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v, bool *bp)
-{
-    *bp = false; // default result if we refuse to perform this action
-    const jsid id = JSID_VOID;
-    GET(DirectProxyHandler::hasInstance(cx, wrapper, v, bp));
-}
-
-JSString *
-Wrapper::obj_toString(JSContext *cx, JSObject *wrapperArg)
-{
-    RootedObject wrapper(cx, wrapperArg);
-    bool status;
-    if (!enter(cx, wrapper, JSID_VOID, GET, &status)) {
-        if (status) {
-            // Perform some default behavior that doesn't leak any information.
-            return JS_NewStringCopyZ(cx, "[object Object]");
-        }
-        return NULL;
-    }
-    JSString *str = DirectProxyHandler::obj_toString(cx, wrapper);
-    return str;
-}
-
-JSString *
-Wrapper::fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent)
-{
-    bool status;
-    if (!enter(cx, wrapper, JSID_VOID, GET, &status)) {
-        if (status) {
-            // Perform some default behavior that doesn't leak any information.
-            if (wrapper->isCallable())
-                return JS_NewStringCopyZ(cx, "function () {\n    [native code]\n}");
-            ReportIsNotFunction(cx, ObjectValue(*wrapper));
-            return NULL;
-        }
-        return NULL;
-    }
-    JSString *str = DirectProxyHandler::fun_toString(cx, wrapper, indent);
-    return str;
-}
-
 Wrapper Wrapper::singleton((unsigned)0);
 Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
 
 /* Compartments. */
 
 extern JSObject *
 js::TransparentObjectWrapper(JSContext *cx, JSObject *existing, JSObject *objArg,
                              JSObject *wrappedProtoArg, JSObject *parentArg,
@@ -833,16 +639,17 @@ CrossCompartmentWrapper CrossCompartment
 
 /* Security wrappers. */
 
 template <class Base>
 SecurityWrapper<Base>::SecurityWrapper(unsigned flags)
   : Base(flags)
 {
     Base::setSafeToUnwrap(false);
+    BaseProxyHandler::setHasPolicy(true);
 }
 
 template <class Base>
 bool
 SecurityWrapper<Base>::enter(JSContext *cx, JSObject *wrapper, jsid id,
                              Wrapper::Action act, bool *bp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNWRAP_DENIED);
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -27,21 +27,17 @@ class DummyFrameGuard;
  * should be careful to avoid unwrapping security wrappers in the wrong context.
  */
 class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
 {
     unsigned mFlags;
     bool mSafeToUnwrap;
 
   public:
-    enum Action {
-        GET,
-        SET,
-        CALL
-    };
+    using BaseProxyHandler::Action;
 
     enum Flags {
         CROSS_COMPARTMENT = 1 << 0,
         LAST_USED_FLAG = CROSS_COMPARTMENT
     };
 
     /*
      * Wrappers can explicitly specify that they are unsafe to unwrap from a
@@ -60,64 +56,21 @@ class JS_FRIEND_API(Wrapper) : public Di
     static Wrapper *wrapperHandler(RawObject wrapper);
 
     static JSObject *wrappedObject(RawObject wrapper);
 
     unsigned flags() const {
         return mFlags;
     }
 
-    /* Policy enforcement traps.
-     *
-     * enter() allows the policy to specify whether the caller may perform |act|
-     * on the underlying object's |id| property. In the case when |act| is CALL,
-     * |id| is generally JSID_VOID.
-     *
-     * The |act| parameter to enter() specifies the action being performed.
-     */
-    virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act,
-                       bool *bp);
-
     explicit Wrapper(unsigned flags, bool hasPrototype = false);
 
     virtual ~Wrapper();
 
     /* ES5 Harmony fundamental wrapper traps. */
-    virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
-                                       jsid id, PropertyDescriptor *desc,
-                                       unsigned flags) MOZ_OVERRIDE;
-    virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper,
-                                          jsid id, PropertyDescriptor *desc,
-                                          unsigned flags) MOZ_OVERRIDE;
-    virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
-    virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper,
-                                     AutoIdVector &props) MOZ_OVERRIDE;
-    virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id,
-                         bool *bp) MOZ_OVERRIDE;
-    virtual bool enumerate(JSContext *cx, JSObject *wrapper,
-                           AutoIdVector &props) MOZ_OVERRIDE;
-
-    /* ES5 Harmony derived wrapper traps. */
-    virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
-    virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
-    virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) MOZ_OVERRIDE;
-    virtual bool set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict,
-                     Value *vp) MOZ_OVERRIDE;
-    virtual bool keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
-    virtual bool iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp) MOZ_OVERRIDE;
-
-    /* Spidermonkey extensions. */
-    virtual bool call(JSContext *cx, JSObject *wrapper, unsigned argc, Value *vp) MOZ_OVERRIDE;
-    virtual bool construct(JSContext *cx, JSObject *wrapper, unsigned argc, Value *argv, Value *rval) MOZ_OVERRIDE;
-    virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
-                            CallArgs args) MOZ_OVERRIDE;
-    virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v, bool *bp) MOZ_OVERRIDE;
-    virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
-    virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent) MOZ_OVERRIDE;
     virtual bool defaultValue(JSContext *cx, JSObject *wrapper_, JSType hint,
                               Value *vp) MOZ_OVERRIDE;
 
     static Wrapper singleton;
     static Wrapper singletonWithPrototype;
 
     static void *getWrapperFamily();
 };
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -935,17 +935,19 @@ js_InternalInterpret(void *returnData, v
        * Each of these cases indicates a point of progress through
        * generatePrologue. Execute the rest of the prologue here.
        */
       case REJOIN_CHECK_ARGUMENTS:
         if (!CheckStackQuota(f))
             return js_InternalThrow(f);
         fp->initVarsToUndefined();
         fp->scopeChain();
-        if (!fp->prologue(cx, types::UseNewTypeAtEntry(cx, fp)))
+        if (types::UseNewTypeAtEntry(cx, fp))
+            fp->setUseNewType();
+        if (!fp->prologue(cx))
             return js_InternalThrow(f);
 
         /*
          * We would normally call ScriptDebugPrologue here. But in debug mode,
          * we only use JITted functions' invokeEntry entry point, whereas
          * CheckArgumentTypes (REJOIN_CHECK_ARGUMENTS) is only reachable via
          * the other entry points.
          *
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -773,17 +773,17 @@ stubs::Interrupt(VMFrame &f, jsbytecode 
 
 #ifdef JS_ION
 void JS_FASTCALL
 stubs::TriggerIonCompile(VMFrame &f)
 {
     AssertCanGC();
     RootedScript script(f.cx, f.script());
 
-    if (ion::js_IonOptions.parallelCompilation) {
+    if (ion::js_IonOptions.parallelCompilation && !f.cx->runtime->profilingScripts) {
         if (script->hasIonScript()) {
             /*
              * Normally TriggerIonCompile is not called if !script->ion, but the
              * latter jump can be bypassed if DisableScriptCodeForIon wants this
              * code to be destroyed so that the Ion code can start running.
              */
             ExpandInlineFrames(f.cx->compartment);
             Recompiler::clearStackReferences(f.cx->runtime->defaultFreeOp(), script);
@@ -803,18 +803,17 @@ stubs::TriggerIonCompile(VMFrame &f)
         if (*osrPC != JSOP_LOOPENTRY)
             osrPC = NULL;
 
         ion::MethodStatus compileStatus;
         if (osrPC) {
             compileStatus = ion::CanEnterAtBranch(f.cx, script, f.cx->fp(), osrPC,
                                                   f.fp()->isConstructing());
         } else {
-            compileStatus = ion::CanEnter(f.cx, script, f.cx->fp(), f.fp()->isConstructing(),
-                                          /* newType = */ false);
+            compileStatus = ion::CanEnter(f.cx, script, f.cx->fp(), f.fp()->isConstructing());
         }
 
         if (compileStatus != ion::Method_Compiled) {
             if (f.cx->isExceptionPending())
                 THROW();
         }
 
         return;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3181,16 +3181,69 @@ DebuggerScript_getAllOffsets(JSContext *
         }
     }
 
     args.rval().setObject(*result);
     return true;
 }
 
 static JSBool
+DebuggerScript_getAllColumnOffsets(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getAllColumnOffsets", args, obj, script);
+
+    /*
+     * First pass: determine which offsets in this script are jump targets and
+     * which positions jump to them.
+     */
+    FlowGraphSummary flowData(cx);
+    if (!flowData.populate(cx, script))
+        return false;
+
+    /* Second pass: build the result array. */
+    RootedObject result(cx, NewDenseEmptyArray(cx));
+    if (!result)
+        return false;
+    for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
+        size_t lineno = r.frontLineNumber();
+        size_t column = r.frontColumnNumber();
+        size_t offset = r.frontOffset();
+
+        /* Make a note, if the current instruction is an entry point for the current position. */
+        if (!flowData[offset].hasNoEdges() &&
+            (flowData[offset].lineno() != lineno ||
+             flowData[offset].column() != column)) {
+            RootedObject entry(cx, NewBuiltinClassInstance(cx, &ObjectClass));
+            if (!entry)
+                return false;
+
+            RootedId id(cx, NameToId(cx->names().lineNumber));
+            RootedValue value(cx, NumberValue(lineno));
+            if (!JSObject::defineGeneric(cx, entry, id, value))
+                return false;
+
+            value = NumberValue(column);
+            if (!JSObject::defineProperty(cx, entry, cx->names().columnNumber, value))
+                return false;
+
+            id = NameToId(cx->names().offset);
+            value = NumberValue(offset);
+            if (!JSObject::defineGeneric(cx, entry, id, value))
+                return false;
+
+            if (!js_NewbornArrayPush(cx, result, ObjectValue(*entry)))
+                return false;
+        }
+    }
+
+    args.rval().setObject(*result);
+    return true;
+}
+
+static JSBool
 DebuggerScript_getLineOffsets(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getLineOffsets", args, obj, script);
     REQUIRE_ARGC("Debugger.Script.getLineOffsets", 1);
 
     /* Parse lineno argument. */
     size_t lineno;
     bool ok = false;
@@ -3351,16 +3404,17 @@ static JSPropertySpec DebuggerScript_pro
     JS_PSG("staticLevel", DebuggerScript_getStaticLevel, 0),
     JS_PSG("sourceMapURL", DebuggerScript_getSourceMapUrl, 0),
     JS_PS_END
 };
 
 static JSFunctionSpec DebuggerScript_methods[] = {
     JS_FN("getChildScripts", DebuggerScript_getChildScripts, 0, 0),
     JS_FN("getAllOffsets", DebuggerScript_getAllOffsets, 0, 0),
+    JS_FN("getAllColumnOffsets", DebuggerScript_getAllColumnOffsets, 0, 0),
     JS_FN("getLineOffsets", DebuggerScript_getLineOffsets, 1, 0),
     JS_FN("getOffsetLine", DebuggerScript_getOffsetLine, 0, 0),
     JS_FN("setBreakpoint", DebuggerScript_setBreakpoint, 2, 0),
     JS_FN("getBreakpoints", DebuggerScript_getBreakpoints, 1, 0),
     JS_FN("clearBreakpoint", DebuggerScript_clearBreakpoint, 1, 0),
     JS_FN("clearAllBreakpoints", DebuggerScript_clearAllBreakpoints, 0, 0),
     JS_FS_END
 };
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -733,16 +733,23 @@ inline bool
 AbstractFramePtr::hasCallObj() const
 {
     if (isStackFrame())
         return asStackFrame()->hasCallObj();
     JS_NOT_REACHED("Invalid frame");
     return false;
 }
 inline bool
+AbstractFramePtr::useNewType() const
+{
+    if (isStackFrame())
+        return asStackFrame()->useNewType();
+    return false;
+}
+inline bool
 AbstractFramePtr::isGeneratorFrame() const
 {
     if (isStackFrame())
         return asStackFrame()->isGeneratorFrame();
     return false;
 }
 inline bool
 AbstractFramePtr::isYielding() const
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -302,17 +302,17 @@ StackFrame::initFunctionScopeObjects(JSC
     if (!callobj)
         return false;
     pushOnScopeChain(*callobj);
     flags_ |= HAS_CALL_OBJ;
     return true;
 }
 
 bool
-StackFrame::prologue(JSContext *cx, bool newType)
+StackFrame::prologue(JSContext *cx)
 {
     RootedScript script(cx, this->script());
 
     JS_ASSERT(!isGeneratorFrame());
     JS_ASSERT(cx->regs().pc == script->code);
 
     if (isEvalFrame()) {
         if (script->strict) {
@@ -334,17 +334,17 @@ StackFrame::prologue(JSContext *cx, bool
     JS_ASSERT(isNonEvalFunctionFrame());
     AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
 
     if (fun()->isHeavyweight() && !initFunctionScopeObjects(cx))
         return false;
 
     if (isConstructing()) {
         RootedObject callee(cx, &this->callee());
-        JSObject *obj = CreateThisForFunction(cx, callee, newType);
+        JSObject *obj = CreateThisForFunction(cx, callee, useNewType());
         if (!obj)
             return false;
         functionThis() = ObjectValue(*obj);
     }
 
     Probes::enterScript(cx, script, script->function(), this);
     return true;
 }
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -292,16 +292,17 @@ class AbstractFramePtr
     inline unsigned numFormalArgs() const;
 
     inline Value *formals() const;
     inline Value *actuals() const;
 
     inline bool hasArgsObj() const;
     inline ArgumentsObject &argsObj() const;
     inline void initArgsObj(ArgumentsObject &argsobj) const;
+    inline bool useNewType() const;
 
     inline bool copyRawFrameSlots(AutoValueVector *vec) const;
 
     inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
 
@@ -384,20 +385,23 @@ class StackFrame
 
         /* Debugger state */
         PREV_UP_TO_DATE    =    0x80000,  /* see DebugScopes::updateLiveScopes */
 
         /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
         HAS_PUSHED_SPS_FRAME = 0x100000,  /* SPS was notified of enty */
 
         /* Ion frame state */
-        RUNNING_IN_ION       = 0x200000,  /* frame is running in Ion */
-        CALLING_INTO_ION     = 0x400000,  /* frame is calling into Ion */
+        RUNNING_IN_ION     =   0x200000,  /* frame is running in Ion */
+        CALLING_INTO_ION   =   0x400000,  /* frame is calling into Ion */
 
-        JIT_REVISED_STACK    = 0x800000   /* sp was revised by JIT for lowered apply */
+        JIT_REVISED_STACK  =   0x800000,  /* sp was revised by JIT for lowered apply */
+
+        /* Miscellaneous state. */
+        USE_NEW_TYPE       =  0x1000000   /* Use new type for constructed |this| object. */
     };
 
   private:
     mutable uint32_t    flags_;         /* bits described by Flags */
     union {                             /* describes what code is executing in a */
         RawScript       script;         /*   global frame */
         JSFunction      *fun;           /*   function frame, pre GetScopeChain */
     } exec;
@@ -484,22 +488,19 @@ class StackFrame
      * frame but do *not* call the prologue/epilogue. That means Interpret
      * must call the prologue/epilogue for the entry frame. This scheme
      * simplifies jit compilation.
      *
      * An important corner case is what happens when an error occurs (OOM,
      * over-recursed) after pushing the stack frame but before 'prologue' is
      * called or completes fully. To simplify usage, 'epilogue' does not assume
      * 'prologue' has completed and handles all the intermediate state details.
-     *
-     * The 'newType' option indicates whether the constructed 'this' value (if
-     * there is one) should be given a new singleton type.
      */
 
-    bool prologue(JSContext *cx, bool newType);
+    bool prologue(JSContext *cx);
     void epilogue(JSContext *cx);
 
     /* Subsets of 'prologue' called from jit code. */
     inline bool jitHeavyweightFunctionPrologue(JSContext *cx);
     bool jitStrictEvalPrologue(JSContext *cx);
 
     /* Called from IonMonkey to transition from bailouts. */
     void initFromBailout(JSContext *cx, ion::SnapshotIterator &iter);
@@ -1047,16 +1048,25 @@ class StackFrame
         return flags_ & HAS_CALL_OBJ;
     }
 
     bool hasArgsObj() const {
         JS_ASSERT(script()->needsArgsObj());
         return flags_ & HAS_ARGS_OBJ;
     }
 
+    void setUseNewType() {
+        JS_ASSERT(isConstructing());
+        flags_ |= USE_NEW_TYPE;
+    }
+    bool useNewType() const {
+        JS_ASSERT(isConstructing());
+        return flags_ & USE_NEW_TYPE;
+    }
+
     /*
      * The method JIT call/apply optimization can erase Function.{call,apply}
      * invocations from the stack and push the callee frame directly. The base
      * of these frames will be offset by one value, however, which the
      * interpreter needs to account for if it ends up popping the frame.
      */
     bool loweredCallOrApply() const {
         return !!(flags_ & LOWERED_CALL_APPLY);
--- a/js/xpconnect/tests/chrome/test_bug760109.xul
+++ b/js/xpconnect/tests/chrome/test_bug760109.xul
@@ -26,22 +26,23 @@ https://bugzilla.mozilla.org/show_bug.cg
     // Check that COWs for objects with standard prototypes use the standard
     // prototype in the home compartment.
     ok(Object.getPrototypeOf(chromeArray) === Array.prototype,
        "Array prototype remapped properly");
     var protoProto = Object.getPrototypeOf(Object.getPrototypeOf(chromeObject));
     ok(protoProto === Object.prototype,
        "Object prototype remapped properly");
 
-    // Check |constructor|. The semantics of this weird for the case of an
-    // object with a custom chrome-implemented prototype, because we'll end up
-    // bouncing up the prototype chain to Object, even though that's not fully
-    // accurate. It's unlikely to be a problem though, so we just verify that
-    // it does what we expect.
-    ok(chromeObject.constructor === Object, "Object constructor does what we expect");
+    // Check |constructor|.
+    // Note that the 'constructor' property of the underlying chrome object
+    // will be resolved on SomeConstructor.prototype, which has an empty
+    // __exposedProps__. This means that we shouldn't remap the property, even
+    // though we'd also be able to find it on Object.prototype. Some recent
+    // refactoring has made it possible to do the right thing here.
+    is(typeof chromeObject.constructor, "undefined", "Object constructor does what we expect");
     ok(chromeArray.constructor === Array, "Array constructor remapped properly");
 
     // We should be able to .forEach on the Array.
     var concat = '';
     chromeArray.forEach(function(val) { concat += val; });
     is(concat, 'abz', "Should be able to .forEach COW-ed Array");
 
     // Try other Array operations.
--- a/js/xpconnect/tests/mochitest/Makefile.in
+++ b/js/xpconnect/tests/mochitest/Makefile.in
@@ -38,17 +38,16 @@ MOCHITEST_FILES =	chrome_wrappers_helper
 		test_bug500691.html \
 		bug500931_helper.html \
 		test_bug502959.html \
 		test_bug503926.html \
 		test_bug504877.html \
 		bug504877_helper.html \
 		test_bug505915.html \
 		file_bug505915.html \
-		test_bug553407.html \
 		test_bug560351.html \
 		bug571849_helper.html \
 		test_bug585745.html \
 		test_bug589028.html \
 		bug589028_helper.html \
 		test_bug601299.html \
 		test_bug605167.html \
 		test_bug618017.html \
--- a/js/xpconnect/tests/mochitest/test_bug478438.html
+++ b/js/xpconnect/tests/mochitest/test_bug478438.html
@@ -12,17 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     function pass(s, e) { ok(true, s) }
     (pass.opposite = fail).opposite = pass;
 
     function test() {
       if (test.calledAlready)
         return;
       test.calledAlready = true;
 
-      var iwin = (new XPCNativeWrapper(document)).getElementById("f").contentWindow;
+      var iwin = document.getElementById("f").contentWindow;
 
       function testOne(fn, onAllow, infinitive) {
         try { fn(); onAllow("able " + infinitive, "") }
         catch (e) { onAllow.opposite("unable " + infinitive, ": " + e) }
       }
 
       testOne(function() iwin.focus, pass,
               "to resolve/get allAccess property iwin.focus");
deleted file mode 100644
--- a/js/xpconnect/tests/mochitest/test_bug553407.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=517163
--->
-<head>
-  <title>Test for Bug 553407</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=553407">Mozilla Bug 553407</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 553407 **/
-is(typeof new XPCNativeWrapper(location), "object", "XPCNativeWrapper(location) is an object")
-is(typeof new XPCNativeWrapper(XMLHttpRequest), "function", "XPCNativeWrapper(XMLHttpRequest) is a function")
-// We no longer support .wrappedJSObject on NW since for same-origin there is no wrapper in between.
-// is(typeof new XPCNativeWrapper(location).wrappedJSObject, "object", "XPCNativeWrapper(location).wrappedJSObject is an object")
-// is(typeof new XPCNativeWrapper(XMLHttpRequest).wrappedJSObject, "function", "XPCNativeWrapper(XMLHttpRequest).wrappedJSObject is a function")
-ok("a".replace("a", new XPCNativeWrapper(location)).indexOf("mochi.test") >= 0, "XPCNativeWrappers can be used as the replacement value for .replace");
-
-</script>
-</pre>
-</body>
-</html>
--- a/js/xpconnect/tests/mochitest/test_bug785096.html
+++ b/js/xpconnect/tests/mochitest/test_bug785096.html
@@ -19,20 +19,20 @@ SimpleTest.waitForExplicitFinish();
 
 function test()
 {
   var sel = document.createElementNS('http://www.w3.org/1999/xhtml', 'select');
   var option=document.createElement("option");
   option.text="Fubar";
   sel.options.add(option);
   try {
-    Components.lookupMethod(sel.options, "add")(option);
+    SpecialPowers.Components.lookupMethod(sel.options, "add")(option);
     ok(true, "function call should not throw")
   } catch(e) {
-    do_throw("this call should just work without any exceptions");
+    ok(false, "this call should just work without any exceptions");
   }
   SimpleTest.finish();
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/js/xpconnect/tests/unit/test_bug780370.js
+++ b/js/xpconnect/tests/unit/test_bug780370.js
@@ -11,10 +11,13 @@ const Cu = Components.utils;
 
 function run_test()
 {
   var sb = Cu.Sandbox("http://www.example.com");
   sb.obj = { foo: 42, __exposedProps__: { hasOwnProperty: 'r' } };
   do_check_eq(Cu.evalInSandbox('typeof obj.foo', sb), 'undefined', "COW works as expected");
   do_check_true(Cu.evalInSandbox('obj.hasOwnProperty === Object.prototype.hasOwnProperty', sb),
                 "Remapping happens even when the property is explicitly exposed");
-  do_check_eq(Cu.evalInSandbox('Object.prototype.bar = 10; obj.bar', sb), 10);
+  // NB: We used to test for the following, but such behavior became very
+  // difficult to implement in a recent refactor. We're moving away from this
+  // API anyway, so we decided to explicitly drop support for this.
+  // do_check_eq(Cu.evalInSandbox('Object.prototype.bar = 10; obj.bar', sb), 10);
 }
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -262,34 +262,16 @@ AccessCheck::isScriptAccessOnly(JSContex
         if (flags & WrapperFactory::SOW_FLAG)
             return !isSystemOnlyAccessPermitted(cx);
         return true;
     }
 
     return false;
 }
 
-void
-AccessCheck::deny(JSContext *cx, jsid id)
-{
-    if (id == JSID_VOID) {
-        JS_ReportError(cx, "Permission denied to access object");
-    } else {
-        jsval idval;
-        if (!JS_IdToValue(cx, id, &idval))
-            return;
-        JSString *str = JS_ValueToString(cx, idval);
-        if (!str)
-            return;
-        const jschar *chars = JS_GetStringCharsZ(cx, str);
-        if (chars)
-            JS_ReportError(cx, "Permission denied to access property '%hs'", chars);
-    }
-}
-
 enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 };
 
 static bool
 IsInSandbox(JSContext *cx, JSObject *obj)
 {
     JSAutoCompartment ac(cx, obj);
     JSObject *global = JS_GetGlobalForObject(cx, obj);
     return !strcmp(js::GetObjectJSClass(global)->name, "Sandbox");
--- a/js/xpconnect/wrappers/AccessCheck.h
+++ b/js/xpconnect/wrappers/AccessCheck.h
@@ -28,94 +28,84 @@ class AccessCheck {
     static nsIPrincipal *getPrincipal(JSCompartment *compartment);
     static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id,
                                              js::Wrapper::Action act);
     static bool isSystemOnlyAccessPermitted(JSContext *cx);
 
     static bool needsSystemOnlyWrapper(JSObject *obj);
 
     static bool isScriptAccessOnly(JSContext *cx, JSObject *wrapper);
-
-    static void deny(JSContext *cx, jsid id);
 };
 
 struct Policy {
 };
 
 // This policy only allows calling the underlying callable. All other operations throw.
 struct Opaque : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
         return act == js::Wrapper::CALL;
     }
-    static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
-        AccessCheck::deny(cx, id);
+    static bool deny(js::Wrapper::Action act) {
         return false;
     }
     static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl)
     {
         return false;
     }
 };
 
 // This policy only permits access to the object if the subject can touch
 // system objects.
 struct OnlyIfSubjectIsSystem : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
         return AccessCheck::isSystemOnlyAccessPermitted(cx);
     }
 
-    static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
-        AccessCheck::deny(cx, id);
+    static bool deny(js::Wrapper::Action act) {
         return false;
     }
 
     static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl)
     {
         return AccessCheck::isSystemOnlyAccessPermitted(cx);
     }
 };
 
 // This policy only permits access to properties that are safe to be used
 // across origins.
 struct CrossOriginAccessiblePropertiesOnly : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
         return AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act);
     }
-    static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
-        AccessCheck::deny(cx, id);
+    static bool deny(js::Wrapper::Action act) {
         return false;
     }
     static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl)
     {
         return false;
     }
 };
 
 // This policy only permits access to properties if they appear in the
 // objects exposed properties list.
 struct ExposedPropertiesOnly : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act);
 
-    static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
-        // For gets, silently fail.
-        if (act == js::Wrapper::GET)
-            return true;
-        // For sets,throw an exception.
-        AccessCheck::deny(cx, id);
-        return false;
+    static bool deny(js::Wrapper::Action act) {
+        // Fail silently for GETs.
+        return act == js::Wrapper::GET;
     }
     static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl);
 };
 
 // Components specific policy
 struct ComponentsObjectPolicy : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act);
 
-    static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
-        AccessCheck::deny(cx, id);
+    static bool deny(js::Wrapper::Action act) {
         return false;
     }
     static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl) {
         return false;
     }
 };
 
 }
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -9,35 +9,67 @@ namespace xpc {
 // from the wrappee's scope.
 //
 // One of the reasons for doing this is to allow standard operations like
 // chromeArray.forEach(..) to Just Work without explicitly listing them in
 // __exposedProps__. Since proxies don't automatically inherit behavior from
 // their prototype, we have to instrument the traps to do this manually.
 ChromeObjectWrapper ChromeObjectWrapper::singleton;
 
+using js::assertEnteredPolicy;
+
+static bool
+AllowedByBase(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act)
+{
+    MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
+               &ChromeObjectWrapper::singleton);
+    bool bp;
+    ChromeObjectWrapper *handler = &ChromeObjectWrapper::singleton;
+    return handler->ChromeObjectWrapperBase::enter(cx, wrapper, id, act, &bp);
+}
+
 static bool
 PropIsFromStandardPrototype(JSContext *cx, JSPropertyDescriptor *desc)
 {
     MOZ_ASSERT(desc->obj);
     JSObject *unwrapped = js::UnwrapObject(desc->obj);
     JSAutoCompartment ac(cx, unwrapped);
     return JS_IdentifyClassPrototype(cx, unwrapped) != JSProto_Null;
 }
 
+// Note that we're past the policy enforcement stage, here, so we can query
+// ChromeObjectWrapperBase and get an unfiltered view of the underlying object.
+// This lets us determine whether the property we would have found (given a
+// transparent wrapper) would have come off a standard prototype.
+static bool
+PropIsFromStandardPrototype(JSContext *cx, JSObject *wrapper, jsid id)
+{
+    MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
+               &ChromeObjectWrapper::singleton);
+    JSPropertyDescriptor desc;
+    ChromeObjectWrapper *handler = &ChromeObjectWrapper::singleton;
+    if (!handler->ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
+                                                                 &desc, 0) ||
+        !desc.obj)
+    {
+        return false;
+    }
+    return PropIsFromStandardPrototype(cx, &desc);
+}
+
 bool
 ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
                                            jsid id, js::PropertyDescriptor *desc,
                                            unsigned flags)
 {
-    // First, try the lookup on the base wrapper. This can throw for various
-    // reasons, including sets (gets fail silently). There's nothing we can really
-    // do for sets, so we can conveniently propagate any exception we hit here.
+    assertEnteredPolicy(cx, wrapper, id);
+    // First, try a lookup on the base wrapper if permitted.
     desc->obj = NULL;
-    if (!ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
+    if (AllowedByBase(cx, wrapper, id, Wrapper::GET) &&
+        !ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
                                                         desc, flags)) {
         return false;
     }
 
     // If the property is something that can be found on a standard prototype,
     // prefer the one we'll get via the prototype chain in the content
     // compartment.
     if (desc->obj && PropIsFromStandardPrototype(cx, desc))
@@ -53,19 +85,23 @@ ChromeObjectWrapper::getPropertyDescript
     // If not, try doing the lookup on the prototype.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
     return JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc);
 }
 
 bool
 ChromeObjectWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
-    // Try the lookup on the base wrapper.
-    if (!ChromeObjectWrapperBase::has(cx, wrapper, id, bp))
+    assertEnteredPolicy(cx, wrapper, id);
+    // Try the lookup on the base wrapper if permitted.
+    if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) &&
+        !ChromeObjectWrapperBase::has(cx, wrapper, id, bp))
+    {
         return false;
+    }
 
     // If we found something or have no prototype, we're done.
     JSObject *wrapperProto;
     if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
         return false;
     if (*bp || !wrapperProto)
         return true;
 
@@ -77,29 +113,25 @@ ChromeObjectWrapper::has(JSContext *cx, 
     *bp = !!desc.obj;
     return true;
 }
 
 bool
 ChromeObjectWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver,
                          jsid id, js::Value *vp)
 {
-    // Start with a call to getPropertyDescriptor. We unfortunately need to do
-    // this because the call signature of ::get doesn't give us any way to
-    // determine the object upon which the property was found.
+    assertEnteredPolicy(cx, wrapper, id);
+    vp->setUndefined();
     JSPropertyDescriptor desc;
-    if (!ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id, &desc,
-                                                        0)) {
-        return false;
-    }
-
-    // Only call through to the get trap on the underlying object if we'll find
-    // something, and if what we'll find is not on a standard prototype.
-    vp->setUndefined();
-    if (desc.obj && !PropIsFromStandardPrototype(cx, &desc)) {
+    // Only call through to the get trap on the underlying object if we're
+    // allowed to see the property, and if what we'll find is not on a standard
+    // prototype.
+    if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) &&
+        !PropIsFromStandardPrototype(cx, wrapper, id))
+    {
         // Call the get trap.
         if (!ChromeObjectWrapperBase::get(cx, wrapper, receiver, id, vp))
             return false;
         // If we found something, we're done.
         if (!vp->isUndefined())
             return true;
     }
 
@@ -110,9 +142,31 @@ ChromeObjectWrapper::get(JSContext *cx, 
     if (!wrapperProto)
         return true;
 
     // Try the prototype.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
     return js::GetGeneric(cx, wrapperProto, receiver, id, vp);
 }
 
+// This mechanism isn't ideal because we end up calling enter() on the base class
+// twice (once during enter() here and once during the trap itself), and policy
+// enforcement or COWs isn't cheap. But it results in the cleanest code, and this
+// whole proto remapping thing for COWs is going to be phased out anyway.
+bool
+ChromeObjectWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id,
+                           js::Wrapper::Action act, bool *bp)
+{
+    if (AllowedByBase(cx, wrapper, id, act))
+        return true;
+    // COWs fail silently for GETs, and that also happens to be the only case
+    // where we might want to redirect the lookup to the home prototype chain.
+    *bp = (act == Wrapper::GET);
+    if (!*bp || id == JSID_VOID)
+        return false;
+
+    // Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor
+    // before we've fully entered the policy. Waive our policy.
+    js::AutoWaivePolicy policy(cx, wrapper, id);
+    return PropIsFromStandardPrototype(cx, wrapper, id);
 }
+
+}
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.h
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.h
@@ -32,16 +32,19 @@ class ChromeObjectWrapper : public Chrom
     virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
                                        jsid id, js::PropertyDescriptor *desc,
                                        unsigned flags) MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, JSObject *wrapper, jsid id,
                      bool *bp) MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver,
                      jsid id, js::Value *vp) MOZ_OVERRIDE;
 
+    virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id,
+                       js::Wrapper::Action act, bool *bp) MOZ_OVERRIDE;
+
     // NB: One might think we'd need to implement enumerate(), keys(), iterate(),
     // and getPropertyNames() here. However, ES5 built-in properties aren't
     // enumerable (and SpiderMonkey's implementation seems to match the spec
     // modulo Error.prototype.fileName and Error.prototype.lineNumber). Since
     // we're only remapping the prototypes of standard objects, there would
     // never be anything more to enumerate up the prototype chain. So we can
     // atually skip these.
 
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -58,60 +58,66 @@ FilterSetter(JSContext *cx, JSObject *wr
     return true;
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                                       js::PropertyDescriptor *desc, unsigned flags)
 {
+    assertEnteredPolicy(cx, wrapper, id);
     if (!Base::getPropertyDescriptor(cx, wrapper, id, desc, flags))
         return false;
     return FilterSetter<Policy>(cx, wrapper, id, desc);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                                          js::PropertyDescriptor *desc,
                                                          unsigned flags)
 {
+    assertEnteredPolicy(cx, wrapper, id);
     if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags))
         return false;
     return FilterSetter<Policy>(cx, wrapper, id, desc);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     return Base::getOwnPropertyNames(cx, wrapper, props) &&
            Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     return Base::enumerate(cx, wrapper, props) &&
            Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     return Base::keys(cx, wrapper, props) &&
            Filter<Policy>(cx, wrapper, props);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::iterate(JSContext *cx, JSObject *wrapper, unsigned flags, Value *vp)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     // We refuse to trigger the iterator hook across chrome wrappers because
     // we don't know how to censor custom iterator objects. Instead we trigger
     // the default proxy iterate trap, which will ask enumerate() for the list
     // of (censored) ids.
     return js::BaseProxyHandler::iterate(cx, wrapper, flags, vp);
 }
 
 template <typename Base, typename Policy>
@@ -124,23 +130,34 @@ FilteringWrapper<Base, Policy>::nativeCa
     return Base::Restrictive::nativeCall(cx, test, impl, args);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::enter(JSContext *cx, JSObject *wrapper, jsid id,
                                       Wrapper::Action act, bool *bp)
 {
+    // This is a super ugly hacky to get around Xray Resolve wonkiness.
+    //
+    // Basically, XPCWN Xrays sometimes call into the Resolve hook of the
+    // scriptable helper, and pass the wrapper itself as the object upon which
+    // the resolve is happening. Then, special handling happens in
+    // XrayWrapper::defineProperty to detect the resolve and redefine the
+    // property on the holder. Really, we should just pass the holder itself to
+    // NewResolve, but there's too much code in nsDOMClassInfo that assumes this
+    // isn't the case (in particular, code expects to be able to look up
+    // properties on the object, which doesn't work for the holder). Given that
+    // these hooks are going away eventually with the new DOM bindings, let's
+    // just hack around this for now.
+    if (XrayUtils::IsXrayResolving(cx, wrapper, id)) {
+        *bp = true;
+        return true;
+    }
     if (!Policy::check(cx, wrapper, id, act)) {
-        if (JS_IsExceptionPending(cx)) {
-            *bp = false;
-            return false;
-        }
-        JSAutoCompartment ac(cx, wrapper);
-        *bp = Policy::deny(cx, id, act);
+        *bp = JS_IsExceptionPending(cx) ? false : Policy::deny(act);
         return false;
     }
     *bp = true;
     return true;
 }
 
 #define SOW FilteringWrapper<CrossCompartmentSecurityWrapper, OnlyIfSubjectIsSystem>
 #define SCSOW FilteringWrapper<SameCompartmentSecurityWrapper, OnlyIfSubjectIsSystem>
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -721,18 +721,17 @@ XPCWrappedNativeXrayTraits::preserveWrap
 
 bool
 XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext *cx, JSObject *wrapper,
                                                   JSObject *holder, jsid id,
                                                   JSPropertyDescriptor *desc, unsigned flags)
 {
     MOZ_ASSERT(js::GetObjectJSClass(holder) == &HolderClass);
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
-    if (!(flags & JSRESOLVE_ASSIGNING) &&
-        id == rt->GetStringID(XPCJSRuntime::IDX_MOZMATCHESSELECTOR) &&
+    if (id == rt->GetStringID(XPCJSRuntime::IDX_MOZMATCHESSELECTOR) &&
         Is<nsIDOMElement>(wrapper))
     {
         // XPC calling mechanism cannot handle call/bind properly in some cases
         // especially through xray wrappers. This is a temporary work around for
         // this problem for mozMatchesSelector. See: bug 763897.
         desc->obj = wrapper;
         desc->attrs = JSPROP_ENUMERATE;
         JSObject *proto;
@@ -979,23 +978,18 @@ XPCWrappedNativeXrayTraits::resolveOwnPr
     // in the wrapper's compartment here, not the wrappee.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     if (AccessCheck::isChrome(wrapper) &&
         (((id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT) ||
            id == rt->GetStringID(XPCJSRuntime::IDX_NODEPRINCIPAL)) &&
           Is<nsINode>(wrapper)) ||
           (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT) &&
-          Is<nsIDocument>(wrapper)))) {
-        bool status;
-        Wrapper::Action action = (flags & JSRESOLVE_ASSIGNING) ? Wrapper::SET : Wrapper::GET;
-        desc->obj = NULL; // default value
-        if (!jsWrapper.enter(cx, wrapper, id, action, &status))
-            return status;
-
+          Is<nsIDocument>(wrapper))))
+    {
         desc->obj = wrapper;
         desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED;
         if (id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT))
             desc->getter = baseURIObject_getter;
         else if (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT))
             desc->getter = documentURIObject_getter;
         else
             desc->getter = nodePrincipal_getter;
@@ -1314,16 +1308,29 @@ GetNativePropertiesObject(JSContext *cx,
     NS_ASSERTION(js::IsWrapper(wrapper) && WrapperFactory::IsXrayWrapper(wrapper),
                  "bad object passed in");
 
     JSObject *holder = GetHolder(wrapper);
     NS_ASSERTION(holder, "uninitialized wrapper being used?");
     return holder;
 }
 
+bool
+IsXrayResolving(JSContext *cx, JSObject *wrapper, jsid id)
+{
+    if (!WrapperFactory::IsXrayWrapper(wrapper) ||
+        GetXrayType(wrapper) != XrayForWrappedNative)
+    {
+        return false;
+    }
+    JSObject *holder =
+      XPCWrappedNativeXrayTraits::singleton.ensureHolder(cx, wrapper);
+    return XPCWrappedNativeXrayTraits::isResolving(cx, holder, id);
+}
+
 }
 
 static JSBool
 XrayToString(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *wrapper = JS_THIS_OBJECT(cx, vp);
     if (!wrapper)
         return false;
@@ -1398,28 +1405,23 @@ DEBUG_CheckXBLLookup(JSContext *cx, JSPr
 #define DEBUG_CheckXBLLookup(a, b) {}
 #endif
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                                  js::PropertyDescriptor *desc, unsigned flags)
 {
+    assertEnteredPolicy(cx, wrapper, id);
     JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper);
     if (Traits::isResolving(cx, holder, id)) {
         desc->obj = NULL;
         return true;
     }
 
-    bool status;
-    Wrapper::Action action = (flags & JSRESOLVE_ASSIGNING) ? Wrapper::SET : Wrapper::GET;
-    desc->obj = NULL; // default value
-    if (!this->enter(cx, wrapper, id, action, &status))
-        return status;
-
     typename Traits::ResolvingIdImpl resolving(wrapper, id);
 
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper, id)) {
         JSObject *obj = Traits::getTargetObject(wrapper);
         {
             JSAutoCompartment ac(cx, obj);
             if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
@@ -1435,22 +1437,16 @@ XrayWrapper<Base, Traits>::getPropertyDe
         return false;
 
     // Only chrome wrappers and same-origin xrays (used by jetpack sandboxes)
     // get .wrappedJSObject. We can check this by determining if the compartment
     // of the wrapper subsumes that of the wrappee.
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     if (AccessCheck::wrapperSubsumes(wrapper) &&
         id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
-        bool status;
-        Wrapper::Action action = (flags & JSRESOLVE_ASSIGNING) ? Wrapper::SET : Wrapper::GET;
-        desc->obj = NULL; // default value
-        if (!this->enter(cx, wrapper, id, action, &status))
-            return status;
-
         desc->obj = wrapper;
         desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED;
         desc->getter = wrappedJSObject_getter;
         desc->setter = NULL;
         desc->shortid = 0;
         desc->value = JSVAL_VOID;
         return true;
     }
@@ -1528,28 +1524,23 @@ XrayWrapper<Base, Traits>::getPropertyDe
     return true;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                                     PropertyDescriptor *desc, unsigned flags)
 {
+    assertEnteredPolicy(cx, wrapper, id);
     JSObject *holder = Traits::singleton.ensureHolder(cx, wrapper);
     if (Traits::isResolving(cx, holder, id)) {
         desc->obj = NULL;
         return true;
     }
 
-    bool status;
-    Wrapper::Action action = (flags & JSRESOLVE_ASSIGNING) ? Wrapper::SET : Wrapper::GET;
-    desc->obj = NULL; // default value
-    if (!this->enter(cx, wrapper, id, action, &status))
-        return status;
-
     typename Traits::ResolvingIdImpl resolving(wrapper, id);
 
     // NB: Nothing we do here acts on the wrapped native itself, so we don't
     // enter our policy.
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper, id)) {
         JSObject *obj = Traits::getTargetObject(wrapper);
         {
@@ -1580,27 +1571,30 @@ XrayWrapper<Base, Traits>::getOwnPropert
     return true;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
                                           js::PropertyDescriptor *desc)
 {
+    assertEnteredPolicy(cx, wrapper, id);
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper, id)) {
         JSObject *obj = Traits::getTargetObject(wrapper);
         JSAutoCompartment ac(cx, obj);
         if (!JS_WrapPropertyDescriptor(cx, desc))
             return false;
 
         return JS_DefinePropertyById(cx, obj, id, desc->value, desc->getter, desc->setter,
                                      desc->attrs);
     }
 
+    // NB: We still need JSRESOLVE_ASSIGNING here for the time being, because it
+    // tells things like nodelists whether they should create the property or not.
     PropertyDescriptor existing_desc;
     if (!getOwnPropertyDescriptor(cx, wrapper, id, &existing_desc, JSRESOLVE_ASSIGNING))
         return false;
 
     if (existing_desc.obj && (existing_desc.attrs & JSPROP_PERMANENT))
         return true; // silently ignore attempt to overwrite native property
 
     bool defined = false;
@@ -1630,23 +1624,25 @@ XrayWrapper<Base, Traits>::definePropert
                                  wrappedDesc.attrs);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper,
                                                JS::AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
+    assertEnteredPolicy(cx, wrapper, id);
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper, id)) {
         JSObject *obj = Traits::getTargetObject(wrapper);
 
         JSAutoCompartment ac(cx, obj);
 
         JSBool b;
         jsval v;
@@ -1673,16 +1669,17 @@ XrayWrapper<Base, Traits>::delete_(JSCon
     return true;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::enumerate(JSContext *cx, JSObject *wrapper, unsigned flags,
                                      JS::AutoIdVector &props)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper, JSID_VOID)) {
         JSObject *obj = Traits::getTargetObject(wrapper);
         JSAutoCompartment ac(cx, obj);
         return js::GetPropertyNames(cx, obj, flags, &props);
     }
 
     if (!AccessCheck::wrapperSubsumes(wrapper)) {
@@ -1766,24 +1763,26 @@ XrayWrapper<Base, Traits>::iterate(JSCon
     // Skip our Base if it isn't already ProxyHandler.
     return BaseProxyHandler::iterate(cx, wrapper, flags, vp);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::call(JSContext *cx, JSObject *wrapper, unsigned argc, js::Value *vp)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     return Traits::call(cx, wrapper, argc, vp);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::construct(JSContext *cx, JSObject *wrapper, unsigned argc,
                                      js::Value *argv, js::Value *rval)
 {
+    assertEnteredPolicy(cx, wrapper, JSID_VOID);
     return Traits::construct(cx, wrapper, argc, argv, rval);
 }
 
 /*
  * The Permissive / Security variants should be used depending on whether the
  * compartment of the wrapper is guranteed to subsume the compartment of the
  * wrapped object (i.e. - whether it is safe from a security perspective to
  * unwrap the wrapper).
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -33,16 +33,19 @@ extern JSClass HolderClass;
 bool CloneExpandoChain(JSContext *cx, JSObject *src, JSObject *dst);
 
 bool
 IsTransparent(JSContext *cx, JSObject *wrapper, jsid id);
 
 JSObject *
 GetNativePropertiesObject(JSContext *cx, JSObject *wrapper);
 
+bool
+IsXrayResolving(JSContext *cx, JSObject *wrapper, jsid id);
+
 }
 
 class XrayTraits;
 class XPCWrappedNativeXrayTraits;
 class ProxyXrayTraits;
 class DOMXrayTraits;
 
 
--- a/layout/inspector/tests/test_bug462787.html
+++ b/layout/inspector/tests/test_bug462787.html
@@ -18,17 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script type="application/javascript">
 
 /** Test for Bug 462787 **/
 
 function do_test() {
   const INVALID_POINTER = 0x80004003;
 
   var utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
-                             .getService(Components.interfaces.inIDOMUtils);
+                             .getService(SpecialPowers.Ci.inIDOMUtils);
   try {
     utils.getCSSStyleRules(null); 
     ok(false, "expected an exception"); 
   }
   catch(e) { is(e.result, INVALID_POINTER, "got the expected exception"); }
 
   try {
     utils.getRuleLine(null); 
--- a/layout/inspector/tests/test_bug806192.html
+++ b/layout/inspector/tests/test_bug806192.html
@@ -8,17 +8,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
 
 const utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
-.getService(Components.interfaces.inIDOMUtils);
+.getService(SpecialPowers.Ci.inIDOMUtils);
 
 try {
     var res = utils.getBindingURLs({});
     ok(false, "didn't get error");
 }
 catch(e) { ok(true, "got expected exception"); }
 </script>
 </pre>
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -564,16 +564,21 @@ public:
     }
     if (mRenderFrame) {
       TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
       BrowserElementParent::DispatchAsyncScrollEvent(browser, aContentRect,
                                                      aContentSize);
     }
   }
 
+  virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE
+  {
+    MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
+  }
+
 private:
   void DoRequestContentRepaint(const FrameMetrics& aFrameMetrics)
   {
     if (mRenderFrame) {
       TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
       browser->UpdateFrame(aFrameMetrics);
     }
   }
--- a/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
+++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp
@@ -354,21 +354,21 @@ nsMathMLmmultiscriptsFrame::Place(nsRend
       }
 
       isSubScript = !isSubScript;
     }
     count++;
     childFrame = childFrame->GetNextSibling();
   }
   // note: width=0 if all sup-sub pairs match correctly
-  if ((0 != width) || !baseFrame || !subScriptFrame || !supScriptFrame) {
+  if ((0 != width) || !baseFrame) {
     // report an error, encourage people to get their markups in order
     if (aPlaceOrigin) {
-      if (count <= 1 || (count == 2 && mprescriptsFrame)) {
-        ReportErrorToConsole("NoSubSup");
+      if (!baseFrame) {
+        ReportErrorToConsole("NoBase");
       } else {
         ReportErrorToConsole("SubSupMismatch");
       }
     }
     return ReflowError(aRenderingContext, aDesiredSize);
   }
 
   // we left out the width of prescripts, so ...
--- a/layout/mathml/tests/test_bug553917.html
+++ b/layout/mathml/tests/test_bug553917.html
@@ -57,17 +57,17 @@ https://bugzilla.mozilla.org/show_bug.cg
           status: [false, false, false, false, false, false],
           args: [["2..0"], ["1.5notaunit"], ["2"],["BADlspace"],["BADheight"],["BADdepth"]]
         },
       /*<math><mmultiscripts></mmultiscripts></math>
         <math><mmultiscripts><mprescripts/><mprescripts/></mmultiscripts></math>
         <math><mmultiscripts><mi>x</mi><mi>y</mi></mmultiscripts></math>*/
         MMultiscriptsErrors: {
           status: [false, false, false],
-          args: ["DuplicateMprescripts", "NoSubSup", "SubSupMismatch"]
+          args: ["NoBase","DuplicateMprescripts", "SubSupMismatch"]
         },
       /*<math><mo minsize="2">+</mo></math>*/
         UnitlessValuesAreDeprecated : {
           status : [false],
           args : [[]] }};
       
       var g_errorTypes = ["ChildCountIncorrect","DeprecatedSupersededBy","AttributeParsingError",
                           "AttributeParsingErrorNoTag","LengthParsingError", "MMultiscriptsErrors",
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mathml-mmultiscript-base-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>mmultiscript with only base</title>
+	</head>
+	
+	<body>
+		<math>
+			<mmultiscripts>
+			<mtext>base</mtext>
+			</mmultiscripts>
+		</math>
+	</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mathml-mmultiscript-base.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>mmultiscript with only base and none as placeholder</title>
+	</head>
+
+	<body>
+		<math> 
+			<mmultiscripts>
+				<mtext>base</mtext>
+				<none/>
+				<none/>
+			</mmultiscripts>
+		</math>
+	</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mathml-mmultiscript-mprescript-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>mmultiscript with mprescripts without none</title>
+	</head>
+
+	<body>
+		<math> 
+			<mmultiscripts>
+				<mtext>base</mtext>
+				<mprescripts/>
+			</mmultiscripts>
+		</math>
+	</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/mathml/mathml-mmultiscript-mprescript.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>mmultiscript with mprescripts with none as placeholders</title>
+	</head>
+	
+	<body>
+		<math>
+			<mmultiscripts>
+				<mtext>base</mtext>
+				<none/>
+				<none/>
+				<mprescripts/>
+			</mmultiscripts>
+
+		</math>
+	</body>
+</html>
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -111,8 +111,10 @@ skip-if(B2G) == maction-dynamic-3.html m
 == whitespace-trim-1.html whitespace-trim-1-ref.html
 == whitespace-trim-2.html whitespace-trim-2-ref.html
 == whitespace-trim-3.html whitespace-trim-3-ref.html
 fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 787215
 == whitespace-trim-5.html whitespace-trim-5-ref.html
 == operator-1.xhtml operator-1-ref.xhtml
 == scriptshift-1.xhtml scriptshift-1-ref.xhtml
 == number-size-1.xhtml number-size-1-ref.xhtml
+== mathml-mmultiscript-base.html mathml-mmultiscript-base-ref.html
+== mathml-mmultiscript-mprescript.html mathml-mmultiscript-mprescript-ref.html
--- a/media/mtransport/nr_timer.cpp
+++ b/media/mtransport/nr_timer.cpp
@@ -48,19 +48,21 @@
 
    ekr@rtfm.com  Sun Feb 22 19:35:24 2004
  */
 
 #include <string>
 
 #include "nsCOMPtr.h"
 #include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
 #include "nsIEventTarget.h"
 #include "nsITimer.h"
 #include "nsNetCID.h"
+#include "runnable_utils.h"
 
 extern "C" {
 #include "nr_api.h"
 #include "async_timer.h"
 }
 
 
 namespace mozilla {
@@ -100,22 +102,35 @@ NS_IMETHODIMP nrappkitTimerCallback::Not
   timer->Release();
   return NS_OK;
 }
 }  // close namespace
 
 
 using namespace mozilla;
 
+// These timers must only be used from the STS thread.
+// This function is a helper that enforces that.
+static void CheckSTSThread() {
+  nsresult rv;
+
+  nsCOMPtr<nsIEventTarget> sts_thread;
+
+  sts_thread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
+
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  ASSERT_ON_THREAD(sts_thread);
+}
+
 int NR_async_timer_set(int timeout, NR_async_cb cb, void *arg, char *func,
                        int l, void **handle) {
   nsresult rv;
+  CheckSTSThread();
 
   nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
-
   if (NS_FAILED(rv)) {
     return(R_FAILED);
   }
 
   rv = timer->InitWithCallback(new nrappkitTimerCallback(cb, arg, func, l),
                                timeout, nsITimer::TYPE_ONE_SHOT);
   if (NS_FAILED(rv)) {
     return R_FAILED;
@@ -129,20 +144,24 @@ int NR_async_timer_set(int timeout, NR_a
   // Bug 818806: if we have no handle to the timer, we have no way to avoid
   // it leaking (though not the callback object) if it never fires (or if
   // we exit before it fires).
 
   return 0;
 }
 
 int NR_async_schedule(NR_async_cb cb, void *arg, char *func, int l) {
+  // No need to check the thread because we check it next in the
+  // timer set.
   return NR_async_timer_set(0, cb, arg, func, l, nullptr);
 }
 
 int NR_async_timer_cancel(void *handle) {
+  CheckSTSThread();
+
   if (!handle)
     return 0;
 
   nsITimer *timer = static_cast<nsITimer *>(handle);
 
   timer->Cancel();
   // Allow the timer to go away.
   timer->Release();
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
@@ -167,19 +167,21 @@ int nr_ice_candidate_pair_destroy(nr_ice
       return(0);
 
     pair=*pairp;
     *pairp=0;
 
     RFREE(pair->as_string);
     RFREE(pair->foundation);
     nr_ice_socket_deregister(pair->local->isock,pair->stun_client_handle);
-    RFREE(pair->stun_client->params.ice_binding_request.username);
-    RFREE(pair->stun_client->params.ice_binding_request.password.data);
-    nr_stun_client_ctx_destroy(&pair->stun_client);
+    if (pair->stun_client) {
+      RFREE(pair->stun_client->params.ice_binding_request.username);
+      RFREE(pair->stun_client->params.ice_binding_request.password.data);
+      nr_stun_client_ctx_destroy(&pair->stun_client);
+    }
 
     RFREE(pair->r2l_user);
     RFREE(pair->r2l_pwd.data);
 
     NR_async_timer_cancel(pair->stun_cb_timer);
     NR_async_timer_cancel(pair->restart_controlled_cb_timer);
     NR_async_timer_cancel(pair->restart_nominated_cb_timer);
 
--- a/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c
@@ -307,17 +307,19 @@ static void nr_ice_peer_ctx_destroy_cb(N
     RFREE(pctx->label);
     RFREE(pctx->peer_ufrag);
     RFREE(pctx->peer_pwd);
 
     STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2){
       STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry);
       nr_ice_media_stream_destroy(&str1);
     }
-    STAILQ_REMOVE(&pctx->ctx->peers, pctx, nr_ice_peer_ctx_, entry);
+    assert(pctx->ctx);
+    if (pctx->ctx)
+      STAILQ_REMOVE(&pctx->ctx->peers, pctx, nr_ice_peer_ctx_, entry);
 
     RFREE(pctx);
   }
 
 int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp)
   {
 
     if(!pctxp || !*pctxp)
--- a/media/mtransport/third_party/nICEr/src/net/nr_socket.c
+++ b/media/mtransport/third_party/nICEr/src/net/nr_socket.c
@@ -29,16 +29,17 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 
 
 static char *RCSSTRING __UNUSED__="$Id: nr_socket.c,v 1.2 2008/04/28 17:59:02 ekr Exp $";
 
+#include <assert.h>
 #include <nr_api.h>
 #include "nr_socket.h"
 
 int nr_socket_create_int(void *obj, nr_socket_vtbl *vtbl, nr_socket **sockp)
   {
     int _status;
     nr_socket *sock=0;
 
@@ -60,17 +61,19 @@ int nr_socket_destroy(nr_socket **sockp)
     nr_socket *sock;
 
     if(!sockp || !*sockp)
       return(0);
 
     sock=*sockp;
     *sockp=0;
 
-    sock->vtbl->destroy(&sock->obj);
+    assert(sock->vtbl);
+    if (sock->vtbl)
+      sock->vtbl->destroy(&sock->obj);
 
     RFREE(sock);
 
     return(0);
   }
 
 int nr_socket_sendto(nr_socket *sock,const void *msg, size_t len, int flags,
   nr_transport_addr *addr)
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -741,30 +741,36 @@ void CreateAnswer(sipcc::MediaConstraint
     ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
                      kDefaultTimeout);
     ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
     SDPSanityCheck(pObserver->lastString, sdpCheck, true);
     offer_ = pObserver->lastString;
   }
 
-  void SetRemote(TestObserver::Action action, std::string remote) {
+  void SetRemote(TestObserver::Action action, std::string remote,
+                 bool ignoreError = false) {
     pObserver->state = TestObserver::stateNoResponse;
     ASSERT_EQ(pc->SetRemoteDescription(action, remote.c_str()), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
                      kDefaultTimeout);
-    ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
+    if (!ignoreError) {
+      ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
+    }
   }
 
-  void SetLocal(TestObserver::Action action, std::string local) {
+  void SetLocal(TestObserver::Action action, std::string local,
+                bool ignoreError = false) {
     pObserver->state = TestObserver::stateNoResponse;
     ASSERT_EQ(pc->SetLocalDescription(action, local.c_str()), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
                      kDefaultTimeout);
-    ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
+    if (!ignoreError) {
+      ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
+    }
   }
 
   void DoTrickleIce(ParsedSDP &sdp) {
     int expectAddIce = 0;
     pObserver->addIceSuccessCount = 0;
     for (std::multimap<int, std::string>::iterator it = sdp.ice_candidates_.begin();
          it != sdp.ice_candidates_.end(); ++it) {
       if ((*it).first != 0) {
@@ -1929,16 +1935,70 @@ TEST_F(SignalingAgentTest, CreateUntilFa
     if (!CreateAgent())
       break;
     std::cerr << "Created agent " << i << std::endl;
   }
   std::cerr << "Failed after creating " << i << " PCs " << std::endl;
   PR_Sleep(10000);  // Wait to see if we crash
 }
 
+/*
+ * Test for Bug 843595
+ */
+TEST_F(SignalingTest, missingUfrag)
+{
+  sipcc::MediaConstraints constraints;
+  std::string offer =
+    "v=0\r\n"
+    "o=Mozilla-SIPUA 2208 0 IN IP4 0.0.0.0\r\n"
+    "s=SIP Call\r\n"
+    "t=0 0\r\n"
+    "a=ice-pwd:4450d5a4a5f097855c16fa079893be18\r\n"
+    "a=fingerprint:sha-256 23:9A:2E:43:94:42:CF:46:68:FC:62:F9:F4:48:61:DB:"
+      "2F:8C:C9:FF:6B:25:54:9D:41:09:EF:83:A8:19:FC:B6\r\n"
+    "m=audio 56187 RTP/SAVPF 109 0 8 101\r\n"
+    "c=IN IP4 77.9.79.167\r\n"
+    "a=rtpmap:109 opus/48000/2\r\n"
+    "a=ptime:20\r\n"
+    "a=rtpmap:0 PCMU/8000\r\n"
+    "a=rtpmap:8 PCMA/8000\r\n"
+    "a=rtpmap:101 telephone-event/8000\r\n"
+    "a=fmtp:101 0-15\r\n"
+    "a=sendrecv\r\n"
+    "a=candidate:0 1 UDP 2113601791 192.168.178.20 56187 typ host\r\n"
+    "a=candidate:1 1 UDP 1694236671 77.9.79.167 56187 typ srflx raddr "
+      "192.168.178.20 rport 56187\r\n"
+    "a=candidate:0 2 UDP 2113601790 192.168.178.20 52955 typ host\r\n"
+    "a=candidate:1 2 UDP 1694236670 77.9.79.167 52955 typ srflx raddr "
+      "192.168.178.20 rport 52955\r\n"
+    "m=video 49929 RTP/SAVPF 120\r\n"
+    "c=IN IP4 77.9.79.167\r\n"
+    "a=rtpmap:120 VP8/90000\r\n"
+    "a=recvonly\r\n"
+    "a=candidate:0 1 UDP 2113601791 192.168.178.20 49929 typ host\r\n"
+    "a=candidate:1 1 UDP 1694236671 77.9.79.167 49929 typ srflx raddr "
+      "192.168.178.20 rport 49929\r\n"
+    "a=candidate:0 2 UDP 2113601790 192.168.178.20 50769 typ host\r\n"
+    "a=candidate:1 2 UDP 1694236670 77.9.79.167 50769 typ srflx raddr "
+      "192.168.178.20 rport 50769\r\n"
+    "m=application 54054 SCTP/DTLS 5000 \r\n"
+    "c=IN IP4 77.9.79.167\r\n"
+    "a=fmtp:HuRUu]Dtcl\\zM,7(OmEU%O$gU]x/z\tD protocol=webrtc-datachannel;"
+      "streams=16\r\n"
+    "a=sendrecv\r\n";
+
+  a1_.SetLocal(TestObserver::OFFER, offer, true);
+  a2_.SetRemote(TestObserver::OFFER, offer, true);
+  a2_.CreateAnswer(constraints, offer, OFFER_AV | ANSWER_AV);
+  a2_.SetLocal(TestObserver::ANSWER, a2_.answer(), true);
+  a1_.SetRemote(TestObserver::ANSWER, a2_.answer(), true);
+  // We don't check anything in particular for success here -- simply not
+  // crashing by now is enough to declare success.
+}
+
 } // End namespace test.
 
 int main(int argc, char **argv) {
   // This test can cause intermittent oranges on the builders
   CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_TESTS")
 
   test_utils = new MtransportTestUtils();
   NSS_NoDB_Init(NULL);
--- a/mobile/android/base/TabsTray.java
+++ b/mobile/android/base/TabsTray.java
@@ -196,16 +196,19 @@ public class TabsTray extends TwoWayView
             updateSelectedPosition();
         }
 
         // Updates the selected position in the list so that it will be scrolled to the right place.
         private void updateSelectedPosition() {
             int selected = getPositionForTab(Tabs.getInstance().getSelectedTab());
             for (int i=0; i < getCount(); i++)
                  TabsTray.this.setItemChecked(i, (i == selected));
+
+            if (selected != -1)
+                TabsTray.this.setSelection(selected);
         }
 
         public void clear() {
             mTabs = null;
             notifyDataSetChanged(); // Be sure to call this whenever mTabs changes.
         }
 
         public int getCount() {
--- a/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml.in
+++ b/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml.in
@@ -65,17 +65,18 @@
                         android:layout_centerVertical="true">
 
             <Gecko.RelativeLayout android:id="@+id/awesome_bar"
                                   style="@style/AddressBar.Button"
                                   android:layout_centerVertical="true"
                                   android:clickable="true"
                                   android:focusable="true">
 
-                <Gecko.ImageView style="@style/AddressBar.Button"
+                <Gecko.ImageView android:id="@+id/awesome_bar_entry"
+                                 style="@style/AddressBar.Button"
                                  android:layout_marginLeft="20dp"
                                  android:layout_marginRight="0dp"
                                  android:layout_marginTop="7dp"
                                  android:layout_marginBottom="7dp"
                                  android:duplicateParentState="true"
                                  android:clickable="false"
                                  android:focusable="false"
                                  android:background="@drawable/address_bar_url"/>
--- a/mobile/android/base/resources/layout/shared_ui_components.xml
+++ b/mobile/android/base/resources/layout/shared_ui_components.xml
@@ -5,18 +5,17 @@
 
 <!-- This file is used to include shared UI components in different gecko app
      layouts, such as gecko_app.xml and web_app.xml -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <org.mozilla.gecko.gfx.LayerView android:id="@+id/layer_view"
                                      android:layout_width="fill_parent"
-                                     android:layout_height="fill_parent"
-                                     android:background="#FFF"/>
+                                     android:layout_height="fill_parent"/>
 
     <AbsoluteLayout android:id="@+id/plugin_container"
                     android:background="@android:color/transparent"
                     android:layout_width="fill_parent"
                     android:layout_height="fill_parent"/>
 
     <org.mozilla.gecko.FormAssistPopup android:id="@+id/form_assist_popup"
                                        android:layout_width="fill_parent"
--- a/mobile/android/base/util/EventDispatcher.java
+++ b/mobile/android/base/util/EventDispatcher.java
@@ -8,17 +8,17 @@ import org.json.JSONObject;
 
 import android.util.Log;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 public final class EventDispatcher {
-    private static final String LOGTAG = "EventDispatcher";
+    private static final String LOGTAG = "GeckoEventDispatcher";
 
     private final Map<String, CopyOnWriteArrayList<GeckoEventListener>> mEventListeners
                   = new HashMap<String, CopyOnWriteArrayList<GeckoEventListener>>();
 
     public void registerEventListener(String event, GeckoEventListener listener) {
         synchronized (mEventListeners) {
             CopyOnWriteArrayList<GeckoEventListener> listeners = mEventListeners.get(event);
             if (listeners == null) {
@@ -51,18 +51,18 @@ public final class EventDispatcher {
     public String dispatchEvent(String message) {
         // {
         //   "type": "value",
         //   "event_specific": "value",
         //   ...
         try {
             JSONObject json = new JSONObject(message);
             if (json.has("gecko")) {
-                Log.w(LOGTAG, "The 'gecko' property of the sendMessageToJava parameter is deprecated.");
                 json = json.getJSONObject("gecko");
+                Log.w(LOGTAG, "The 'gecko' property of the sendMessageToJava parameter is deprecated; message of type " + json.getString("type"));
             }
             String type = json.getString("type");
 
             CopyOnWriteArrayList<GeckoEventListener> listeners;
             synchronized (mEventListeners) {
                 listeners = mEventListeners.get(type);
             }
 
--- a/mobile/android/base/widget/TwoWayView.java
+++ b/mobile/android/base/widget/TwoWayView.java
@@ -3779,25 +3779,25 @@ public class TwoWayView extends AdapterV
             delta = 0;
         }
 
         if (delta != 0) {
             offsetChildren(-delta);
         }
     }
 
-    @TargetApi(11)
+    @TargetApi(14)
     private SparseBooleanArray cloneCheckStates() {
         if (mCheckStates == null) {
             return null;
         }
 
         SparseBooleanArray checkedStates;
 
-        if (Build.VERSION.SDK_INT >= 11) {
+        if (Build.VERSION.SDK_INT >= 14) {
             checkedStates = mCheckStates.clone();
         } else {
             checkedStates = new SparseBooleanArray();
 
             for (int i = 0; i < mCheckStates.size(); i++) {
                 checkedStates.put(mCheckStates.keyAt(i), mCheckStates.valueAt(i));
             }
         }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -562,17 +562,17 @@ var BrowserApp = {
       if (window.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).isFirstPaint)
         return false;
     } catch (e) {
       return false;
     }
 
     let tab = this.selectedTab;
     if (!tab)
-      return true;
+      return false;
     return tab.contentDocumentIsDisplayed;
   },
 
   displayedDocumentChanged: function() {
     window.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).isFirstPaint = true;
   },
 
   get tabs() {
--- a/python/mozboot/mozboot/base.py
+++ b/python/mozboot/mozboot/base.py
@@ -67,8 +67,29 @@ class BaseBootstrapper(object):
         retcode = proc.poll()
         if retcode:
             cmd = kwargs.get('args', args[0])
             e = subprocess.CalledProcessError(retcode, cmd)
             e.output = output
             raise e
 
         return output
+
+    def prompt_int(self, prompt, low, high, limit=5):
+        ''' Prompts the user with prompt and requires an integer between low and high. '''
+        valid = False
+        while not valid and limit > 0:
+            try:
+                choice = int(raw_input(prompt))
+                if not low <= choice <= high:
+                    print("ERROR! Please enter a valid option!")
+                    limit -= 1
+                else:
+                    valid = True
+            except ValueError:
+                print("ERROR! Please enter a valid option!")
+                limit -= 1
+
+        if limit > 0:
+            return choice
+        else:
+            raise Exception("Error! Reached max attempts of entering option.")
+
--- a/python/mozboot/mozboot/osx.py
+++ b/python/mozboot/mozboot/osx.py
@@ -15,16 +15,20 @@ from distutils.version import StrictVers
 
 from mozboot.base import BaseBootstrapper
 
 HOMEBREW_BOOTSTRAP = 'http://raw.github.com/mxcl/homebrew/go'
 XCODE_APP_STORE = 'macappstore://itunes.apple.com/app/id497799835?mt=12'
 XCODE_LEGACY = 'https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_3.2.6_and_ios_sdk_4.3__final/xcode_3.2.6_and_ios_sdk_4.3.dmg'
 HOMEBREW_AUTOCONF213 = 'https://raw.github.com/Homebrew/homebrew-versions/master/autoconf213.rb'
 
+MACPORTS_URL = {'8': 'https://distfiles.macports.org/MacPorts/MacPorts-2.1.3-10.8-MountainLion.pkg',
+                '7': 'https://distfiles.macports.org/MacPorts/MacPorts-2.1.3-10.7-Lion.pkg',
+                '6': 'https://distfiles.macports.org/MacPorts/MacPorts-2.1.3-10.6-SnowLeopard.pkg',}
+
 RE_CLANG_VERSION = re.compile('Apple (?:clang|LLVM) version (\d+\.\d+)')
 
 APPLE_CLANG_MINIMUM_VERSION = StrictVersion('4.0')
 
 XCODE_REQUIRED = '''
 Xcode is required to build Firefox. Please complete the install of Xcode
 through the App Store.
 '''
@@ -51,49 +55,84 @@ Perform the following steps to install t
 When that has finished installing, please relaunch this script.
 '''
 
 UPGRADE_XCODE_COMMAND_LINE_TOOLS = '''
 An old version of the Xcode command line tools is installed. You will need to
 install a newer version in order to compile Firefox.
 '''
 
-HOMEBREW_INSTALL = '''
-We will install the Homebrew package manager to install required packages.
+PACKAGE_MANAGER_INSTALL = '''
+We will install the %s package manager to install required packages.
 
-You will be prompted to install Homebrew with its default settings. If you
-would prefer to do this manually, hit CTRL+c, install Homebrew yourself, ensure
-"brew" is in your $PATH, and relaunch bootstrap.
+You will be prompted to install %s with its default settings. If you
+would prefer to do this manually, hit CTRL+c, install %s yourself, ensure
+"%s" is in your $PATH, and relaunch bootstrap.
 '''
 
-HOMEBREW_PACKAGES = '''
-We are now installing all required packages via Homebrew. You will see a lot of
+PACKAGE_MANAGER_PACKAGES = '''
+We are now installing all required packages via %s. You will see a lot of
 output as packages are built.
 '''
 
-HOMEBREW_OLD_CLANG = '''
+PACKAGE_MANAGER_OLD_CLANG = '''
 We require a newer compiler than what is provided by your version of Xcode.
 
-We will install a modern version of Clang through Homebrew.
+We will install a modern version of Clang through %s.
+'''
+
+PACKAGE_MANAGER_CHOICE = '''
+Please choose a package manager you'd like:
+1. Homebrew
+2. MacPorts
+Your choice:
+'''
+
+NO_PACKAGE_MANAGER_WARNING = '''
+It seems you don't have any supported package manager installed.
+'''
+
+PACKAGE_MANAGER_EXISTS = '''
+Looks like you have %s installed. We will install all required packages via %s.
+'''
+
+MULTI_PACKAGE_MANAGER_EXISTS = '''
+It looks like you have multiple package managers installed.
+'''
+
+# May add support for other package manager on os x.
+PACKAGE_MANAGER = {'Homebrew': 'brew',
+                   'MacPorts': 'port'}
+
+PACKAGE_MANAGER_CHOICES = ['Homebrew', 'MacPorts']
+
+MACPORTS_POSTINSTALL_RESTART_REQUIRED = '''
+MacPorts was installed successfully. However, you'll need to start a new shell
+to pick up the environment changes so MacPorts can be found by your tools.
+
+Please start a new shell or terminal window and run this bootstrapper again.
 '''
 
 
 class OSXBootstrapper(BaseBootstrapper):
     def __init__(self, version):
         BaseBootstrapper.__init__(self)
 
         self.os_version = StrictVersion(version)
 
         if self.os_version < StrictVersion('10.6'):
             raise Exception('OS X 10.6 or above is required.')
 
+        self.minor_version = version.split('.')[1]
+
     def install_system_packages(self):
         self.ensure_xcode()
-        self.ensure_homebrew()
-        self.ensure_homebrew_packages()
+
+        choice = self.ensure_package_manager()
+        getattr(self, 'ensure_%s_packages' % choice)()
 
     def ensure_xcode(self):
         if self.os_version < StrictVersion('10.7'):
             if not os.path.exists('/Developer/Applications/Xcode.app'):
                 print(XCODE_REQUIRED_LEGACY)
 
                 subprocess.check_call(['open', XCODE_LEGACY])
                 sys.exit(1)
@@ -133,28 +172,16 @@ class OSXBootstrapper(BaseBootstrapper):
 
             version = StrictVersion(match.group(1))
 
             if version < APPLE_CLANG_MINIMUM_VERSION:
                 print(UPGRADE_XCODE_COMMAND_LINE_TOOLS)
                 print(INSTALL_XCODE_COMMAND_LINE_TOOLS_STEPS)
                 sys.exit(1)
 
-    def ensure_homebrew(self):
-        if self.which('brew') is not None:
-            return
-
-        print(HOMEBREW_INSTALL)
-        bootstrap = urllib2.urlopen(url=HOMEBREW_BOOTSTRAP, timeout=20).read()
-        with tempfile.NamedTemporaryFile() as tf:
-            tf.write(bootstrap)
-            tf.flush()
-
-            subprocess.check_call(['ruby', tf.name])
-
     def ensure_homebrew_packages(self):
         brew = self.which('brew')
         assert brew is not None
 
         installed = self.check_output([brew, 'list']).split()
 
         packages = [
             # We need to install Python because Mercurial requires the Python
@@ -179,8 +206,82 @@ class OSXBootstrapper(BaseBootstrapper):
 
             subprocess.check_call([brew, '-v', 'install', package])
 
         if self.os_version < StrictVersion('10.7') and 'llvm' not in installed:
             print(HOMEBREW_OLD_CLANG)
 
             subprocess.check_call([brew, '-v', 'install', 'llvm',
                 '--with-clang', '--all-targets'])
+
+    def ensure_macports_packages(self):
+        port = self.which('port')
+        assert port is not None
+
+        installed = set(self.check_output([port, 'installed']).split())
+
+        packages = ['python27',
+                    'mercurial',
+                    'yasm',
+                    'libidl',
+                    'autoconf213']
+
+        missing = [package for package in packages if package not in installed]
+        if missing:
+            self.run_as_root([port, '-v', 'install'] + missing)
+
+        if self.os_version < StrictVersion('10.7') and 'llvm' not in installed:
+            print(MACPORTS_OLD_CLANG)
+            self.run_as_root([port, '-v', 'install', 'llvm'])
+
+    def ensure_package_manager(self):
+        '''
+        Search package mgr in sys.path, if none is found, prompt the user to install one.
+        If only one is found, use that one. If both are found, prompt the user to choose
+        one.
+        '''
+        installed = []
+        for name, cmd in PACKAGE_MANAGER.iteritems():
+            if self.which(cmd) is not None:
+                installed.append(name)
+
+        if not installed:
+            print(NO_PACKAGE_MANAGER_WARNING)
+            choice = self.prompt_int(prompt=PACKAGE_MANAGER_CHOICE, low=1, high=2)
+            getattr(self, 'install_%s' % PACKAGE_MANAGER_CHOICES[choice - 1].lower())()
+            return PACKAGE_MANAGER_CHOICES[choice - 1].lower()
+        elif len(installed) == 1:
+            print(PACKAGE_MANAGER_EXISTS % (installed[0], installed[0]))
+            return installed[0].lower()
+        else:
+            print(MULTI_PACKAGE_MANAGER_EXISTS)
+            choice = self.prompt_int(prompt=PACKAGE_MANAGER_CHOICE, low=1, high=2)
+            return PACKAGE_MANAGER_CHOICES[choice - 1].lower()
+
+    def install_homebrew(self):
+        print(PACKAGE_MANAGER_INSTALL % ('Homebrew', 'Homebrew', 'Homebrew', 'brew'))
+        bootstrap = urllib2.urlopen(url=HOMEBREW_BOOTSTRAP, timeout=20).read()
+        with tempfile.NamedTemporaryFile() as tf:
+            tf.write(bootstrap)
+            tf.flush()
+
+            subprocess.check_call(['ruby', tf.name])
+
+    def install_macports(self):
+        url = MACPORTS_URL.get(self.minor_version, None)
+        if not url:
+            raise Exception('We do not have a MacPorts install URL for your '
+                'OS X version. You will need to install MacPorts manually.')
+
+        print(PACKAGE_MANAGER_INSTALL % ('MacPorts', 'MacPorts', 'MacPorts', 'port'))
+        pkg = urllib2.urlopen(url=url, timeout=300).read()
+        with tempfile.NamedTemporaryFile(suffix='.pkg') as tf:
+            tf.write(pkg)
+            tf.flush()
+
+            self.run_as_root(['installer', '-pkg', tf.name, '-target', '/'])
+
+        # MacPorts installs itself into a location likely not on the PATH. If
+        # we can't find it, prompt to restart.
+        if self.which('port') is None:
+            print(MACPORTS_POSTINSTALL_RESTART_REQUIRED)
+            sys.exit(1)
+
--- a/testing/marionette/marionette-actors.js
+++ b/testing/marionette/marionette-actors.js
@@ -180,17 +180,21 @@ MarionetteDriverActor.prototype = {
    * ChromeMessageSender.  Has no effect if the global ChromeMessageBroadcaster is already
    * in use.  If this replaces a frame-specific ChromeMessageSender, it removes the message
    * listeners from that sender, and then puts the corresponding frame script "to sleep",
    * which removes most of the message listeners from it as well.
    */
   switchToGlobalMessageManager: function MDA_switchToGlobalMM() {
     if (this.currentRemoteFrame !== null) {
       this.removeMessageManagerListeners(this.messageManager);
-      this.sendAsync("sleepSession");
+      try {
+        // this can fail if the frame is already gone
+        this.sendAsync("sleepSession");
+      }
+      catch(e) {}
     }
     this.messageManager = this.globalMessageManager;
     this.currentRemoteFrame = null;
   },
 
   /**
    * Helper method to send async messages to the content listener
    *
@@ -1200,17 +1204,17 @@ MarionetteDriverActor.prototype = {
         }
         checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
       } else {
         this.sendError("Unable to locate frame: " + aRequest.value, 8, null,
                        command_id);
       }
     }
     else {
-      if ((aRequest.value == null) && (aRequest.element == null) &&
+      if ((!aRequest.value) && (!aRequest.element) &&
           (this.currentRemoteFrame !== null)) {
         // We're currently using a ChromeMessageSender for a remote frame, so this
         // request indicates we need to switch back to the top-level (parent) frame.
         // We'll first switch to the parent's (global) ChromeMessageBroadcaster, so
         // we send the message to the right listener.
         this.switchToGlobalMessageManager();
       }
       aRequest.command_id = command_id;
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -27,16 +27,17 @@
     "dom/devicestorage/test/test_enumerateMultipleContinue.html":" /tests/dom/devicestorage/test/test_enumerate.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
     "dom/devicestorage/test/test_enumerateOptions.html":" /tests/dom/devicestorage/test/test_enumerate.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
     "dom/devicestorage/test/test_lastModificationFilter.html":" /tests/dom/devicestorage/test/test_enumerate.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
     "dom/devicestorage/test/test_overwrite.html":" /tests/dom/devicestorage/test/test_enumerate.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
     "dom/devicestorage/test/test_sanity.html":" /tests/dom/devicestorage/test/test_enumerate.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
     "dom/devicestorage/test/test_stat.html":" /tests/dom/devicestorage/test/test_enumerate.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
     "dom/devicestorage/test/test_watch.html":" /tests/dom/devicestorage/test/test_enumerate.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
     "dom/devicestorage/test/test_watchOther.html":" addError was called : SecurityError",
+    "dom/encoding/test/test_stringencoding.html":" Test timed out.",
     "dom/file/test/test_append_read_data.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_archivereader.html":" uncaught exception - NS_ERROR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIProperties.get] at chrome://specialpowers/content/specialpowersAPI.js:120",
     "dom/file/test/test_archivereader_nonUnicode.html":" uncaught exception - NS_ERROR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIProperties.get] at chrome://specialpowers/content/specialpowersAPI.js:120",
     "dom/file/test/test_archivereader_zip_in_zip.html":" uncaught exception - NS_ERROR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIProperties.get] at chrome://specialpowers/content/specialpowersAPI.js:120",
     "dom/file/test/test_location.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_lockedfile_lifetimes.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_lockedfile_lifetimes_nested.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_lockedfile_ordering.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
@@ -47,25 +48,31 @@
     "dom/file/test/test_stream_tracking.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_success_events_after_abort.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_truncate.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_workers.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/file/test/test_write_read_data.html":" uncaught exception - UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. at http://mochi.test:8888/tests/dom/file/test/helpers.js:126",
     "dom/imptests/editing/conformancetest/test_event.html":" Command fontName, value \"serif\": input event, canceled; assert_equals: number of input events fired expected 0 but got 1",
     "dom/imptests/editing/conformancetest/test_runtest.html":" Test timed out.",
     "dom/imptests/editing/selecttest/test_Document-open.html":" Test runner timed us out.",
+    "dom/imptests/webapps/DOMCore/tests/approved/test_Range-cloneContents.html":" Resulting DOM for range 0 [paras[0].firstChild, 0, paras[0].firstChild, 0]",
+    "dom/imptests/webapps/DOMCore/tests/approved/test_Range-deleteContents.html":" Resulting DOM for range 0 [paras[0].firstChild, 0, paras[0].firstChild, 0]",
+    "dom/imptests/webapps/DOMCore/tests/approved/test_Range-extractContents.html":" Resulting DOM for range 0 [paras[0].firstChild, 0, paras[0].firstChild, 0]",
+    "dom/imptests/webapps/DOMCore/tests/approved/test_Range-insertNode.html":" Test timed out.",
+    "dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html":" Test timed out.",
     "dom/indexedDB/": "",
 
     "dom/sms": "",
 
     "dom/media/tests/mochitest/test_getUserMedia_exceptions.html":" Exception for wrong object type as third parameter",
     "dom/network/tests/test_networkstats_basics.html":" uncaught exception - uncaught exception: 2147500033 at :0",
     "dom/permission/tests/test_permission_basics.html":" uncaught exception - NS_ERROR_XPC_GS_RETURNED_FAILURE: Component returned failure code: 0x80570016 (NS_ERROR_XPC_GS_RETURNED_FAILURE) [nsIJSCID.getService] at resource://gre/modules/XPCOMUtils.jsm:202",
     "dom/settings/tests/test_settings_basics.html":" uncaught exception - NS_ERROR_XPC_GS_RETURNED_FAILURE: Component returned failure code: 0x80570016 (NS_ERROR_XPC_GS_RETURNED_FAILURE) [nsIJSCID.getService] at resource://gre/modules/XPCOMUtils.jsm:202",
     "dom/settings/tests/test_settings_onsettingchange.html":" uncaught exception - NS_ERROR_XPC_GS_RETURNED_FAILURE: Component returned failure code: 0x80570016 (NS_ERROR_XPC_GS_RETURNED_FAILURE) [nsIJSCID.getService] at resource://gre/modules/XPCOMUtils.jsm:202",
+    "dom/tests/mochitest/ajax/jquery/test_jQuery.html":" Test timed out.",
     "dom/tests/mochitest/ajax/offline/test_badManifestMagic.html":" uncaught exception - NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPermissionManager.addFromPrincipal] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js:114",
     "dom/tests/mochitest/ajax/offline/test_badManifestMime.html":" uncaught exception - NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPermissionManager.addFromPrincipal] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js:114",
     "dom/tests/mochitest/ajax/offline/test_bug445544.html":" uncaught exception - NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPermissionManager.addFromPrincipal] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js:114",
     "dom/tests/mochitest/ajax/offline/test_bug460353.html":" uncaught exception - NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPermissionManager.addFromPrincipal] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/test_bug460353.html:37",
     "dom/tests/mochitest/ajax/offline/test_bug474696.html":" uncaught exception - NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPermissionManager.addFromPrincipal] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js:114",
     "dom/tests/mochitest/ajax/offline/test_bug544462.html":" uncaught exception - NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPermissionManager.addFromPrincipal] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js:114",
     "dom/tests/mochitest/ajax/offline/test_bug744719-cancel.html":" uncaught exception - NS_ERROR_NOT_IMPLEMENTED: Component returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED) [nsIDOMOfflineResourceList.mozItems] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/test_bug744719-cancel.html:17",
     "dom/tests/mochitest/ajax/offline/test_bug744719.html":" uncaught exception - NS_ERROR_NOT_IMPLEMENTED: Component returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED) [nsIDOMOfflineResourceList.mozItems] at http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/test_bug744719.html:16",
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -27,53 +27,19 @@ function SpecialPowersAPI() {
   this._fm = null;
   this._cb = null;
 }
 
 function bindDOMWindowUtils(aWindow) {
   if (!aWindow)
     return
 
-  var util = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                   .getInterface(Components.interfaces.nsIDOMWindowUtils);
-  // This bit of magic brought to you by the letters
-  // B Z, and E, S and the number 5.
-  //
-  // Take all of the properties on the nsIDOMWindowUtils-implementing
-  // object, and rebind them onto a new object with a stub that uses
-  // apply to call them from this privileged scope. This way we don't
-  // have to explicitly stub out new methods that appear on
-  // nsIDOMWindowUtils.
-  //
-  // Note that this will be a chrome object that is (possibly) exposed to
-  // content. Make sure to define __exposedProps__ for each property to make
-  // sure that it gets through the security membrane.
-  var proto = Object.getPrototypeOf(util);
-  var target = { __exposedProps__: {} };
-  function rebind(desc, prop) {
-    if (prop in desc && typeof(desc[prop]) == "function") {
-      var oldval = desc[prop];
-      try {
-        desc[prop] = function() {
-          return oldval.apply(util, arguments);
-        };
-      } catch (ex) {
-        dump("WARNING: Special Powers failed to rebind function: " + desc + "::" + prop + "\n");
-      }
-    }
-  }
-  for (var i in proto) {
-    var desc = Object.getOwnPropertyDescriptor(proto, i);
-    rebind(desc, "get");
-    rebind(desc, "set");
-    rebind(desc, "value");
-    Object.defineProperty(target, i, desc);
-    target.__exposedProps__[i] = 'rw';
-  }
-  return target;
+   var util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                     .getInterface(Ci.nsIDOMWindowUtils);
+   return wrapPrivileged(util);
 }
 
 function getRawComponents(aWindow) {
   return Cu.getComponentsForScope(aWindow);
 }
 
 function isWrappable(x) {
   if (typeof x === "object")
--- a/toolkit/components/osfile/osfile_shared_front.jsm
+++ b/toolkit/components/osfile/osfile_shared_front.jsm
@@ -303,27 +303,25 @@ AbstractFile.read = function read(path, 
   try {
     return file.read(bytes);
   } finally {
     file.close();
   }
 };
 
 /**
- * Write a file, atomically.
- *
- * By opposition to a regular |write|, this operation ensures that,
- * until the contents are fully written, the destination file is
- * not modified.
+ * Write a file in one operation.
  *
- * By default, files are flushed for additional safety, i.e. to lower
- * the risks of losing data in case the device is suddenly removed or
- * in case of sudden shutdown. This additional safety is important
- * for user-critical data (e.g. preferences, application data, etc.)
- * but comes at a performance cost. For non-critical data (e.g. cache,
+ * By default, this operation ensures that, until the contents are
+ * fully written, the destination file is not modified. By default,
+ * files are flushed for additional safety, i.e. to lower the risks of
+ * losing data in case the device is suddenly removed or in case of
+ * sudden shutdown. This additional safety is important for
+ * user-critical data (e.g. preferences, application data, etc.) but
+ * comes at a performance cost. For non-critical data (e.g. cache,
  * thumbnails, etc.), you may wish to deactivate flushing by passing
  * option |flush: false|.
  *
  * Important note: In the current implementation, option |tmpPath|
  * is required. This requirement should disappear as part of bug 793660.
  *
  * @param {string} path The path of the file to modify.
  * @param {Typed Array | C pointer} buffer A buffer containing the bytes to write.
@@ -342,33 +340,44 @@ AbstractFile.read = function read(path, 
  * file may be corrupted.
  *
  * @return {number} The number of bytes actually written.
  */
 AbstractFile.writeAtomic =
      function writeAtomic(path, buffer, options) {
   options = options || noOptions;
 
+  let noOverwrite = options.noOverwrite;
+  if (noOverwrite && OS.File.exists(path)) {
+    throw OS.File.Error.exists("writeAtomic");
+  }
+
+  if ("flush" in options && !options.flush) {
+    // Just write, without any renaming trick
+    let dest;
+    try {
+      dest = OS.File.open(path, {write: true, truncate: true});
+      return dest.write(buffer, options);
+    } finally {
+      dest.close();
+    }
+  }
+
+
   let tmpPath = options.tmpPath;
   if (!tmpPath) {
     throw new TypeError("Expected option tmpPath");
   }
 
-  let noOverwrite = options.noOverwrite;
-  if (noOverwrite && OS.File.exists(path)) {
-    throw OS.File.Error.exists("writeAtomic");
-  }
 
   let tmpFile = OS.File.open(tmpPath, {write: true, truncate: true});
   let bytesWritten;
   try {
     bytesWritten = tmpFile.write(buffer, options);
-    if ("flush" in options && options.flush) {
-      tmpFile.flush();
-    }
+    tmpFile.flush();
   } catch (x) {
     OS.File.remove(tmpPath);
     throw x;
   } finally {
     tmpFile.close();
   }
 
   OS.File.move(tmpPath, path, {noCopy: true});
--- a/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
+++ b/toolkit/components/osfile/tests/mochi/main_test_osfile_async.js
@@ -397,16 +397,70 @@ let test_read_write_all = maketest("read
       yield OS.File.writeAtomic(pathDest, contents, {});
       test.fail("Without a tmpPath, writeAtomic should have failed");
     } catch (err) {
       test.ok(true, "Without a tmpPath, writeAtomic has failed as expected");
     }
 
     // Cleanup.
     OS.File.remove(pathDest);
+
+    // Same tests with |flush: false|
+    // Check that read + writeAtomic performs a correct copy
+    options = {tmpPath: tmpPath, flush: false};
+    optionsBackup = {tmpPath: tmpPath, flush: false};
+    bytesWritten = yield OS.File.writeAtomic(pathDest, contents, options);
+    test.is(contents.byteLength, bytesWritten, "Wrote the correct number of bytes (without flush)");
+
+    // Check that options are not altered
+    test.is(Object.keys(options).length, Object.keys(optionsBackup).length,
+            "The number of options was not changed (without flush)");
+    for (let k in options) {
+      test.is(options[k], optionsBackup[k], "Option was not changed (without flush)");
+    }
+    yield reference_compare_files(pathSource, pathDest, test);
+
+    // Check that temporary file was removed
+    test.info("Compare complete (without flush)");
+    test.ok(!(new FileUtils.File(tmpPath).exists()), "Temporary file was removed (without flush)");
+
+    // Check that writeAtomic fails if noOverwrite is true and the destination
+    // file already exists!
+    view = new Uint8Array(contents.buffer, 10, 200);
+    try {
+      options = {tmpPath: tmpPath, noOverwrite: true, flush: false};
+      yield OS.File.writeAtomic(pathDest, view, options);
+      test.fail("With noOverwrite, writeAtomic should have refused to overwrite file (without flush)");
+    } catch (err) {
+      test.info("With noOverwrite, writeAtomic correctly failed (without flush)");
+      test.ok(err instanceof OS.File.Error, "writeAtomic correctly failed with a file error (without flush)");
+      test.ok(err.becauseExists, "writeAtomic file error confirmed that the file already exists (without flush)");
+    }
+    yield reference_compare_files(pathSource, pathDest, test);
+    test.ok(!(new FileUtils.File(tmpPath).exists()), "Temporary file was removed (without flush)");
+
+    // Now write a subset
+    START = 10;
+    LENGTH = 100;
+    view = new Uint8Array(contents.buffer, START, LENGTH);
+    bytesWritten = yield OS.File.writeAtomic(pathDest, view, {tmpPath: tmpPath, flush: false});
+    test.is(bytesWritten, LENGTH, "Partial write wrote the correct number of bytes (without flush)");
+    array2 = yield OS.File.read(pathDest);
+    view1 = new Uint8Array(contents.buffer, START, LENGTH);
+    test.is(view1.length, array2.length, "Re-read partial write with the correct number of bytes (without flush)");
+    for (let i = 0; i < LENGTH; ++i) {
+      if (view1[i] != array2[i]) {
+        test.is(view1[i], array2[i], "Offset " + i + " is correct (without flush)");
+      }
+      test.ok(true, "Compared re-read of partial write (without flush)");
+    }
+
+    // Cleanup.
+    OS.File.remove(pathDest);
+
   });
 });
 
 /**
  * Test file.{getPosition, setPosition}
  */
 let test_position = maketest("position", function position(test) {
   return Task.spawn(function() {
--- a/toolkit/components/passwordmgr/test/test_bug_654348.html
+++ b/toolkit/components/passwordmgr/test/test_bug_654348.html
@@ -21,17 +21,17 @@ https://bugzilla.mozilla.org/show_bug.cg
  *    we must use the creds that are provided to the xhr witch are different and expected
  */
 
 SimpleTest.waitForExplicitFinish();
 
 function clearAuthCache()
 {
   var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
-                             .getService(Components.interfaces.nsIHttpAuthManager);
+                             .getService(SpecialPowers.Ci.nsIHttpAuthManager);
   authMgr.clearAll();
 }
 
 function doxhr(URL, user, pass, code, next)
 {
   var xhr = new XMLHttpRequest();
   if (user && pass)
     xhr.open("POST", URL, true, user, pass);
--- a/toolkit/components/passwordmgr/test/test_bug_776171.html
+++ b/toolkit/components/passwordmgr/test/test_bug_776171.html
@@ -23,17 +23,17 @@ https://bugzilla.mozilla.org/show_bug.cg
  *    for this path (that is a parent for auth2 path in the first step)
  */
 
 SimpleTest.waitForExplicitFinish();
 
 function clearAuthCache()
 {
   var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
-                             .getService(Components.interfaces.nsIHttpAuthManager);
+                             .getService(SpecialPowers.Ci.nsIHttpAuthManager);
   authMgr.clearAll();
 }
 
 function doxhr(URL, user, pass, next)
 {
   var xhr = new XMLHttpRequest();
   if (user && pass)
     xhr.open("POST", URL, true, user, pass);
--- a/toolkit/components/passwordmgr/test/test_notifications_popup.html
+++ b/toolkit/components/passwordmgr/test/test_notifications_popup.html
@@ -158,28 +158,28 @@ function checkTest() {
         break;
 
       default:
         ok(false, "Unexpected call to checkTest for test #" + testNum);
 
     }
 }
 
-const Ci = Components.interfaces;
-const Cc = SpecialPowers.wrap(Components).classes;
+const Ci = SpecialPowers.Ci;
+const Cc = SpecialPowers.Cc;
 ok(Ci != null, "Access Ci");
 ok(Cc != null, "Access Cc");
 
 var pwmgr = Cc["@mozilla.org/login-manager;1"].
             getService(Ci.nsILoginManager);
 ok(pwmgr != null, "Access pwmgr");
 
 pwmgr.removeAllLogins();
 
-var nsLoginInfo = new SpecialPowers.wrap(Components).
+var nsLoginInfo = new SpecialPowers.wrap(SpecialPowers.Components).
                       Constructor("@mozilla.org/login-manager/loginInfo;1",
                                   Ci.nsILoginInfo, "init");
 var login1 = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
                              "notifyu1", "notifyp1", "user", "pass");
 var login2 = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
                              "notifyu2", "notifyp2", "user", "pass");
 
 var observerService = Cc["@mozilla.org/observer-service;1"].
--- a/toolkit/components/passwordmgr/test/test_prompt_async.html
+++ b/toolkit/components/passwordmgr/test/test_prompt_async.html
@@ -28,17 +28,17 @@
         dialogMonitor.prototype = {
             windowsOpen : 0,
             windowsRegistered : 0,
 
             QueryInterface : function (iid) {
                 const interfaces = [Ci.nsIObserver, Ci.nsISupports];
 
                 if (!interfaces.some( function(v) { return iid.equals(v) } ))
-                        throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
+                        throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
                 return this;
             },
 
             observe: function(subject, topic, data) {
                 if (topic === "domwindowopened") {
                     this.windowsOpen++;
                     ok(this.windowsOpen == 1, "Didn't open more then one dialog at a time");
                     this.windowsRegistered++;
@@ -120,34 +120,32 @@
             SimpleTest.finish();
         }
 
 	var resolveCallback = {
 	QueryInterface : function (iid) {
 	const interfaces = [Ci.nsIProtocolProxyCallback, Ci.nsISupports];
 
         if (!interfaces.some( function(v) { return iid.equals(v) } ))
-          throw Components.results.NS_ERROR_NO_INTERFACE;
+          throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
 	  return this;
 	},
 
 	onProxyAvailable : function (req, uri, pi, status) {
           initLogins(pi);
           doTest(testNum);
 	}
 	};
 
 	function startup() {
             //need to allow for arbitrary network servers defined in PAC instead of a hardcoded moz-proxy.
-            var ios = SpecialPowers.wrap(Components)
-                                   .classes["@mozilla.org/network/io-service;1"]
-                                   .getService(Components.interfaces.nsIIOService);
+            var ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
+                                   .getService(SpecialPowers.Ci.nsIIOService);
 
-            var pps = SpecialPowers.wrap(Components)
-                                   .classes["@mozilla.org/network/protocol-proxy-service;1"]
+            var pps = SpecialPowers.Cc["@mozilla.org/network/protocol-proxy-service;1"]
                                    .getService();
 
             var uri = ios.newURI("http://example.com", null, null);
             pps.asyncResolve(uri, 0, resolveCallback);
 	}
 
         // --------------- Test loop spin ----------------
         var testNum = 1;
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -2659,39 +2659,30 @@ SearchService.prototype = {
         let cacheEntry = {};
         cacheEntry.lastModifiedTime = parent.lastModifiedTime;
         cacheEntry.engines = [];
         cache.directories[cacheKey] = cacheEntry;
       }
       cache.directories[cacheKey].engines.push(engine._serializeToJSON(true));
     }
 
-    let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
-                  createInstance(Ci.nsIFileOutputStream);
-    let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
-                    createInstance(Ci.nsIScriptableUnicodeConverter);
-    let cacheFile = getDir(NS_APP_USER_PROFILE_50_DIR);
-    cacheFile.append("search.json");
-
     try {
       LOG("_buildCache: Writing to cache file.");
-      ostream.init(cacheFile, (MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE), PERMS_FILE, ostream.DEFER_OPEN);
-      converter.charset = "UTF-8";
-      let data = converter.convertToInputStream(JSON.stringify(cache));
-
-      // Write to the cache file asynchronously
-      NetUtil.asyncCopy(data, ostream, function(rv) {
-        if (Components.isSuccessCode(rv)) {
-          Services.obs.notifyObservers(null,
-                                       SEARCH_SERVICE_TOPIC,
-                                       SEARCH_SERVICE_CACHE_WRITTEN);
-        } else {
-          LOG("_buildCache: failure during asyncCopy: " + rv);
+      let path = OS.Path.join(OS.Constants.Path.profileDir, "search.json");
+      let data = gEncoder.encode(JSON.stringify(cache));
+      let promise = OS.File.writeAtomic(path, data, { tmpPath: path + ".tmp"});
+
+      promise.then(
+        function onSuccess() {
+          Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, SEARCH_SERVICE_CACHE_WRITTEN);
+        },
+        function onError(e) {
+          LOG("_buildCache: failure during writeAtomic: " + e);
         }
-      });
+      );
     } catch (ex) {
       LOG("_buildCache: Could not write to cache file: " + ex);
     }
     TelemetryStopwatch.finish("SEARCH_SERVICE_BUILD_CACHE_MS");
   },
 
   _syncLoadEngines: function SRCH_SVC__syncLoadEngines() {
     LOG("_syncLoadEngines: start");
--- a/toolkit/components/search/tests/xpcshell/head_search.js
+++ b/toolkit/components/search/tests/xpcshell/head_search.js
@@ -47,31 +47,61 @@ function removeCacheFile()
   let file = gProfD.clone();
   file.append("search.json");
   if (file.exists()) {
     file.remove(false);
   }
 }
 
 /**
+ * Clean the profile of any cache file left from a previous run.
+ */
+function removeCache()
+{
+  let file = gProfD.clone();
+  file.append("search.json");
+  if (file.exists()) {
+    file.remove(false);
+  }
+
+}
+
+/**
  * Run some callback once metadata has been committed to disk.
  */
 function afterCommit(callback)
 {
   let obs = function(result, topic, verb) {
     if (verb == "write-metadata-to-disk-complete") {
       Services.obs.removeObserver(obs, topic);
       callback(result);
     } else {
       dump("TOPIC: " + topic+ "\n");
     }
   }
   Services.obs.addObserver(obs, "browser-search-service", false);
 }
 
+/**
+ * Run some callback once cache has been built.
+ */
+function afterCache(callback)
+{
+  let obs = function(result, topic, verb) {
+    do_print("afterCache: " + verb);
+    if (verb == "write-cache-to-disk-complete") {
+      Services.obs.removeObserver(obs, topic);
+      callback(result);
+    } else {
+      dump("TOPIC: " + topic+ "\n");
+    }
+  }
+  Services.obs.addObserver(obs, "browser-search-service", false);
+}
+
 function  parseJsonFromStream(aInputStream) {
   const json = Cc["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON);
   const data = json.decodeFromStream(aInputStream, aInputStream.available());
   return data;
 }
 
 /**
  * Read a JSON file and return the JS object
--- a/toolkit/components/search/tests/xpcshell/test_init_async_multiple_then_sync.js
+++ b/toolkit/components/search/tests/xpcshell/test_init_async_multiple_then_sync.js
@@ -31,31 +31,38 @@ function run_test() {
     Services.search.init(function search_initialized(aStatus) {
       do_check_true(Components.isSuccessCode(aStatus));
       init_complete(me);
     });
   }
 
   // Ensure that all asynchronous initializers eventually complete
   let init_complete = function init_complete(i) {
+    do_print("init complete " + i);
     do_check_true(pending[i]);
     pending[i] = false;
     numberPending--;
     do_check_true(numberPending >= 0);
     do_check_true(Services.search.isInitialized);
-    if (numberPending == 0) {
-      // Just check that we can access a list of engines.
-      let engines = Services.search.getEngines();
-      do_check_neq(engines, null);
+    if (numberPending != 0) {
+      do_print("Still waiting for the following initializations: " + JSON.stringify(pending));
+      return;
+    }
+    do_print("All initializations have completed");
+    // Just check that we can access a list of engines.
+    let engines = Services.search.getEngines();
+    do_check_neq(engines, null);
 
-      // Wait a little before quitting: if some initializer is
-      // triggered twice, we want to catch that error.
-      do_timeout(1000, function() {
-        do_test_finished();
-      });
-    }
+    do_print("Waiting a second before quitting");
+    // Wait a little before quitting: if some initializer is
+    // triggered twice, we want to catch that error.
+    do_timeout(1000, function() {
+      do_print("Test is complete");
+      do_test_finished();
+    });
   };
 
   // ... but don't wait for asynchronous initializations to complete
   let engines = Services.search.getEngines();
   do_check_neq(engines, null);
+  do_print("Synchronous part of the test complete");
 }
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_nocache.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let Cu = Components.utils;
+let Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/osfile.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://testing-common/httpd.js");
+
+/*
+ * test_nocache: Start search engine
+ * - without search.json
+ *
+ * Ensure that :
+ * - nothing explodes;
+ * - search.json is created.
+ */
+
+
+function run_test()
+{
+  removeCache();
+  updateAppInfo();
+  do_load_manifest("data/chrome.manifest");
+
+  let httpServer = new HttpServer();
+  httpServer.start(4444);
+  httpServer.registerDirectory("/", do_get_cwd());
+
+  let search = Services.search;
+
+  do_test_pending();
+
+  // Check that cache is created at startup
+  afterCache(function cacheCreated() {
+    // Check that search.json has been created.
+    let cache = gProfD.clone();
+    cache.append("search.json");
+    do_check_true(cache.exists());
+  });
+
+  // Perform initialization
+  search.init(function ss_initialized(rv) {
+    do_check_true(Components.isSuccessCode(rv));
+
+    do_print("Setting up observer");
+    function observer(aSubject, aTopic, aData) {
+      do_print("Observing topic " + aTopic);
+      if ("engine-added" == aData) {
+        let engine = search.getEngineByName("Test search engine");
+        if (!engine) {
+          return;
+        }
+        Services.obs.removeObserver(observer, "browser-search-engine-modified");
+        do_print("Engine has been added, let's wait for the cache to be built");
+        afterCache(function() {
+          do_print("Success");
+
+          Task.spawn(function task() {
+            do_print("Searching test engine in cache");
+            try {
+              let path = OS.Path.join(OS.Constants.Path.profileDir, "search.json");
+              let data = yield OS.File.read(path);
+              let text = new TextDecoder().decode(data);
+              let cache = JSON.parse(text);
+              let found = false;
+              for (let dirName in cache.directories) {
+                for (let engine of cache.directories[dirName].engines) {
+                  if (engine._id == "[app]/test-search-engine.xml") {
+                    found = true;
+                    break;
+                  }
+                }
+                if (found) {
+                  break;
+                }
+              }
+              do_check_true(found);
+            } catch (ex) {
+              do_throw(ex);
+            } finally {
+              removeCache();
+              httpServer.stop(function() {
+                // httpServer doesn't seem to stop cleanly if there is no callback
+              });
+              do_test_finished();
+            }
+          });
+        });
+      }
+    };
+    Services.obs.addObserver(observer, "browser-search-engine-modified", false);
+
+    // Add an engine, check if it appears in the cache
+    search.addEngine("http://localhost:4444/data/engine.xml",
+                   Ci.nsISearchEngine.DATA_XML,
+                   null, false);
+  });
+}
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
 head = head_search.js
 tail = 
 firefox-appdir = browser
 
+[test_nocache.js]
 [test_645970.js]
 [test_init_async_multiple.js]
 [test_init_async_multiple_then_sync.js]
 [test_json_cache.js]
 [test_migratedb.js]
 [test_nodb.js]
 [test_nodb_pluschanges.js]
 [test_purpose.js]
--- a/toolkit/identity/tests/chrome/sandbox_content_perms.html
+++ b/toolkit/identity/tests/chrome/sandbox_content_perms.html
@@ -14,16 +14,20 @@
           aFunc();
         } catch (ex) {
           return true;
         }
         return false;
       }
 
       function CcDenied() {
+        // Once Components goes away in content, the question of whether or not
+        // Components.classes throws is not well-formed.
+        if (typeof Components === 'undefined')
+          return true;
         try {
           Components.classes;
           return false;
         } catch (e) {
           return !!/denied/.exec(e);
         }
       }
 
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -305,16 +305,18 @@ void nsView::SetDimensions(const nsRect&
 
 void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible)
 {
   if (!aEffectivelyVisible)
   {
     DropMouseGrabbing();
   }
 
+  SetForcedRepaint(true);
+
   if (nullptr != mWindow)
   {
     if (aEffectivelyVisible)
     {
       DoResetWidgetBounds(false, true);
       mWindow->Show(true);
     }
     else
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -480,16 +480,17 @@ public:
 
   virtual nsresult SynthesizeNativeMouseMove(nsIntPoint aPoint)
   { return SynthesizeNativeMouseEvent(aPoint, NSMouseMoved, 0); }
 
   // Mac specific methods
   
   virtual bool      DispatchWindowEvent(nsGUIEvent& event);
 
+  void WillPaintWindow();
   bool PaintWindow(nsIntRegion aRegion, bool aIsAlternate);
 
 #ifdef ACCESSIBILITY
   already_AddRefed<mozilla::a11y::Accessible> GetDocumentAccessible();
 #endif
 
   virtual void CreateCompositor();
   virtual gfxASurface* GetThebesSurface();
@@ -553,16 +554,18 @@ protected:
   virtual already_AddRefed<nsIWidget>
   AllocateChildPopupWidget()
   {
     static NS_DEFINE_IID(kCPopUpCID, NS_POPUP_CID);
     nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
     return widget.forget();
   }
 
+  nsIWidget* GetWidgetForListenerEvents();
+
 protected:
 
   NSView<mozView>*      mView;      // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG]
   nsRefPtr<mozilla::widget::TextInputHandler> mTextInputHandler;
   InputContext          mInputContext;
 
   NSView<mozView>*      mParentView;
   nsIWidget*            mParentWidget;
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1489,29 +1489,45 @@ NS_IMETHODIMP nsChildView::DispatchEvent
 
 bool nsChildView::DispatchWindowEvent(nsGUIEvent &event)
 {
   nsEventStatus status;
   DispatchEvent(&event, status);
   return ConvertStatus(status);
 }
 
-bool nsChildView::PaintWindow(nsIntRegion aRegion, bool aIsAlternate)
-{
-  nsCOMPtr<nsIWidget> widget = this;
-
+nsIWidget*
+nsChildView::GetWidgetForListenerEvents()
+{
   // If there is no listener, use the parent popup's listener if that exists.
   if (!mWidgetListener && mParentWidget) {
     nsWindowType type;
     mParentWidget->GetWindowType(type);
     if (type == eWindowType_popup) {
-      widget = mParentWidget;
+      return mParentWidget;
     }
   }
 
+  return this;
+}
+
+void nsChildView::WillPaintWindow()
+{
+  nsCOMPtr<nsIWidget> widget = GetWidgetForListenerEvents();
+
+  nsIWidgetListener* listener = widget->GetWidgetListener();
+  if (listener) {
+    listener->WillPaintWindow(widget);
+  }
+}
+
+bool nsChildView::PaintWindow(nsIntRegion aRegion, bool aIsAlternate)
+{
+  nsCOMPtr<nsIWidget> widget = GetWidgetForListenerEvents();
+
   nsIWidgetListener* listener = widget->GetWidgetListener();
   if (!listener)
     return false;
 
   bool returnValue = false;
   bool oldDispatchPaint = mIsDispatchPaint;
   mIsDispatchPaint = true;
   uint32_t flags = 0;
@@ -2688,20 +2704,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
       }
       NS_ADDREF(mGeckoChild);
       [widgetArray addObject:[NSNumber numberWithUnsignedInteger:(NSUInteger)mGeckoChild]];
       [self performSelector:@selector(releaseWidgets:)
                  withObject:widgetArray
                  afterDelay:0];
     }
 
-    nsIWidgetListener* listener = mGeckoChild->GetWidgetListener();
-    if (listener) {
-      listener->WillPaintWindow(mGeckoChild);
-    }
+    mGeckoChild->WillPaintWindow();
   }
   [super viewWillDraw];
 }
 
 // Allows us to turn off setting up the clip region
 // before each drawRect. We already clip within gecko.
 - (BOOL)wantsDefaultClipping
 {
--- a/widget/windows/winrt/nsMetroFilePicker.cpp
+++ b/widget/windows/winrt/nsMetroFilePicker.cpp
@@ -469,15 +469,16 @@ nsMetroFilePicker::AppendFilter(const ns
 
     if (WindowsIsStringEmpty(mFirstTitle.Get())) {
       mFirstTitle.Set(key.Get());
     }
 
     boolean replaced;
     map->Insert(key.Get(), saveTypes.Get(), &replaced);
   }
+  break;
 
   default:
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
--- a/widget/xpwidgets/GfxInfoBase.cpp
+++ b/widget/xpwidgets/GfxInfoBase.cpp
@@ -28,16 +28,17 @@
 #include "mozilla/Preferences.h"
 
 #if defined(MOZ_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #endif
 
 using namespace mozilla::widget;
 using namespace mozilla;
+using mozilla::MutexAutoLock;
 
 nsTArray<GfxDriverInfo>* GfxInfoBase::mDriverInfo;
 bool GfxInfoBase::mDriverInfoObserverInitialized;
 
 // Observes for shutdown so that the child GfxDriverInfo list is freed.
 class ShutdownObserver : public nsIObserver
 {
 public:
@@ -81,17 +82,17 @@ void InitGfxDriverInfoShutdownObserver()
 
   ShutdownObserver *obs = new ShutdownObserver();
   observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 }
 
 using namespace mozilla::widget;
 using namespace mozilla;
 
-NS_IMPL_ISUPPORTS3(GfxInfoBase, nsIGfxInfo, nsIObserver, nsISupportsWeakReference)
+NS_IMPL_THREADSAFE_ISUPPORTS3(GfxInfoBase, nsIGfxInfo, nsIObserver, nsISupportsWeakReference)
 
 #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
 #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
 #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
 
 static const char*
 GetPrefNameForFeature(int32_t aFeature)
 {
@@ -526,16 +527,17 @@ GfxInfoBase::Observe(nsISupports* aSubje
     }
   }
 
   return NS_OK;
 }
 
 GfxInfoBase::GfxInfoBase()
     : mFailureCount(0)
+    , mMutex("GfxInfoBase")
 {
 }
 
 GfxInfoBase::~GfxInfoBase()
 {
 }
 
 nsresult
@@ -833,24 +835,25 @@ GfxInfoBase::EvaluateDownloadedBlacklist
 
     ++i;
   }
 }
 
 NS_IMETHODIMP_(void)
 GfxInfoBase::LogFailure(const nsACString &failure)
 {
+  MutexAutoLock lock(mMutex);
   /* We only keep the first 9 failures */
   if (mFailureCount < ArrayLength(mFailures)) {
     mFailures[mFailureCount++] = failure;
 
     /* record it in the crash notes too */
-#if defined(MOZ_CRASHREPORTER)
-    CrashReporter::AppendAppNotesToCrashReport(failure);
-#endif
+    #if defined(MOZ_CRASHREPORTER)
+      CrashReporter::AppendAppNotesToCrashReport(failure);
+    #endif
   }
 
 }
 
 /* void getFailures ([optional] out unsigned long failureCount, [array, size_is (failureCount), retval] out string failures); */
 /* XPConnect method of returning arrays is very ugly. Would not recommend. Fallable nsMemory::Alloc makes things worse */
 NS_IMETHODIMP GfxInfoBase::GetFailures(uint32_t *failureCount, char ***failures)
 {
--- a/widget/xpwidgets/GfxInfoBase.h
+++ b/widget/xpwidgets/GfxInfoBase.h
@@ -12,16 +12,17 @@
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "GfxDriverInfo.h"
 #include "nsTArray.h"
 #include "nsString.h"
 #include "GfxInfoCollector.h"
 #include "nsIGfxInfoDebug.h"
+#include "mozilla/Mutex.h"
 
 namespace mozilla {
 namespace widget {  
 
 class GfxInfoBase : public nsIGfxInfo,
                     public nsIObserver,
                     public nsSupportsWeakReference
 #ifdef DEBUG
@@ -90,15 +91,16 @@ private:
                                               nsAString& aSuggestedVersion,
                                               int32_t aFeature,
                                               OperatingSystem os);
 
   void EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo);
 
   nsCString mFailures[9]; // The choice of 9 is Ehsan's
   uint32_t mFailureCount;
+  Mutex mMutex;
 
 };
 
 }
 }
 
 #endif /* __mozilla_widget_GfxInfoBase_h__ */
--- a/xpcom/string/public/nsTSubstring.h
+++ b/xpcom/string/public/nsTSubstring.h
@@ -270,19 +270,20 @@ class nsTSubstring_CharT
       bool NS_FASTCALL EqualsASCII( const char* data, size_type len ) const;
         /**
          * An efficient comparison with ASCII that can be used even
          * for wide strings. Call this version when 'data' is
          * null-terminated.
          */
       bool NS_FASTCALL EqualsASCII( const char* data ) const;
 
-    // EqualsLiteral must ONLY be applied to an actual literal string.
-    // Do not attempt to use it with a regular char* pointer, or with a char
-    // array variable.
+    // EqualsLiteral must ONLY be applied to an actual literal string, or
+    // a char array *constant* declared without an explicit size.
+    // Do not attempt to use it with a regular char* pointer, or with a
+    // non-constant char array variable. Use EqualsASCII for them.
     // The template trick to acquire the array length at compile time without
     // using a macro is due to Corey Kosak, with much thanks.
 #ifdef NS_DISABLE_LITERAL_TEMPLATE
       inline bool EqualsLiteral( const char* str ) const
         {
           return EqualsASCII(str);
         }
 #else
@@ -304,18 +305,19 @@ class nsTSubstring_CharT
     // ASCII/Literal string. The ASCII string is *not* lowercased for
     // you. If you compare to an ASCII or literal string that contains an
     // uppercase character, it is guaranteed to return false. We will
     // throw assertions too.
       bool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const;
       bool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const;
 
     // LowerCaseEqualsLiteral must ONLY be applied to an actual
-    // literal string.  Do not attempt to use it with a regular char*
-    // pointer, or with a char array variable. Use
+    // literal string, or a char array *constant* declared without an 
+    // explicit size.  Do not attempt to use it with a regular char*
+    // pointer, or with a non-constant char array variable. Use
     // LowerCaseEqualsASCII for them.
 #ifdef NS_DISABLE_LITERAL_TEMPLATE
       inline bool LowerCaseEqualsLiteral( const char* str ) const
         {
           return LowerCaseEqualsASCII(str);
         }
 #else
       template<int N>
@@ -355,19 +357,20 @@ class nsTSubstring_CharT
         {
           AssignASCII(data, strlen(data));
         }
       bool NS_FASTCALL AssignASCII( const char* data, const fallible_t& ) NS_WARN_UNUSED_RESULT
         {
           return AssignASCII(data, strlen(data), fallible_t());
         }
 
-    // AssignLiteral must ONLY be applied to an actual literal string.
-    // Do not attempt to use it with a regular char* pointer, or with a char
-    // array variable. Use AssignASCII for those.
+    // AssignLiteral must ONLY be applied to an actual literal string, or
+    // a char array *constant* declared without an explicit size.
+    // Do not attempt to use it with a regular char* pointer, or with a 
+    // non-constant char array variable. Use AssignASCII for those.
     // There are not fallible version of these methods because they only really
     // apply to small allocations that we wouldn't want to check anyway.
 #ifdef NS_DISABLE_LITERAL_TEMPLATE
       void AssignLiteral( const char* str )
                   { AssignASCII(str); }
 #else
       template<int N>
       void AssignLiteral( const char (&str)[N] )
@@ -477,18 +480,21 @@ class nsTSubstring_CharT
       void Cut( index_type cutStart, size_type cutLength )                                       { Replace(cutStart, cutLength, char_traits::sEmptyBuffer, 0); }
 
 
         /**
          * buffer sizing
          */
 
         /**
-         * Attempts to set the capacity to the given size, without affecting
-         * the length of the string. Also ensures that the buffer is mutable.
+         * Attempts to set the capacity to the given size in number of 
+         * characters, without affecting the length of the string.
+         * There is no need to include room for the null terminator: it is
+         * the job of the string class.
+         * Also ensures that the buffer is mutable.
          */
       void NS_FASTCALL SetCapacity( size_type newCapacity );
       bool NS_FASTCALL SetCapacity( size_type newCapacity, const fallible_t& ) NS_WARN_UNUSED_RESULT;
 
       void NS_FASTCALL SetLength( size_type newLength );
       bool NS_FASTCALL SetLength( size_type newLength, const fallible_t& ) NS_WARN_UNUSED_RESULT;
 
       void Truncate( size_type newLength = 0 )