Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 23 Aug 2013 10:53:17 -0400
changeset 144089 ebf9d108717c54f83c8aa7ed006cc154a493a843
parent 144088 617b9050b5ed0d4c9d814038cbb99dd6f17e0099 (current diff)
parent 144066 fa56d4c9e630e86b9527665b8882af29307bca1e (diff)
child 144090 9459d5c2e605aebf95c0fb2ff1e2e3f34c55477e
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone26.0a1
Merge m-c to fx-team.
dom/encoding/TextDecoderBase.h
dom/encoding/TextEncoderBase.h
dom/mobilemessage/tests/marionette/test_filter_number_multiple.js
dom/mobilemessage/tests/marionette/test_filter_number_single.js
dom/workers/TextDecoder.cpp
dom/workers/TextDecoder.h
dom/workers/TextEncoder.cpp
dom/workers/TextEncoder.h
js/src/jsclone.cpp
js/src/jsclone.h
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 904831 - MSVC_ENABLE_PGO in js/src/Makefile.in
+Bug 908208 - ipdl dependencies are busted, so we must clobber.  See Bug 907394 for a solution.
--- a/Makefile.in
+++ b/Makefile.in
@@ -55,16 +55,17 @@ ifndef MOZ_PROFILE_USE
 # a specific subdirectory of the object directory. The invoked Python
 # script simply iterates over all the manifests, purging files as
 # necessary. To manage new directories or add files to the manifests,
 # modify the backend generator.
 #
 # We need to explicitly put backend.RecursiveMakeBackend.built here
 # otherwise the rule in rules.mk doesn't run early enough.
 default alldep all:: CLOBBER $(topsrcdir)/configure config.status backend.RecursiveMakeBackend.built
+	$(call SUBMAKE,backend.RecursiveMakeBackend.built,js/src,1)
 	$(call py_action,purge_manifests,-d _build_manifests/purge .)
 endif
 
 CLOBBER: $(topsrcdir)/CLOBBER
 	@echo "STOP!  The CLOBBER file has changed."
 	@echo "Please run the build through a sanctioned build wrapper, such as"
 	@echo "'mach build' or client.mk."
 	@exit 1
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "bdac3547cbc0423bcdcf3b1650be326bfd1c601f", 
+    "revision": "a96d83d7e0bbd6b3fb8ecb78712c924ba8094659", 
     "repo_path": "/integration/gaia-central"
 }
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -31,16 +31,17 @@ pref("metro.debug.selection.dumpEvents",
 // Enable tab-modal prompts
 pref("prompts.tab_modal.enabled", true);
 
 
 // Enable off main thread compositing
 pref("layers.offmainthreadcomposition.enabled", true);
 pref("layers.async-pan-zoom.enabled", false);
 pref("layers.componentalpha.enabled", false);
+pref("gfx.azpc.touch_start_tolerance", "0.1"); // dpi * tolerance = pixel threshold
 pref("gfx.axis.fling_friction", "0.002");
 
 // Enable Microsoft TSF support by default for imes.
 pref("intl.enable_tsf_support", true);
 
 pref("general.autoScroll", true);
 pref("general.smoothScroll", true);
 pref("general.smoothScroll.durationToIntervalRatio", 200);
--- a/build/cl.py
+++ b/build/cl.py
@@ -1,18 +1,53 @@
 # 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 ctypes
 import os, os.path
 import subprocess
 import sys
+from mozbuild.makeutil import Makefile
 
 CL_INCLUDES_PREFIX = os.environ.get("CL_INCLUDES_PREFIX", "Note: including file:")
 
+GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW
+GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
+
+
+# cl.exe likes to print inconsistent paths in the showIncludes output
+# (some lowercased, some not, with different directions of slashes),
+# and we need the original file case for make/pymake to be happy.
+# As this is slow and needs to be called a lot of times, use a cache
+# to speed things up.
+_normcase_cache = {}
+
+def normcase(path):
+    # Get*PathName want paths with backslashes
+    path = path.replace('/', os.sep)
+    dir = os.path.dirname(path)
+    # name is fortunately always going to have the right case,
+    # so we can use a cache for the directory part only.
+    name = os.path.basename(path)
+    if dir in _normcase_cache:
+        result = _normcase_cache[dir]
+    else:
+        path = ctypes.create_unicode_buffer(dir)
+        length = GetShortPathName(path, None, 0)
+        shortpath = ctypes.create_unicode_buffer(length)
+        GetShortPathName(path, shortpath, length)
+        length = GetLongPathName(shortpath, None, 0)
+        if length > len(path):
+            path = ctypes.create_unicode_buffer(length)
+        GetLongPathName(shortpath, path, length)
+        result = _normcase_cache[dir] = path.value
+    return os.path.join(result, name)
+
+
 def InvokeClWithDependencyGeneration(cmdline):
     target = ""
     # Figure out what the target is
     for arg in cmdline:
         if arg.startswith("-Fo"):
             target = arg[3:]
             break
 
@@ -24,27 +59,29 @@ def InvokeClWithDependencyGeneration(cmd
     assert not source.startswith('-')
 
     # The deps target lives here
     depstarget = os.path.basename(target) + ".pp"
 
     cmdline += ['-showIncludes']
     cl = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
 
-    deps = set([os.path.normcase(source).replace(os.sep, '/')])
+    mk = Makefile()
+    rule = mk.create_rule(target)
+    rule.add_dependencies([normcase(source)])
     for line in cl.stdout:
         # cl -showIncludes prefixes every header with "Note: including file:"
         # and an indentation corresponding to the depth (which we don't need)
         if line.startswith(CL_INCLUDES_PREFIX):
             dep = line[len(CL_INCLUDES_PREFIX):].strip()
             # We can't handle pathes with spaces properly in mddepend.pl, but
             # we can assume that anything in a path with spaces is a system
             # header and throw it away.
             if ' ' not in dep:
-                deps.add(os.path.normcase(dep).replace(os.sep, '/'))
+                rule.add_dependencies([normcase(dep)])
         else:
             sys.stdout.write(line) # Make sure we preserve the relevant output
                                    # from cl
 
     ret = cl.wait()
     if ret != 0 or target == "":
         sys.exit(ret)
 
@@ -54,17 +91,12 @@ def InvokeClWithDependencyGeneration(cmd
         try:
             os.makedirs(depsdir)
         except OSError:
             pass # This suppresses the error we get when the dir exists, at the
                  # cost of masking failure to create the directory.  We'll just
                  # die on the next line though, so it's not that much of a loss.
 
     with open(depstarget, "w") as f:
-        f.write("%s: %s" % (target, source))
-        for dep in sorted(deps):
-            f.write(" \\\n%s" % dep)
-        f.write('\n')
-        for dep in sorted(deps):
-            f.write("%s:\n" % dep)
+        mk.dump(f)
 
 if __name__ == "__main__":
     InvokeClWithDependencyGeneration(sys.argv[1:])
--- a/build/pymake/pymake/parserdata.py
+++ b/build/pymake/pymake/parserdata.py
@@ -167,21 +167,20 @@ class Rule(Statement):
         This lets us go really fast and is generally good.
         """
         assert context.weak
         deps = self.depexp.resolvesplit(makefile, makefile.variables)
         # Skip targets with no rules and no dependencies
         if not deps:
             return
         targets = self.targetexp.resolvesplit(makefile, makefile.variables)
-        assert len(targets) == 1
-        target = targets[0]
         rule = data.Rule(deps, self.doublecolon, loc=self.targetexp.loc, weakdeps=True)
-        makefile.gettarget(target).addrule(rule)
-        makefile.foundtarget(target)
+        for target in targets:
+            makefile.gettarget(target).addrule(rule)
+            makefile.foundtarget(target)
         context.currule = rule
 
     def _execute(self, makefile, context):
         assert not context.weak
 
         atargets = data.stripdotslashes(self.targetexp.resolvesplit(makefile, makefile.variables))
         targets = [data.Pattern(p) for p in _expandwildcards(makefile, atargets)]
 
--- a/build/virtualenv/populate_virtualenv.py
+++ b/build/virtualenv/populate_virtualenv.py
@@ -1,16 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # This file contains code for populating the virtualenv environment for
 # Mozilla's build system. It is typically called as part of configure.
 
-from __future__ import print_function, unicode_literals, with_statement
+from __future__ import print_function, unicode_literals
 
 import distutils.sysconfig
 import os
 import shutil
 import subprocess
 import sys
 
 
--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -297,28 +297,50 @@ def check_style():
 
 
 def module_name(name):
     '''Strip the trailing .cpp, .h, inlines.h or -inl.h from a filename.'''
 
     return name.replace('inlines.h', '').replace('-inl.h', '').replace('.h', '').replace('.cpp', '')
 
 
+def is_module_header(enclosing_inclname, header_inclname):
+    '''Determine if an included name is the "module header", i.e. should be
+    first in the file.'''
+
+    module = module_name(enclosing_inclname)
+
+    # Normal case, e.g. module == "foo/Bar", header_inclname == "foo/Bar.h".
+    if module == module_name(header_inclname):
+        return True
+
+    # A public header, e.g. module == "foo/Bar", header_inclname == "js/Bar.h".
+    m = re.match(r'js\/(.*)\.h', header_inclname)
+    if m is not None and module.endswith('/' + m.group(1)):
+        return True
+
+    # A weird public header case.
+    if module == 'jsmemorymetrics' and header_inclname == 'js/MemoryMetrics.h':
+        return True
+
+    return False
+
+
 class Include(object):
     '''Important information for a single #include statement.'''
 
     def __init__(self, inclname, linenum, is_system):
         self.inclname = inclname
         self.linenum = linenum
         self.is_system = is_system
 
     def isLeaf(self):
         return True
 
-    def section(self, module):
+    def section(self, enclosing_inclname):
         '''Identify which section inclname belongs to.
 
         The section numbers are as follows.
           0. Module header (e.g. jsfoo.h or jsfooinlines.h within jsfoo.cpp)
           1. mozilla/Foo.h
           2. <foo.h> or <foo>
           3. jsfoo.h, prmjtime.h, etc
           4. foo/Bar.h
@@ -328,21 +350,19 @@ class Include(object):
         '''
 
         if self.is_system:
             return 2
 
         if not self.inclname.endswith('.h'):
             return 7
 
-        # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
-        # handling.
-        if module == module_name(self.inclname) or \
-           module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
-           module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h':
+        # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
+        # special handling.
+        if is_module_header(enclosing_inclname, self.inclname):
             return 0
 
         if '/' in self.inclname:
             if self.inclname.startswith('mozilla/'):
                 return 1
 
             if self.inclname.endswith('-inl.h'):
                 return 6
@@ -446,27 +466,25 @@ def do_file(filename, inclname, file_kin
                     error(filename, include.linenum,
                           'vanilla header includes an inline-header file ' + include.quote())
 
                 # Check a file doesn't #include itself.  (We do this here because the cycle
                 # detection below doesn't detect this case.)
                 if inclname == include.inclname:
                     error(filename, include.linenum, 'the file includes itself')
 
-    module = module_name(inclname)
-
     def check_includes_order(include1, include2):
         '''Check the ordering of two #include statements.'''
 
         if include1.inclname in oddly_ordered_inclnames or \
            include2.inclname in oddly_ordered_inclnames:
             return
 
-        section1 = include1.section(module)
-        section2 = include2.section(module)
+        section1 = include1.section(inclname)
+        section2 = include2.section(inclname)
         if (section1 > section2) or \
            ((section1 == section2) and (include1.inclname.lower() > include2.inclname.lower())):
             error(filename, str(include1.linenum) + ':' + str(include2.linenum),
                   include1.quote() + ' should be included after ' + include2.quote())
 
     # The #include statements in the files in assembler/ and yarr/ have all manner of implicit
     # ordering requirements.  Boo.  Ignore them.
     skip_order_checking = inclname.startswith(('assembler/', 'yarr/'))
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -94,19 +94,19 @@ class CDATASection;
 class Comment;
 class DocumentFragment;
 class DocumentType;
 class DOMImplementation;
 class Element;
 struct ElementRegistrationOptions;
 class EventTarget;
 class FrameRequestCallback;
-class GlobalObject;
 class HTMLBodyElement;
 class Link;
+class GlobalObject;
 class NodeFilter;
 class NodeIterator;
 class ProcessingInstruction;
 class Touch;
 class TreeWalker;
 class UndoManager;
 template<typename> class OwningNonNull;
 template<typename> class Sequence;
@@ -145,16 +145,17 @@ NS_GetContentList(nsINode* aRootNode,
                   int32_t aMatchNameSpaceId,
                   const nsAString& aTagname);
 //----------------------------------------------------------------------
 
 // Document interface.  This is implemented by all document objects in
 // Gecko.
 class nsIDocument : public nsINode
 {
+  typedef mozilla::dom::GlobalObject GlobalObject;
 public:
   typedef mozilla::dom::Element Element;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_IID)
   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 
 #ifdef MOZILLA_INTERNAL_API
   nsIDocument();
@@ -1919,17 +1920,17 @@ public:
   }
 
   // WebIDL API
   nsIGlobalObject* GetParentObject() const
   {
     return GetScopeObject();
   }
   static already_AddRefed<nsIDocument>
-    Constructor(const mozilla::dom::GlobalObject& aGlobal,
+    Constructor(const GlobalObject& aGlobal,
                 mozilla::ErrorResult& rv);
   virtual mozilla::dom::DOMImplementation*
     GetImplementation(mozilla::ErrorResult& rv) = 0;
   void GetURL(nsString& retval) const;
   void GetDocumentURI(nsString& retval) const;
   void GetCompatMode(nsString& retval) const;
   void GetCharacterSet(nsAString& retval) const;
   // Skip GetContentType, because our NS_IMETHOD version above works fine here.
--- a/content/base/src/Comment.cpp
+++ b/content/base/src/Comment.cpp
@@ -55,20 +55,20 @@ Comment::List(FILE* out, int32_t aIndent
   ToCString(tmp, 0, mText.GetLength());
   fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
 
   fputs("-->\n", out);
 }
 #endif
 
 /* static */ already_AddRefed<Comment>
-Comment::Constructor(const GlobalObject& aGlobal, const nsAString& aData,
-                     ErrorResult& aRv)
+Comment::Constructor(const GlobalObject& aGlobal,
+                     const nsAString& aData, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window || !window->GetDoc()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return window->GetDoc()->CreateComment(aData);
 }
 
--- a/content/base/src/DocumentFragment.cpp
+++ b/content/base/src/DocumentFragment.cpp
@@ -117,19 +117,20 @@ DocumentFragment::DumpContent(FILE* out,
 
   if(aIndent) {
     fputs("\n", out);
   }
 }
 #endif
 
 /* static */ already_AddRefed<DocumentFragment>
-DocumentFragment::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+DocumentFragment::Constructor(const GlobalObject& aGlobal,
+                              ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window || !window->GetDoc()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return window->GetDoc()->CreateDocumentFragment();
 }
 
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -280,22 +280,23 @@ EventSource::Init(nsISupports* aOwner,
 
 /* virtual */ JSObject*
 EventSource::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return EventSourceBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */ already_AddRefed<EventSource>
-EventSource::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
+EventSource::Constructor(const GlobalObject& aGlobal,
+                         const nsAString& aURL,
                          const EventSourceInit& aEventSourceInitDict,
                          ErrorResult& aRv)
 {
   nsRefPtr<EventSource> eventSource = new EventSource();
-  aRv = eventSource->Init(aGlobal.Get(), aURL,
+  aRv = eventSource->Init(aGlobal.GetAsSupports(), aURL,
                           aEventSourceInitDict.mWithCredentials);
   return eventSource.forget();
 }
 
 //-----------------------------------------------------------------------------
 // EventSource::nsIObserver
 //-----------------------------------------------------------------------------
 
--- a/content/base/src/Text.cpp
+++ b/content/base/src/Text.cpp
@@ -16,20 +16,20 @@ Text::SplitText(uint32_t aOffset, ErrorR
   rv = SplitData(aOffset, getter_AddRefs(newChild));
   if (rv.Failed()) {
     return nullptr;
   }
   return newChild.forget().downcast<Text>();
 }
 
 /* static */ already_AddRefed<Text>
-Text::Constructor(const GlobalObject& aGlobal, const nsAString& aData,
-                  ErrorResult& aRv)
+Text::Constructor(const GlobalObject& aGlobal,
+                  const nsAString& aData, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window || !window->GetDoc()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return window->GetDoc()->CreateTextNode(aData);
 }
 
--- a/content/base/src/Text.h
+++ b/content/base/src/Text.h
@@ -24,16 +24,16 @@ public:
   // WebIDL API
   already_AddRefed<Text> SplitText(uint32_t aOffset, ErrorResult& rv);
   void GetWholeText(nsAString& aWholeText, ErrorResult& rv)
   {
     rv = GetWholeText(aWholeText);
   }
 
   static already_AddRefed<Text>
-  Constructor(const GlobalObject& aGlobal, const nsAString& aData,
-              ErrorResult& aRv);
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aData, ErrorResult& aRv);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Text_h
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -516,35 +516,35 @@ WebSocket::Constructor(const GlobalObjec
                        ErrorResult& aRv)
 {
   if (!PrefEnabled()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
-    do_QueryInterface(aGlobal.Get());
+    do_QueryInterface(aGlobal.GetAsSupports());
   if (!scriptPrincipal) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
   if (!principal) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports());
   if (!sgo) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
   if (!ownerWindow) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsTArray<nsString> protocolArray;
 
   for (uint32_t index = 0, len = aProtocols.Length(); index < len; ++index) {
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -29,17 +29,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Base64.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLTemplateElement.h"
-#include "mozilla/dom/TextDecoderBase.h"
+#include "mozilla/dom/TextDecoder.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Selection.h"
 #include "mozilla/Util.h"
 #include "nsAString.h"
 #include "nsAttrName.h"
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
@@ -3417,25 +3417,25 @@ nsContentUtils::ConvertStringFromCharset
 {
   if (aCharset.IsEmpty()) {
     // Treat the string as UTF8
     CopyUTF8toUTF16(aInput, aOutput);
     return NS_OK;
   }
 
   ErrorResult rv;
-  TextDecoderBase decoder;
-  decoder.Init(NS_ConvertUTF8toUTF16(aCharset), false, rv);
+  nsAutoPtr<TextDecoder> decoder(new TextDecoder());
+  decoder->Init(NS_ConvertUTF8toUTF16(aCharset), false, rv);
   if (rv.Failed()) {
     rv.ClearMessage();
     return rv.ErrorCode();
   }
 
-  decoder.Decode(aInput.BeginReading(), aInput.Length(), false,
-                 aOutput, rv);
+  decoder->Decode(aInput.BeginReading(), aInput.Length(), false,
+                  aOutput, rv);
   return rv.ErrorCode();
 }
 
 /* static */
 bool
 nsContentUtils::CheckForBOM(const unsigned char* aBuffer, uint32_t aLength,
                             nsACString& aCharset)
 {
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -181,31 +181,22 @@ nsDOMMultipartFile::Initialize(nsISuppor
 nsresult
 nsDOMMultipartFile::InitBlob(JSContext* aCx,
                              uint32_t aArgc,
                              JS::Value* aArgv,
                              UnwrapFuncPtr aUnwrapFunc)
 {
   bool nativeEOL = false;
   if (aArgc > 1) {
-    if (NS_IsMainThread()) {
-      BlobPropertyBag d;
-      if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
-        return NS_ERROR_TYPE_ERR;
-      }
-      mContentType = d.mType;
-      nativeEOL = d.mEndings == EndingTypes::Native;
-    } else {
-      BlobPropertyBagWorkers d;
-      if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
-        return NS_ERROR_TYPE_ERR;
-      }
-      mContentType = d.mType;
-      nativeEOL = d.mEndings == EndingTypes::Native;
+    BlobPropertyBag d;
+    if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
+      return NS_ERROR_TYPE_ERR;
     }
+    mContentType = d.mType;
+    nativeEOL = d.mEndings == EndingTypes::Native;
   }
 
   if (aArgc > 0) {
     if (!aArgv[0].isObject()) {
       return NS_ERROR_TYPE_ERR; // We're not interested
     }
 
     JS::Rooted<JSObject*> obj(aCx, &aArgv[0].toObject());
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -142,17 +142,17 @@ nsDOMFileReader::Init()
   return NS_OK;
 }
 
 /* static */ already_AddRefed<nsDOMFileReader>
 nsDOMFileReader::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
   nsRefPtr<nsDOMFileReader> fileReader = new nsDOMFileReader();
 
-  nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> owner = do_QueryInterface(aGlobal.GetAsSupports());
   if (!owner) {
     NS_WARNING("Unexpected nsIJSNativeInitializer owner");
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   fileReader->BindToOwner(owner);
 
--- a/content/base/src/nsDOMFileReader.h
+++ b/content/base/src/nsDOMFileReader.h
@@ -29,16 +29,17 @@
 #include "FileIOObject.h"
 
 class nsDOMFileReader : public mozilla::dom::FileIOObject,
                         public nsIDOMFileReader,
                         public nsIInterfaceRequestor,
                         public nsSupportsWeakReference
 {
   typedef mozilla::ErrorResult ErrorResult;
+  typedef mozilla::dom::GlobalObject GlobalObject;
 public:
   nsDOMFileReader();
   virtual ~nsDOMFileReader();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMFILEREADER
 
@@ -60,17 +61,17 @@ public:
   {
     return GetOwner();
   }
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL
   static already_AddRefed<nsDOMFileReader>
-  Constructor(const mozilla::dom::GlobalObject& aGlobal, ErrorResult& aRv);
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
   void ReadAsArrayBuffer(JSContext* aCx, nsIDOMBlob* aBlob, ErrorResult& aRv)
   {
     MOZ_ASSERT(aBlob);
     ReadFileContent(aCx, aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
   }
   void ReadAsText(nsIDOMBlob* aBlob, const nsAString& aLabel, ErrorResult& aRv)
   {
     MOZ_ASSERT(aBlob);
--- a/content/base/src/nsDOMMutationObserver.cpp
+++ b/content/base/src/nsDOMMutationObserver.cpp
@@ -526,17 +526,17 @@ nsDOMMutationObserver::TakeRecords(
 }
 
 // static
 already_AddRefed<nsDOMMutationObserver>
 nsDOMMutationObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                                    mozilla::dom::MutationCallback& aCb,
                                    mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   MOZ_ASSERT(window->IsInnerWindow());
   nsRefPtr<nsDOMMutationObserver> observer =
     new nsDOMMutationObserver(window.forget(), aCb);
   return observer.forget();
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -356,35 +356,36 @@ nsDOMParser::Init(nsIPrincipal* principa
 
   NS_POSTCONDITION(mPrincipal, "Must have principal");
   NS_POSTCONDITION(mOriginalPrincipal, "Must have original principal");
   NS_POSTCONDITION(mDocumentURI, "Must have document URI");
   return NS_OK;
 }
 
 /*static */already_AddRefed<nsDOMParser>
-nsDOMParser::Constructor(const GlobalObject& aOwner, nsIPrincipal* aPrincipal,
-                         nsIURI* aDocumentURI, nsIURI* aBaseURI,
-                         ErrorResult& rv)
+nsDOMParser::Constructor(const GlobalObject& aOwner,
+                         nsIPrincipal* aPrincipal, nsIURI* aDocumentURI,
+                         nsIURI* aBaseURI, ErrorResult& rv)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
-  nsRefPtr<nsDOMParser> domParser = new nsDOMParser(aOwner.Get());
-  rv = domParser->InitInternal(aOwner.Get(), aPrincipal, aDocumentURI,
+  nsRefPtr<nsDOMParser> domParser = new nsDOMParser(aOwner.GetAsSupports());
+  rv = domParser->InitInternal(aOwner.GetAsSupports(), aPrincipal, aDocumentURI,
                                aBaseURI);
   if (rv.Failed()) {
     return nullptr;
   }
   return domParser.forget();
 }
 
 /*static */already_AddRefed<nsDOMParser>
-nsDOMParser::Constructor(const GlobalObject& aOwner, ErrorResult& rv)
+nsDOMParser::Constructor(const GlobalObject& aOwner,
+                         ErrorResult& rv)
 {
   nsCOMPtr<nsIPrincipal> prin;
   nsCOMPtr<nsIURI> documentURI;
   nsCOMPtr<nsIURI> baseURI;
   // No arguments; use the subject principal
   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   if (!secMan) {
     rv.Throw(NS_ERROR_UNEXPECTED);
@@ -397,18 +398,18 @@ nsDOMParser::Constructor(const GlobalObj
   }
 
   // We're called from JS; there better be a subject principal, really.
   if (!prin) {
     rv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
-  nsRefPtr<nsDOMParser> domParser = new nsDOMParser(aOwner.Get());
-  rv = domParser->InitInternal(aOwner.Get(), prin, documentURI, baseURI);
+  nsRefPtr<nsDOMParser> domParser = new nsDOMParser(aOwner.GetAsSupports());
+  rv = domParser->InitInternal(aOwner.GetAsSupports(), prin, documentURI, baseURI);
   if (rv.Failed()) {
     return nullptr;
   }
   return domParser.forget();
 }
 
 nsresult
 nsDOMParser::InitInternal(nsISupports* aOwner, nsIPrincipal* prin,
--- a/content/base/src/nsDOMParser.h
+++ b/content/base/src/nsDOMParser.h
@@ -16,34 +16,35 @@
 #include "mozilla/dom/TypedArray.h"
 
 class nsIDocument;
 
 class nsDOMParser MOZ_FINAL : public nsIDOMParser,
                               public nsSupportsWeakReference,
                               public nsWrapperCache
 {
+  typedef mozilla::dom::GlobalObject GlobalObject;
 public: 
   nsDOMParser();
   virtual ~nsDOMParser();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDOMParser,
                                                          nsIDOMParser)
 
   // nsIDOMParser
   NS_DECL_NSIDOMPARSER
 
   // WebIDL API
   static already_AddRefed<nsDOMParser>
-  Constructor(const mozilla::dom::GlobalObject& aOwner,
+  Constructor(const GlobalObject& aOwner,
               mozilla::ErrorResult& rv);
 
   static already_AddRefed<nsDOMParser>
-  Constructor(const mozilla::dom::GlobalObject& aOwner,
+  Constructor(const GlobalObject& aOwner,
               nsIPrincipal* aPrincipal, nsIURI* aDocumentURI, nsIURI* aBaseURI,
               mozilla::ErrorResult& rv);
 
   already_AddRefed<nsIDocument>
   ParseFromString(const nsAString& aStr, mozilla::dom::SupportedType aType,
                   mozilla::ErrorResult& rv);
 
   already_AddRefed<nsIDocument>
--- a/content/base/src/nsDOMSerializer.h
+++ b/content/base/src/nsDOMSerializer.h
@@ -27,17 +27,17 @@ public:
   // nsIDOMSerializer
   NS_DECL_NSIDOMSERIALIZER
 
   // WebIDL API
   static already_AddRefed<nsDOMSerializer>
   Constructor(const mozilla::dom::GlobalObject& aOwner,
               mozilla::ErrorResult& rv)
   {
-    nsRefPtr<nsDOMSerializer> domSerializer = new nsDOMSerializer(aOwner.Get());
+    nsRefPtr<nsDOMSerializer> domSerializer = new nsDOMSerializer(aOwner.GetAsSupports());
     return domSerializer.forget();
   }
 
   void
   SerializeToString(nsINode& aRoot, nsAString& aStr,
                     mozilla::ErrorResult& rv);
 
   void
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -11228,25 +11228,26 @@ nsDocument::QuerySelector(const nsAStrin
 
 NS_IMETHODIMP
 nsDocument::QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn)
 {
   return nsINode::QuerySelectorAll(aSelector, aReturn);
 }
 
 already_AddRefed<nsIDocument>
-nsIDocument::Constructor(const GlobalObject& aGlobal, ErrorResult& rv)
-{
-  nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aGlobal.Get());
+nsIDocument::Constructor(const GlobalObject& aGlobal,
+                         ErrorResult& rv)
+{
+  nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   if (!global) {
     rv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
-  nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(aGlobal.GetAsSupports());
   if (!prin) {
     rv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> uri;
   NS_NewURI(getter_AddRefs(uri), "about:blank");
   if (!uri) {
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -106,17 +106,17 @@ nsFormData::WrapObject(JSContext* aCx, J
   return FormDataBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */ already_AddRefed<nsFormData>
 nsFormData::Constructor(const GlobalObject& aGlobal,
                         const Optional<NonNull<HTMLFormElement> >& aFormElement,
                         ErrorResult& aRv)
 {
-  nsRefPtr<nsFormData> formData = new nsFormData(aGlobal.Get());
+  nsRefPtr<nsFormData> formData = new nsFormData(aGlobal.GetAsSupports());
   if (aFormElement.WasPassed()) {
     aRv = aFormElement.Value().WalkFormElements(formData);
   }
   return formData.forget();
 }
 
 // -------------------------------------------------------------------------
 // nsIXHRSendable
--- a/content/base/src/nsFormData.h
+++ b/content/base/src/nsFormData.h
@@ -37,17 +37,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsFormData,
                                                          nsIDOMFormData)
 
   NS_DECL_NSIDOMFORMDATA
   NS_DECL_NSIXHRSENDABLE
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext* aCx,
-			       JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL
   nsISupports*
   GetParentObject() const
   {
     return mOwner;
   }
   static already_AddRefed<nsFormData>
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -2995,18 +2995,19 @@ nsRange::AutoInvalidateSelection::~AutoI
   ::InvalidateAllFrames(mCommonAncestor);
   nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
   if (commonAncestor != mCommonAncestor) {
     ::InvalidateAllFrames(commonAncestor);
   }
 }
 
 /* static */ already_AddRefed<nsRange>
-nsRange::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+nsRange::Constructor(const GlobalObject& aGlobal,
+                     ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window || !window->GetDoc()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return window->GetDoc()->CreateRange(aRv);
 }
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -137,19 +137,19 @@ public:
 
   // The WebIDL constructors.
   static already_AddRefed<nsXMLHttpRequest>
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
               JSContext* aCx,
               const mozilla::dom::MozXMLHttpRequestParameters& aParams,
               ErrorResult& aRv)
   {
-    nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.Get());
+    nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
     nsCOMPtr<nsIScriptObjectPrincipal> principal =
-      do_QueryInterface(aGlobal.Get());
+      do_QueryInterface(aGlobal.GetAsSupports());
     if (!global || ! principal) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     nsRefPtr<nsXMLHttpRequest> req = new nsXMLHttpRequest();
     req->Construct(principal->GetPrincipal(), global);
     req->InitParameters(aParams.mMozAnon, aParams.mMozSystem);
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -869,17 +869,17 @@ CanvasRenderingContext2D::EnsureTarget()
           AddDemotableContext(this);
         } else {
           mTarget = layerManager->CreateDrawTarget(size, format);
         }
       } else
 #endif
        mTarget = layerManager->CreateDrawTarget(size, format);
      } else {
-       mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(size, format);
+       mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
      }
   }
 
   if (mTarget) {
     static bool registered = false;
     if (!registered) {
       registered = true;
       NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory));
@@ -3561,17 +3561,17 @@ CanvasRenderingContext2D::GetImageDataAr
 
 void
 CanvasRenderingContext2D::EnsureErrorTarget()
 {
   if (sErrorTarget) {
     return;
   }
 
-  RefPtr<DrawTarget> errorTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
+  RefPtr<DrawTarget> errorTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
   NS_ABORT_IF_FALSE(errorTarget, "Failed to allocate the error target!");
 
   sErrorTarget = errorTarget;
   NS_ADDREF(sErrorTarget);
 }
 
 void
 CanvasRenderingContext2D::FillRuleChanged()
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -11,31 +11,31 @@
 #include "nsICanvasRenderingContextInternal.h"
 #include "mozilla/RefPtr.h"
 #include "nsColor.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CanvasUtils.h"
 #include "gfxFont.h"
 #include "mozilla/ErrorResult.h"
-#include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/CanvasGradient.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasPattern.h"
 #include "mozilla/gfx/Rect.h"
 
 class nsXULElement;
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
 }
 
 namespace dom {
 class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
+class ImageData;
 class StringOrCanvasGradientOrCanvasPattern;
 class StringOrCanvasGradientOrCanvasPatternReturnValue;
 class TextMetrics;
 
 extern const mozilla::gfx::Float SIGMA_MAX;
 
 template<typename T> class Optional;
 
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -43,17 +43,17 @@ public:
   uint32_t Width() const
   {
     return mWidth;
   }
   uint32_t Height() const
   {
     return mHeight;
   }
-  JSObject* Data(JSContext* cx) const
+  JSObject* Data(JSContext* cx, JS::Handle<JSObject*> /* unused */) const
   {
     return GetDataObject();
   }
   JSObject* GetDataObject() const
   {
     xpc_UnmarkGrayObject(mData);
     return mData;
   }
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -47,16 +47,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ImageData.h"
 #include "mozilla/ProcessPriorityManager.h"
 
 #include "Layers.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "mozilla/layers/ShadowLayers.h"
 #endif
 
@@ -150,16 +151,17 @@ WebGLContext::WebGLContext()
     mStencilRefBack = 0;
     mStencilValueMaskFront = 0xffffffff;
     mStencilValueMaskBack  = 0xffffffff;
     mStencilWriteMaskFront = 0xffffffff;
     mStencilWriteMaskBack  = 0xffffffff;
 
     mScissorTestEnabled = 0;
     mDitherEnabled = 1;
+    mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
 
     // initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays,
     // so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes.
     mGLMaxVertexAttribs = 0;
     mGLMaxTextureUnits = 0;
     mGLMaxTextureSize = 0;
     mGLMaxCubeMapTextureSize = 0;
     mGLMaxRenderbufferSize = 0;
@@ -1322,23 +1324,31 @@ WebGLContext::ForceClearFramebufferWithD
     if (initializeStencilBuffer) {
         // "The clear operation always uses the front stencil write mask
         //  when clearing the stencil buffer."
         gl->fStencilMaskSeparate(LOCAL_GL_FRONT, 0xffffffff);
         gl->fStencilMaskSeparate(LOCAL_GL_BACK,  0xffffffff);
         gl->fClearStencil(0);
     }
 
+    if (mRasterizerDiscardEnabled) {
+        gl->fDisable(LOCAL_GL_RASTERIZER_DISCARD);
+    }
+
     // Do the clear!
     gl->fClear(mask);
 
     // And reset!
     if (mScissorTestEnabled)
         gl->fEnable(LOCAL_GL_SCISSOR_TEST);
 
+    if (mRasterizerDiscardEnabled) {
+        gl->fEnable(LOCAL_GL_RASTERIZER_DISCARD);
+    }
+
     // Restore GL state after clearing.
     if (initializeColorBuffer) {
         if (drawBuffersIsEnabled) {
             gl->fDrawBuffers(mGLMaxDrawBuffers, currentDrawBuffers);
         }
 
         gl->fColorMask(mColorWriteMask[0],
                        mColorWriteMask[1],
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -20,17 +20,16 @@
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "nsWrapperCache.h"
 #include "nsIObserver.h"
 
 #include "GLContextProvider.h"
 
 #include "mozilla/LinkedList.h"
 #include "mozilla/CheckedInt.h"
-#include "mozilla/dom/ImageData.h"
 
 #ifdef XP_MACOSX
 #include "ForceDiscreteGPUHelperCGL.h"
 #endif
 
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/ErrorResult.h"
 
@@ -68,16 +67,18 @@ class WebGLQuery;
 class WebGLUniformLocation;
 class WebGLFramebuffer;
 class WebGLRenderbuffer;
 class WebGLShaderPrecisionFormat;
 class WebGLTexture;
 class WebGLVertexArray;
 
 namespace dom {
+class ImageData;
+
 struct WebGLContextAttributes;
 struct WebGLContextAttributesInitializer;
 template<typename> class Nullable;
 }
 
 using WebGLTexelConversions::WebGLTexelFormat;
 
 WebGLTexelFormat GetWebGLTexelFormat(GLenum format, GLenum type);
@@ -775,17 +776,23 @@ private:
 public:
     void Disable(WebGLenum cap);
     void Enable(WebGLenum cap);
     JS::Value GetParameter(JSContext* cx, WebGLenum pname, ErrorResult& rv);
     JS::Value GetParameterIndexed(JSContext* cx, WebGLenum pname, WebGLuint index);
     bool IsEnabled(WebGLenum cap);
 
 private:
+    // State tracking slots
+    realGLboolean mDitherEnabled;
+    realGLboolean mRasterizerDiscardEnabled;
+    realGLboolean mScissorTestEnabled;
+
     bool ValidateCapabilityEnum(WebGLenum cap, const char* info);
+    realGLboolean* GetStateTrackingSlot(WebGLenum cap);
 
 // -----------------------------------------------------------------------------
 // Vertices Feature (WebGLContextVertices.cpp)
 public:
     void DrawArrays(GLenum mode, WebGLint first, WebGLsizei count);
     void DrawArraysInstanced(GLenum mode, WebGLint first, WebGLsizei count, WebGLsizei primcount);
     void DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, WebGLintptr byteOffset);
     void DrawElementsInstanced(WebGLenum mode, WebGLsizei count, WebGLenum type,
@@ -1161,18 +1168,16 @@ protected:
     GLuint mFakeVertexAttrib0BufferObject;
     int mFakeVertexAttrib0BufferStatus;
 
     WebGLint mStencilRefFront, mStencilRefBack;
     WebGLuint mStencilValueMaskFront, mStencilValueMaskBack,
               mStencilWriteMaskFront, mStencilWriteMaskBack;
     realGLboolean mColorWriteMask[4];
     realGLboolean mDepthWriteMask;
-    realGLboolean mScissorTestEnabled;
-    realGLboolean mDitherEnabled;
     WebGLfloat mColorClearValue[4];
     WebGLint mStencilClearValue;
     WebGLfloat mDepthClearValue;
 
     nsCOMPtr<nsITimer> mContextRestorer;
     bool mAllowRestore;
     bool mContextLossTimerRunning;
     bool mDrawSinceContextLossTimerSet;
--- a/content/canvas/src/WebGLContextFramebufferOperations.cpp
+++ b/content/canvas/src/WebGLContextFramebufferOperations.cpp
@@ -19,16 +19,18 @@ WebGLContext::Clear(WebGLbitfield mask)
     MakeContextCurrent();
 
     uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
     if (mask != m)
         return ErrorInvalidValue("clear: invalid mask bits");
 
     if (mask == 0) {
         GenerateWarning("Calling gl.clear(0) has no effect.");
+    } else if (mRasterizerDiscardEnabled) {
+        GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
     }
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
             return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
 
         gl->fClear(mask);
         return;
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -37,16 +37,17 @@
 #include <algorithm>
 
 // needed to check if current OS is lower than 10.7
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ImageData.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gl;
 
 static bool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize);
 static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2);
 
--- a/content/canvas/src/WebGLContextState.cpp
+++ b/content/canvas/src/WebGLContextState.cpp
@@ -20,45 +20,41 @@ void
 WebGLContext::Disable(WebGLenum cap)
 {
     if (!IsContextStable())
         return;
 
     if (!ValidateCapabilityEnum(cap, "disable"))
         return;
 
-    switch(cap) {
-        case LOCAL_GL_SCISSOR_TEST:
-            mScissorTestEnabled = 0;
-            break;
-        case LOCAL_GL_DITHER:
-            mDitherEnabled = 0;
-            break;
+    realGLboolean* trackingSlot = GetStateTrackingSlot(cap);
+
+    if (trackingSlot)
+    {
+        *trackingSlot = 0;
     }
 
     MakeContextCurrent();
     gl->fDisable(cap);
 }
 
 void
 WebGLContext::Enable(WebGLenum cap)
 {
     if (!IsContextStable())
         return;
 
     if (!ValidateCapabilityEnum(cap, "enable"))
         return;
 
-    switch(cap) {
-        case LOCAL_GL_SCISSOR_TEST:
-            mScissorTestEnabled = 1;
-            break;
-        case LOCAL_GL_DITHER:
-            mDitherEnabled = 1;
-            break;
+    realGLboolean* trackingSlot = GetStateTrackingSlot(cap);
+
+    if (trackingSlot)
+    {
+        *trackingSlot = 1;
     }
 
     MakeContextCurrent();
     gl->fEnable(cap);
 }
 
 static JS::Value
 StringValue(JSContext* cx, const char* chars, ErrorResult& rv)
@@ -542,8 +538,23 @@ WebGLContext::ValidateCapabilityEnum(Web
             return true;
         case LOCAL_GL_RASTERIZER_DISCARD:
             return IsWebGL2();
         default:
             ErrorInvalidEnumInfo(info, cap);
             return false;
     }
 }
+
+realGLboolean*
+WebGLContext::GetStateTrackingSlot(WebGLenum cap)
+{
+    switch (cap) {
+        case LOCAL_GL_SCISSOR_TEST:
+            return &mScissorTestEnabled;
+        case LOCAL_GL_DITHER:
+            return &mDitherEnabled;
+        case LOCAL_GL_RASTERIZER_DISCARD:
+            return &mRasterizerDiscardEnabled;
+    }
+
+    return nullptr;
+}
--- a/content/events/src/DOMWheelEvent.cpp
+++ b/content/events/src/DOMWheelEvent.cpp
@@ -145,17 +145,17 @@ GetModifierList(bool aCtrl, bool aShift,
 }
 
 already_AddRefed<DOMWheelEvent>
 DOMWheelEvent::Constructor(const GlobalObject& aGlobal,
                            const nsAString& aType,
                            const WheelEventInit& aParam,
                            mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<DOMWheelEvent> e = new DOMWheelEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   nsAutoString modifierList;
   GetModifierList(aParam.mCtrlKey, aParam.mShiftKey,
                   aParam.mAltKey, aParam.mMetaKey,
                   modifierList);
   aRv = e->InitWheelEvent(aType, aParam.mBubbles, aParam.mCancelable,
                           aParam.mView, aParam.mDetail,
--- a/content/events/src/SpeechRecognitionError.cpp
+++ b/content/events/src/SpeechRecognitionError.cpp
@@ -17,17 +17,17 @@ SpeechRecognitionError::SpeechRecognitio
 SpeechRecognitionError::~SpeechRecognitionError() {}
 
 already_AddRefed<SpeechRecognitionError>
 SpeechRecognitionError::Constructor(const GlobalObject& aGlobal,
                                     const nsAString& aType,
                                     const SpeechRecognitionErrorInit& aParam,
                                     ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<SpeechRecognitionError> e = new SpeechRecognitionError(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   e->InitSpeechRecognitionError(aType, aParam.mBubbles, aParam.mCancelable, aParam.mError, aParam.mMessage, aRv);
   e->SetTrusted(trusted);
   return e.forget();
 }
 
 void
--- a/content/events/src/SpeechRecognitionError.h
+++ b/content/events/src/SpeechRecognitionError.h
@@ -15,20 +15,21 @@ namespace dom {
 class SpeechRecognitionError : public nsDOMEvent
 {
 public:
   SpeechRecognitionError(mozilla::dom::EventTarget* aOwner,
                          nsPresContext* aPresContext,
                          nsEvent* aEvent);
   virtual ~SpeechRecognitionError();
 
-  static already_AddRefed<SpeechRecognitionError> Constructor(const GlobalObject& aGlobal,
-                                                              const nsAString& aType,
-                                                              const SpeechRecognitionErrorInit& aParam,
-                                                              ErrorResult& aRv);
+  static already_AddRefed<SpeechRecognitionError>
+  Constructor(const GlobalObject& aGlobal,
+              const nsAString& aType,
+              const SpeechRecognitionErrorInit& aParam,
+              ErrorResult& aRv);
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
   {
     return mozilla::dom::SpeechRecognitionErrorBinding::Wrap(aCx, aScope, this);
   }
 
   void
   GetMessage(nsAString& aString)
--- a/content/events/src/nsDOMAnimationEvent.cpp
+++ b/content/events/src/nsDOMAnimationEvent.cpp
@@ -42,17 +42,17 @@ NS_IMPL_RELEASE_INHERITED(nsDOMAnimation
 
 //static
 already_AddRefed<nsDOMAnimationEvent>
 nsDOMAnimationEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                                  const nsAString& aType,
                                  const mozilla::dom::AnimationEventInit& aParam,
                                  mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<nsDOMAnimationEvent> e = new nsDOMAnimationEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
 
   aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
 
   e->AnimationEvent()->animationName = aParam.mAnimationName;
   e->AnimationEvent()->elapsedTime = aParam.mElapsedTime;
   e->AnimationEvent()->pseudoElement = aParam.mPseudoElement;
--- a/content/events/src/nsDOMClipboardEvent.cpp
+++ b/content/events/src/nsDOMClipboardEvent.cpp
@@ -51,17 +51,17 @@ nsDOMClipboardEvent::InitClipboardEvent(
 }
 
 already_AddRefed<nsDOMClipboardEvent>
 nsDOMClipboardEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                                  const nsAString& aType,
                                  const mozilla::dom::ClipboardEventInit& aParam,
                                  mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<nsDOMClipboardEvent> e =
     new nsDOMClipboardEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
 
   nsRefPtr<nsDOMDataTransfer> clipboardData;
   if (e->mEventIsInternal) {
     nsClipboardEvent* event = static_cast<nsClipboardEvent*>(e->mEvent);
     if (event) {
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -351,17 +351,17 @@ nsDOMEvent::Init(mozilla::dom::EventTarg
 
 //static
 already_AddRefed<nsDOMEvent>
 nsDOMEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                         const nsAString& aType,
                         const mozilla::dom::EventInit& aParam,
                         mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<nsDOMEvent> e = new nsDOMEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
   e->SetTrusted(trusted);
   return e.forget();
 }
 
 uint16_t
--- a/content/events/src/nsDOMFocusEvent.cpp
+++ b/content/events/src/nsDOMFocusEvent.cpp
@@ -63,17 +63,17 @@ nsDOMFocusEvent::InitFocusEvent(const ns
 }
 
 already_AddRefed<nsDOMFocusEvent>
 nsDOMFocusEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                              const nsAString& aType,
                              const mozilla::dom::FocusEventInit& aParam,
                              mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<nsDOMFocusEvent> e = new nsDOMFocusEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   aRv = e->InitFocusEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
                           aParam.mDetail, aParam.mRelatedTarget);
   e->SetTrusted(trusted);
   return e.forget();
 }
 
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -147,17 +147,17 @@ nsDOMMouseEvent::InitMouseEvent(const ns
 }
 
 already_AddRefed<nsDOMMouseEvent>
 nsDOMMouseEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                              const nsAString& aType,
                              const mozilla::dom::MouseEventInit& aParam,
                              mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<nsDOMMouseEvent> e = new nsDOMMouseEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable,
                     aParam.mView, aParam.mDetail, aParam.mScreenX,
                     aParam.mScreenY, aParam.mClientX, aParam.mClientY,
                     aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey,
                     aParam.mMetaKey, aParam.mButton, aParam.mRelatedTarget,
                     aRv);
--- a/content/events/src/nsDOMTransitionEvent.cpp
+++ b/content/events/src/nsDOMTransitionEvent.cpp
@@ -42,17 +42,17 @@ NS_IMPL_RELEASE_INHERITED(nsDOMTransitio
 
 //static
 already_AddRefed<nsDOMTransitionEvent>
 nsDOMTransitionEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                                   const nsAString& aType,
                                   const mozilla::dom::TransitionEventInit& aParam,
                                   mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<nsDOMTransitionEvent> e = new nsDOMTransitionEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
 
   aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
 
   e->TransitionEvent()->propertyName = aParam.mPropertyName;
   e->TransitionEvent()->elapsedTime = aParam.mElapsedTime;
   e->TransitionEvent()->pseudoElement = aParam.mPseudoElement;
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -77,17 +77,17 @@ nsDOMUIEvent::nsDOMUIEvent(mozilla::dom:
 
 //static
 already_AddRefed<nsDOMUIEvent>
 nsDOMUIEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
                           const nsAString& aType,
                           const mozilla::dom::UIEventInit& aParam,
                           mozilla::ErrorResult& aRv)
 {
-  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   nsRefPtr<nsDOMUIEvent> e = new nsDOMUIEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   aRv = e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
                        aParam.mDetail);
   e->SetTrusted(trusted);
   return e.forget();
 }
 
--- a/content/html/content/public/HTMLAudioElement.h
+++ b/content/html/content/public/HTMLAudioElement.h
@@ -41,19 +41,19 @@ public:
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel);
 
   virtual nsIDOMNode* AsDOMNode() MOZ_OVERRIDE { return this; }
 
   // WebIDL
 
-  static already_AddRefed<HTMLAudioElement> Audio(const GlobalObject& global,
-                                                  const Optional<nsAString>& src,
-                                                  ErrorResult& aRv);
+  static already_AddRefed<HTMLAudioElement>
+  Audio(const GlobalObject& aGlobal,
+        const Optional<nsAString>& aSrc, ErrorResult& aRv);
 
   void MozSetup(uint32_t aChannels, uint32_t aRate, ErrorResult& aRv);
 
   uint32_t MozWriteAudio(const Float32Array& aData, ErrorResult& aRv)
   {
     return MozWriteAudio(aData.Data(), aData.Length(), aRv);
   }
   uint32_t MozWriteAudio(const Sequence<float>& aData, ErrorResult& aRv)
--- a/content/html/content/src/HTMLAudioElement.cpp
+++ b/content/html/content/src/HTMLAudioElement.cpp
@@ -48,17 +48,17 @@ HTMLAudioElement::~HTMLAudioElement()
 }
 
 
 already_AddRefed<HTMLAudioElement>
 HTMLAudioElement::Audio(const GlobalObject& aGlobal,
                         const Optional<nsAString>& aSrc,
                         ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
   nsIDocument* doc;
   if (!win || !(doc = win->GetExtantDoc())) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsINodeInfo> nodeInfo =
     doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::audio, nullptr,
--- a/content/html/content/src/HTMLImageElement.cpp
+++ b/content/html/content/src/HTMLImageElement.cpp
@@ -524,19 +524,20 @@ HTMLImageElement::IntrinsicState() const
   return nsGenericHTMLElement::IntrinsicState() |
     nsImageLoadingContent::ImageState();
 }
 
 // static
 already_AddRefed<HTMLImageElement>
 HTMLImageElement::Image(const GlobalObject& aGlobal,
                         const Optional<uint32_t>& aWidth,
-                        const Optional<uint32_t>& aHeight, ErrorResult& aError)
+                        const Optional<uint32_t>& aHeight,
+                        ErrorResult& aError)
 {
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
   nsIDocument* doc;
   if (!win || !(doc = win->GetExtantDoc())) {
     aError.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsINodeInfo> nodeInfo =
     doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::img, nullptr,
--- a/content/html/content/src/HTMLImageElement.h
+++ b/content/html/content/src/HTMLImageElement.h
@@ -20,18 +20,20 @@ class HTMLImageElement MOZ_FINAL : publi
                                    public nsImageLoadingContent,
                                    public nsIDOMHTMLImageElement
 {
 public:
   explicit HTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~HTMLImageElement();
 
   static already_AddRefed<HTMLImageElement>
-    Image(const GlobalObject& aGlobal, const Optional<uint32_t>& aWidth,
-          const Optional<uint32_t>& aHeight, ErrorResult& aError);
+    Image(const GlobalObject& aGlobal,
+          const Optional<uint32_t>& aWidth,
+          const Optional<uint32_t>& aHeight,
+          ErrorResult& aError);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual bool Draggable() const MOZ_OVERRIDE;
 
   // nsIDOMHTMLImageElement
   NS_DECL_NSIDOMHTMLIMAGEELEMENT
--- a/content/html/content/src/HTMLOptionElement.cpp
+++ b/content/html/content/src/HTMLOptionElement.cpp
@@ -330,17 +330,17 @@ HTMLOptionElement::GetSelect()
 
 already_AddRefed<HTMLOptionElement>
 HTMLOptionElement::Option(const GlobalObject& aGlobal,
                           const Optional<nsAString>& aText,
                           const Optional<nsAString>& aValue,
                           const Optional<bool>& aDefaultSelected,
                           const Optional<bool>& aSelected, ErrorResult& aError)
 {
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
   nsIDocument* doc;
   if (!win || !(doc = win->GetExtantDoc())) {
     aError.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsINodeInfo> nodeInfo =
     doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::option, nullptr,
--- a/content/html/content/src/HTMLOptionElement.h
+++ b/content/html/content/src/HTMLOptionElement.h
@@ -21,17 +21,18 @@ class HTMLSelectElement;
 class HTMLOptionElement MOZ_FINAL : public nsGenericHTMLElement,
                                     public nsIDOMHTMLOptionElement
 {
 public:
   HTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~HTMLOptionElement();
 
   static already_AddRefed<HTMLOptionElement>
-    Option(const GlobalObject& aGlobal, const Optional<nsAString>& aText,
+    Option(const GlobalObject& aGlobal,
+           const Optional<nsAString>& aText,
            const Optional<nsAString>& aValue,
            const Optional<bool>& aDefaultSelected,
            const Optional<bool>& aSelected, ErrorResult& aError);
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLOptionElement, option)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -119,17 +119,17 @@ MediaRecorder::~MediaRecorder()
     mStreamPort->Destroy();
   }
   if (mTrackUnionStream) {
     mTrackUnionStream->Destroy();
   }
 }
 
 void
-MediaRecorder::Init(JSContext* aCx, nsPIDOMWindow* aOwnerWindow)
+MediaRecorder::Init(nsPIDOMWindow* aOwnerWindow)
 {
   MOZ_ASSERT(aOwnerWindow);
   MOZ_ASSERT(aOwnerWindow->IsInnerWindow());
   BindToOwner(aOwnerWindow);
 }
 
 MediaRecorder::MediaRecorder(DOMMediaStream& aStream)
   : mTimeSlice(0),
@@ -268,33 +268,33 @@ MediaRecorder::RequestData(ErrorResult& 
 
 JSObject*
 MediaRecorder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return MediaRecorderBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */ already_AddRefed<MediaRecorder>
-MediaRecorder::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
+MediaRecorder::Constructor(const GlobalObject& aGlobal,
                            DOMMediaStream& aStream, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports());
   if (!sgo) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
   if (!ownerWindow) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<MediaRecorder> object = new MediaRecorder(aStream);
-  object->Init(aCx, ownerWindow);
+  object->Init(ownerWindow);
   return object.forget();
 }
 
 nsresult
 MediaRecorder::CreateAndDispatchBlobEvent()
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
--- a/content/media/MediaRecorder.h
+++ b/content/media/MediaRecorder.h
@@ -68,29 +68,29 @@ public:
   // Return the The DOMMediaStream passed from UA.
   DOMMediaStream* Stream() const { return mStream; }
   // The current state of the MediaRecorder object.
   RecordingState State() const { return mState; }
   // Return the current encoding MIME type selected by the MediaEncoder.
   void GetMimeType(nsString &aMimeType) { aMimeType = mMimeType; }
 
   static already_AddRefed<MediaRecorder>
-  Constructor(const GlobalObject& aGlobal, JSContext* aCx, DOMMediaStream& aStream,
-              ErrorResult& aRv);
+  Constructor(const GlobalObject& aGlobal,
+              DOMMediaStream& aStream, ErrorResult& aRv);
 
   // EventHandler
   IMPL_EVENT_HANDLER(dataavailable)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(stop)
   IMPL_EVENT_HANDLER(warning)
 
   friend class ExtractEncodedData;
 
 protected:
-  void Init(JSContext* aCx, nsPIDOMWindow* aOwnerWindow);
+  void Init(nsPIDOMWindow* aOwnerWindow);
   // Copy encoded data from encoder to EncodedBufferCache. This function runs in the Media Encoder Thread.
   void ExtractEncodedData();
 
   MediaRecorder& operator = (const MediaRecorder& x) MOZ_DELETE;
   // Create dataavailable event with Blob data and it runs in main thread
   nsresult CreateAndDispatchBlobEvent();
   // Creating a simple event to notify UA simple event.
   void DispatchSimpleEvent(const nsAString & aStr);
--- a/content/media/TextTrackCue.h
+++ b/content/media/TextTrackCue.h
@@ -32,17 +32,17 @@ public:
   // See bug 868509 about splitting out the WebVTT-specific interfaces.
   static already_AddRefed<TextTrackCue>
   Constructor(GlobalObject& aGlobal,
               double aStartTime,
               double aEndTime,
               const nsAString& aText,
               ErrorResult& aRv)
   {
-    nsRefPtr<TextTrackCue> ttcue = new TextTrackCue(aGlobal.Get(), aStartTime,
+    nsRefPtr<TextTrackCue> ttcue = new TextTrackCue(aGlobal.GetAsSupports(), aStartTime,
                                                     aEndTime, aText, aRv);
     return ttcue.forget();
   }
   TextTrackCue(nsISupports* aGlobal, double aStartTime, double aEndTime,
                const nsAString& aText, ErrorResult& aRv);
 
   TextTrackCue(nsISupports* aGlobal, double aStartTime, double aEndTime,
                const nsAString& aText, HTMLTrackElement* aTrackElement,
--- a/content/media/mediasource/MediaSource.cpp
+++ b/content/media/mediasource/MediaSource.cpp
@@ -26,19 +26,20 @@ already_AddRefed<nsIInputStream>
 MediaSource::CreateInternalStream()
 {
   nsRefPtr<MediaSourceInputAdapter> adapter = new MediaSourceInputAdapter(this);
   mAdapters.AppendElement(adapter);
   return adapter.forget();
 }
 
 /* static */ already_AddRefed<MediaSource>
-MediaSource::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+MediaSource::Constructor(const GlobalObject& aGlobal,
+                         ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<MediaSource> mediaSource = new MediaSource(window);
   return mediaSource.forget();
 }
@@ -146,17 +147,18 @@ MediaSource::EndOfStream(const Optional<
       mSourceBuffers->AnyUpdating()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
   EndOfStreamInternal(aError, aRv);
 }
 
 /* static */ bool
-MediaSource::IsTypeSupported(const GlobalObject& aGlobal, const nsAString& aType)
+MediaSource::IsTypeSupported(const GlobalObject& aGlobal,
+                             const nsAString& aType)
 {
   ErrorResult unused;
   return IsTypeSupportedInternal(aType, unused);
 }
 
 void
 MediaSource::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
 {
--- a/content/media/mediasource/MediaSource.h
+++ b/content/media/mediasource/MediaSource.h
@@ -30,30 +30,33 @@ class TimeRanges;
 #define MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID \
   { 0x3839d699, 0x22c5, 0x439f, \
   { 0x94, 0xca, 0x0e, 0x0b, 0x26, 0xf9, 0xca, 0xbf } }
 
 class MediaSource MOZ_FINAL : public nsDOMEventTargetHelper
 {
 public:
   /** WebIDL Methods. */
-  static already_AddRefed<MediaSource> Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+  static already_AddRefed<MediaSource>
+  Constructor(const GlobalObject& aGlobal,
+              ErrorResult& aRv);
 
   SourceBufferList* SourceBuffers();
   SourceBufferList* ActiveSourceBuffers();
   MediaSourceReadyState ReadyState();
 
   double Duration();
   void SetDuration(double aDuration, ErrorResult& aRv);
 
   already_AddRefed<SourceBuffer> AddSourceBuffer(const nsAString& aType, ErrorResult& aRv);
   void RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv);
 
   void EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv);
-  static bool IsTypeSupported(const GlobalObject& aGlobal, const nsAString& aType);
+  static bool IsTypeSupported(const GlobalObject& aGlobal,
+                              const nsAString& aType);
   /** End WebIDL Methods. */
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaSource, nsDOMEventTargetHelper)
   NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)
 
   nsPIDOMWindow* GetParentObject() const;
 
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -79,19 +79,20 @@ AudioContext::WrapObject(JSContext* aCx,
   if (mIsOffline) {
     return OfflineAudioContextBinding::Wrap(aCx, aScope, this);
   } else {
     return AudioContextBinding::Wrap(aCx, aScope, this);
   }
 }
 
 /* static */ already_AddRefed<AudioContext>
-AudioContext::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+AudioContext::Constructor(const GlobalObject& aGlobal,
+                          ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<AudioContext> object = new AudioContext(window, false);
   window->AddAudioContext(object);
   return object.forget();
@@ -99,17 +100,17 @@ AudioContext::Constructor(const GlobalOb
 
 /* static */ already_AddRefed<AudioContext>
 AudioContext::Constructor(const GlobalObject& aGlobal,
                           uint32_t aNumberOfChannels,
                           uint32_t aLength,
                           float aSampleRate,
                           ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   if (aNumberOfChannels == 0 ||
       aNumberOfChannels > WebAudioUtils::MaxChannelCount ||
       aLength == 0 ||
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -44,19 +44,19 @@ class AudioDestinationNode;
 class AudioListener;
 class BiquadFilterNode;
 class ChannelMergerNode;
 class ChannelSplitterNode;
 class ConvolverNode;
 class DelayNode;
 class DynamicsCompressorNode;
 class GainNode;
-class GlobalObject;
 class HTMLMediaElement;
 class MediaElementAudioSourceNode;
+class GlobalObject;
 class MediaStreamAudioDestinationNode;
 class MediaStreamAudioSourceNode;
 class OscillatorNode;
 class PannerNode;
 class ScriptProcessorNode;
 class WaveShaperNode;
 class PeriodicWave;
 
--- a/content/media/webspeech/recognition/SpeechGrammar.cpp
+++ b/content/media/webspeech/recognition/SpeechGrammar.cpp
@@ -26,19 +26,20 @@ SpeechGrammar::SpeechGrammar(nsISupports
   SetIsDOMBinding();
 }
 
 SpeechGrammar::~SpeechGrammar()
 {
 }
 
 SpeechGrammar*
-SpeechGrammar::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+SpeechGrammar::Constructor(const GlobalObject& aGlobal,
+                           ErrorResult& aRv)
 {
-  return new SpeechGrammar(aGlobal.Get());
+  return new SpeechGrammar(aGlobal.GetAsSupports());
 }
 
 nsISupports*
 SpeechGrammar::GetParentObject() const
 {
   return mParent;
 }
 
--- a/content/media/webspeech/recognition/SpeechGrammar.h
+++ b/content/media/webspeech/recognition/SpeechGrammar.h
@@ -34,17 +34,18 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechGrammar)
 
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
-  static SpeechGrammar* Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+  static SpeechGrammar* Constructor(const GlobalObject& aGlobal,
+                                    ErrorResult& aRv);
 
   void GetSrc(nsString& aRetVal, ErrorResult& aRv) const;
 
   void SetSrc(const nsAString& aArg, ErrorResult& aRv);
 
   float GetWeight(ErrorResult& aRv) const;
 
   void SetWeight(float aArg, ErrorResult& aRv);
--- a/content/media/webspeech/recognition/SpeechGrammarList.cpp
+++ b/content/media/webspeech/recognition/SpeechGrammarList.cpp
@@ -25,19 +25,20 @@ SpeechGrammarList::SpeechGrammarList(nsI
   SetIsDOMBinding();
 }
 
 SpeechGrammarList::~SpeechGrammarList()
 {
 }
 
 SpeechGrammarList*
-SpeechGrammarList::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+SpeechGrammarList::Constructor(const GlobalObject& aGlobal,
+                               ErrorResult& aRv)
 {
-  return new SpeechGrammarList(aGlobal.Get());
+  return new SpeechGrammarList(aGlobal.GetAsSupports());
 }
 
 JSObject*
 SpeechGrammarList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SpeechGrammarListBinding::Wrap(aCx, aScope, this);
 }
 
--- a/content/media/webspeech/recognition/SpeechGrammarList.h
+++ b/content/media/webspeech/recognition/SpeechGrammarList.h
@@ -28,17 +28,18 @@ class SpeechGrammarList MOZ_FINAL : publ
 {
 public:
   SpeechGrammarList(nsISupports* aParent);
   ~SpeechGrammarList();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechGrammarList)
 
-  SpeechGrammarList* Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+  SpeechGrammarList* Constructor(const GlobalObject& aGlobal,
+                                 ErrorResult& aRv);
 
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   uint32_t Length() const;
 
--- a/content/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognition.cpp
@@ -102,19 +102,20 @@ SpeechRecognition::SetState(FSMState sta
 
 JSObject*
 SpeechRecognition::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return SpeechRecognitionBinding::Wrap(aCx, aScope, this);
 }
 
 already_AddRefed<SpeechRecognition>
-SpeechRecognition::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+SpeechRecognition::Constructor(const GlobalObject& aGlobal,
+                               ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
   }
 
   MOZ_ASSERT(win->IsInnerWindow());
   nsRefPtr<SpeechRecognition> object = new SpeechRecognition();
   object->BindToOwner(win);
   return object.forget();
--- a/content/media/webspeech/recognition/SpeechRecognition.h
+++ b/content/media/webspeech/recognition/SpeechRecognition.h
@@ -65,17 +65,18 @@ public:
 
   NS_DECL_NSIOBSERVER
 
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
-  static already_AddRefed<SpeechRecognition> Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+  static already_AddRefed<SpeechRecognition>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
   already_AddRefed<SpeechGrammarList> GetGrammars(ErrorResult& aRv) const;
 
   void SetGrammars(mozilla::dom::SpeechGrammarList& aArg, ErrorResult& aRv);
 
   void GetLang(nsString& aRetVal, ErrorResult& aRv) const;
 
   void SetLang(const nsAString& aArg, ErrorResult& aRv);
--- a/content/media/webspeech/synth/SpeechSynthesisUtterance.cpp
+++ b/content/media/webspeech/synth/SpeechSynthesisUtterance.cpp
@@ -58,17 +58,17 @@ SpeechSynthesisUtterance::Constructor(Gl
   return Constructor(aGlobal, NS_LITERAL_STRING(""), aRv);
 }
 
 already_AddRefed<SpeechSynthesisUtterance>
 SpeechSynthesisUtterance::Constructor(GlobalObject& aGlobal,
                                       const nsAString& aText,
                                       ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
 
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
   }
 
   MOZ_ASSERT(win->IsInnerWindow());
   nsRefPtr<SpeechSynthesisUtterance> object =
     new SpeechSynthesisUtterance(aText);
--- a/content/xslt/src/xpath/nsXPathEvaluator.cpp
+++ b/content/xslt/src/xpath/nsXPathEvaluator.cpp
@@ -216,17 +216,18 @@ nsXPathEvaluator::CreateExpression(const
 JSObject*
 nsXPathEvaluator::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
     return dom::XPathEvaluatorBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */
 already_AddRefed<nsXPathEvaluator>
-nsXPathEvaluator::Constructor(const GlobalObject& aGlobal, ErrorResult& rv)
+nsXPathEvaluator::Constructor(const GlobalObject& aGlobal,
+                              ErrorResult& rv)
 {
     nsRefPtr<nsXPathEvaluator> newObj = new nsXPathEvaluator(nullptr);
     newObj->Init();
     return newObj.forget();
 }
 
 already_AddRefed<nsIDOMXPathExpression>
 nsXPathEvaluator::CreateExpression(const nsAString& aExpression,
--- a/dom/activities/src/Activity.h
+++ b/dom/activities/src/Activity.h
@@ -33,17 +33,17 @@ public:
   }
 
   static already_AddRefed<Activity>
   Constructor(const GlobalObject& aOwner,
               nsIDOMMozActivityOptions* aOptions,
               ErrorResult& aRv)
   {
     nsRefPtr<Activity> activity = new Activity();
-    aRv = activity->Initialize(aOwner.Get(), aOptions);
+    aRv = activity->Initialize(aOwner.GetAsSupports(), aOptions);
     return activity.forget();
   }
 
   Activity();
 
 protected:
   nsresult Initialize(nsISupports* aOwner,
                       nsIDOMMozActivityOptions* aOptions);
--- a/dom/alarm/nsIAlarmHalService.idl
+++ b/dom/alarm/nsIAlarmHalService.idl
@@ -16,17 +16,17 @@ interface nsITimezoneChangedCb : nsISupp
   void onTimezoneChanged(in int32_t aTimezoneOffset);
 };
 
 %{C++
 #define NS_ALARMHALSERVICE_CID { 0x7dafea4c, 0x7163, 0x4b70, { 0x95, 0x4e, 0x5a, 0xd4, 0x09, 0x94, 0x83, 0xd7 } }
 #define ALARMHALSERVICE_CONTRACTID "@mozilla.org/alarmHalService;1"
 %}
 
-[scriptable, builtinclass, uuid(057b1ee4-f696-486d-bd55-205e21e88fab)]
+[scriptable, uuid(057b1ee4-f696-486d-bd55-205e21e88fab)]
 interface nsIAlarmHalService : nsISupports
 {
   bool setAlarm(in int32_t aSeconds, in int32_t aNanoseconds);
   void setAlarmFiredCb(in nsIAlarmFiredCb aAlarmFiredCb);
   void setTimezoneChangedCb(in nsITimezoneChangedCb aTimezoneChangedCb);
 };
 
 
--- a/dom/base/DOMError.cpp
+++ b/dom/base/DOMError.cpp
@@ -60,20 +60,21 @@ DOMError::~DOMError()
 
 JSObject*
 DOMError::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return DOMErrorBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */ already_AddRefed<DOMError>
-DOMError::Constructor(const GlobalObject& aGlobal, const nsAString& aName,
-                      const nsAString& aMessage, ErrorResult& aRv)
+DOMError::Constructor(const GlobalObject& aGlobal,
+                      const nsAString& aName, const nsAString& aMessage,
+                      ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
 
   // Window is null for chrome code.
 
   nsRefPtr<DOMError> ret = new DOMError(window, aName, aMessage);
   return ret.forget();
 }
 
 } // namespace dom
--- a/dom/base/IndexedDBHelper.jsm
+++ b/dom/base/IndexedDBHelper.jsm
@@ -63,17 +63,17 @@ IndexedDBHelper.prototype = {
         debug("Database needs upgrade:" + self.dbName + aEvent.oldVersion + aEvent.newVersion);
         debug("Correct new database version:" + (aEvent.newVersion == this.dbVersion));
       }
 
       let _db = aEvent.target.result;
       self.upgradeSchema(req.transaction, _db, aEvent.oldVersion, aEvent.newVersion);
     };
     req.onerror = function (aEvent) {
-      if (DEBUG) debug("Failed to open database:" + self.dbName);
+      if (DEBUG) debug("Failed to open database: " + self.dbName);
       aFailureCb(aEvent.target.error.name);
     };
     req.onblocked = function (aEvent) {
       if (DEBUG) debug("Opening database request is blocked.");
     };
   },
 
   /**
--- a/dom/base/StructuredCloneTags.h
+++ b/dom/base/StructuredCloneTags.h
@@ -1,15 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef StructuredCloneTags_h__
 #define StructuredCloneTags_h__
 
+#include "js/StructuredClone.h"
+
 namespace mozilla {
 namespace dom {
 
 // CHANGING THE ORDER/PLACEMENT OF EXISTING ENUM VALUES MAY BREAK INDEXEDDB.
 // PROCEED WITH EXTREME CAUTION.
 enum StructuredCloneTags {
   SCTAG_BASE = JS_SCTAG_USER_MIN,
 
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -12,44 +12,45 @@
 #include "nsIDocument.h"
 #include "nsIPrincipal.h"
 #include "nsHostObjectProtocolHandler.h"
 
 namespace mozilla {
 namespace dom {
 
 void
-URL::CreateObjectURL(const GlobalObject& aGlobal, nsIDOMBlob* aBlob,
+URL::CreateObjectURL(const GlobalObject& aGlobal,
+                     nsIDOMBlob* aBlob,
                      const objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal.Get(), aBlob,
+  CreateObjectURLInternal(aGlobal.GetAsSupports(), aBlob,
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal.Get(), &aStream,
+  CreateObjectURLInternal(aGlobal.GetAsSupports(), &aStream,
                           NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME), aOptions,
                           aResult, aError);
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
                      const objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal.Get(), &aSource,
+  CreateObjectURLInternal(aGlobal.GetAsSupports(), &aSource,
                           NS_LITERAL_CSTRING(MEDIASOURCEURI_SCHEME), aOptions,
                           aResult, aError);
 }
 
 void
 URL::CreateObjectURLInternal(nsISupports* aGlobal, nsISupports* aObject,
                              const nsACString& aScheme,
                              const mozilla::dom::objectURLOptions& aOptions,
@@ -78,17 +79,17 @@ URL::CreateObjectURLInternal(nsISupports
 
   doc->RegisterHostObjectUri(url);
   CopyASCIItoUTF16(url, aResult);
 }
 
 void
 URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL)
 {
-  nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
   nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
   NS_PRECONDITION(!window || window->IsInnerWindow(),
                   "Should be inner window");
   if (!window)
     return;
 
   NS_LossyConvertUTF16toASCII asciiurl(aURL);
 
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -21,17 +21,18 @@ namespace dom {
 class MediaSource;
 class GlobalObject;
 struct objectURLOptions;
 
 class URL MOZ_FINAL
 {
 public:
   // WebIDL methods
-  static void CreateObjectURL(const GlobalObject& aGlobal, nsIDOMBlob* aBlob,
+  static void CreateObjectURL(const GlobalObject& aGlobal,
+                              nsIDOMBlob* aBlob,
                               const objectURLOptions& aOptions,
                               nsString& aResult,
                               ErrorResult& aError);
   static void CreateObjectURL(const GlobalObject& aGlobal,
                               DOMMediaStream& aStream,
                               const mozilla::dom::objectURLOptions& aOptions,
                               nsString& aResult,
                               mozilla::ErrorResult& aError);
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -9,16 +9,17 @@
 
 #include "nsCOMPtr.h"
 #include "nsIScriptContext.h"
 #include "nsIVariant.h"
 #include "nsIXPConnect.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
+#include "js/StructuredClone.h"
 
 #include "mozilla/Base64.h"
 
 using namespace mozilla;
 
 NS_IMPL_ADDREF(nsStructuredCloneContainer)
 NS_IMPL_RELEASE(nsStructuredCloneContainer)
 
new file mode 100644
--- /dev/null
+++ b/dom/bindings/AtomList.h
@@ -0,0 +1,23 @@
+#ifndef mozilla_dom_AtomList_h__
+#define mozilla_dom_AtomList_h__
+
+#include "jsapi.h"
+#include "mozilla/dom/GeneratedAtomList.h"
+
+namespace mozilla {
+namespace dom {
+
+template<class T>
+T* GetAtomCache(JSContext* aCx)
+{
+  JSRuntime* rt = JS_GetRuntime(aCx);
+
+  auto atomCache = static_cast<PerThreadAtomCache*>(JS_GetRuntimePrivate(rt));
+
+  return static_cast<T*>(atomCache);
+}
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_AtomList_h__
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -59,57 +59,41 @@ struct EnumEntry {
   size_t length;
 };
 
 class MOZ_STACK_CLASS GlobalObject
 {
 public:
   GlobalObject(JSContext* aCx, JSObject* aObject);
 
-  nsISupports* Get() const
-  {
-    return mGlobalObject;
-  }
-
-  bool Failed() const
-  {
-    return !Get();
-  }
-
-private:
-  JS::Rooted<JSObject*> mGlobalJSObject;
-  nsISupports* mGlobalObject;
-  nsCOMPtr<nsISupports> mGlobalObjectRef;
-};
-
-class MOZ_STACK_CLASS WorkerGlobalObject
-{
-public:
-  WorkerGlobalObject(JSContext* aCx, JSObject* aObject);
-
   JSObject* Get() const
   {
     return mGlobalJSObject;
   }
+
+  nsISupports* GetAsSupports() const;
+
   // The context that this returns is not guaranteed to be in the compartment of
   // the object returned from Get(), in fact it's generally in the caller's
   // compartment.
   JSContext* GetContext() const
   {
     return mCx;
   }
 
   bool Failed() const
   {
     return !Get();
   }
 
-private:
+protected:
   JS::RootedObject mGlobalJSObject;
   JSContext* mCx;
+  mutable nsISupports* mGlobalObject;
+  mutable nsCOMPtr<nsISupports> mGlobalObjectRef;
 };
 
 /**
  * A class for representing string return values.  This can be either passed to
  * callees that have an nsString or nsAString out param or passed to a callee
  * that actually knows about this class and can work with it.  Such a callee may
  * call SetStringBuffer on this object, but only if it plans to keep holding a
  * strong ref to the stringbuffer!
--- a/dom/bindings/BindingGen.py
+++ b/dom/bindings/BindingGen.py
@@ -1,32 +1,38 @@
 # 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 mozbuild.makeutil import Makefile
+from mozbuild.pythonutil import iter_modules_in_path
+from buildconfig import topsrcdir
+
 
 def generate_binding_files(config, outputprefix, srcprefix, webidlfile):
     """
     |config| Is the configuration object.
     |outputprefix| is a prefix to use for the header guards and filename.
     """
 
     depsname = ".deps/" + outputprefix + ".pp"
     root = CGBindingRoot(config, outputprefix, webidlfile)
     replaceFileIfChanged(outputprefix + ".h", root.declare())
     replaceFileIfChanged(outputprefix + ".cpp", root.define())
 
-    with open(depsname, 'wb') as f:
-        # Sort so that our output is stable
-        f.write("\n".join(outputprefix + ": " + os.path.join(srcprefix, x) for
-                          x in sorted(root.deps())))
+    mk = Makefile()
+    rule = mk.create_rule([outputprefix + '.h', outputprefix + '.cpp'])
+    rule.add_dependencies(os.path.join(srcprefix, x) for x in root.deps())
+    rule.add_dependencies(iter_modules_in_path(topsrcdir))
+    with open(depsname, 'w') as f:
+        mk.dump(f)
 
 def main():
     # Parse arguments.
     from optparse import OptionParser
     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.")
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1699,63 +1699,63 @@ ReparentWrapper(JSContext* aCx, JS::Hand
 
   if (newParent && !JS_SetParent(aCx, aObj, newParent)) {
     MOZ_CRASH();
   }
 
   return NS_OK;
 }
 
-template<bool mainThread>
-inline JSObject*
-GetGlobalObject(JSContext* aCx, JSObject* aObject,
-                Maybe<JSAutoCompartment>& aAutoCompartment)
+GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
+  : mGlobalJSObject(aCx),
+    mCx(aCx),
+    mGlobalObject(nullptr)
 {
+  Maybe<JSAutoCompartment> ac;
   JS::Rooted<JSObject*> obj(aCx, aObject);
   if (js::IsWrapper(obj)) {
     obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
     if (!obj) {
-      Throw<mainThread>(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
-      return nullptr;
+      // We should never end up here on a worker thread, since there shouldn't
+      // be any security wrappers to worry about.
+      if (!MOZ_LIKELY(NS_IsMainThread())) {
+        MOZ_CRASH();
+      }
+
+      Throw<true>(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
+      return;
     }
-    aAutoCompartment.construct(aCx, obj);
+    ac.construct(aCx, obj);
   }
 
-  return JS_GetGlobalForObject(aCx, obj);
+  mGlobalJSObject = JS_GetGlobalForObject(aCx, obj);
 }
 
-GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
-  : mGlobalJSObject(aCx)
+nsISupports*
+GlobalObject::GetAsSupports() const
 {
-  Maybe<JSAutoCompartment> ac;
-  mGlobalJSObject = GetGlobalObject<true>(aCx, aObject, ac);
-  if (!mGlobalJSObject) {
-    mGlobalObject = nullptr;
-    return;
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mGlobalObject) {
+    return mGlobalObject;
   }
 
-  JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*mGlobalJSObject));
+  JS::Rooted<JS::Value> val(mCx, JS::ObjectValue(*mGlobalJSObject));
 
   // Switch this to UnwrapDOMObjectToISupports once our global objects are
   // using new bindings.
-  nsresult rv = xpc_qsUnwrapArg<nsISupports>(aCx, val, &mGlobalObject,
+  nsresult rv = xpc_qsUnwrapArg<nsISupports>(mCx, val, &mGlobalObject,
                                              static_cast<nsISupports**>(getter_AddRefs(mGlobalObjectRef)),
                                              val.address());
   if (NS_FAILED(rv)) {
     mGlobalObject = nullptr;
-    Throw<true>(aCx, NS_ERROR_XPC_BAD_CONVERT_JS);
+    Throw<true>(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);
   }
-}
 
-WorkerGlobalObject::WorkerGlobalObject(JSContext* aCx, JSObject* aObject)
-  : mGlobalJSObject(aCx),
-    mCx(aCx)
-{
-  Maybe<JSAutoCompartment> ac;
-  mGlobalJSObject = GetGlobalObject<false>(aCx, aObject, ac);
+  return mGlobalObject;
 }
 
 bool
 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
                      JS::Handle<JSObject*> instance,
                      bool* bp)
 {
   const DOMIfaceAndProtoJSClass* clasp =
@@ -1842,17 +1842,17 @@ InterfaceHasInstance(JSContext* cx, int 
 
 bool
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj)
 {
   GlobalObject global(cx, obj);
   if (global.Failed()) {
     return false;
   }
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.GetAsSupports());
   if (window && window->GetDoc()) {
     window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);
   }
   return true;
 }
 
 bool
 GetWindowForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
@@ -1879,29 +1879,29 @@ GetWindowForJSImplementedObject(JSContex
   // doing unwrapping as needed.
   GlobalObject global(cx, &domImplVal.toObject());
   if (global.Failed()) {
     return false;
   }
 
   // It's OK if we have null here: that just means the content-side
   // object really wasn't associated with any window.
-  nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(global.Get()));
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(global.GetAsSupports()));
   win.forget(window);
   return true;
 }
 
 already_AddRefed<nsPIDOMWindow>
 ConstructJSImplementation(JSContext* aCx, const char* aContractId,
                           const GlobalObject& aGlobal,
                           JS::MutableHandle<JSObject*> aObject,
                           ErrorResult& aRv)
 {
   // Get the window to use as a parent and for initialization.
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   // Make sure to have nothing on the JS context stack while creating and
   // initializing the object, so exceptions from that will get reported
   // properly, since those are never exceptions that a spec wants to be thrown.
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -710,17 +710,16 @@ DOMInterfaces = {
 },
 
 'MediaStreamTrack': {
     'concrete': False
 },
 
 'MediaRecorder': {
     'headerFile': 'MediaRecorder.h',
-    'implicitJSContext': [ 'constructor' ],
     'resultNotAddRefed': [ 'stream' ]
 },
 
 'MessageEvent': {
     'nativeType': 'nsDOMMessageEvent',
 },
 
 'MimeType': {
@@ -870,20 +869,16 @@ DOMInterfaces = {
 'Position': {
     'headerFile': 'nsGeoPosition.h'
 },
 
 'PositionError': {
     'headerFile': 'nsGeolocation.h'
 },
 
-'Promise': {
-    'implicitJSContext': [ 'constructor' ]
-},
-
 'PropertyNodeList': {
     'headerFile': 'HTMLPropertiesCollection.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'Range': {
     'nativeType': 'nsRange',
     'resultNotAddRefed': [ 'startContainer', 'endContainer', 'commonAncestorContainer' ],
@@ -1169,29 +1164,23 @@ DOMInterfaces = {
 },
 
 'Text': {
     # Total hack to allow binding code to realize that nsTextNode can
     # in fact be cast to Text.
     'headerFile': 'nsTextNode.h',
 },
 
-'TextDecoder': [
-{
-    'workers': True,
-}],
+'TextDecoder': {
+    'nativeOwnership': 'owned',
+},
 
-'TextEncoder': [
-{
-    'implicitJSContext': [ 'encode' ],
+'TextEncoder': {
+    'nativeOwnership': 'owned',
 },
-{
-    'workers': True,
-    'implicitJSContext': [ 'encode' ],
-}],
 
 'TextMetrics': {
     'wrapperCache': False,
     'nativeOwnership': 'owned',
 },
 
 'TimeEvent': {
     'nativeType': 'nsDOMTimeEvent',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3476,18 +3476,17 @@ for (uint32_t i = 0; i < length; ++i) {
                             "not None and we don't know we're an object")
 
         # There are no nullable dictionaries
         assert not type.nullable()
         # All optional dictionaries always have default values, so we
         # should be able to assume not isOptional here.
         assert not isOptional
 
-        typeName = CGDictionary.makeDictionaryName(type.inner,
-                                                   descriptorProvider.workers)
+        typeName = CGDictionary.makeDictionaryName(type.inner)
         actualTypeName = typeName
 
         declType = CGGeneric(actualTypeName)
 
         # We do manual default value handling here, because we
         # actually do want a jsval, and we only handle null anyway
         # NOTE: if isNullOrUndefined or isDefinitelyObject are true,
         # we know we have a value, so we don't have to worry about the
@@ -3724,17 +3723,17 @@ def instantiateJSToNativeConversion(info
              CGIndenter(conversion),
              CGGeneric("}")],
             "\n")
 
     result.append(conversion)
     # Add an empty CGGeneric to get an extra newline after the argument
     # conversion.
     result.append(CGGeneric(""))
-    return result;
+    return result
 
 def convertConstIDLValueToJSVal(value):
     if isinstance(value, IDLNullValue):
         return "JSVAL_NULL"
     tag = value.type.tag()
     if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
                IDLType.Tags.uint16, IDLType.Tags.int32]:
         return "INT_TO_JSVAL(%s)" % (value.value)
@@ -4257,28 +4256,35 @@ def infallibleForMember(member, type, de
                                   memberIsCreator(member), "return false;",
                                   False)[1]
 
 def leafTypeNeedsCx(type, descriptorProvider, retVal):
     return (type.isAny() or type.isObject() or
             (retVal and type.isSpiderMonkeyInterface()) or
             (descriptorProvider.workers and type.isCallback()))
 
+def leafTypeNeedsScopeObject(type, descriptorProvider, retVal):
+    return (retVal and type.isSpiderMonkeyInterface())
+
 def leafTypeNeedsRooting(type, descriptorProvider):
     return (leafTypeNeedsCx(type, descriptorProvider, False) or
             type.isSpiderMonkeyInterface())
 
 def typeNeedsRooting(type, descriptorProvider):
     return typeMatchesLambda(type,
                              lambda t: leafTypeNeedsRooting(t, descriptorProvider))
 
 def typeNeedsCx(type, descriptorProvider, retVal=False):
     return typeMatchesLambda(type,
                              lambda t: leafTypeNeedsCx(t, descriptorProvider, retVal))
 
+def typeNeedsScopeObject(type, descriptorProvider, retVal=False):
+    return typeMatchesLambda(type,
+                             lambda t: leafTypeNeedsScopeObject(t, descriptorProvider, retVal))
+
 def typeMatchesLambda(type, func):
     if type is None:
         return False
     if type.nullable():
         return typeMatchesLambda(type.inner, func)
     if type.isSequence() or type.isArray():
         return typeMatchesLambda(type.inner, func)
     if type.isUnion():
@@ -4329,21 +4335,21 @@ def getRetvalDeclarationForType(returnTy
     if returnType.isEnum():
         result = CGGeneric(returnType.unroll().inner.identifier.name)
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
         return result, False, None, None
     if returnType.isGeckoInterface():
         result = CGGeneric(descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeType)
-        if resultAlreadyAddRefed:
-            result = CGTemplatedType("nsRefPtr", result)
-        elif descriptorProvider.getDescriptor(
+        if descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeOwnership == 'owned':
             result = CGTemplatedType("nsAutoPtr", result)
+        elif resultAlreadyAddRefed:
+            result = CGTemplatedType("nsRefPtr", result)
         else:
             result = CGWrapper(result, post="*")
         return result, False, None, None
     if returnType.isCallback():
         name = returnType.unroll().identifier.name
         if descriptorProvider.workers:
             return CGGeneric("JSObject*"), False, None, None
         return CGGeneric("nsRefPtr<%s>" % name), False, None, None
@@ -4368,18 +4374,17 @@ def getRetvalDeclarationForType(returnTy
         else:
             rooter = None
         result = CGTemplatedType("nsTArray", result)
         if nullable:
             result = CGTemplatedType("Nullable", result)
         return result, True, rooter, None
     if returnType.isDictionary():
         nullable = returnType.nullable()
-        dictName = (CGDictionary.makeDictionaryName(returnType.unroll().inner,
-                                                    descriptorProvider.workers) +
+        dictName = (CGDictionary.makeDictionaryName(returnType.unroll().inner) +
                     "Initializer")
         result = CGGeneric(dictName)
         if not isMember and typeNeedsRooting(returnType, descriptorProvider):
             if nullable:
                 result = CGTemplatedType("NullableRootedDictionary", result)
             else:
                 result = CGTemplatedType("RootedDictionary", result)
             resultArgs = "cx"
@@ -4406,16 +4411,22 @@ def isResultAlreadyAddRefed(descriptor, 
 
 def needCx(returnType, arguments, extendedAttributes, descriptorProvider,
            considerTypes):
     return (considerTypes and
             (typeNeedsCx(returnType, descriptorProvider, True) or
              any(typeNeedsCx(a.type, descriptorProvider) for a in arguments)) or
             'implicitJSContext' in extendedAttributes)
 
+def needScopeObject(returnType, arguments, extendedAttributes,
+                    descriptorProvider, isWrapperCached, considerTypes):
+    return (considerTypes and not isWrapperCached and
+            (typeNeedsScopeObject(returnType, descriptorProvider, True) or
+             any(typeNeedsScopeObject(a.type, descriptorProvider) for a in arguments)))
+
 class CGCallGenerator(CGThing):
     """
     A class to generate an actual call to a C++ object.  Assumes that the C++
     object is stored in a variable whose name is given by the |object| argument.
 
     errorReport should be a CGThing for an error report or None if no
     error reporting is needed.
     """
@@ -4661,34 +4672,41 @@ class CGPerSignatureCall(CGThing):
             elif idlNode.isMethod():
                 lenientFloatCode = ("args.rval().set(JSVAL_VOID);\n"
                                     "return true;")
 
         argsPre = []
         if static:
             nativeMethodName = "%s::%s" % (descriptor.nativeType,
                                            nativeMethodName)
-            globalObjectType = "GlobalObject"
-            if descriptor.workers:
-                globalObjectType = "Worker" + globalObjectType
-            cgThings.append(CGGeneric("""%s global(cx, obj);
+            cgThings.append(CGGeneric("""GlobalObject global(cx, obj);
 if (global.Failed()) {
   return false;
 }
-""" % globalObjectType))
+"""))
             argsPre.append("global")
 
         # For JS-implemented interfaces we do not want to base the
         # needsCx decision on the types involved, just on our extended
         # attributes.
         needsCx = needCx(returnType, arguments, self.extendedAttributes,
                          descriptor, not descriptor.interface.isJSImplemented())
         if needsCx and not (static and descriptor.workers):
             argsPre.append("cx")
 
+        needsUnwrap = isConstructor
+        if needScopeObject(returnType, arguments, self.extendedAttributes,
+                           descriptor, descriptor.wrapperCache,
+                           not descriptor.interface.isJSImplemented()):
+            # We cannot assign into obj because it's a Handle, not a
+            # MutableHandle, so we need a separate Rooted.
+            cgThings.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;"))
+            argsPre.append("unwrappedObj.empty() ? obj : unwrappedObj.ref()")
+            needsUnwrap = True
+
         if idlNode.isMethod() and idlNode.isLegacycaller():
             # If we can have legacycaller with identifier, we can't
             # just use the idlNode to determine whether we're
             # generating code for the legacycaller or not.
             assert idlNode.isIdentifierLess()
             # Pass in our thisVal
             argsPre.append("args.thisv()")
 
@@ -4703,36 +4721,46 @@ if (global.Failed()) {
 
         cgThings.extend([CGArgumentConverter(arguments[i], i, self.descriptor,
                                              argDescription % { "index": i + 1 },
                                              invalidEnumValueFatal=not setter,
                                              allowTreatNonCallableAsNull=setter,
                                              lenientFloatCode=lenientFloatCode) for
                          i in range(argConversionStartsAt, self.argCount)])
 
-        if isConstructor:
-            # If we're called via an xray, we need to enter the underlying
-            # object's compartment and then wrap up all of our arguments into
-            # that compartment as needed.  This is all happening after we've
-            # already done the conversions from JS values to WebIDL (C++)
-            # values, so we only need to worry about cases where there are 'any'
-            # or 'object' types, or other things that we represent as actual
-            # JSAPI types, present.  Effectively, we're emulating a
-            # CrossCompartmentWrapper, but working with the C++ types, not the
-            # original list of JS::Values.
-            cgThings.append(CGGeneric("Maybe<JSAutoCompartment> ac;"))
-            xraySteps = [
-                CGGeneric("obj = js::CheckedUnwrap(obj);\n"
-                          "if (!obj) {\n"
-                          "  return false;\n"
-                          "}\n"
-                          "ac.construct(cx, obj);") ]
-            xraySteps.extend(
-                wrapArgIntoCurrentCompartment(arg, argname, isMember=False)
-                for (arg, argname) in self.getArguments())
+        if needsUnwrap:
+            # Something depends on having the unwrapped object, so unwrap it now.
+            xraySteps = []
+            if not isConstructor:
+                xraySteps.append(
+                    CGGeneric("unwrappedObj.construct(cx, obj);"))
+
+            # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
+            # not null.
+            xraySteps.append(
+                CGGeneric(string.Template("""${obj} = js::CheckedUnwrap(${obj});
+if (!${obj}) {
+  return false;
+}""").substitute({ 'obj' : 'obj' if isConstructor else 'unwrappedObj.ref()' })))
+            if isConstructor:
+                # If we're called via an xray, we need to enter the underlying
+                # object's compartment and then wrap up all of our arguments into
+                # that compartment as needed.  This is all happening after we've
+                # already done the conversions from JS values to WebIDL (C++)
+                # values, so we only need to worry about cases where there are 'any'
+                # or 'object' types, or other things that we represent as actual
+                # JSAPI types, present.  Effectively, we're emulating a
+                # CrossCompartmentWrapper, but working with the C++ types, not the
+                # original list of JS::Values.
+                cgThings.append(CGGeneric("Maybe<JSAutoCompartment> ac;"))
+                xraySteps.append(CGGeneric("ac.construct(cx, obj);"))
+                xraySteps.extend(
+                    wrapArgIntoCurrentCompartment(arg, argname, isMember=False)
+                    for (arg, argname) in self.getArguments())
+
             cgThings.append(
                 CGIfWrapper(CGList(xraySteps, "\n"),
                             "xpc::WrapperFactory::IsXrayWrapper(obj)"))
 
         cgThings.append(CGCallGenerator(
                     self.getErrorReport() if self.isFallible() else None,
                     self.getArguments(), argsPre, returnType,
                     self.extendedAttributes, descriptor, nativeMethodName,
@@ -7931,19 +7959,17 @@ class CGNamespacedEnum(CGThing):
         return self.node.declare()
     def define(self):
         assert False # Only for headers.
 
 class CGDictionary(CGThing):
     def __init__(self, dictionary, descriptorProvider):
         self.dictionary = dictionary
         self.descriptorProvider = descriptorProvider
-        self.workers = descriptorProvider.workers
-        # NOTE: jsids are per-runtime, so don't use them in workers
-        self.needToInitIds = not self.workers and len(dictionary.members) > 0
+        self.needToInitIds = len(dictionary.members) > 0
         self.memberInfo = [
             (member,
              getJSToNativeConversionInfo(
                             member.type,
                             descriptorProvider,
                             isMember="Dictionary",
                             isOptional=(not member.defaultValue),
                             defaultValue=member.defaultValue,
@@ -7957,31 +7983,36 @@ class CGDictionary(CGThing):
         return self.structs.declare()
 
     def define(self):
         return self.structs.define()
 
     def base(self):
         if self.dictionary.parent:
             return self.makeClassName(self.dictionary.parent)
-        if not self.workers:
-            return "MainThreadDictionaryBase"
-        return "DictionaryBase"
+        return "MainThreadDictionaryBase"
 
     def initMethod(self):
         body = (
             "// Passing a null JSContext is OK only if we're initing from null,\n"
             "// Since in that case we will not have to do any property gets\n"
             "MOZ_ASSERT_IF(!cx, val.isNull());\n")
 
         if self.needToInitIds:
-            body += (
-                "if (cx && !initedIds && !InitIds(cx)) {\n"
-                "  return false;\n"
-                "}\n")
+            initIdText = """${dictName}Atoms* atomsCache = nullptr;
+if (cx) {
+  atomsCache = GetAtomCache<${dictName}Atoms>(cx);
+  if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
+    return false;
+  }
+}
+
+"""
+            body += string.Template(initIdText).substitute(
+              { "dictName": self.makeClassName(self.dictionary)})
 
         if self.dictionary.parent:
             body += (
                 "// Per spec, we init the parent's members first\n"
                 "if (!%s::Init(cx, val)) {\n"
                 "  return false;\n"
                 "}\n"
                 "MOZ_ASSERT(IsConvertibleToDictionary(cx, val));\n"
@@ -8009,34 +8040,38 @@ class CGDictionary(CGThing):
 
         return ClassMethod("Init", "bool", [
             Argument('JSContext*', 'cx'),
             Argument('JS::Handle<JS::Value>', 'val'),
             Argument('const char*', 'sourceDescription', default='"Value"')
         ], body=body)
 
     def initFromJSONMethod(self):
-        assert not self.workers
         return ClassMethod("Init", "bool", [
                 Argument('const nsAString&', 'aJSON'),
             ], body=(
+                "MOZ_ASSERT(NS_IsMainThread());\n"
                 "AutoSafeJSContext cx;\n"
                 "JS::Rooted<JS::Value> json(cx);\n"
                 "bool ok = ParseJSON(cx, aJSON, &json);\n"
                 "NS_ENSURE_TRUE(ok, false);\n"
                 "return Init(cx, json);"
             ))
 
     def toObjectMethod(self):
         body = ""
         if self.needToInitIds:
-            body += (
-                "if (!initedIds && !InitIds(cx)) {\n"
-                "  return false;\n"
-                "}\n")
+            initIdText = """${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
+if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
+  return false;
+}
+
+"""
+            body += string.Template(initIdText).substitute(
+              { "dictName": self.makeClassName(self.dictionary)})
 
         if self.dictionary.parent:
             body += (
                 "// Per spec, we define the parent's members first\n"
                 "if (!%s::ToObject(cx, parentObject, rval)) {\n"
                 "  return false;\n"
                 "}\n"
                 "JS::Rooted<JSObject*> obj(cx, &rval.toObject());\n"
@@ -8057,33 +8092,38 @@ class CGDictionary(CGThing):
         return ClassMethod("ToObject", "bool", [
             Argument('JSContext*', 'cx'),
             Argument('JS::Handle<JSObject*>', 'parentObject'),
             Argument('JS::MutableHandle<JS::Value>', 'rval'),
         ], const=True, body=body)
 
     def initIdsMethod(self):
         assert self.needToInitIds
-        idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
+        idinit = [CGGeneric('!InternJSString(cx, atomsCache->%s, "%s")' %
                             (m.identifier.name + "_id", m.identifier.name))
                   for m in self.dictionary.members]
+        idinit.reverse();
         idinit = CGList(idinit, " ||\n")
-        idinit = CGWrapper(idinit, pre="if (",
+        idinit = CGWrapper(idinit, pre="""
+// Initialize these in reverse order so that any failure leaves the first one
+// uninitialized.
+if (""",
                            post=(") {\n"
                                  "  return false;\n"
                                  "}"),
                            reindent=True)
         body = (
-           "MOZ_ASSERT(!initedIds);\n"
+           "MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));\n"
            "%s\n"
-           "initedIds = true;\n"
            "return true;") % idinit.define()
 
         return ClassMethod("InitIds", "bool", [
             Argument("JSContext*", "cx"),
+            Argument("%sAtoms*" % self.makeClassName(self.dictionary),
+                     "atomsCache"),
         ], static=True, body=body, visibility="private")
 
     def traceDictionaryMethod(self):
         body = ""
         if self.dictionary.parent:
             cls = self.makeClassName(self.dictionary.parent)
             body += "%s::TraceDictionary(trc);\n" % cls
 
@@ -8105,26 +8145,19 @@ class CGDictionary(CGThing):
                                visibility="public",
                                body=self.getMemberInitializer(m))
                    for m in self.memberInfo]
         ctor = ClassConstructor([], bodyInHeader=True, visibility="public")
         methods = []
 
         if self.needToInitIds:
             methods.append(self.initIdsMethod())
-            members.append(ClassMember("initedIds", "bool", static=True, body="false"))
-            members.extend(
-                ClassMember(self.makeIdName(m.identifier.name), "jsid", static=True, body="JSID_VOID")
-                for m in d.members)
 
         methods.append(self.initMethod())
-
-        if not self.workers:
-            methods.append(self.initFromJSONMethod())
-
+        methods.append(self.initFromJSONMethod())
         methods.append(self.toObjectMethod())
         methods.append(self.traceDictionaryMethod())
 
         struct = CGClass(selfName,
             bases=[ClassBase(self.base())],
             members=members,
             constructors=[ctor],
             methods=methods,
@@ -8144,22 +8177,21 @@ class CGDictionary(CGThing):
             isStruct=True)
 
         return CGList([struct, initializerStruct])
 
     def deps(self):
         return self.dictionary.getDeps()
 
     @staticmethod
-    def makeDictionaryName(dictionary, workers):
-        suffix = "Workers" if workers else ""
-        return dictionary.identifier.name + suffix
+    def makeDictionaryName(dictionary):
+        return dictionary.identifier.name
 
     def makeClassName(self, dictionary):
-        return self.makeDictionaryName(dictionary, self.workers)
+        return self.makeDictionaryName(dictionary)
 
     @staticmethod
     def makeMemberName(name):
         return "m" + name[0].upper() + name[1:]
 
     def getMemberType(self, memberInfo):
         (_, conversionInfo) = memberInfo
         # We can't handle having a holderType here
@@ -8180,25 +8212,19 @@ class CGDictionary(CGThing):
                          "holderName": "holder" }
         # We can't handle having a holderType here
         assert conversionInfo.holderType is None
         if conversionInfo.dealWithOptional:
             replacements["declName"] = "(" + replacements["declName"] + ".Value())"
         if member.defaultValue:
             replacements["haveValue"] = "!isNull && !temp.ref().isUndefined()"
 
-        # NOTE: jsids are per-runtime, so don't use them in workers
-        if self.workers:
-            propName = member.identifier.name
-            propGet = ('JS_GetProperty(cx, &val.toObject(), "%s", &temp.ref())' %
-                       propName)
-        else:
-            propId = self.makeIdName(member.identifier.name);
-            propGet = ("JS_GetPropertyById(cx, &val.toObject(), %s, &temp.ref())" %
-                       propId)
+        propId = self.makeIdName(member.identifier.name);
+        propGet = ("JS_GetPropertyById(cx, &val.toObject(), atomsCache->%s, &temp.ref())" %
+                   propId)
 
         conversionReplacements = {
             "prop": self.makeMemberName(member.identifier.name),
             "convert": string.Template(conversionInfo.template).substitute(replacements),
             "propGet": propGet
             }
         conversion = ("if (!isNull && !${propGet}) {\n"
                       "  return false;\n"
@@ -8224,24 +8250,19 @@ class CGDictionary(CGThing):
         declType = memberInfo[1].declType
         memberLoc = self.makeMemberName(member.identifier.name)
         if member.defaultValue:
             memberData = memberLoc
         else:
             # The data is inside the Optional<>
             memberData = "%s.InternalValue()" % memberLoc
 
-        if self.workers:
-            propDef = (
-                'JS_DefineProperty(cx, obj, "%s", temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
-                member.identifier.name)
-        else:
-            propDef = (
-                'JS_DefinePropertyById(cx, obj, %s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
-                self.makeIdName(member.identifier.name))
+        propDef = (
+            'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
+            self.makeIdName(member.identifier.name))
 
         innerTemplate = wrapForType(
             member.type, self.descriptorProvider,
             {
                 'result' : "currentValue",
                 'successCode' : ("if (!%s) {\n"
                                  "  return false;\n"
                                  "}\n"
@@ -8494,17 +8515,17 @@ class ForwardDeclarationBuilder:
         return self._build(atTopLevel=True)
 
 
 class CGForwardDeclarations(CGWrapper):
     """
     Code generate the forward declarations for a header file.
     """
     def __init__(self, config, descriptors, mainCallbacks, workerCallbacks,
-                 mainDictionaries, workerDictionaries, callbackInterfaces):
+                 dictionaries, callbackInterfaces):
         builder = ForwardDeclarationBuilder()
 
         def forwardDeclareForType(t, workerness='both'):
             t = t.unroll()
             if t.isGeckoInterface():
                 name = t.inner.identifier.name
                 # Find and add the non-worker implementation, if any.
                 if workerness != 'workeronly':
@@ -8545,23 +8566,21 @@ class CGForwardDeclarations(CGWrapper):
             for t in getTypesFromCallback(callback):
                 forwardDeclareForType(t, workerness='workeronly')
 
         for d in callbackInterfaces:
             builder.add(d.nativeType)
             for t in getTypesFromDescriptor(d):
                 forwardDeclareForType(t)
 
-        for d in mainDictionaries:
+        for d in dictionaries:
+            if len(d.members) > 0:
+                builder.addInMozillaDom(d.identifier.name + "Atoms", isStruct=True)
             for t in getTypesFromDictionary(d):
-                forwardDeclareForType(t, workerness='mainthreadonly')
-
-        for d in workerDictionaries:
-            for t in getTypesFromDictionary(d):
-                forwardDeclareForType(t, workerness='workeronly')
+                forwardDeclareForType(t)
 
         CGWrapper.__init__(self, builder.build())
 
 
 class CGBindingRoot(CGThing):
     """
     Root codegen class for binding generation. Instantiate the class, and call
     declare or define to generate header or cpp code (respectively).
@@ -8583,20 +8602,18 @@ class CGBindingRoot(CGThing):
                     # chromeonly _create method.
                     (desc.interface.isJSImplemented() and
                      desc.interface.hasInterfaceObject()))
         hasChromeOnly = any(descriptorHasChromeOnly(d) for d in descriptors)
         # XXXkhuey ugly hack but this is going away soon.
         isEventTarget = webIDLFile.endswith("EventTarget.webidl")
         hasWorkerStuff = len(config.getDescriptors(webIDLFile=webIDLFile,
                                                    workers=True)) != 0
-        mainDictionaries = config.getDictionaries(webIDLFile=webIDLFile,
-                                                  workers=False)
-        workerDictionaries = config.getDictionaries(webIDLFile=webIDLFile,
-                                                    workers=True)
+        dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
+        requiresAtoms = any([len(dict.members) > 0 for dict in dictionaries])
         mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
                                             workers=False)
         workerCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
                                               workers=True)
         callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
                                                     isCallback=True)
         jsImplemented = config.getDescriptors(webIDLFile=webIDLFile,
                                               isJSImplemented=True)
@@ -8622,24 +8639,19 @@ class CGBindingRoot(CGThing):
 
         # Do codegen for all the enums
         cgthings = [ CGEnum(e) for e in config.getEnums(webIDLFile) ]
 
         # Do codegen for all the dictionaries.  We have to be a bit careful
         # here, because we have to generate these in order from least derived
         # to most derived so that class inheritance works out.  We also have to
         # generate members before the dictionary that contains them.
-        cgthings.extend([CGDictionary(d, config.getDescriptorProvider(True))
-                         for d in
-                         dependencySortObjects(workerDictionaries,
-                                               CGDictionary.getDictionaryDependencies,
-                                               lambda d: d.identifier.name)])
         cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
                          for d in
-                         dependencySortObjects(mainDictionaries,
+                         dependencySortObjects(dictionaries,
                                                CGDictionary.getDictionaryDependencies,
                                                lambda d: d.identifier.name)])
 
         # Do codegen for all the callbacks.  Only do non-worker codegen for now,
         # since we don't have a sane setup yet for invoking callbacks in workers
         # and managing their lifetimes.
         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(False))
                         for c in mainCallbacks)
@@ -8666,26 +8678,26 @@ class CGBindingRoot(CGThing):
         curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'],
                                  CGWrapper(curr, pre="\n"))
 
         curr = CGList([CGForwardDeclarations(config, descriptors,
                                              mainCallbacks, workerCallbacks,
-                                             mainDictionaries, workerDictionaries,
+                                             dictionaries,
                                              callbackDescriptors + jsImplemented),
                        CGWrapper(CGGeneric("using namespace mozilla::dom;"),
                                  defineOnly=True),
                        traitsClasses, curr],
                       "\n")
 
         # Add header includes.
         curr = CGHeaders(descriptors,
-                         mainDictionaries + workerDictionaries,
+                         dictionaries,
                          mainCallbacks + workerCallbacks,
                          callbackDescriptors,
                          ['mozilla/dom/BindingDeclarations.h',
                           'mozilla/ErrorResult.h',
                           'mozilla/dom/DOMJSClass.h',
                           'mozilla/dom/DOMJSProxyHandler.h'],
                          ['mozilla/dom/BindingUtils.h',
                           'mozilla/dom/Nullable.h',
@@ -8694,19 +8706,20 @@ class CGBindingRoot(CGThing):
                           # Have to include nsDOMQS.h to get fast arg unwrapping
                           # for old-binding things with castability.
                           'nsDOMQS.h'
                           ] + (['WorkerPrivate.h',
                                 'nsThreadUtils.h'] if hasWorkerStuff else [])
                             + (['mozilla/Preferences.h'] if requiresPreferences else [])
                             + (['mozilla/dom/NonRefcountedDOMObject.h'] if hasOwnedDescriptors else [])
                             + (['nsContentUtils.h'] if requiresContentUtils else [])
-                            + (['nsCxPusher.h'] if mainDictionaries else [])
+                            + (['nsCxPusher.h'] if dictionaries else [])
                             + (['AccessCheck.h'] if hasChromeOnly else [])
-                            + (['xpcprivate.h'] if isEventTarget else []),
+                            + (['xpcprivate.h'] if isEventTarget else [])
+                            + (['AtomList.h'] if requiresAtoms else []),
                          prefix,
                          curr,
                          config,
                          jsImplemented)
 
         # Add include guards.
         curr = CGIncludeGuard(prefix, curr)
 
@@ -8721,32 +8734,32 @@ class CGBindingRoot(CGThing):
     def define(self):
         return stripTrailingWhitespace(self.root.define())
 
     def deps(self):
         return self.root.deps()
 
 class CGNativeMember(ClassMethod):
     def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
-                 breakAfter=True, passCxAsNeeded=True, visibility="public",
+                 breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
                  jsObjectsArePtr=False, variadicIsSequence=False):
         """
         If jsObjectsArePtr is true, typed arrays and "object" will be
         passed as JSObject*.
 
-        If passCxAsNeeded is false, we don't automatically pass in a
-        JSContext* based on the return and argument types.  We can
-        still pass it based on 'implicitJSContext' annotations.
+        If passJSBitsAsNeeded is false, we don't automatically pass in a
+        JSContext* or a JSObject* based on the return and argument types.  We
+        can still pass it based on 'implicitJSContext' annotations.
         """
         self.descriptorProvider = descriptorProvider
         self.member = member
         self.extendedAttrs = extendedAttrs
         self.resultAlreadyAddRefed = isResultAlreadyAddRefed(self.descriptorProvider,
                                                              self.extendedAttrs)
-        self.passCxAsNeeded = passCxAsNeeded
+        self.passJSBitsAsNeeded = passJSBitsAsNeeded
         self.jsObjectsArePtr = jsObjectsArePtr
         self.variadicIsSequence = variadicIsSequence
         breakAfterSelf = "\n" if breakAfter else ""
         ClassMethod.__init__(self, name,
                              self.getReturnType(signature[0], False),
                              self.getArgs(signature[0], signature[1]),
                              static=member.isStatic(),
                              # Mark our getters, which are attrs that
@@ -8897,24 +8910,25 @@ class CGNativeMember(ClassMethod):
             args.append(Argument("ErrorResult&", "aRv"))
         # The legacycaller thisval
         if self.member.isMethod() and self.member.isLegacycaller():
             # If it has an identifier, we can't deal with it yet
             assert self.member.isIdentifierLess()
             args.insert(0, Argument("JS::Value", "aThisVal"))
         # And jscontext bits.
         if needCx(returnType, argList, self.extendedAttrs,
-                  self.descriptorProvider, self.passCxAsNeeded):
+                  self.descriptorProvider, self.passJSBitsAsNeeded):
             args.insert(0, Argument("JSContext*", "cx"))
+            if needScopeObject(returnType, argList, self.extendedAttrs,
+                               self.descriptorProvider, self.descriptorProvider,
+                               self.passJSBitsAsNeeded):
+                args.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
         # And if we're static, a global
         if self.member.isStatic():
-            globalObjectType = "GlobalObject"
-            if self.descriptorProvider.workers:
-                globalObjectType = "Worker" + globalObjectType
-            args.insert(0, Argument("const %s&" % globalObjectType, "global"))
+            args.insert(0, Argument("const GlobalObject&", "global"))
         return args
 
     def doGetArgType(self, type, optional, isMember):
         """
         The main work of getArgType.  Returns a string type decl, whether this
         is a const ref, as well as whether the type should be wrapped in
         Nullable as needed.
 
@@ -9009,18 +9023,17 @@ class CGNativeMember(ClassMethod):
         if type.isObject():
             if isMember:
                 declType = "JSObject*"
             else:
                 declType = "JS::Handle<JSObject*>"
             return declType, False, False
 
         if type.isDictionary():
-            typeName = CGDictionary.makeDictionaryName(
-                type.inner, self.descriptorProvider.workers)
+            typeName = CGDictionary.makeDictionaryName(type.inner)
             return typeName, True, True
 
         if type.isDate():
             return "Date", False, True
 
         assert type.isPrimitive()
 
         return builtinNames[type.tag()], False, True
@@ -9349,17 +9362,17 @@ class CGJSImplMethod(CGNativeMember):
     def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
         CGNativeMember.__init__(self, descriptor, method,
                                 CGSpecializedMethod.makeNativeName(descriptor,
                                                                    method),
                                 signature,
                                 descriptor.getExtendedAttributes(method),
                                 breakAfter=breakAfter,
                                 variadicIsSequence=True,
-                                passCxAsNeeded=False)
+                                passJSBitsAsNeeded=False)
         self.signature = signature
         self.descriptor = descriptor
         if isConstructor:
             self.body = self.getConstructorImpl()
         else:
             self.body = self.getImpl()
 
     def getImpl(self):
@@ -9427,33 +9440,33 @@ def callbackSetterName(attr):
 class CGJSImplGetter(CGNativeMember):
     def __init__(self, descriptor, attr):
         CGNativeMember.__init__(self, descriptor, attr,
                                 CGSpecializedGetter.makeNativeName(descriptor,
                                                                    attr),
                                 (attr.type, []),
                                 descriptor.getExtendedAttributes(attr,
                                                                  getter=True),
-                                passCxAsNeeded=False)
+                                passJSBitsAsNeeded=False)
         self.body = self.getImpl()
 
     def getImpl(self):
         callbackArgs = [arg.name for arg in self.getArgs(self.member.type, [])]
         return 'return mImpl->%s(%s);' % (callbackGetterName(self.member), ", ".join(callbackArgs))
 
 class CGJSImplSetter(CGNativeMember):
     def __init__(self, descriptor, attr):
         CGNativeMember.__init__(self, descriptor, attr,
                                 CGSpecializedSetter.makeNativeName(descriptor,
                                                                    attr),
                                 (BuiltinTypes[IDLBuiltinType.Types.void],
                                  [FakeArgument(attr.type, attr)]),
                                 descriptor.getExtendedAttributes(attr,
                                                                  setter=True),
-                                passCxAsNeeded=False)
+                                passJSBitsAsNeeded=False)
         self.body = self.getImpl()
 
     def getImpl(self):
         callbackArgs = [arg.name for arg in self.getArgs(BuiltinTypes[IDLBuiltinType.Types.void],
                                                          [FakeArgument(self.member.type, self.member)])]
         return 'mImpl->%s(%s);' % (callbackSetterName(self.member), ", ".join(callbackArgs))
 
 class CGJSImplClass(CGBindingImplClass):
@@ -9594,17 +9607,17 @@ class CGJSImplClass(CGBindingImplClass):
             "}\n"
             "\n"
             "// GlobalObject will go through wrappers as needed for us, and\n"
             "// is simpler than the right UnwrapArg incantation.\n"
             "GlobalObject global(cx, &args[0].toObject());\n"
             "if (global.Failed()) {\n"
             "  return false;\n"
             "}\n"
-            "nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.Get());\n"
+            "nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.GetAsSupports());\n"
             "if (!window) {\n"
             '  return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "Argument 1 of ${ifaceName}._create", "Window");\n'
             "}\n"
             "JS::Rooted<JSObject*> arg(cx, &args[1].toObject());\n"
             "nsRefPtr<${implName}> impl = new ${implName}(arg, window);\n"
             "return WrapNewBindingObject(cx, arg, impl, args.rval());").substitute({
                 "ifaceName": self.descriptor.interface.identifier.name,
                 "implName": self.descriptor.name
@@ -9788,17 +9801,17 @@ class CallbackMember(CGNativeMember):
         # will handle generating public versions that handle the "this" stuff.
         visibility = "private" if needThisHandling else "public"
         # We don't care, for callback codegen, whether our original member was
         # a method or attribute or whatnot.  Just always pass FakeMember()
         # here.
         CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
                                 name, (self.retvalType, args),
                                 extendedAttrs={},
-                                passCxAsNeeded=False,
+                                passJSBitsAsNeeded=False,
                                 visibility=visibility,
                                 jsObjectsArePtr=True)
         # We have to do all the generation of our body now, because
         # the caller relies on us throwing if we can't manage it.
         self.exceptionCode=("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
                             "return%s;" % self.getDefaultRetval())
         self.body = self.getImpl()
 
@@ -10138,16 +10151,64 @@ class GlobalGenRoots():
     """
     Roots for global codegen.
 
     To generate code, call the method associated with the target, and then
     call the appropriate define/declare method.
     """
 
     @staticmethod
+    def GeneratedAtomList(config):
+        # Atom enum
+        dictionaries = config.dictionaries
+
+        structs = []
+
+        for dict in dictionaries:
+            dictMembers = dict.members
+            if len(dictMembers) == 0:
+                continue
+
+            classMembers = [ClassMember(m.identifier.name + "_id",
+                                        "jsid",
+                                        visibility="public",
+                                        body="JSID_VOID") for m in dictMembers]
+
+            structName = dict.identifier.name + "Atoms"
+            structs.append((structName,
+                            CGWrapper(CGClass(structName,
+                bases=None,
+                isStruct=True,
+                members=classMembers), post='\n')))
+
+        structs.sort()
+        generatedStructs = [struct for (structName, struct) in structs]
+        structNames = [structName for (structName, struct) in structs]
+
+        mainStruct = CGWrapper(CGClass("PerThreadAtomCache",
+            bases=[ClassBase(structName) for structName in structNames],
+            isStruct=True), post='\n')
+
+        structs = CGList(generatedStructs + [mainStruct])
+
+        # Wrap all of that in our namespaces.
+        curr = CGNamespace.build(['mozilla', 'dom'],
+                                  CGWrapper(structs, pre='\n'))
+        curr = CGWrapper(curr, post='\n')
+
+        # Add include guards.
+        curr = CGIncludeGuard('GeneratedAtomList', curr)
+
+        # Add the auto-generated comment.
+        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
+
+        # Done.
+        return curr
+
+    @staticmethod
     def PrototypeList(config):
 
         # Prototype ID enum.
         protos = [d.name for d in config.getDescriptors(hasInterfacePrototypeObject=True)]
         idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + protos,
                                   [0, '_ID_Start'])
         idEnum = CGList([idEnum])
 
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -94,18 +94,16 @@ class Configuration:
                           c.isCallback() and not c.isInterface()]
 
         def flagWorkerOrMainThread(items, main, worker):
             for item in items:
                 if item in main:
                     item.setUserData("mainThread", True)
                 if item in worker:
                     item.setUserData("workers", True)
-        flagWorkerOrMainThread(self.dictionaries, mainDictionaries,
-                               workerDictionaries);
         flagWorkerOrMainThread(self.callbacks, mainCallbacks, workerCallbacks)
 
     def getInterface(self, ifname):
         return self.interfaces[ifname]
     def getDescriptors(self, **filters):
         """Gets the descriptors that match the given filters."""
         curr = self.descriptors
         # Collect up our filters, because we may have a webIDLFile filter that
--- a/dom/bindings/GlobalGen.py
+++ b/dom/bindings/GlobalGen.py
@@ -58,16 +58,19 @@ def main():
     # Load the configuration.
     config = Configuration(configFile, parserResults)
 
     # Write the configuration out to a pickle.
     resultsFile = open('ParserResults.pkl', 'wb')
     cPickle.dump(config, resultsFile, -1)
     resultsFile.close()
 
+    # Generate the atom list.
+    generate_file(config, 'GeneratedAtomList', 'declare')
+
     # Generate the prototype list.
     generate_file(config, 'PrototypeList', 'declare')
 
     # Generate the common code.
     generate_file(config, 'RegisterBindings', 'declare')
     generate_file(config, 'RegisterBindings', 'define')
 
     generate_file(config, 'UnionTypes', 'declare')
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -34,16 +34,17 @@ binding_cpp_files := $(subst .webidl,Bin
 # binding_dependency_trackers targets have dependencies on the right .webidl
 # files via generated .pp files, having a .BindingGen target that depends on the
 # binding_dependency_trackers and which has all the generated binding .h/.cpp
 # depending on it, and then in the make commands for that target being able to
 # check which exact binding_dependency_trackers changed.
 binding_dependency_trackers := $(subst .webidl,Binding,$(all_webidl_files))
 
 globalgen_targets := \
+  GeneratedAtomList.h \
   PrototypeList.h \
   RegisterBindings.h \
   RegisterBindings.cpp \
   UnionTypes.h \
   UnionTypes.cpp \
   UnionConversions.h \
   $(NULL)
 
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -93,25 +93,44 @@ struct TypedArray : public TypedArray_ba
   {}
 
   TypedArray() :
     TypedArray_base<T,UnboxArray>()
   {}
 
   static inline JSObject*
   Create(JSContext* cx, nsWrapperCache* creator, uint32_t length,
-         const T* data = NULL) {
+         const T* data = nullptr) {
     JS::Rooted<JSObject*> creatorWrapper(cx);
     Maybe<JSAutoCompartment> ac;
     if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) {
       ac.construct(cx, creatorWrapper);
     }
+
+    return CreateCommon(cx, creatorWrapper, length, data);
+  }
+
+  static inline JSObject*
+  Create(JSContext* cx, JS::Handle<JSObject*> creator, uint32_t length,
+         const T* data = nullptr) {
+    Maybe<JSAutoCompartment> ac;
+    if (creator) {
+      ac.construct(cx, creator);
+    }
+
+    return CreateCommon(cx, creator, length, data);
+  }
+
+private:
+  static inline JSObject*
+  CreateCommon(JSContext* cx, JS::Handle<JSObject*> creator, uint32_t length,
+               const T* data) {
     JSObject* obj = CreateNew(cx, length);
     if (!obj) {
-      return NULL;
+      return nullptr;
     }
     if (data) {
       T* buf = static_cast<T*>(GetData(obj));
       memcpy(buf, data, length*sizeof(T));
     }
     return obj;
   }
 };
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -6,25 +6,27 @@
 
 MODULE = 'dom'
 
 EXPORTS.mozilla += [
     'ErrorResult.h',
 ]
 
 EXPORTS.mozilla.dom += [
+    'AtomList.h',
     'BindingDeclarations.h',
     'BindingUtils.h',
     'CallbackFunction.h',
     'CallbackInterface.h',
     'CallbackObject.h',
     'DOMJSClass.h',
     'DOMJSProxyHandler.h',
     'Date.h',
     'Errors.msg',
+    'GeneratedAtomList.h',
     'NonRefcountedDOMObject.h',
     'Nullable.h',
     'PrimitiveConversions.h',
     'TypedArray.h',
 ]
 
 FAIL_ON_WARNINGS = True
 
--- a/dom/bluetooth/BluetoothReplyRunnable.h
+++ b/dom/bluetooth/BluetoothReplyRunnable.h
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 #define mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 
 #include "mozilla/Attributes.h"
 #include "BluetoothCommon.h"
 #include "nsThreadUtils.h"
-#include "jsapi.h"
+#include "js/Value.h"
 
 class nsIDOMDOMRequest;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothReply;
 
 class BluetoothReplyRunnable : public nsRunnable
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -807,44 +807,27 @@ GetPropertiesInternal(const nsAString& a
   if (!success) {
     BT_WARNING("Failed to get device properties");
     return false;
   }
 
   return true;
 }
 
-class GetPropertiesReplyHandler : public DBusReplyHandler
-{
-public:
-  GetPropertiesReplyHandler(const nsCString& aIface)
-    : mIface(aIface)
-  {
-    MOZ_ASSERT(!mIface.IsEmpty());
-  }
-
-  const nsCString& GetInterface() const
-  {
-    return mIface;
-  }
-
-private:
-  nsCString mIface;
-};
-
-class AppendDeviceNameReplyHandler: public GetPropertiesReplyHandler
+class AppendDeviceNameReplyHandler: public DBusReplyHandler
 {
 public:
   AppendDeviceNameReplyHandler(const nsCString& aIface,
                                const nsString& aDevicePath,
                                const BluetoothSignal& aSignal)
-    : GetPropertiesReplyHandler(aIface)
+    : mIface(aIface)
     , mDevicePath(aDevicePath)
     , mSignal(aSignal)
   {
+    MOZ_ASSERT(!mIface.IsEmpty());
     MOZ_ASSERT(!mDevicePath.IsEmpty());
   }
 
   void Handle(DBusMessage* aReply) MOZ_OVERRIDE
   {
     MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
 
     if (!aReply || (dbus_message_get_type(aReply) == DBUS_MESSAGE_TYPE_ERROR)) {
@@ -854,17 +837,17 @@ public:
     // Get device properties from result of GetProperties
 
     DBusError err;
     dbus_error_init(&err);
 
     BluetoothValue deviceProperties;
 
     bool success = UnpackPropertiesMessage(aReply, &err, deviceProperties,
-                                           GetInterface().get());
+                                           mIface.get());
     if (!success) {
       BT_WARNING("Failed to get device properties");
       return;
     }
 
     // First we replace object path with device address.
 
     InfallibleTArray<BluetoothNamedValue>& parameters =
@@ -889,16 +872,17 @@ public:
     MOZ_ASSERT_IF(i == properties.Length(), "failed to get device name");
 
     nsRefPtr<DistributeBluetoothSignalTask> task =
       new DistributeBluetoothSignalTask(mSignal);
     NS_DispatchToMainThread(task);
   }
 
 private:
+  nsCString mIface;
   nsString mDevicePath;
   BluetoothSignal mSignal;
 };
 
 static void
 AppendDeviceName(BluetoothSignal& aSignal)
 {
   BluetoothValue v = aSignal.value();
@@ -1800,78 +1784,155 @@ BluetoothDBusService::StopInternal()
 }
 
 bool
 BluetoothDBusService::IsEnabledInternal()
 {
   return mEnabled;
 }
 
-class DefaultAdapterPropertiesRunnable : public nsRunnable
+class DefaultAdapterPathReplyHandler : public DBusReplyHandler
 {
 public:
-  DefaultAdapterPropertiesRunnable(BluetoothReplyRunnable* aRunnable)
-    : mRunnable(dont_AddRef(aRunnable))
+  DefaultAdapterPathReplyHandler(BluetoothReplyRunnable* aRunnable)
+    : mRunnable(aRunnable)
   {
+    MOZ_ASSERT(mRunnable);
   }
 
-  nsresult Run()
+  void Handle(DBusMessage* aReply) MOZ_OVERRIDE
   {
-    MOZ_ASSERT(!NS_IsMainThread());
-
-    BluetoothValue v;
+    MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
+
+    if (!aReply || (dbus_message_get_type(aReply) == DBUS_MESSAGE_TYPE_ERROR)) {
+      const char* errStr = "Timeout in DefaultAdapterPathReplyHandler";
+      if (aReply) {
+        errStr = dbus_message_get_error_name(aReply);
+        if (!errStr) {
+          errStr = "Bluetooth DBus Error";
+        }
+      }
+      DispatchBluetoothReply(mRunnable, BluetoothValue(),
+                             NS_ConvertUTF8toUTF16(errStr));
+      return;
+    }
+
+    bool success;
     nsAutoString replyError;
-    if (!GetDefaultAdapterPath(v, replyError)) {
-      DispatchBluetoothReply(mRunnable, v, replyError);
-      return NS_ERROR_FAILURE;
+
+    if (mAdapterPath.IsEmpty()) {
+      success = HandleDefaultAdapterPathReply(aReply, replyError);
+    } else {
+      success = HandleGetPropertiesReply(aReply, replyError);
+    }
+
+    if (!success) {
+      DispatchBluetoothReply(mRunnable, BluetoothValue(), replyError);
+    }
+  }
+
+protected:
+  bool HandleDefaultAdapterPathReply(DBusMessage* aReply,
+                                     nsAString& aReplyError)
+  {
+    BluetoothValue value;
+    DBusError error;
+    dbus_error_init(&error);
+
+    MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
+
+    UnpackObjectPathMessage(aReply, &error, value, aReplyError);
+
+    if (!aReplyError.IsEmpty()) {
+      return false;
     }
 
-    DBusError err;
-    dbus_error_init(&err);
-
-    nsString objectPath = v.get_nsString();
-    v = InfallibleTArray<BluetoothNamedValue>();
-    if (!GetPropertiesInternal(objectPath, DBUS_ADAPTER_IFACE, v)) {
-      NS_WARNING("Getting properties failed!");
-      return NS_ERROR_FAILURE;
+    mAdapterPath = value.get_nsString();
+
+    // Acquire another reference to this reply handler
+    nsRefPtr<DefaultAdapterPathReplyHandler> handler = this;
+
+    nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
+
+    if (!threadConnection.get()) {
+      aReplyError = NS_LITERAL_STRING("DBus connection has been closed.");
+      return false;
+    }
+
+    bool success = dbus_func_args_async(threadConnection->GetConnection(), 1000,
+                                        DefaultAdapterPathReplyHandler::Callback,
+                                        handler.get(),
+                                        NS_ConvertUTF16toUTF8(mAdapterPath).get(),
+                                        DBUS_ADAPTER_IFACE, "GetProperties",
+                                        DBUS_TYPE_INVALID);
+    if (!success) {
+      aReplyError = NS_LITERAL_STRING("dbus_func_args_async failed");
+      return false;
+    }
+
+    handler.forget();
+
+    return true;
+  }
+
+  bool HandleGetPropertiesReply(DBusMessage* aReply,
+                                nsAutoString& aReplyError)
+  {
+    BluetoothValue value;
+    DBusError error;
+    dbus_error_init(&error);
+
+    MOZ_ASSERT(!NS_IsMainThread()); // DBus thread
+
+    bool success = UnpackPropertiesMessage(aReply, &error, value,
+                                           DBUS_ADAPTER_IFACE);
+    if (!success) {
+      aReplyError = NS_ConvertUTF8toUTF16(error.message);
+      return false;
     }
 
     // We have to manually attach the path to the rest of the elements
-    v.get_ArrayOfBluetoothNamedValue().AppendElement(
-      BluetoothNamedValue(NS_LITERAL_STRING("Path"), objectPath));
-
-    DispatchBluetoothReply(mRunnable, v, replyError);
-
-    return NS_OK;
+    value.get_ArrayOfBluetoothNamedValue().AppendElement(
+      BluetoothNamedValue(NS_LITERAL_STRING("Path"), mAdapterPath));
+
+    // Dispatch result
+    DispatchBluetoothReply(mRunnable, value, aReplyError);
+
+    return true;
   }
 
 private:
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
+  nsString mAdapterPath;
 };
 
 nsresult
 BluetoothDBusService::GetDefaultAdapterPathInternal(
                                               BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!IsReady()) {
     NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
     DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
     return NS_OK;
   }
 
-  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
-  nsRefPtr<nsRunnable> func(new DefaultAdapterPropertiesRunnable(runnable));
-  if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
-    NS_WARNING("Cannot dispatch firmware loading task!");
-    return NS_ERROR_FAILURE;
-  }
-
-  runnable.forget();
+  nsRefPtr<DefaultAdapterPathReplyHandler> handler =
+    new DefaultAdapterPathReplyHandler(aRunnable);
+  bool success = dbus_func_args_async(mConnection, 1000,
+                                      DefaultAdapterPathReplyHandler::Callback,
+                                      handler.get(),
+                                      "/",
+                                      DBUS_MANAGER_IFACE, "DefaultAdapter",
+                                      DBUS_TYPE_INVALID);
+  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
+
+  handler.forget();
+
   return NS_OK;
 }
 
 static void
 OnSendDiscoveryMessageReply(DBusMessage *aReply, void *aData)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -653,16 +653,22 @@ ContactManager.prototype = {
         req = this.getRequest(msg.requestID);
         if (req) {
           if (req.request) {
             req = req.request;
           }
           Services.DOMRequest.fireError(req, msg.errorMsg);
         }
         break;
+      case "Contacts:GetAll:Return:KO":
+        req = this.getRequest(msg.requestID);
+        if (req) {
+          Services.DOMRequest.fireError(req.cursor, msg.errorMsg);
+        }
+        break;
       case "PermissionPromptHelper:AskPermission:OK":
         if (DEBUG) debug("id: " + msg.requestID);
         req = this.getRequest(msg.requestID);
         if (!req) {
           break;
         }
 
         if (msg.result == Ci.nsIPermissionManager.ALLOW_ACTION) {
@@ -681,24 +687,24 @@ ContactManager.prototype = {
           });
           this._oncontactchange.handleEvent(event);
         }
         break;
       case "Contacts:Revision":
         if (DEBUG) debug("new revision: " + msg.revision);
         req = this.getRequest(msg.requestID);
         if (req) {
-          Services.DOMRequest.fireSuccess(req, msg.revision);
+          Services.DOMRequest.fireSuccess(req.request, msg.revision);
         }
         break;
       case "Contacts:Count":
         if (DEBUG) debug("count: " + msg.count);
         req = this.getRequest(msg.requestID);
         if (req) {
-          Services.DOMRequest.fireSuccess(req, msg.count);
+          Services.DOMRequest.fireSuccess(req.request, msg.count);
         }
         break;
       default:
         if (DEBUG) debug("Wrong message: " + aMessage.name);
     }
     this.removeRequest(msg.requestID);
   },
 
@@ -866,18 +872,22 @@ ContactManager.prototype = {
       }
     } else {
       if (DEBUG) debug("waiting for contact");
       data.waitingForNext = true;
     }
   },
 
   remove: function removeContact(aRecord) {
-    let request;
-    request = this.createRequest();
+    let request = this.createRequest();
+    if (!aRecord || !aRecord.id) {
+      Services.DOMRequest.fireErrorAsync(request, true);
+      return request;
+    }
+
     let options = { id: aRecord.id };
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contact:Remove", {requestID: this.getRequestId({request: request, reason: "remove"}), options: options});
     }.bind(this)
     this.askPermission("remove", request, allowCallback);
     return request;
   },
 
@@ -893,34 +903,34 @@ ContactManager.prototype = {
     return request;
   },
 
   getRevision: function() {
     let request = this.createRequest();
 
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetRevision", {
-        requestID: this.getRequestId(request)
+        requestID: this.getRequestId({ request: request })
       });
     }.bind(this);
 
     let cancelCallback = function() {
       Services.DOMRequest.fireError(request);
     };
 
     this.askPermission("revision", request, allowCallback, cancelCallback);
     return request;
   },
 
   getCount: function() {
     let request = this.createRequest();
 
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetCount", {
-        requestID: this.getRequestId(request)
+        requestID: this.getRequestId({ request: request })
       });
     }.bind(this);
 
     let cancelCallback = function() {
       Services.DOMRequest.fireError(request);
     };
 
     this.askPermission("count", request, allowCallback, cancelCallback);
@@ -929,17 +939,18 @@ ContactManager.prototype = {
 
   init: function(aWindow) {
     this.initDOMRequestHelper(aWindow, ["Contacts:Find:Return:OK", "Contacts:Find:Return:KO",
                               "Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO",
                               "Contact:Save:Return:OK", "Contact:Save:Return:KO",
                               "Contact:Remove:Return:OK", "Contact:Remove:Return:KO",
                               "Contact:Changed",
                               "PermissionPromptHelper:AskPermission:OK",
-                              "Contacts:GetAll:Next", "Contacts:Count",
+                              "Contacts:GetAll:Next", "Contacts:GetAll:Return:KO",
+                              "Contacts:Count",
                               "Contacts:Revision", "Contacts:GetRevision:Return:KO",]);
   },
 
   // Called from DOMRequestIpcHelper
   uninit: function uninit() {
     if (DEBUG) debug("uninit call");
     if (this._oncontactchange)
       this._oncontactchange = null;
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -138,17 +138,17 @@ let ContactService = {
                 let index = this._cursors[mm].indexOf(msg.cursorId);
                 this._cursors[mm].splice(index, 1);
               }
             } catch (e) {
               if (DEBUG) debug("Child is dead, DB should stop sending contacts");
               throw e;
             }
           }.bind(this),
-          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.cursorId, errorMsg: aErrorMsg }); },
+          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:GetAll:Return:KO", { requestID: msg.cursorId, errorMsg: aErrorMsg }); },
           msg.findOptions, msg.cursorId);
         break;
       case "Contacts:GetAll:SendNow":
         // sendNow is a no op if there isn't an existing cursor in the DB, so we
         // don't need to assert the permission again.
         this._db.sendNow(msg.cursorId);
         break;
       case "Contact:Save":
@@ -187,45 +187,51 @@ let ContactService = {
         if (!this.assertPermission(aMessage, "contacts-write")) {
           return null;
         }
         this._db.clear(
           function() {
             mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID });
             this.broadcastMessage("Contact:Changed", { reason: "remove" });
           }.bind(this),
-          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
+          function(aErrorMsg) {
+            mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
+          }.bind(this)
         );
         break;
       case "Contacts:GetRevision":
         if (!this.assertPermission(aMessage, "contacts-read")) {
           return null;
         }
         this._db.getRevision(
           function(revision) {
             mm.sendAsyncMessage("Contacts:Revision", {
               requestID: msg.requestID,
               revision: revision
             });
           },
-          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:GetRevision:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
+          function(aErrorMsg) {
+            mm.sendAsyncMessage("Contacts:GetRevision:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
+          }.bind(this)
         );
         break;
       case "Contacts:GetCount":
         if (!this.assertPermission(aMessage, "contacts-read")) {
           return null;
         }
         this._db.getCount(
           function(count) {
             mm.sendAsyncMessage("Contacts:Count", {
               requestID: msg.requestID,
               count: count
             });
           },
-          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Count:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
+          function(aErrorMsg) {
+            mm.sendAsyncMessage("Contacts:Count:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
+          }.bind(this)
         );
         break;
       case "Contacts:RegisterForMessages":
         if (!aMessage.target.assertPermission("contacts-read")) {
           return null;
         }
         if (DEBUG) debug("Register!");
         if (this._children.indexOf(mm) == -1) {
--- a/dom/contacts/tests/test_contacts_basics.html
+++ b/dom/contacts/tests/test_contacts_basics.html
@@ -153,16 +153,17 @@ function clearTemps() {
 }
 
 function onUnwantedSuccess() {
   ok(false, "onUnwantedSuccess: shouldn't get here");
 }
 
 function onFailure() {
   ok(false, "in on Failure!");
+  next();
 }
 
 function checkStr(str1, str2, msg) {
   if (str1 ^ str2) {
     ok(false, "Expected both strings to be either present or absent");
     return;
   }
   is(str1, str2, msg);
@@ -796,31 +797,35 @@ var steps = [
       ok(findResult1.updated, "Has updated field");
       ok(findResult1.published, "Has published field");
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Modifying contact1");
-    findResult1.impp = properties1.impp = [{value:"phil impp"}];
-    req = navigator.mozContacts.save(findResult1);
-    req.onsuccess = function () {
-      var req2 = mozContacts.find({});
-      req2.onsuccess = function() {
-        is(req2.result.length, 1, "Found exactly 1 contact.");
-        findResult2 = req2.result[0];
-        ok(findResult2.id == sample_id1, "Same ID");
-        checkContacts(findResult2, properties1);
-        is(findResult2.impp.length, 1, "Found exactly 1 IMS info.");
-        next();
+    if (!findResult1) {
+      SpecialPowers.executeSoon(next);
+    } else {
+      findResult1.impp = properties1.impp = [{value:"phil impp"}];
+      req = navigator.mozContacts.save(findResult1);
+      req.onsuccess = function () {
+        var req2 = mozContacts.find({});
+        req2.onsuccess = function() {
+          is(req2.result.length, 1, "Found exactly 1 contact.");
+          findResult2 = req2.result[0];
+          ok(findResult2.id == sample_id1, "Same ID");
+          checkContacts(findResult2, properties1);
+          is(findResult2.impp.length, 1, "Found exactly 1 IMS info.");
+          next();
+        };
+        req2.onerror = onFailure;
       };
-      req2.onerror = onFailure;
-    };
-    req.onerror = onFailure;
+      req.onerror = onFailure;
+    }
   },
   function() {
     // Android does not support published/updated fields. Skip this.
     if (isAndroid) {
       next();
       return;
     }
 
@@ -856,31 +861,35 @@ var steps = [
       ok(findResult1.id == sample_id1, "Same ID");
       checkContacts(findResult1, properties1);
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Modifying contact2");
-    findResult1.impp = properties1.impp = [{value: "phil impp"}];
-    req = mozContacts.save(findResult1);
-    req.onsuccess = function () {
-      var req2 = mozContacts.find({});
-      req2.onsuccess = function () {
-        is(req2.result.length, 1, "Found exactly 1 contact.");
-        findResult1 = req2.result[0];
-        ok(findResult1.id == sample_id1, "Same ID");
-        checkContacts(findResult1, properties1);
-        is(findResult1.impp.length, 1, "Found exactly 1 IMS info.");
-        next();
-      }
-      req2.onerror = onFailure;
-    };
-    req.onerror = onFailure;
+    if (!findResult1) {
+      SpecialPowers.executeSoon(next);
+    } else {
+      findResult1.impp = properties1.impp = [{value: "phil impp"}];
+      req = mozContacts.save(findResult1);
+      req.onsuccess = function () {
+        var req2 = mozContacts.find({});
+        req2.onsuccess = function () {
+          is(req2.result.length, 1, "Found exactly 1 contact.");
+          findResult1 = req2.result[0];
+          ok(findResult1.id == sample_id1, "Same ID");
+          checkContacts(findResult1, properties1);
+          is(findResult1.impp.length, 1, "Found exactly 1 IMS info.");
+          next();
+        }
+        req2.onerror = onFailure;
+      };
+      req.onerror = onFailure;
+    }
   },
   function () {
     ok(true, "Searching contacts by query");
     var options = {filterBy: ["givenName", "email"],
                    filterOp: "startsWith",
                    filterValue: properties1.givenName[0].substring(0,4)};
     req = mozContacts.find(options);
     req.onsuccess = function () {
@@ -919,38 +928,42 @@ var steps = [
       ok(findResult1.id == sample_id1, "Same ID");
       checkContacts(findResult1, properties1);
       next();
     };
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Modifying contact3");
-    findResult1.email = [{value: properties1.nickname}];
-    findResult1.nickname = "TEST";
-    var newContact = new mozContact();
-    newContact.init(findResult1);
-    req = mozContacts.save(newContact);
-    req.onsuccess = function () {
-      var options = {filterBy: ["email", "givenName"],
-                     filterOp: "startsWith",
-                     filterValue: properties1.givenName[0]};
-      // One contact has it in nickname and the other in email
-      var req2 = mozContacts.find(options);
-      req2.onsuccess = function () {
-        is(req2.result.length, 2, "Found exactly 2 contacts.");
-        ok(req2.result[0].id != req2.result[1].id, "Different ID");
-        next();
-      }
-      req2.onerror = onFailure;
-    };
-    req.onerror = onFailure;
+    if (!findResult1) {
+      SpecialPowers.executeSoon(next);
+    } else {
+      findResult1.email = [{value: properties1.nickname}];
+      findResult1.nickname = "TEST";
+      var newContact = new mozContact();
+      newContact.init(findResult1);
+      req = mozContacts.save(newContact);
+      req.onsuccess = function () {
+        var options = {filterBy: ["email", "givenName"],
+                       filterOp: "startsWith",
+                       filterValue: properties1.givenName[0]};
+        // One contact has it in nickname and the other in email
+        var req2 = mozContacts.find(options);
+        req2.onsuccess = function () {
+          is(req2.result.length, 2, "Found exactly 2 contacts.");
+          ok(req2.result[0].id != req2.result[1].id, "Different ID");
+          next();
+        }
+        req2.onerror = onFailure;
+      };
+      req.onerror = onFailure;
+    }
   },
   function () {
-    ok(true, "Deleting contact" + findResult1.id);
+    ok(true, "Deleting contact" + findResult1);
     req = mozContacts.remove(findResult1);
     req.onsuccess = function () {
       var req2 = mozContacts.find({});
       req2.onsuccess = function () {
         is(req2.result.length, 1, "One contact left.");
         findResult1 = req2.result[0];
         next();
       }
--- a/dom/contacts/tests/test_contacts_blobs.html
+++ b/dom/contacts/tests/test_contacts_blobs.html
@@ -106,16 +106,17 @@ var createResult1;
 var findResult1;
 
 function onUnwantedSuccess() {
   ok(false, "onUnwantedSuccess: shouldn't get here");
 }
 
 function onFailure() {
   ok(false, "in on Failure!");
+  next();
 }
 
 function verifyBlob(blob1, blob2, isLast)
 {
   is(blob1 instanceof SpecialPowers.Ci.nsIDOMBlob, true,
      "Instance of nsIDOMBlob");
   is(blob1 instanceof SpecialPowers.Ci.nsIDOMFile,
      blob2 instanceof SpecialPowers.Ci.nsIDOMFile,
--- a/dom/contacts/tests/test_contacts_getall.html
+++ b/dom/contacts/tests/test_contacts_getall.html
@@ -51,16 +51,17 @@ let properties1 = {
   nickname: "nicktest",
   tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+9-876-5432"}],
   adr: adr1,
   email: [{type: ["work"], value: "x@y.com"}]
 };
 
 function onFailure() {
   ok(false, "in on Failure!");
+  next();
 }
 
 function checkStr(str1, str2, msg) {
   // comparing /[null(,null)+]/ and undefined should pass
   function nonNull(e) {
     return e != null;
   }
   if ((Array.isArray(str1) && str1.filter(nonNull).length == 0 && str2 == undefined)
--- a/dom/contacts/tests/test_contacts_international.html
+++ b/dom/contacts/tests/test_contacts_international.html
@@ -32,16 +32,17 @@ SpecialPowers.addPermission("contacts-cr
 
 var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
 var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
                                   .getService(SpecialPowers.Ci.nsIPropertyBag2)
                                   .getProperty('version');
 
 function onFailure() {
   ok(false, "in on Failure!");
+  next();
 }
 
 var number1 = {
   local: "7932012345",
   international: "+557932012345"
 };
 
 var number2 = {
@@ -162,21 +163,25 @@ var steps = [
     req.onsuccess = function() {
       ok(req.result.length == 1, "Found the contact equally matching the shortNumber.");
       next();
     };
     req.onerror = onFailure;
   },
   function() {
     ok(true, "Modifying number");
-    findResult1.tel[0].value = number2.local;
-    req = mozContacts.save(findResult1);
-    req.onsuccess = function () {
-      next();
-    };
+    if (!findResult1) {
+      SpecialPowers.executeSoon(next);
+    } else {
+      findResult1.tel[0].value = number2.local;
+      req = mozContacts.save(findResult1);
+      req.onsuccess = function () {
+        next();
+      };
+    }
   },
   function () {
     ok(true, "Searching for local number");
     var options = {filterBy: ["tel"],
                    filterOp: "startsWith",
                    filterValue: number1.local};
     req = mozContacts.find(options);
     req.onsuccess = function () {
@@ -220,17 +225,17 @@ var steps = [
     req.onsuccess = function () {
       ok(req.result.length == 0, "Found exactly 1 contact.");
       next();
     };
     req.onerror = onFailure;
   },
   function () {
     ok(true, "Deleting database");
-    req = mozContacts.clear()
+    req = mozContacts.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "all done!\n");
--- a/dom/contacts/tests/test_contacts_substringmatching.html
+++ b/dom/contacts/tests/test_contacts_substringmatching.html
@@ -39,16 +39,17 @@ var androidVersion = SpecialPowers.Cc['@
                                   .getProperty('version');
 
 var sample_id1;
 var createResult1;
 var findResult1;
 
 function onFailure() {
   ok(false, "in on Failure!");
+  next();
 }
 
 var prop = {
   tel: [{value: "7932012345" }, {value: "7932012346"}]
 };
 
 var prop2 = {
   tel: [{value: "01187654321" }]
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -295,16 +295,17 @@ private:
   class VolumeNameCache : public mozilla::RefCounted<VolumeNameCache>
   {
   public:
     nsTArray<nsString>  mVolumeNames;
   };
   static mozilla::StaticRefPtr<VolumeNameCache> sVolumeNameCache;
 
 #ifdef MOZ_WIDGET_GONK
+  nsString mLastStatus;
   void DispatchMountChangeEvent(nsAString& aVolumeStatus);
 #endif
 
   // nsIDOMDeviceStorage.type
   enum {
       DEVICE_STORAGE_TYPE_DEFAULT = 0,
       DEVICE_STORAGE_TYPE_SHARED,
       DEVICE_STORAGE_TYPE_EXTERNAL
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1256,24 +1256,37 @@ DeviceStorageFile::GetStatus(nsAString& 
   aStatus.AssignLiteral("unavailable");
 #ifdef MOZ_WIDGET_GONK
   nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
   NS_ENSURE_TRUE_VOID(vs);
 
   nsCOMPtr<nsIVolume> vol;
   nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol));
   NS_ENSURE_SUCCESS_VOID(rv);
+  if (!vol) {
+    return;
+  }
+  bool isMediaPresent;
+  rv = vol->GetIsMediaPresent(&isMediaPresent);
+  NS_ENSURE_SUCCESS_VOID(rv);
+  if (!isMediaPresent) {
+    return;
+  }
+  bool isSharing;
+  rv = vol->GetIsSharing(&isSharing);
+  NS_ENSURE_SUCCESS_VOID(rv);
+  if (isSharing) {
+    aStatus.AssignLiteral("shared");
+    return;
+  }
   int32_t volState;
   rv = vol->GetState(&volState);
   NS_ENSURE_SUCCESS_VOID(rv);
   if (volState == nsIVolume::STATE_MOUNTED) {
     aStatus.AssignLiteral("available");
-  } else if (volState == nsIVolume::STATE_SHARED ||
-             volState == nsIVolume::STATE_SHAREDMNT) {
-    aStatus.AssignLiteral("shared");
   }
 #endif
 }
 
 NS_IMPL_ISUPPORTS0(DeviceStorageFile)
 
 static void
 RegisterForSDCardChanges(nsIObserver* aObserver)
@@ -3154,16 +3167,22 @@ nsDOMDeviceStorage::EnumerateInternal(co
 
   return cursor.forget();
 }
 
 #ifdef MOZ_WIDGET_GONK
 void
 nsDOMDeviceStorage::DispatchMountChangeEvent(nsAString& aVolumeStatus)
 {
+  if (aVolumeStatus == mLastStatus) {
+    // We've already sent this status, don't bother sending it again.
+    return;
+  }
+  mLastStatus = aVolumeStatus;
+
   nsCOMPtr<nsIDOMEvent> event;
   NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), this,
                                     nullptr, nullptr);
 
   nsCOMPtr<nsIDOMDeviceStorageChangeEvent> ce = do_QueryInterface(event);
   nsresult rv = ce->InitDeviceStorageChangeEvent(NS_LITERAL_STRING("change"),
                                                  true, false,
                                                  mStorageName,
--- a/dom/encoding/TextDecoder.cpp
+++ b/dom/encoding/TextDecoder.cpp
@@ -9,18 +9,18 @@
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 static const PRUnichar kReplacementChar = static_cast<PRUnichar>(0xFFFD);
 
 void
-TextDecoderBase::Init(const nsAString& aEncoding, const bool aFatal,
-                      ErrorResult& aRv)
+TextDecoder::Init(const nsAString& aEncoding, const bool aFatal,
+                  ErrorResult& aRv)
 {
   nsAutoString label(aEncoding);
   EncodingUtils::TrimSpaceCharacters(label);
 
   // Let encoding be the result of getting an encoding from label.
   // If encoding is failure, throw a TypeError.
   if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
     aRv.ThrowTypeError(MSG_ENCODING_NOT_SUPPORTED, &label);
@@ -47,19 +47,19 @@ TextDecoderBase::Init(const nsAString& a
   }
 
   if (mFatal) {
     mDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Signal);
   }
 }
 
 void
-TextDecoderBase::Decode(const char* aInput, const int32_t aLength,
-                        const bool aStream, nsAString& aOutDecodedString,
-                        ErrorResult& aRv)
+TextDecoder::Decode(const char* aInput, const int32_t aLength,
+                    const bool aStream, nsAString& aOutDecodedString,
+                    ErrorResult& aRv)
 {
   aOutDecodedString.Truncate();
 
   // Run or resume the decoder algorithm of the decoder object's encoder.
   int32_t outLen;
   nsresult rv = mDecoder->GetMaxLength(aInput, aLength, &outLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
@@ -96,21 +96,16 @@ TextDecoderBase::Decode(const char* aInp
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(NS_ERROR_DOM_ENCODING_DECODE_ERR);
   }
 }
 
 void
-TextDecoderBase::GetEncoding(nsAString& aEncoding)
+TextDecoder::GetEncoding(nsAString& aEncoding)
 {
   CopyASCIItoUTF16(mEncoding, aEncoding);
   nsContentUtils::ASCIIToLower(aEncoding);
 }
 
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TextDecoder, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TextDecoder, Release)
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TextDecoder, mGlobal)
-
 } // dom
 } // mozilla
--- a/dom/encoding/TextDecoder.h
+++ b/dom/encoding/TextDecoder.h
@@ -1,81 +1,122 @@
 /* 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_textdecoder_h_
 #define mozilla_dom_textdecoder_h_
 
-#include "mozilla/dom/TextDecoderBase.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
 #include "mozilla/dom/TextDecoderBinding.h"
+#include "mozilla/dom/TypedArray.h"
+#include "nsIUnicodeDecoder.h"
 
 namespace mozilla {
+
+class ErrorResult;
+
 namespace dom {
 
 class TextDecoder MOZ_FINAL
-  : public nsWrapperCache, public TextDecoderBase
+  : public NonRefcountedDOMObject
 {
 public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TextDecoder)
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(TextDecoder)
-
   // The WebIDL constructor.
-  static already_AddRefed<TextDecoder>
+  static TextDecoder*
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aEncoding,
               const TextDecoderOptions& aOptions,
               ErrorResult& aRv)
   {
-    nsRefPtr<TextDecoder> txtDecoder = new TextDecoder(aGlobal.Get());
+    nsAutoPtr<TextDecoder> txtDecoder(new TextDecoder());
     txtDecoder->Init(aEncoding, aOptions.mFatal, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
     return txtDecoder.forget();
   }
 
-  TextDecoder(nsISupports* aGlobal)
-    : mGlobal(aGlobal)
+  TextDecoder()
+    : mFatal(false)
   {
-    MOZ_ASSERT(aGlobal);
-    SetIsDOMBinding();
+    MOZ_COUNT_CTOR(TextDecoder);
   }
 
-  virtual
   ~TextDecoder()
-  {}
+  {
+    MOZ_COUNT_DTOR(TextDecoder);
+  }
 
-  virtual JSObject* WrapObject(JSContext* aCx,
-                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
+  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope,
+                       bool* aTookOwnership)
   {
-    return TextDecoderBinding::Wrap(aCx, aScope, this);
+    return TextDecoderBinding::Wrap(aCx, aScope, this, aTookOwnership);
   }
 
   nsISupports*
   GetParentObject()
   {
-    return mGlobal;
+    return nullptr;
   }
 
+  /**
+   * Validates provided encoding and throws an exception if invalid encoding.
+   * If no encoding is provided then mEncoding is default initialised to "utf-8".
+   *
+   * @param aEncoding    Optional encoding (case insensitive) provided.
+   *                     Default value is "utf-8" if no encoding is provided.
+   * @param aFatal       aFatal, indicates whether to throw an 'EncodingError'
+   *                     exception or not.
+   * @return aRv         EncodingError exception else null.
+   */
+  void Init(const nsAString& aEncoding, const bool aFatal, ErrorResult& aRv);
+
+  /**
+   * Return the encoding name.
+   *
+   * @param aEncoding, current encoding.
+   */
+  void GetEncoding(nsAString& aEncoding);
+
+  /**
+   * Decodes incoming byte stream of characters in charset indicated by
+   * encoding.
+   *
+   * The encoding algorithm state is reset if aOptions.mStream is not set.
+   *
+   * If the fatal flag is set then a decoding error will throw EncodingError.
+   * Else the decoder will return a decoded string with replacement
+   * character(s) for unidentified character(s).
+   *
+   * @param      aView, incoming byte stream of characters to be decoded to
+   *                    to UTF-16 code points.
+   * @param      aOptions, indicates if streaming or not.
+   * @param      aOutDecodedString, decoded string of UTF-16 code points.
+   * @param      aRv, error result.
+   */
+  void Decode(const char* aInput, const int32_t aLength,
+              const bool aStream, nsAString& aOutDecodedString,
+              ErrorResult& aRv);
+
   void Decode(nsAString& aOutDecodedString,
               ErrorResult& aRv) {
-    TextDecoderBase::Decode(nullptr, 0, false,
-                            aOutDecodedString, aRv);
+    Decode(nullptr, 0, false, aOutDecodedString, aRv);
   }
 
   void Decode(const ArrayBufferView& aView,
               const TextDecodeOptions& aOptions,
               nsAString& aOutDecodedString,
               ErrorResult& aRv) {
-    TextDecoderBase::Decode(reinterpret_cast<char*>(aView.Data()),
-                            aView.Length(), aOptions.mStream,
-                            aOutDecodedString, aRv);
+    Decode(reinterpret_cast<char*>(aView.Data()), aView.Length(),
+           aOptions.mStream, aOutDecodedString, aRv);
   }
 
 private:
-  nsCOMPtr<nsISupports> mGlobal;
+  nsCString mEncoding;
+  nsCOMPtr<nsIUnicodeDecoder> mDecoder;
+  bool mFatal;
 };
 
 } // dom
 } // mozilla
 
 #endif // mozilla_dom_textdecoder_h_
deleted file mode 100644
--- a/dom/encoding/TextDecoderBase.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 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_textdecoderbase_h_
-#define mozilla_dom_textdecoderbase_h_
-
-#include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/TypedArray.h"
-#include "nsIUnicodeDecoder.h"
-
-namespace mozilla {
-class ErrorResult;
-
-namespace dom {
-
-class TextDecoderBase
-{
-public:
-  TextDecoderBase()
-    : mFatal(false)
-  {}
-
-  virtual
-  ~TextDecoderBase()
-  {}
-
-  /**
-   * Validates provided encoding and throws an exception if invalid encoding.
-   * If no encoding is provided then mEncoding is default initialised to "utf-8".
-   *
-   * @param aEncoding    Optional encoding (case insensitive) provided.
-   *                     Default value is "utf-8" if no encoding is provided.
-   * @param aFatal       aFatal, indicates whether to throw an 'EncodingError'
-   *                     exception or not.
-   * @return aRv         EncodingError exception else null.
-   */
-  void Init(const nsAString& aEncoding, const bool aFatal, ErrorResult& aRv);
-
-  /**
-   * Return the encoding name.
-   *
-   * @param aEncoding, current encoding.
-   */
-  void GetEncoding(nsAString& aEncoding);
-
-  /**
-   * Decodes incoming byte stream of characters in charset indicated by
-   * encoding.
-   *
-   * The encoding algorithm state is reset if aOptions.mStream is not set.
-   *
-   * If the fatal flag is set then a decoding error will throw EncodingError.
-   * Else the decoder will return a decoded string with replacement
-   * character(s) for unidentified character(s).
-   *
-   * @param      aView, incoming byte stream of characters to be decoded to
-   *                    to UTF-16 code points.
-   * @param      aOptions, indicates if streaming or not.
-   * @param      aOutDecodedString, decoded string of UTF-16 code points.
-   * @param      aRv, error result.
-   */
-  void Decode(const char* aInput, const int32_t aLength,
-              const bool aStream, nsAString& aOutDecodedString,
-              ErrorResult& aRv);
-
-private:
-  nsCString mEncoding;
-  nsCOMPtr<nsIUnicodeDecoder> mDecoder;
-  bool mFatal;
-};
-
-} // dom
-} // mozilla
-
-#endif // mozilla_dom_textdecoderbase_h_
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -7,17 +7,17 @@
 #include "nsContentUtils.h"
 #include "nsICharsetConverterManager.h"
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 void
-TextEncoderBase::Init(const nsAString& aEncoding, ErrorResult& aRv)
+TextEncoder::Init(const nsAString& aEncoding, ErrorResult& aRv)
 {
   nsAutoString label(aEncoding);
   EncodingUtils::TrimSpaceCharacters(label);
 
   // Let encoding be the result of getting an encoding from label.
   // If encoding is failure, or is none of utf-8, utf-16, and utf-16be,
   // throw a TypeError.
   if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
@@ -43,20 +43,21 @@ TextEncoderBase::Init(const nsAString& a
   ccm->GetUnicodeEncoderRaw(mEncoding.get(), getter_AddRefs(mEncoder));
   if (!mEncoder) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 }
 
 JSObject*
-TextEncoderBase::Encode(JSContext* aCx,
-                        const nsAString& aString,
-                        const bool aStream,
-                        ErrorResult& aRv)
+TextEncoder::Encode(JSContext* aCx,
+                    JS::Handle<JSObject*> aObj,
+                    const nsAString& aString,
+                    const bool aStream,
+                    ErrorResult& aRv)
 {
   // Run the steps of the encoding algorithm.
   int32_t srcLen = aString.Length();
   int32_t maxLen;
   const PRUnichar* data = PromiseFlatString(aString).get();
   nsresult rv = mEncoder->GetMaxLength(data, srcLen, &maxLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
@@ -82,35 +83,30 @@ TextEncoderBase::Encode(JSContext* aCx,
     if (NS_SUCCEEDED(rv)) {
       dstLen += finishLen;
     }
   }
 
   JSObject* outView = nullptr;
   if (NS_SUCCEEDED(rv)) {
     buf[dstLen] = '\0';
-    outView = CreateUint8Array(aCx, buf, dstLen);
+    outView = CreateUint8Array(aCx, aObj, buf, dstLen);
     if (!outView) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return nullptr;
     }
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
   return outView;
 }
 
 void
-TextEncoderBase::GetEncoding(nsAString& aEncoding)
+TextEncoder::GetEncoding(nsAString& aEncoding)
 {
   CopyASCIItoUTF16(mEncoding, aEncoding);
   nsContentUtils::ASCIIToLower(aEncoding);
 }
 
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TextEncoder, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TextEncoder, Release)
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TextEncoder, mGlobal)
-
 } // dom
 } // mozilla
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoder.h
@@ -1,80 +1,120 @@
 /* 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_textencoder_h_
 #define mozilla_dom_textencoder_h_
 
-#include "mozilla/dom/TextEncoderBase.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
 #include "mozilla/dom/TextEncoderBinding.h"
+#include "mozilla/dom/TypedArray.h"
+#include "nsIUnicodeEncoder.h"
 
 namespace mozilla {
+class ErrorResult;
+
 namespace dom {
 
-class TextEncoder MOZ_FINAL
-  : public nsWrapperCache, public TextEncoderBase
+class TextEncoder MOZ_FINAL : public NonRefcountedDOMObject
 {
 public:
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TextEncoder)
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(TextEncoder)
+  // The WebIDL constructor.
 
-  // The WebIDL constructor.
-  static already_AddRefed<TextEncoder>
+  static TextEncoder*
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aEncoding,
               ErrorResult& aRv)
   {
-    nsRefPtr<TextEncoder> txtEncoder = new TextEncoder(aGlobal.Get());
+    nsAutoPtr<TextEncoder> txtEncoder(new TextEncoder());
     txtEncoder->Init(aEncoding, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
     return txtEncoder.forget();
   }
 
-  TextEncoder(nsISupports* aGlobal)
-    : mGlobal(aGlobal)
+  TextEncoder()
   {
-    MOZ_ASSERT(aGlobal);
-    SetIsDOMBinding();
   }
 
   virtual
   ~TextEncoder()
   {}
 
-  virtual JSObject* WrapObject(JSContext* aCx,
-                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
+  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope,
+                       bool* aTookOwnership)
   {
-    return TextEncoderBinding::Wrap(aCx, aScope, this);
+    return TextEncoderBinding::Wrap(aCx, aScope, this, aTookOwnership);
   }
 
   nsISupports*
   GetParentObject()
   {
-    return mGlobal;
+    return nullptr;
   }
 
   JSObject* Encode(JSContext* aCx,
+                   JS::Handle<JSObject*> aObj,
                    const nsAString& aString,
                    const TextEncodeOptions& aOptions,
                    ErrorResult& aRv) {
-    return TextEncoderBase::Encode(aCx, aString, aOptions.mStream, aRv);
+    return TextEncoder::Encode(aCx, aObj, aString, aOptions.mStream, aRv);
   }
 
 protected:
-  virtual JSObject*
-  CreateUint8Array(JSContext* aCx, char* aBuf, uint32_t aLen) MOZ_OVERRIDE
+
+  /**
+   * Validates provided encoding and throws an exception if invalid encoding.
+   * If no encoding is provided then mEncoding is default initialised to "utf-8".
+   *
+   * @param aEncoding    Optional encoding (case insensitive) provided.
+   *                     (valid values are "utf-8", "utf-16", "utf-16be")
+   *                     Default value is "utf-8" if no encoding is provided.
+   * @return aRv         EncodingError exception else null.
+   */
+  void Init(const nsAString& aEncoding, ErrorResult& aRv);
+
+public:
+  /**
+   * Return the encoding name.
+   *
+   * @param aEncoding, current encoding.
+   */
+  void GetEncoding(nsAString& aEncoding);
+
+  /**
+   * Encodes incoming utf-16 code units/ DOM string to the requested encoding.
+   *
+   * @param aCx        Javascript context.
+   * @param aObj       the wrapper of the TextEncoder
+   * @param aString    utf-16 code units to be encoded.
+   * @param aOptions   Streaming option. Initialised by default to false.
+   *                   If the streaming option is false, then the encoding
+   *                   algorithm state will get reset. If set to true then
+   *                   the previous encoding is reused/continued.
+   * @return JSObject* The Uint8Array wrapped in a JS object.
+   */
+  JSObject* Encode(JSContext* aCx,
+                   JS::Handle<JSObject*> aObj,
+                   const nsAString& aString,
+                   const bool aStream,
+                   ErrorResult& aRv);
+
+protected:
+  JSObject*
+  CreateUint8Array(JSContext* aCx, JS::Handle<JSObject*> aObj, 
+                   char* aBuf, uint32_t aLen) const
   {
-    return Uint8Array::Create(aCx, this, aLen,
+    return Uint8Array::Create(aCx, aObj, aLen,
                               reinterpret_cast<uint8_t*>(aBuf));
   }
 
 private:
-  nsCOMPtr<nsISupports> mGlobal;
+  nsCString mEncoding;
+  nsCOMPtr<nsIUnicodeEncoder> mEncoder;
 };
 
 } // dom
 } // mozilla
 
 #endif // mozilla_dom_textencoder_h_
deleted file mode 100644
--- a/dom/encoding/TextEncoderBase.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* 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_textencoderbase_h_
-#define mozilla_dom_textencoderbase_h_
-
-#include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/TypedArray.h"
-#include "nsIUnicodeEncoder.h"
-
-namespace mozilla {
-class ErrorResult;
-
-namespace dom {
-
-class TextEncoderBase
-{
-protected:
-  TextEncoderBase()
-  {}
-
-  virtual
-  ~TextEncoderBase()
-  {}
-
-  /**
-   * Validates provided encoding and throws an exception if invalid encoding.
-   * If no encoding is provided then mEncoding is default initialised to "utf-8".
-   *
-   * @param aEncoding    Optional encoding (case insensitive) provided.
-   *                     (valid values are "utf-8", "utf-16", "utf-16be")
-   *                     Default value is "utf-8" if no encoding is provided.
-   * @return aRv         EncodingError exception else null.
-   */
-  void Init(const nsAString& aEncoding, ErrorResult& aRv);
-
-public:
-  /**
-   * Return the encoding name.
-   *
-   * @param aEncoding, current encoding.
-   */
-  void GetEncoding(nsAString& aEncoding);
-
-  /**
-   * Encodes incoming utf-16 code units/ DOM string to the requested encoding.
-   *
-   * @param aCx        Javascript context.
-   * @param aString    utf-16 code units to be encoded.
-   * @param aOptions   Streaming option. Initialised by default to false.
-   *                   If the streaming option is false, then the encoding
-   *                   algorithm state will get reset. If set to true then
-   *                   the previous encoding is reused/continued.
-   * @return JSObject* The Uint8Array wrapped in a JS object.
-   */
-  JSObject* Encode(JSContext* aCx, const nsAString& aString,
-                   const bool aStream, ErrorResult& aRv);
-
-protected:
-  virtual JSObject*
-  CreateUint8Array(JSContext* aCx, char* aBuf, uint32_t aLen) = 0;
-
-private:
-  nsCString mEncoding;
-  nsCOMPtr<nsIUnicodeEncoder> mEncoder;
-};
-
-} // dom
-} // mozilla
-
-#endif // mozilla_dom_textencoderbase_h_
--- a/dom/encoding/moz.build
+++ b/dom/encoding/moz.build
@@ -6,19 +6,17 @@
 
 TEST_DIRS += ['test']
 
 MODULE = 'dom'
 
 EXPORTS.mozilla.dom += [
     'EncodingUtils.h',
     'TextDecoder.h',
-    'TextDecoderBase.h',
     'TextEncoder.h',
-    'TextEncoderBase.h',
 ]
 
 CPP_SOURCES += [
     'EncodingUtils.cpp',
     'TextDecoder.cpp',
     'TextEncoder.cpp',
 ]
 
--- a/dom/file/ArchiveReader.cpp
+++ b/dom/file/ArchiveReader.cpp
@@ -18,24 +18,25 @@
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 USING_FILE_NAMESPACE
 
 /* static */ already_AddRefed<ArchiveReader>
-ArchiveReader::Constructor(const GlobalObject& aGlobal, nsIDOMBlob* aBlob,
+ArchiveReader::Constructor(const GlobalObject& aGlobal,
+                           nsIDOMBlob* aBlob,
                            const ArchiveReaderOptions& aOptions,
                            ErrorResult& aError)
 {
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(PrefEnabled());
 
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aError.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<ArchiveReader> reader =
     new ArchiveReader(aBlob, window, aOptions.mEncoding);
   return reader.forget();
--- a/dom/indexedDB/AsyncConnectionHelper.h
+++ b/dom/indexedDB/AsyncConnectionHelper.h
@@ -112,21 +112,16 @@ public:
     return !!mTransaction;
   }
 
   IDBTransaction* GetTransaction() const
   {
     return mTransaction;
   }
 
-  nsISupports* GetSource() const
-  {
-    return mRequest ? mRequest->Source() : nullptr;
-  }
-
   virtual nsresult GetResultCode() MOZ_OVERRIDE
   {
     return mResultCode;
   }
 
   enum ChildProcessSendResult
   {
     // The result was successfully sent to the child process
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -22,20 +22,22 @@
 #include "ProfilerHelpers.h"
 #include "TransactionThreadPool.h"
 
 #include "ipc/IndexedDBChild.h"
 #include "ipc/IndexedDBParent.h"
 
 #include "IndexedDatabaseInlines.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/UnionTypes.h"
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom::indexedDB::ipc;
 using mozilla::dom::Optional;
+using mozilla::dom::IDBObjectStoreOrIDBIndexReturnValue;
 using mozilla::ErrorResult;
 
 static_assert(sizeof(size_t) >= sizeof(IDBCursor::Direction),
               "Relying on conversion between size_t and "
               "IDBCursor::Direction");
 
 namespace {
 
@@ -513,30 +515,27 @@ IDBCursor::GetDirection() const
     case DIRECTION_INVALID:
     default:
       MOZ_CRASH("Unknown direction!");
       return mozilla::dom::IDBCursorDirection::Next;
   }
 }
 
 
-already_AddRefed<nsISupports>
-IDBCursor::Source() const
+void
+IDBCursor::GetSource(IDBObjectStoreOrIDBIndexReturnValue& aSource) const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  nsCOMPtr<nsISupports> source;
   if (mType == OBJECTSTORE) {
-    source = do_QueryInterface(mObjectStore);
+    aSource.SetAsIDBObjectStore() = mObjectStore;
   }
   else {
-    source = do_QueryInterface(mIndex);
+    aSource.SetAsIDBIndex() = mIndex;
   }
-
-  return source.forget();
 }
 
 JS::Value
 IDBCursor::GetKey(JSContext* aCx, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ASSERTION(!mKey.IsUnset() || !mHaveValue, "Bad key!");
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -17,16 +17,22 @@
 
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
 #include "mozilla/dom/indexedDB/Key.h"
 
 class nsIRunnable;
 class nsIScriptContext;
 class nsPIDOMWindow;
 
+namespace mozilla {
+namespace dom {
+class IDBObjectStoreOrIDBIndexReturnValue;
+}
+}
+
 BEGIN_INDEXEDDB_NAMESPACE
 
 class ContinueHelper;
 class ContinueObjectStoreHelper;
 class ContinueIndexHelper;
 class ContinueIndexObjectHelper;
 class IDBIndex;
 class IDBRequest;
@@ -154,18 +160,18 @@ public:
 
   // WebIDL
   IDBTransaction*
   GetParentObject() const
   {
     return mTransaction;
   }
 
-  already_AddRefed<nsISupports>
-  Source() const;
+  void
+  GetSource(IDBObjectStoreOrIDBIndexReturnValue& aSource) const;
 
   IDBCursorDirection
   GetDirection() const;
 
   JS::Value
   GetKey(JSContext* aCx, ErrorResult& aRv);
 
   JS::Value
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -697,17 +697,17 @@ IDBDatabase::MozCreateFileHandle(const n
     return nullptr;
   }
 
   if (mClosed) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
     return nullptr;
   }
 
-  nsRefPtr<IDBRequest> request = IDBRequest::Create(nullptr, this, nullptr);
+  nsRefPtr<IDBRequest> request = IDBRequest::Create(this, nullptr);
 
   nsRefPtr<CreateFileHelper> helper =
     new CreateFileHelper(this, request, aName,
                          aType.WasPassed() ? aType.Value() : EmptyString());
 
   QuotaManager* quotaManager = QuotaManager::Get();
   NS_ASSERTION(quotaManager, "We should definitely have a manager here");
 
--- a/dom/indexedDB/IDBEvents.h
+++ b/dom/indexedDB/IDBEvents.h
@@ -64,17 +64,17 @@ public:
               const nsAString& aType,
               const IDBVersionChangeEventInit& aOptions,
               ErrorResult& aRv)
   {
     uint64_t newVersion = 0;
     if (!aOptions.mNewVersion.IsNull()) {
       newVersion = aOptions.mNewVersion.Value();
     }
-    nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.Get());
+    nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.GetAsSupports());
     return CreateInternal(target, aType, aOptions.mOldVersion, newVersion);
   }
 
   uint64_t OldVersion()
   {
     return mOldVersion;
   }
 
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -4,42 +4,47 @@
  * 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 "IDBRequest.h"
 
 #include "nsIScriptContext.h"
 
 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
+#include "mozilla/dom/UnionTypes.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsStringGlue.h"
 #include "nsThreadUtils.h"
 #include "nsWrapperCacheInlines.h"
 
 #include "AsyncConnectionHelper.h"
+#include "IDBCursor.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
+#include "IDBIndex.h"
+#include "IDBObjectStore.h"
 #include "IDBTransaction.h"
 
 namespace {
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 uint64_t gNextSerialNumber = 1;
 #endif
 
 } // anonymous namespace
 
 USING_INDEXEDDB_NAMESPACE
+using mozilla::dom::IDBObjectStoreOrIDBIndexOrIDBCursorReturnValue;
 
 IDBRequest::IDBRequest()
 : mResultVal(JSVAL_VOID),
   mActorParent(nullptr),
 #ifdef MOZ_ENABLE_PROFILER_SPS
   mSerialNumber(gNextSerialNumber++),
 #endif
   mErrorCode(NS_OK),
@@ -54,32 +59,99 @@ IDBRequest::IDBRequest()
 IDBRequest::~IDBRequest()
 {
   mResultVal = JSVAL_VOID;
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 // static
 already_AddRefed<IDBRequest>
-IDBRequest::Create(nsISupports* aSource,
-                   IDBWrapperCache* aOwnerCache,
+IDBRequest::Create(IDBWrapperCache* aOwnerCache,
                    IDBTransaction* aTransaction)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBRequest> request(new IDBRequest());
 
-  request->mSource = aSource;
   request->mTransaction = aTransaction;
   request->BindToOwner(aOwnerCache);
   request->SetScriptOwner(aOwnerCache->GetScriptOwner());
   request->CaptureCaller();
 
   return request.forget();
 }
 
+// static
+already_AddRefed<IDBRequest>
+IDBRequest::Create(IDBObjectStore* aSourceAsObjectStore,
+                   IDBWrapperCache* aOwnerCache,
+                   IDBTransaction* aTransaction)
+{
+  nsRefPtr<IDBRequest> request = Create(aOwnerCache, aTransaction);
+
+  request->mSourceAsObjectStore = aSourceAsObjectStore;
+
+  return request.forget();
+}
+
+// static
+already_AddRefed<IDBRequest>
+IDBRequest::Create(IDBIndex* aSourceAsIndex,
+                   IDBWrapperCache* aOwnerCache,
+                   IDBTransaction* aTransaction)
+{
+  nsRefPtr<IDBRequest> request = Create(aOwnerCache, aTransaction);
+
+  request->mSourceAsIndex = aSourceAsIndex;
+
+  return request.forget();
+}
+
+// static
+already_AddRefed<IDBRequest>
+IDBRequest::Create(IDBCursor* aSourceAsCursor,
+                   IDBWrapperCache* aOwnerCache,
+                   IDBTransaction* aTransaction)
+{
+  nsRefPtr<IDBRequest> request = Create(aOwnerCache, aTransaction);
+
+  request->mSourceAsCursor = aSourceAsCursor;
+
+  return request.forget();
+}
+
+#ifdef DEBUG
+void
+IDBRequest::AssertSourceIsCorrect() const
+{
+  // At most one of mSourceAs* is allowed to be non-null.  Check that by
+  // summing the double negation of each one and asserting the sum is at most
+  // 1.
+
+  MOZ_ASSERT(!!mSourceAsObjectStore + !!mSourceAsIndex + !!mSourceAsCursor <= 1);
+}
+#endif
+
+void
+IDBRequest::GetSource(Nullable<IDBObjectStoreOrIDBIndexOrIDBCursorReturnValue>& aSource) const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  AssertSourceIsCorrect();
+
+  if (mSourceAsObjectStore) {
+    aSource.SetValue().SetAsIDBObjectStore() = mSourceAsObjectStore;
+  } else if (mSourceAsIndex) {
+    aSource.SetValue().SetAsIDBIndex() = mSourceAsIndex;
+  } else if (mSourceAsCursor) {
+    aSource.SetValue().SetAsIDBCursor() = mSourceAsCursor;
+  } else {
+    aSource.SetNull();
+  }
+}
+
 void
 IDBRequest::Reset()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   mResultVal = JSVAL_VOID;
   mHaveResultOrErrorCode = false;
   mError = nullptr;
 }
@@ -276,24 +348,28 @@ IDBRequest::GetError(mozilla::ErrorResul
   return mError;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
   // nsDOMEventTargetHelper does it for us.
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   tmp->mResultVal = JSVAL_VOID;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsObjectStore)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsIndex)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsCursor)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
   // nsDOMEventTargetHelper does it for us.
   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultVal)
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -16,42 +16,61 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 
 #include "mozilla/dom/indexedDB/IDBWrapperCache.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
+namespace mozilla {
+namespace dom {
+class IDBObjectStoreOrIDBIndexOrIDBCursorReturnValue;
+}
+}
+
 BEGIN_INDEXEDDB_NAMESPACE
 
 class HelperBase;
+class IDBCursor;
 class IDBFactory;
+class IDBIndex;
+class IDBObjectStore;
 class IDBTransaction;
 class IndexedDBRequestParentBase;
 
 class IDBRequest : public IDBWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBRequest,
                                                          IDBWrapperCache)
 
   static
-  already_AddRefed<IDBRequest> Create(nsISupports* aSource,
+  already_AddRefed<IDBRequest> Create(IDBWrapperCache* aOwnerCache,
+                                      IDBTransaction* aTransaction);
+
+  static
+  already_AddRefed<IDBRequest> Create(IDBObjectStore* aSource,
+                                      IDBWrapperCache* aOwnerCache,
+                                      IDBTransaction* aTransaction);
+
+  static
+  already_AddRefed<IDBRequest> Create(IDBIndex* aSource,
+                                      IDBWrapperCache* aOwnerCache,
+                                      IDBTransaction* aTransaction);
+  static
+  already_AddRefed<IDBRequest> Create(IDBCursor* aSource,
                                       IDBWrapperCache* aOwnerCache,
                                       IDBTransaction* aTransaction);
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
 
-  nsISupports* Source()
-  {
-    return mSource;
-  }
+  void GetSource(Nullable<IDBObjectStoreOrIDBIndexOrIDBCursorReturnValue>& aSource) const;
 
   void Reset();
 
   nsresult NotifyHelperCompleted(HelperBase* aHelper);
   void NotifyHelperSentResultsToChildProcess(nsresult aRv);
 
   void SetError(nsresult aRv);
 
@@ -110,23 +129,16 @@ public:
   GetParentObject() const
   {
     return GetOwner();
   }
 
   JS::Value
   GetResult(JSContext* aCx, ErrorResult& aRv) const;
 
-  nsISupports*
-  GetSource() const
-  {
-    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-    return mSource;
-  }
-
   IDBTransaction*
   GetTransaction() const
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     return mTransaction;
   }
 
   IDBRequestReadyState
@@ -134,17 +146,28 @@ public:
 
   IMPL_EVENT_HANDLER(success);
   IMPL_EVENT_HANDLER(error);
 
 protected:
   IDBRequest();
   ~IDBRequest();
 
-  nsCOMPtr<nsISupports> mSource;
+  // At most one of these three fields can be non-null.
+  nsRefPtr<IDBObjectStore> mSourceAsObjectStore;
+  nsRefPtr<IDBIndex> mSourceAsIndex;
+  nsRefPtr<IDBCursor> mSourceAsCursor;
+
+  // Check that the above condition holds.
+#ifdef DEBUG
+  void AssertSourceIsCorrect() const;
+#else
+  void AssertSourceIsCorrect() const {}
+#endif
+
   nsRefPtr<IDBTransaction> mTransaction;
 
   JS::Heap<JS::Value> mResultVal;
   nsRefPtr<mozilla::dom::DOMError> mError;
   IndexedDBRequestParentBase* mActorParent;
   nsString mFilename;
 #ifdef MOZ_ENABLE_PROFILER_SPS
   uint64_t mSerialNumber;
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_indexeddb_indexeddatabase_h__
 #define mozilla_dom_indexeddb_indexeddatabase_h__
 
 #include "nsIProgrammingLanguage.h"
 
 #include "mozilla/Attributes.h"
-#include "jsapi.h"
+#include "js/StructuredClone.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
 #define BEGIN_INDEXEDDB_NAMESPACE \
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -6,16 +6,18 @@
 
 #ifndef mozilla_dom_indexeddb_key_h__
 #define mozilla_dom_indexeddb_key_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "mozIStorageStatement.h"
 
+#include "js/Value.h"
+
 namespace IPC {
 template <typename T> struct ParamTraits;
 } // namespace IPC
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class Key
 {
@@ -154,17 +156,17 @@ public:
   void SetFromInteger(int64_t aInt)
   {
     mBuffer.Truncate();
     EncodeNumber(double(aInt), eFloat);
     TrimBuffer();
   }
 
   nsresult SetFromJSVal(JSContext* aCx,
-                        const jsval aVal)
+                        const JS::Value aVal)
   {
     mBuffer.Truncate();
 
     if (JSVAL_IS_NULL(aVal) || JSVAL_IS_VOID(aVal)) {
       Unset();
       return NS_OK;
     }
 
@@ -204,17 +206,17 @@ public:
     if (NS_SUCCEEDED(rv)) {
       aVal = value;
     }
     return rv;
   }
 
   nsresult AppendItem(JSContext* aCx,
                       bool aFirstOfArray,
-                      const jsval aVal)
+                      const JS::Value aVal)
   {
     nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0);
     if (NS_FAILED(rv)) {
       Unset();
       return rv;
     }
 
     return NS_OK;
@@ -298,17 +300,17 @@ private:
     while (!*end) {
       --end;
     }
 
     mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
   }
 
   // Encoding functions. These append the encoded value to the end of mBuffer
-  inline nsresult EncodeJSVal(JSContext* aCx, const jsval aVal,
+  inline nsresult EncodeJSVal(JSContext* aCx, const JS::Value aVal,
                               uint8_t aTypeOffset)
   {
     return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0);
   }
   void EncodeString(const nsAString& aString, uint8_t aTypeOffset);
   void EncodeNumber(double aFloat, uint8_t aType);
 
   // Decoding functions. aPos points into mBuffer and is adjusted to point
@@ -324,17 +326,17 @@ private:
                            const unsigned char* aEnd,
                            nsString& aString);
   static double DecodeNumber(const unsigned char*& aPos,
                              const unsigned char* aEnd);
 
   nsCString mBuffer;
 
 private:
-  nsresult EncodeJSValInternal(JSContext* aCx, const jsval aVal,
+  nsresult EncodeJSValInternal(JSContext* aCx, const JS::Value aVal,
                                uint8_t aTypeOffset, uint16_t aRecursionDepth);
 
   static nsresult DecodeJSValInternal(const unsigned char*& aPos,
                                       const unsigned char* aEnd,
                                       JSContext* aCx, uint8_t aTypeOffset,
                                       JS::MutableHandle<JS::Value> aVal, uint16_t aRecursionDepth);
 };
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1243,32 +1243,37 @@ ContentChild::RecvFilePathUpdate(const n
     obs->NotifyObservers(dsf, "file-watcher-update", reason.get());
     return true;
 }
 
 bool
 ContentChild::RecvFileSystemUpdate(const nsString& aFsName,
                                    const nsString& aVolumeName,
                                    const int32_t& aState,
-                                   const int32_t& aMountGeneration)
+                                   const int32_t& aMountGeneration,
+                                   const bool& aIsMediaPresent,
+                                   const bool& aIsSharing)
 {
 #ifdef MOZ_WIDGET_GONK
     nsRefPtr<nsVolume> volume = new nsVolume(aFsName, aVolumeName, aState,
-                                             aMountGeneration);
+                                             aMountGeneration, aIsMediaPresent,
+                                             aIsSharing);
 
     nsRefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
     if (vs) {
         vs->UpdateVolume(volume);
     }
 #else
     // Remove warnings about unused arguments
     unused << aFsName;
     unused << aVolumeName;
     unused << aState;
     unused << aMountGeneration;
+    unused << aIsMediaPresent;
+    unused << aIsSharing;
 #endif
     return true;
 }
 
 bool
 ContentChild::RecvNotifyProcessPriorityChanged(
     const hal::ProcessPriority& aPriority)
 {
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -203,17 +203,19 @@ public:
 
     virtual bool RecvFilePathUpdate(const nsString& aStorageType,
                                     const nsString& aStorageName,
                                     const nsString& aPath,
                                     const nsCString& aReason);
     virtual bool RecvFileSystemUpdate(const nsString& aFsName,
                                       const nsString& aVolumeName,
                                       const int32_t& aState,
-                                      const int32_t& aMountGeneration);
+                                      const int32_t& aMountGeneration,
+                                      const bool& aIsMediaPresent,
+                                      const bool& aIsSharing);
 
     virtual bool RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority);
     virtual bool RecvMinimizeMemoryUsage();
     virtual bool RecvCancelMinimizeMemoryUsage();
 
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1671,24 +1671,29 @@ ContentParent::Observe(nsISupports* aSub
         if (!vol) {
             return NS_ERROR_NOT_AVAILABLE;
         }
 
         nsString volName;
         nsString mountPoint;
         int32_t  state;
         int32_t  mountGeneration;
+        bool     isMediaPresent;
+        bool     isSharing;
 
         vol->GetName(volName);
         vol->GetMountPoint(mountPoint);
         vol->GetState(&state);
         vol->GetMountGeneration(&mountGeneration);
+        vol->GetIsMediaPresent(&isMediaPresent);
+        vol->GetIsSharing(&isSharing);
 
         unused << SendFileSystemUpdate(volName, mountPoint, state,
-                                       mountGeneration);
+                                       mountGeneration, isMediaPresent,
+                                       isSharing);
     }
 #endif
 #ifdef ACCESSIBILITY
     // Make sure accessibility is running in content process when accessibility
     // gets initiated in chrome process.
     else if (aData && (*aData == '1') &&
              !strcmp(aTopic, "a11y-init-or-shutdown")) {
         unused << SendActivateA11y();
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -264,17 +264,18 @@ child:
 
     // Notify child that last-pb-context-exited notification was observed
     LastPrivateDocShellDestroyed();
 
     FilePathUpdate(nsString storageType, nsString storageName, nsString filepath,
                    nsCString reasons);
 
     FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState,
-                     int32_t mountGeneration);
+                     int32_t mountGeneration, bool isMediaPresent,
+                     bool isSharing);
 
     NotifyProcessPriorityChanged(ProcessPriority priority);
     MinimizeMemoryUsage();
     CancelMinimizeMemoryUsage();
 
 parent:
     /**
      * Tell the content process some attributes of itself.  This is
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -10,16 +10,17 @@
 #include "nsIDOMDOMException.h"
 #include "nsIMutable.h"
 #include "nsIXPConnect.h"
 
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "nsThreadUtils.h"
 #include "StructuredCloneTags.h"
+#include "jsapi.h"
 
 using namespace mozilla::dom;
 
 namespace {
 
 void
 Error(JSContext* aCx, uint32_t aErrorId)
 {
--- a/dom/ipc/StructuredCloneUtils.h
+++ b/dom/ipc/StructuredCloneUtils.h
@@ -6,17 +6,17 @@
 
 #ifndef mozilla_dom_StructuredCloneUtils_h
 #define mozilla_dom_StructuredCloneUtils_h
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsIDOMFile.h"
 
-#include "jsapi.h"
+#include "js/StructuredClone.h"
 
 namespace mozilla {
 
 struct SerializedStructuredCloneBuffer;
 
 namespace dom {
 
 struct
--- a/dom/mobilemessage/src/gonk/MmsPduHelper.jsm
+++ b/dom/mobilemessage/src/gonk/MmsPduHelper.jsm
@@ -8,16 +8,26 @@ const {classes: Cc, interfaces: Ci, util
 
 let WSP = {};
 Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP);
 
 Cu.import("resource://gre/modules/mms_consts.js");
 
 let DEBUG; // set to true to see debug messages
 
+this.MMS_VERSION = (function () {
+  Cu.import("resource://gre/modules/Services.jsm");
+
+  try {
+    return Services.prefs.getIntPref("dom.mms.version");
+  } catch(ex) {}
+
+  return MMS_VERSION_1_3;
+})();
+
 this.translatePduErrorToStatus = function translatePduErrorToStatus(error) {
   if (error == MMS_PDU_ERROR_OK) {
     return MMS_PDU_STATUS_RETRIEVED;
   }
 
   if ((error >= MMS_PDU_ERROR_TRANSIENT_FAILURE)
       && (error < MMS_PDU_ERROR_PERMANENT_FAILURE)) {
     return MMS_PDU_STATUS_DEFERRED;
@@ -1694,16 +1704,19 @@ if (DEBUG) {
   debug = function (s) {
     dump("-$- MmsPduHelper: " + s + "\n");
   };
 } else {
   debug = function (s) {};
 }
 
 this.EXPORTED_SYMBOLS = ALL_CONST_SYMBOLS.concat([
+  // Constant values
+  "MMS_VERSION",
+
   // Utility functions
   "translatePduErrorToStatus",
 
   // Decoders
   "BooleanValue",
   "Address",
   "HeaderField",
   "MmsHeader",
--- a/dom/mobilemessage/src/gonk/MmsService.js
+++ b/dom/mobilemessage/src/gonk/MmsService.js
@@ -1156,16 +1156,22 @@ AcknowledgeTransaction.prototype = {
                                       this.istream, requestCallback);
   }
 };
 
 /**
  * MmsService
  */
 function MmsService() {
+  if (DEBUG) {
+    let macro = (MMS.MMS_VERSION >> 4) & 0x0f;
+    let minor = MMS.MMS_VERSION & 0x0f;
+    debug("Running protocol version: " + macro + "." + minor);
+  }
+
   // TODO: bug 810084 - support application identifier
 }
 MmsService.prototype = {
 
   classID:   RIL_MMSSERVICE_CID,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMmsService,
                                          Ci.nsIWapPushApplication]),
   /*
--- a/dom/mobilemessage/src/gonk/mms_consts.js
+++ b/dom/mobilemessage/src/gonk/mms_consts.js
@@ -24,19 +24,20 @@ this.MMS_PDU_TYPE_MBOX_UPLOAD_CONF = 144
 this.MMS_PDU_TYPE_MBOX_DELETE_REQ = 145;
 this.MMS_PDU_TYPE_MBOX_DELETE_CONF = 146;
 this.MMS_PDU_TYPE_MBOX_DESCR = 147;
 this.MMS_PDU_TYPE_DELETE_REQ = 148;
 this.MMS_PDU_TYPE_DELETE_CONF = 149;
 this.MMS_PDU_TYPE_CANCEL_REQ = 150;
 this.MMS_PDU_TYPE_CANCEL_CONF = 151;
 
-// MMS version 1.3
+// MMS version
 // @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34
-this.MMS_VERSION = (0x01 << 4) | 0x03;
+this.MMS_VERSION_1_1 = (0x01 << 4) | 0x01;
+this.MMS_VERSION_1_3 = (0x01 << 4) | 0x03;
 
 // Common Status Values
 this.MMS_PDU_ERROR_OK                = 128;
 this.MMS_PDU_ERROR_TRANSIENT_FAILURE = 192;
 this.MMS_PDU_ERROR_PERMANENT_FAILURE = 224;
 
 // X-Mms-Response-Status values
 // @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.48
--- a/dom/mobilemessage/tests/marionette/manifest.ini
+++ b/dom/mobilemessage/tests/marionette/manifest.ini
@@ -11,18 +11,17 @@ qemu = true
 [test_incoming_delete.js]
 [test_outgoing_delete.js]
 [test_getmessage.js]
 [test_getmessage_notfound.js]
 [test_incoming_multipart.js]
 [test_getmessages.js]
 [test_filter_date.js]
 [test_filter_date_notfound.js]
-[test_filter_number_single.js]
-[test_filter_number_multiple.js]
+[test_filter_number.js]
 [test_filter_received.js]
 [test_filter_sent.js]
 [test_filter_read.js]
 [test_filter_unread.js]
 [test_filter_mixed.js]
 [test_segment_info.js]
 [test_mark_msg_read.js]
 [test_mark_msg_read_error.js]
new file mode 100644
--- /dev/null
+++ b/dom/mobilemessage/tests/marionette/test_filter_number.js
@@ -0,0 +1,201 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+
+const NUM_THREADS = 10;
+const REMOTE_NATIONAL_NUMBER = "555531555";
+const REMOTE_INTERNATIONAL_NUMBER = "+1" + REMOTE_NATIONAL_NUMBER;
+
+SpecialPowers.addPermission("sms", true, document);
+SpecialPowers.setBoolPref("dom.sms.enabled", true);
+
+let pendingEmulatorCmdCount = 0;
+function sendSmsToEmulator(from, text) {
+  ++pendingEmulatorCmdCount;
+
+  let cmd = "sms send " + from + " " + text;
+  runEmulatorCmd(cmd, function (result) {
+    --pendingEmulatorCmdCount;
+
+    is(result[0], "OK", "Emulator response");
+  });
+}
+
+let tasks = {
+  // List of test fuctions. Each of them should call |tasks.next()| when
+  // completed or |tasks.finish()| to jump to the last one.
+  _tasks: [],
+  _nextTaskIndex: 0,
+
+  push: function push(func) {
+    this._tasks.push(func);
+  },
+
+  next: function next() {
+    let index = this._nextTaskIndex++;
+    let task = this._tasks[index];
+    try {
+      task();
+    } catch (ex) {
+      ok(false, "test task[" + index + "] throws: " + ex);
+      // Run last task as clean up if possible.
+      if (index != this._tasks.length - 1) {
+        this.finish();
+      }
+    }
+  },
+
+  finish: function finish() {
+    this._tasks[this._tasks.length - 1]();
+  },
+
+  run: function run() {
+    this.next();
+  }
+};
+
+let manager;
+function getAllMessages(callback, filter, reverse) {
+  if (!filter) {
+    filter = new MozSmsFilter;
+  }
+  let messages = [];
+  let request = manager.getMessages(filter, reverse || false);
+  request.onsuccess = function(event) {
+    if (request.result) {
+      messages.push(request.result);
+      request.continue();
+      return;
+    }
+
+    window.setTimeout(callback.bind(null, messages), 0);
+  }
+}
+
+function deleteAllMessages() {
+  log("Deleting all messages.");
+  getAllMessages(function deleteAll(messages) {
+    let message = messages.shift();
+    if (!message) {
+      ok(true, "all messages deleted");
+      tasks.next();
+      return;
+    }
+
+    let request = manager.delete(message.id);
+    request.onsuccess = deleteAll.bind(null, messages);
+    request.onerror = function (event) {
+      ok(false, "failed to delete all messages");
+      tasks.finish();
+    }
+  });
+}
+
+function checkMessage(needle, secondary) {
+  log("  Verifying " + needle);
+
+  let filter = new MozSmsFilter();
+  filter.numbers = [needle];
+  getAllMessages(function (messages) {
+    is(messages.length, 2, "should have exactly 2 messages");
+
+    // Check the messages are sent to/received from either 'needle' or
+    // 'secondary' number.
+    let validNumbers = [needle, secondary];
+    for (let message of messages) {
+      let number = (message.delivery === "received") ? message.sender
+                                                     : message.receiver;
+      let index = validNumbers.indexOf(number);
+      ok(index >= 0, "message.number");
+      validNumbers.splice(index, 1); // Remove from validNumbers.
+    }
+
+    tasks.next();
+  }, filter);
+}
+
+tasks.push(function verifyInitialState() {
+  log("Verifying initial state.");
+  manager = window.navigator.mozMobileMessage;
+  ok(manager instanceof MozMobileMessageManager,
+     "manager is instance of " + manager.constructor);
+  tasks.next();
+});
+
+tasks.push(deleteAllMessages);
+
+/**
+ * Populate database with messages to being tests. We'll have NUM_THREADS
+ * sent and received messages.
+ *
+ *   send    to   "+15555315550"
+ *   receive from "5555315550", count = 1
+ *
+ *   send    to   "+15555315551"
+ *   receive from "5555315551", count = 2
+ *   ...
+ *   send    to   "+15555315559"
+ *   receive from "5555315559", count = 10
+ */
+tasks.push(function populateMessages() {
+  log("Populating messages.");
+  let count = 0;
+
+  function sendMessage(iter) {
+    let request = manager.send(REMOTE_INTERNATIONAL_NUMBER + iter,
+                               "Nice to meet you");
+    request.onsuccess = function onRequestSuccess(event) {
+      sendSmsToEmulator(REMOTE_NATIONAL_NUMBER + iter,
+                        "Nice to meet you, too");
+    }
+    request.onerror = function onRequestError(event) {
+      tasks.finish();
+    }
+  }
+
+  manager.addEventListener("received", function onReceived(event) {
+    ++count;
+    if (count < NUM_THREADS) {
+      sendMessage(count);
+    } else {
+      manager.removeEventListener("received", onReceived);
+      tasks.next();
+    }
+  });
+
+  sendMessage(count);
+});
+
+tasks.push(function () {
+  log("Verifying number of messages in database");
+  getAllMessages(function (messages) {
+    is(messages.length, NUM_THREADS * 2,
+       "should have exactly " + (NUM_THREADS * 2) + " messages");
+
+    tasks.next();
+  });
+});
+
+for (let iter = 0; iter < NUM_THREADS; iter++) {
+  let national = REMOTE_NATIONAL_NUMBER + iter;
+  let international = REMOTE_INTERNATIONAL_NUMBER + iter;
+  tasks.push(checkMessage.bind(null, national, international));
+  tasks.push(checkMessage.bind(null, international, national));
+}
+
+tasks.push(deleteAllMessages);
+
+// WARNING: All tasks should be pushed before this!!!
+tasks.push(function cleanUp() {
+  if (pendingEmulatorCmdCount) {
+    window.setTimeout(cleanUp, 100);
+    return;
+  }
+
+  SpecialPowers.removePermission("sms", document);
+  SpecialPowers.clearUserPref("dom.sms.enabled");
+  finish();
+});
+
+tasks.run();
deleted file mode 100644
--- a/dom/mobilemessage/tests/marionette/test_filter_number_multiple.js
+++ /dev/null
@@ -1,249 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 60000;
-
-SpecialPowers.addPermission("sms", true, document);
-SpecialPowers.setBoolPref("dom.sms.enabled", true);
-
-let manager = window.navigator.mozMobileMessage;
-let numberMsgs = 10;
-let smsList = new Array();
-let defaultRemoteNumber = "+15552227777";
-
-function verifyInitialState() {
-  log("Verifying initial state.");
-  ok(manager instanceof MozMobileMessageManager,
-     "manager is instance of " + manager.constructor);
-  // Ensure test is starting clean with no existing sms messages
-  deleteAllMsgs(sendSms);
-}
-
-function deleteAllMsgs(nextFunction) {
-  // Check for any existing SMS messages, if any are found delete them
-  let msgList = new Array();
-  let filter = new MozSmsFilter;
-
-  let cursor = manager.getMessages(filter, false);
-  ok(cursor instanceof DOMCursor,
-      "cursor is instanceof " + cursor.constructor);
-
-  cursor.onsuccess = function(event) {
-    // Check if message was found
-    if (cursor.result) {
-      msgList.push(cursor.result.id);
-      // Now get next message in the list
-      cursor.continue();
-    } else {
-      // No (more) messages found
-      if (msgList.length) {
-        log("Found " + msgList.length + " SMS messages to delete.");
-        deleteMsgs(msgList, nextFunction);
-      } else {
-        log("No SMS messages found.");
-        nextFunction();
-      }
-    }
-  };
-
-  cursor.onerror = function(event) {
-    log("Received 'onerror' event.");
-    ok(event.target.error, "domerror obj");
-    log("manager.getMessages error: " + event.target.error.name);
-    ok(false,"Could not get SMS messages");
-    cleanUp();
-  };
-}
-
-function deleteMsgs(msgList, nextFunction) {
-  // Delete the SMS messages specified in the given list
-  let smsId = msgList.shift();
-
-  log("Deleting SMS (id: " + smsId + ").");
-  let request = manager.delete(smsId);
-  ok(request instanceof DOMRequest,
-      "request is instanceof " + request.constructor);
-
-  request.onsuccess = function(event) {
-    log("Received 'onsuccess' smsrequest event.");
-    if (event.target.result) {
-      // Message deleted, continue until none are left
-      if (msgList.length) {
-        deleteMsgs(msgList, nextFunction);
-      } else {
-        log("Finished deleting SMS messages.");
-        nextFunction();
-      }
-    } else {
-      log("SMS delete failed.");
-      ok(false,"manager.delete request returned false");
-      cleanUp();
-    }
-  };
-
-  request.onerror = function(event) {
-    log("Received 'onerror' smsrequest event.");
-    ok(event.target.error, "domerror obj");
-    ok(false, "manager.delete request returned unexpected error: "
-        + event.target.error.name );
-    cleanUp();
-  };
-}
-
-function sendSms() {
-  // Send an SMS to a unique number that will fall outside of the filter
-  let gotSmsSent = false;
-  let gotRequestSuccess = false;
-  let remoteNumber = "+15558120649";
-  let text = "Outgoing SMS brought to you by Firefox OS!";
-
-  log("Sending an SMS.");
-
-  manager.onsent = function(event) {
-    log("Received 'onsent' event.");
-    gotSmsSent = true;
-    log("Sent SMS (id: " + event.message.id + ").");
-    if (gotSmsSent && gotRequestSuccess) {
-      simulateIncomingSms();
-    }
-  };
-
-  let request = manager.send(remoteNumber, text);
-  ok(request instanceof DOMRequest,
-      "request is instanceof " + request.constructor);
-
-  request.onsuccess = function(event) {
-    log("Received 'onsuccess' smsrequest event.");
-    if (event.target.result) {
-      gotRequestSuccess = true;
-      if (gotSmsSent && gotRequestSuccess) {
-        simulateIncomingSms();
-      }
-    } else {
-      log("smsrequest returned false for manager.send");
-      ok(false,"SMS send failed");
-      cleanUp();
-    }
-  };
-
-  request.onerror = function(event) {
-    log("Received 'onerror' smsrequest event.");
-    ok(event.target.error, "domerror obj");
-    ok(false, "manager.send request returned unexpected error: "
-        + event.target.error.name );
-    cleanUp();
-  };
-}
-
-function simulateIncomingSms(remoteNumber) {
-  // Simulate incoming SMS messages from specified (or default) remote number
-  let text = "Incoming SMS number " + (smsList.length + 1);
-  remoteNumber = typeof remoteNumber !== 'undefined'
-    ? remoteNumber : defaultRemoteNumber;
-
-  log("Simulating incoming SMS number " + (smsList.length + 1) + " of "
-      + (numberMsgs - 1) + ".");
-
-  // Simulate incoming SMS sent from remoteNumber to our emulator
-  rcvdEmulatorCallback = false;
-  runEmulatorCmd("sms send " + remoteNumber + " " + text, function(result) {
-    is(result[0], "OK", "emulator callback");
-    rcvdEmulatorCallback = true;
-  });
-}
-
-manager.onreceived = function onreceived(event) {
-  // Callback for incoming SMS
-  log("Received 'onreceived' sms event.");
-  let incomingSms = event.message;
-  log("Received SMS (id: " + incomingSms.id + ").");
-
-  smsList.push(incomingSms);
-
-  // Wait for emulator to catch up before continuing
-  waitFor(nextRep,function() {
-    return(rcvdEmulatorCallback);
-  });
-};
-
-function nextRep() {
-  // Keep simulating incoming messages until have received specified number
-  let secondNumber = "+15559990000";
-  if (smsList.length < (numberMsgs - 1)) {
-    // Have every other SMS be from different number, so filter won't find all
-    if (smsList.length % 2) {
-      simulateIncomingSms(secondNumber);
-    } else {
-      simulateIncomingSms();
-    }
-  } else {
-    getMsgs(secondNumber);
-  }
-}
-
-function getMsgs(secondNumber) {
-  // Set the filter and test it via getMessages
-  var filter = new MozSmsFilter();
-  let foundSmsList = new Array();
-
-  // Set filter for default and second number
-  filter.numbers = new Array(defaultRemoteNumber, secondNumber);
-
-  log("Getting the SMS messages with numbers " + defaultRemoteNumber + " and "
-      + secondNumber + ".");
-  let cursor = manager.getMessages(filter, false);
-  ok(cursor instanceof DOMCursor,
-      "cursor is instanceof " + cursor.constructor);
-
-  cursor.onsuccess = function(event) {
-    log("Received 'onsuccess' event.");
-
-    if (cursor.result) {
-      // Another message found
-      log("Got SMS (id: " + cursor.result.id + ").");
-      // Store found message
-      foundSmsList.push(cursor.result);
-      // Now get next message in the list
-      cursor.continue();
-    } else {
-      // No more messages; ensure correct number of SMS messages were found
-      if (foundSmsList.length == smsList.length) {
-        log("SMS getMessages returned " + foundSmsList.length +
-            " messages as expected.");
-        verifyFoundMsgs(foundSmsList);
-      } else {
-        log("SMS getMessages returned " + foundSmsList.length +
-            " messages, but expected " + smsList.length + ".");
-        ok(false, "Incorrect number of messages returned by manager.getMessages");
-        deleteAllMsgs(cleanUp);
-      }
-    }
-  };
-
-  cursor.onerror = function(event) {
-    log("Received 'onerror' event.");
-    ok(event.target.error, "domerror obj");
-    log("manager.getMessages error: " + event.target.error.name);
-    ok(false,"Could not get SMS messages");
-    cleanUp();
-  };
-}
-
-function verifyFoundMsgs(foundSmsList) {
-  // Verify the SMS messages returned by getMessages are the correct ones
-  for (var x = 0; x < foundSmsList.length; x++) {
-    is(foundSmsList[x].id, smsList[x].id, "id");
-    is(foundSmsList[x].sender, smsList[x].sender, "number");
-  }
-  deleteAllMsgs(cleanUp);
-}
-
-function cleanUp() {
-  manager.onreceived = null;
-  SpecialPowers.removePermission("sms", document);
-  SpecialPowers.clearUserPref("dom.sms.enabled");
-  finish();
-}
-
-// Start the test
-verifyInitialState();
deleted file mode 100644
--- a/dom/mobilemessage/tests/marionette/test_filter_number_single.js
+++ /dev/null
@@ -1,207 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-MARIONETTE_TIMEOUT = 60000;
-
-SpecialPowers.addPermission("sms", true, document);
-SpecialPowers.setBoolPref("dom.sms.enabled", true);
-
-let manager = window.navigator.mozMobileMessage;
-let numberMsgs = 10;
-let smsList = new Array();
-let defaultRemoteNumber = "+15552227777";
-
-function verifyInitialState() {
-  log("Verifying initial state.");
-  ok(manager instanceof MozMobileMessageManager,
-     "manager is instance of " + manager.constructor);
-  // Ensure test is starting clean with no existing sms messages
-  deleteAllMsgs(simulateIncomingSms);
-}
-
-function deleteAllMsgs(nextFunction) {
-  // Check for any existing SMS messages, if any are found delete them
-  let msgList = new Array();
-  let filter = new MozSmsFilter;
-
-  let cursor = manager.getMessages(filter, false);
-  ok(cursor instanceof DOMCursor,
-      "cursor is instanceof " + cursor.constructor);
-
-  cursor.onsuccess = function(event) {
-    // Check if message was found
-    if (cursor.result) {
-      msgList.push(cursor.result.id);
-      // Now get next message in the list
-      cursor.continue();
-    } else {
-      // No (more) messages found
-      if (msgList.length) {
-        log("Found " + msgList.length + " SMS messages to delete.");
-        deleteMsgs(msgList, nextFunction);
-      } else {
-        log("No SMS messages found.");
-        nextFunction();
-      }
-    }
-  };
-
-  cursor.onerror = function(event) {
-    log("Received 'onerror' event.");
-    ok(event.target.error, "domerror obj");
-    log("manager.getMessages error: " + event.target.error.name);
-    ok(false,"Could not get SMS messages");
-    cleanUp();
-  };
-}
-
-function deleteMsgs(msgList, nextFunction) {
-  // Delete the SMS messages specified in the given list
-  let smsId = msgList.shift();
-
-  log("Deleting SMS (id: " + smsId + ").");
-  let request = manager.delete(smsId);
-  ok(request instanceof DOMRequest,
-      "request is instanceof " + request.constructor);
-
-  request.onsuccess = function(event) {
-    log("Received 'onsuccess' smsrequest event.");
-    if (event.target.result) {
-      // Message deleted, continue until none are left
-      if (msgList.length) {
-        deleteMsgs(msgList, nextFunction);
-      } else {
-        log("Finished deleting SMS messages.");
-        nextFunction();
-      }
-    } else {
-      log("SMS delete failed.");
-      ok(false,"manager.delete request returned false");
-      cleanUp();
-    }
-  };
-
-  request.onerror = function(event) {
-    log("Received 'onerror' smsrequest event.");
-    ok(event.target.error, "domerror obj");
-    ok(false, "manager.delete request returned unexpected error: "
-        + event.target.error.name );
-    cleanUp();
-  };
-}
-
-function simulateIncomingSms(remoteNumber) {
-  // Simulate incoming SMS messages from specified (or default) remote number
-  let text = "Incoming SMS number " + (smsList.length + 1);
-  remoteNumber = typeof remoteNumber !== 'undefined'
-    ? remoteNumber : defaultRemoteNumber;
-
-  log("Simulating incoming SMS number " + (smsList.length + 1) + " of "
-      + numberMsgs + ".");
-
-  // Simulate incoming sms sent from remoteNumber to our emulator
-  rcvdEmulatorCallback = false;
-  runEmulatorCmd("sms send " + remoteNumber + " " + text, function(result) {
-    is(result[0], "OK", "emulator callback");
-    rcvdEmulatorCallback = true;
-  });
-}
-
-manager.onreceived = function onreceived(event) {
-  // Callback for incoming SMS
-  log("Received 'onreceived' sms event.");
-  let incomingSms = event.message;
-  log("Received SMS (id: " + incomingSms.id + ").");
-
-  smsList.push(incomingSms);
-
-  // Wait for emulator to catch up before continuing
-  waitFor(nextRep,function() {
-    return(rcvdEmulatorCallback);
-  });
-};
-
-function nextRep() {
-  // Keep simulating incoming messages until have received specified number
-  if (smsList.length < numberMsgs) {
-    // Have every other sms be from different number, so filter won't find all
-    if (smsList.length % 2) {
-      simulateIncomingSms("+15559990000");
-    } else {
-      simulateIncomingSms();
-    }
-  } else {
-    getMsgs();
-  }
-}
-
-function getMsgs() {
-  // Set the filter and test it via getMessages
-  var filter = new MozSmsFilter();
-  let foundSmsList = new Array();
-
-  // Going to filter for one number only, so set our expected SMS array
-  smsList = smsList.filter(function(i) {
-    return i.sender != defaultRemoteNumber ? false: true;
-  });
-
-  // Set filter for default remote number
-  filter.numbers = new Array(defaultRemoteNumber);
-
-  log("Getting the SMS messages from sender " + defaultRemoteNumber + ".");
-  let cursor = manager.getMessages(filter, false);
-  ok(cursor instanceof DOMCursor,
-      "cursor is instanceof " + cursor.constructor);
-
-  cursor.onsuccess = function(event) {
-    log("Received 'onsuccess' event.");
-
-    if (cursor.result) {
-      // Another message found
-      log("Got SMS (id: " + cursor.result.id + ").");
-      // Store found message
-      foundSmsList.push(cursor.result);
-      // Now get next message in the list
-      cursor.continue();
-    } else {
-      // No more messages; ensure correct number of SMS messages were found
-      if (foundSmsList.length == smsList.length) {
-        log("SMS getMessages returned " + foundSmsList.length +
-            " messages as expected.");
-        verifyFoundMsgs(foundSmsList);
-      } else {
-        log("SMS getMessages returned " + foundSmsList.length +
-            " messages, but expected " + smsList.length + ".");
-        ok(false, "Incorrect number of messages returned by manager.getMessages");
-        deleteAllMsgs(cleanUp);
-      }
-    }
-  };
-
-  cursor.onerror = function(event) {
-    log("Received 'onerror' event.");
-    ok(event.target.error, "domerror obj");
-    log("manager.getMessages error: " + event.target.error.name);
-    ok(false,"Could not get SMS messages");
-    cleanUp();
-  };
-}
-
-function verifyFoundMsgs(foundSmsList) {
-  // Verify the SMS messages returned by getMessages are the correct ones
-  for (var x = 0; x < foundSmsList.length; x++) {
-    is(foundSmsList[x].id, smsList[x].id, "id");
-    is(foundSmsList[x].sender, smsList[x].sender, "number");
-  }
-  deleteAllMsgs(cleanUp);
-}
-
-function cleanUp() {
-  manager.onreceived = null;
-  SpecialPowers.removePermission("sms", document);
-  SpecialPowers.clearUserPref("dom.sms.enabled");
-  finish();
-}
-
-// Start the test
-verifyInitialState();
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -139,65 +139,66 @@ EnterCompartment(Maybe<JSAutoCompartment
   // FIXME Bug 878849
   if (aValue.WasPassed() && aValue.Value().isObject()) {
     JS::Rooted<JSObject*> rooted(aCx, &aValue.Value().toObject());
     aAc.construct(aCx, rooted);
   }
 }
 
 /* static */ already_AddRefed<Promise>
-Promise::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
+Promise::Constructor(const GlobalObject& aGlobal,
                      PromiseInit& aInit, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  JSContext* cx = aGlobal.GetContext();
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<Promise> promise = new Promise(window);
 
   aInit.Call(promise, *promise->mResolver, aRv,
              CallbackObject::eRethrowExceptions);
   aRv.WouldReportJSException();
 
   if (aRv.IsJSException()) {
-    Optional<JS::Handle<JS::Value> > value(aCx);
-    aRv.StealJSException(aCx, &value.Value());
+    Optional<JS::Handle<JS::Value> > value(cx);
+    aRv.StealJSException(cx, &value.Value());
 
     Maybe<JSAutoCompartment> ac;
-    EnterCompartment(ac, aCx, value);
-    promise->mResolver->Reject(aCx, value);
+    EnterCompartment(ac, cx, value);
+    promise->mResolver->Reject(cx, value);
   }
 
   return promise.forget();
 }
 
 /* static */ already_AddRefed<Promise>
 Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
                  JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<Promise> promise = new Promise(window);
 
   Optional<JS::Handle<JS::Value> > value(aCx, aValue);
   promise->mResolver->Resolve(aCx, value);
   return promise.forget();
 }
 
 /* static */ already_AddRefed<Promise>
 Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
                 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<Promise> promise = new Promise(window);
 
   Optional<JS::Handle<JS::Value> > value(aCx, aValue);
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -49,17 +49,17 @@ public:
   {
     return mWindow;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   static already_AddRefed<Promise>
-  Constructor(const GlobalObject& aGlobal, JSContext* aCx, PromiseInit& aInit,
+  Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
               ErrorResult& aRv);
 
   static already_AddRefed<Promise>
   Resolve(const GlobalObject& aGlobal, JSContext* aCx,
           JS::Handle<JS::Value> aValue, ErrorResult& aRv);
 
   static already_AddRefed<Promise>
   Reject(const GlobalObject& aGlobal, JSContext* aCx,
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -300,17 +300,17 @@ Notification::Constructor(const GlobalOb
 
   nsRefPtr<Notification> notification = new Notification(aTitle,
                                                          aOptions.mBody,
                                                          aOptions.mDir,
                                                          aOptions.mLang,
                                                          tag,
                                                          aOptions.mIcon);
 
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
   MOZ_ASSERT(window, "Window should not be null.");
   notification->BindToOwner(window);
 
   // Queue a task to show the notification.
   nsCOMPtr<nsIRunnable> showNotificationTask =
     new NotificationTask(notification, NotificationTask::eShow);
   NS_DispatchToMainThread(showNotificationTask);
 
@@ -365,18 +365,18 @@ Notification::ShowInternal()
 }
 
 void
 Notification::RequestPermission(const GlobalObject& aGlobal,
                                 const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
                                 ErrorResult& aRv)
 {
   // Get principal from global to make permission request for notifications.
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
-  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal.GetAsSupports());
   if (!sop) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
 
   NotificationPermissionCallback* permissionCallback = nullptr;
   if (aCallback.WasPassed()) {
@@ -386,17 +386,17 @@ Notification::RequestPermission(const Gl
     new NotificationPermissionRequest(principal, window, permissionCallback);
 
   NS_DispatchToMainThread(request);
 }
 
 NotificationPermission
 Notification::GetPermission(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
-  return GetPermissionInternal(aGlobal.Get(), aRv);
+  return GetPermissionInternal(aGlobal.GetAsSupports(), aRv);
 }
 
 NotificationPermission
 Notification::GetPermissionInternal(nsISupports* aGlobal, ErrorResult& aRv)
 {
   // Get principal from global to check permission for notifications.
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
   if (!sop) {
--- a/dom/system/gonk/AutoMounter.cpp
+++ b/dom/system/gonk/AutoMounter.cpp
@@ -438,16 +438,17 @@ AutoMounter::UpdateState()
                               NewRunnableMethod(this, &AutoMounter::UpdateState),
                               5000);
             break;
           }
 
           // Volume is mounted, we need to unmount before
           // we can share.
           LOG("UpdateState: Unmounting %s", vol->NameStr());
+          vol->SetIsSharing(true);
           vol->StartUnmount(mResponseCallback);
           return; // UpdateState will be called again when the Unmount command completes
         }
         case nsIVolume::STATE_IDLE: {
           // Volume is unmounted. We can go ahead and share.
           LOG("UpdateState: Sharing %s", vol->NameStr());
           vol->StartShare(mResponseCallback);
           return; // UpdateState will be called again when the Share command completes
--- a/dom/system/gonk/Volume.cpp
+++ b/dom/system/gonk/Volume.cpp
@@ -54,22 +54,29 @@ static int32_t sMountGeneration = 0;
 // assume it's present, and we'll be told that it's missing.
 Volume::Volume(const nsCSubstring& aName)
   : mMediaPresent(true),
     mState(nsIVolume::STATE_INIT),
     mName(aName),
     mMountGeneration(-1),
     mMountLocked(true),  // Needs to agree with nsVolume::nsVolume
     mSharingEnabled(false),
-    mCanBeShared(true)
+    mCanBeShared(true),
+    mIsSharing(false)
 {
   DBG("Volume %s: created", NameStr());
 }
 
 void
+Volume::SetIsSharing(bool aIsSharing)
+{
+  mIsSharing = aIsSharing;
+}
+
+void
 Volume::SetMediaPresent(bool aMediaPresent)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   // mMediaPresent is slightly redunant to the state, however
   // when media is removed (while Idle), we get the following:
   //    631 Volume sdcard /mnt/sdcard disk removed (179:0)
@@ -128,19 +135,39 @@ Volume::SetState(Volume::STATE aNewState
         StateStr(aNewState), mMountPoint.get(), mEventObserverList.Length(),
         mMountGeneration, (int)mMountLocked);
   } else {
     LOG("Volume %s: changing state from %s to %s (%d observers)",
         NameStr(), StateStr(mState),
         StateStr(aNewState), mEventObserverList.Length());
   }
 
-  if (aNewState == nsIVolume::STATE_NOMEDIA) {
-    // Cover the startup case where we don't get insertion/removal events
-    mMediaPresent = false;
+  switch (aNewState) {
+     case nsIVolume::STATE_NOMEDIA:
+       // Cover the startup case where we don't get insertion/removal events
+       mMediaPresent = false;
+       mIsSharing = false;
+       break;
+
+     case nsIVolume::STATE_MOUNTED:
+     case nsIVolume::STATE_FORMATTING:
+       mIsSharing = false;
+       break;
+
+     case nsIVolume::STATE_SHARED:
+     case nsIVolume::STATE_SHAREDMNT:
+       // Covers startup cases. Normally, mIsSharing would be set to true
+       // when we issue the command to initiate the sharing process, but
+       // it's conceivable that a volume could already be in a shared state
+       // when b2g starts.
+       mIsSharing = true;
+       break;
+
+     default:
+       break;
   }
   mState = aNewState;
   mEventObserverList.Broadcast(this);
 }
 
 void
 Volume::SetMountPoint(const nsCSubstring& aMountPoint)
 {
--- a/dom/system/gonk/Volume.h
+++ b/dom/system/gonk/Volume.h
@@ -42,16 +42,17 @@ public:
   // (i.e. path that leads to the files stored on the volume).
   const nsCString& MountPoint() const { return mMountPoint; }
 
   int32_t MountGeneration() const     { return mMountGeneration; }
   bool IsMountLocked() const          { return mMountLocked; }
   bool MediaPresent() const           { return mMediaPresent; }
   bool CanBeShared() const            { return mCanBeShared; }
   bool IsSharingEnabled() const       { return mCanBeShared && mSharingEnabled; }
+  bool IsSharing() const              { return mIsSharing; }
 
   void SetSharingEnabled(bool aSharingEnabled);
 
   typedef mozilla::Observer<Volume *>     EventObserver;
   typedef mozilla::ObserverList<Volume *> EventObserverList;
 
   // NOTE: that observers must live in the IOThread.
   static void RegisterObserver(EventObserver* aObserver);
@@ -66,16 +67,17 @@ private:
   // The StartXxx functions will queue up a command to the VolumeManager.
   // You can queue up as many commands as you like, and aCallback will
   // be called as each one completes.
   void StartMount(VolumeResponseCallback* aCallback);
   void StartUnmount(VolumeResponseCallback* aCallback);
   void StartShare(VolumeResponseCallback* aCallback);
   void StartUnshare(VolumeResponseCallback* aCallback);
 
+  void SetIsSharing(bool aIsSharing);
   void SetState(STATE aNewState);
   void SetMediaPresent(bool aMediaPresent);
   void SetMountPoint(const nsCSubstring& aMountPoint);
   void StartCommand(VolumeCommand* aCommand);
 
   void HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer);
 
   static void UpdateMountLock(const nsACString& aVolumeName,
@@ -85,16 +87,17 @@ private:
   bool              mMediaPresent;
   STATE             mState;
   const nsCString   mName;
   nsCString         mMountPoint;
   int32_t           mMountGeneration;
   bool              mMountLocked;
   bool              mSharingEnabled;
   bool              mCanBeShared;
+  bool              mIsSharing;
 
   static EventObserverList mEventObserverList;
 };
 
 } // system
 } // mozilla
 
 #endif  // mozilla_system_volumemanager_h__
--- a/dom/system/gonk/nsIVolume.idl
+++ b/dom/system/gonk/nsIVolume.idl
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIVolumeStat.idl"
 
-[scriptable, uuid(4b5bd562-bd05-4658-ab0f-f668a9e25fb5)]
+[scriptable, uuid(e476e7ea-5cde-4d5a-b00d-d60daad76398)]
 interface nsIVolume : nsISupports
 {
   // These MUST match the states from android's system/vold/Volume.h header
   const long STATE_INIT        = -1;
   const long STATE_NOMEDIA     = 0;
   const long STATE_IDLE        = 1;
   const long STATE_PENDING     = 2;
   const long STATE_CHECKING    = 3;
@@ -43,16 +43,30 @@ interface nsIVolume : nsISupports
   // using the name of this attribute. Note that mountLockName changes
   // every time the mountGeneration changes, so you'll need to reacquire
   // the wakelock every time the volume becomes mounted.
   readonly attribute DOMString mountLockName;
 
   // Determines if a mountlock is currently being held against this volume.
   readonly attribute boolean isMountLocked;
 
+  // Determines if media is actually present or not. Note, that when an sdcard
+  // is ejected, it may go through several tranistory states before finally
+  // arriving at STATE_NOMEDIA. So isMediaPresent may be false even when the
+  // current state isn't STATE_NOMEDIA.
+  readonly attribute boolean isMediaPresent;
+
+  // Determines if the volume is currently being shared. This covers off
+  // more than just state == STATE_SHARED. isSharing will return true from the
+  // time that the volume leaves the mounted state, until it gets back to
+  // mounted, nomedia, or formatting states. This attribute is to allow
+  // device storage to suppress unwanted 'unavailable' status when
+  // transitioning from mounted to sharing and back again.
+  readonly attribute boolean isSharing;
+
   nsIVolumeStat getStats();
 
   // Whether this is a fake volume.
   readonly attribute boolean isFake;
 };
 
 %{C++
 // For use with the ObserverService
--- a/dom/system/gonk/nsVolume.cpp
+++ b/dom/system/gonk/nsVolume.cpp
@@ -46,17 +46,19 @@ NS_VolumeStateStr(int32_t aState)
 NS_IMPL_ISUPPORTS1(nsVolume, nsIVolume)
 
 nsVolume::nsVolume(const Volume* aVolume)
   : mName(NS_ConvertUTF8toUTF16(aVolume->Name())),
     mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())),
     mState(aVolume->State()),
     mMountGeneration(aVolume->MountGeneration()),
     mMountLocked(aVolume->IsMountLocked()),
-    mIsFake(false)
+    mIsFake(false),
+    mIsMediaPresent(aVolume->MediaPresent()),
+    mIsSharing(aVolume->IsSharing())
 {
 }
 
 bool nsVolume::Equals(nsIVolume* aVolume)
 {
   nsString volName;
   aVolume->GetName(volName);
   if (!mName.Equals(volName)) {
@@ -91,22 +93,34 @@ bool nsVolume::Equals(nsIVolume* aVolume
   aVolume->GetIsFake(&isFake);
   if (mIsFake != isFake) {
     return false;
   }
 
   return true;
 }
 
+NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool *aIsMediaPresent)
+{
+  *aIsMediaPresent = mIsMediaPresent;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsVolume::GetIsMountLocked(bool *aIsMountLocked)
 {
   *aIsMountLocked = mMountLocked;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsVolume::GetIsSharing(bool *aIsSharing)
+{
+  *aIsSharing = mIsSharing;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsVolume::GetName(nsAString& aName)
 {
   aName = mName;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration)
 {
@@ -149,33 +163,37 @@ NS_IMETHODIMP nsVolume::GetIsFake(bool *
   *aIsFake = mIsFake;
   return NS_OK;
 }
 
 void
 nsVolume::LogState() const
 {
   if (mState == nsIVolume::STATE_MOUNTED) {
-    LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d",
+    LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d "
+        "media %d sharing %d",
         NameStr().get(), StateStr(), MountPointStr().get(),
-        MountGeneration(), (int)IsMountLocked(), (int)IsFake());
+        MountGeneration(), (int)IsMountLocked(), (int)IsFake(),
+        (int)IsMediaPresent(), (int)IsSharing());
     return;
   }
 
   LOG("nsVolume: %s state %s", NameStr().get(), StateStr());
 }
 
 void nsVolume::Set(nsIVolume* aVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   aVolume->GetName(mName);
   aVolume->GetMountPoint(mMountPoint);
   aVolume->GetState(&mState);
   aVolume->GetIsFake(&mIsFake);
+  aVolume->GetIsMediaPresent(&mIsMediaPresent);
+  aVolume->GetIsSharing(&mIsSharing);
 
   int32_t volMountGeneration;
   aVolume->GetMountGeneration(&volMountGeneration);
 
   if (mState != nsIVolume::STATE_MOUNTED) {
     // Since we're not in the mounted state, we need to
     // forgot whatever mount generation we may have had.
     mMountGeneration = -1;
@@ -233,16 +251,27 @@ nsVolume::UpdateMountLock(bool aMountLoc
   XRE_GetIOMessageLoop()->PostTask(
      FROM_HERE,
      NewRunnableFunction(Volume::UpdateMountLock,
                          NS_LossyConvertUTF16toASCII(Name()),
                          MountGeneration(), aMountLocked));
 }
 
 void
+nsVolume::SetIsFake(bool aIsFake)
+{
+  mIsFake = aIsFake;
+  if (mIsFake) {
+    // The media is always present for fake volumes.
+    mIsMediaPresent = true;
+    MOZ_ASSERT(!mIsSharing);
+  }
+}
+
+void
 nsVolume::SetState(int32_t aState)
 {
   static int32_t sMountGeneration = 0;
 
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(IsFake());
 
--- a/dom/system/gonk/nsVolume.h
+++ b/dom/system/gonk/nsVolume.h
@@ -20,36 +20,42 @@ class nsVolume : public nsIVolume
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIVOLUME
 
   // This constructor is used by the UpdateVolumeRunnable constructor
   nsVolume(const Volume* aVolume);
 
-  // This constructor is used by ContentChild::RecvFileSystemUpdate
+  // This constructor is used by ContentChild::RecvFileSystemUpdate which is
+  // used to update the volume cache maintained in the child process.
   nsVolume(const nsAString& aName, const nsAString& aMountPoint,
-           const int32_t& aState, const int32_t& aMountGeneration)
+           const int32_t& aState, const int32_t& aMountGeneration,
+           const bool& aIsMediaPresent, const bool& aIsSharing)
     : mName(aName),
       mMountPoint(aMountPoint),
       mState(aState),
       mMountGeneration(aMountGeneration),
       mMountLocked(false),
-      mIsFake(false)
+      mIsFake(false),
+      mIsMediaPresent(aIsMediaPresent),
+      mIsSharing(aIsSharing)
   {
   }
 
   // This constructor is used by nsVolumeService::FindAddVolumeByName, and
   // will be followed shortly by a Set call.
   nsVolume(const nsAString& aName)
     : mName(aName),
       mState(STATE_INIT),
       mMountGeneration(-1),
       mMountLocked(true),  // Needs to agree with Volume::Volume
-      mIsFake(false)
+      mIsFake(false),
+      mIsMediaPresent(false),
+      mIsSharing(false)
   {
   }
 
   bool Equals(nsIVolume* aVolume);
   void Set(nsIVolume* aVolume);
 
   void LogState() const;
 
@@ -70,23 +76,27 @@ public:
 private:
   ~nsVolume() {}
 
   friend class nsVolumeService; // Calls the following XxxMountLock functions
   void UpdateMountLock(const nsAString& aMountLockState);
   void UpdateMountLock(bool aMountLocked);
 
   bool IsFake() const                 { return mIsFake; }
-  void SetIsFake(bool aIsFake)        { mIsFake = aIsFake; }
+  bool IsMediaPresent() const         { return mIsMediaPresent; }
+  bool IsSharing() const              { return mIsSharing; }
+  void SetIsFake(bool aIsFake);
   void SetState(int32_t aState);
 
   nsString mName;
   nsString mMountPoint;
   int32_t  mState;
   int32_t  mMountGeneration;
   bool     mMountLocked;
   bool     mIsFake;
+  bool     mIsMediaPresent;
+  bool     mIsSharing;
 };
 
 } // system
 } // mozilla
 
 #endif  // mozilla_system_nsvolume_h__
--- a/dom/system/gonk/nsVolumeService.cpp
+++ b/dom/system/gonk/nsVolumeService.cpp
@@ -241,17 +241,19 @@ nsVolumeService::CreateOrGetVolumeByPath
   if (rv == NS_OK) {
     return NS_OK;
   }
 
   // In order to support queries by the updater, we will fabricate a volume
   // from the pathname, so that the caller can determine the volume size.
   nsCOMPtr<nsIVolume> vol = new nsVolume(NS_LITERAL_STRING("fake"),
                                          aPath, nsIVolume::STATE_MOUNTED,
-                                         -1 /*generation*/);
+                                         -1    /* generation */,
+                                         true  /* isMediaPresent*/,
+                                         false /* isSharing */);
   vol.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsVolumeService::GetVolumeNames(nsTArray<nsString>& aVolNames)
 {
   MonitorAutoLock autoLock(mArrayMonitor);
@@ -370,17 +372,20 @@ nsVolumeService::UpdateVolume(nsIVolume*
   NS_ConvertUTF8toUTF16 stateStr(vol->StateStr());
   obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
 }
 
 NS_IMETHODIMP
 nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
-    nsRefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT, -1);
+    nsRefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT,
+                                          -1    /* mountGeneration */,
+                                          true  /* isMediaPresent */,
+                                          false /* isSharing */);
     vol->SetIsFake(true);
     vol->LogState();
     UpdateVolume(vol.get());
     return NS_OK;
   }
 
   ContentChild::GetSingleton()->SendCreateFakeVolume(nsString(name), nsString(path));
   return NS_OK;
@@ -420,35 +425,39 @@ public:
       mVolume(new nsVolume(aVolume))
   {
     MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d",
+    DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d "
+        "media %d sharing %d",
         mVolume->NameStr().get(), mVolume->StateStr(),
-        mVolume->MountGeneration(), (int)mVolume->IsMountLocked());
+        mVolume->MountGeneration(), (int)mVolume->IsMountLocked(),
+        (int)mVolume->IsMediaPresent(), mVolume->IsSharing());
 
     mVolumeService->UpdateVolume(mVolume);
     mVolumeService = nullptr;
     mVolume = nullptr;
     return NS_OK;
   }
 
 private:
   nsRefPtr<nsVolumeService> mVolumeService;
   nsRefPtr<nsVolume>        mVolume;
 };
 
 void
 nsVolumeService::UpdateVolumeIOThread(const Volume* aVolume)
 {
-  DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d",
+  DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d "
+      "media %d sharing %d",
       aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get(),
-      aVolume->MountGeneration(), (int)aVolume->IsMountLocked());
+      aVolume->MountGeneration(), (int)aVolume->IsMountLocked(),
+      (int)aVolume->IsMediaPresent(), (int)aVolume->IsSharing());
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   NS_DispatchToMainThread(new UpdateVolumeRunnable(this, aVolume));
 }
 
 } // namespace system
 } // namespace mozilla
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -2358,19 +2358,35 @@ let RIL = {
    *        DATACALL_AUTH_NONE        => PAP and CHAP is never performed.
    *        DATACALL_AUTH_PAP         => PAP may be performed.
    *        DATACALL_AUTH_CHAP        => CHAP may be performed.
    *        DATACALL_AUTH_PAP_OR_CHAP => PAP / CHAP may be performed.
    * @param pdptype
    *        String containing PDP type to request. ("IP", "IPV6", ...)
    */
   setupDataCall: function setupDataCall(options) {
+    // From ./hardware/ril/include/telephony/ril.h:
+    // ((const char **)data)[0] Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2...
+    // for values above 2 this is RIL_RadioTechnology + 2.
+    //
+    // From frameworks/base/telephony/java/com/android/internal/telephony/DataConnection.java:
+    // if the mRilVersion < 6, radio technology must be GSM/UMTS or CDMA.
+    // Otherwise, it must be + 2
+    //
+    // See also bug 901232 and 867873
+    let radioTech;
+    if (RILQUIRKS_V5_LEGACY) {
+      radioTech = this._isCdma ? DATACALL_RADIOTECHNOLOGY_CDMA
+                               : DATACALL_RADIOTECHNOLOGY_GSM;
+    } else {
+      radioTech = options.radioTech + 2;
+    }
     let token = Buf.newParcel(REQUEST_SETUP_DATA_CALL, options);
     Buf.writeUint32(7);
-    Buf.writeString(options.radioTech.toString());
+    Buf.writeString(radioTech.toString());
     Buf.writeString(DATACALL_PROFILE_DEFAULT.toString());
     Buf.writeString(options.apn);
     Buf.writeString(options.user);
     Buf.writeString(options.passwd);
     Buf.writeString(options.chappap.toString());
     Buf.writeString(options.pdptype);
     Buf.sendParcel();
     return token;
--- a/dom/telephony/CallEvent.cpp
+++ b/dom/telephony/CallEvent.cpp
@@ -48,17 +48,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEve
 
 // WebIDL
 
 /* static */
 already_AddRefed<CallEvent>
 CallEvent::Constructor(const GlobalObject& aGlobal, const nsAString& aType,
                        const CallEventInit& aOptions, ErrorResult& aRv)
 {
-  nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.Get());
+  nsCOMPtr<EventTarget> target = do_QueryInterface(aGlobal.GetAsSupports());
 
   if (!target) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<CallEvent> event = Create(target, aType, aOptions.mCall, false, false);
 
--- a/dom/tests/mochitest/bugs/test_bug597809.html
+++ b/dom/tests/mochitest/bugs/test_bug597809.html
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 597809 **/
 
 SimpleTest.waitForExplicitFinish();
 
-SpecialPowers.addCategoryEntry("JavaScript-global-property", "testSNSM", "@mozilla.org/embedcomp/prompt-service;1",
+SpecialPowers.addCategoryEntry("JavaScript-global-property", "testSNSM", "@mozilla.org/xmlextras/xmlhttprequest;1",
                     false, true);
 
 SimpleTest.executeSoon(function () {
   ok(window.testSNSM, "testSNSM should return an object");
   // The category entry must be removed before finishing the test,
   // otherwise it will affect all following tests in the test suite.
   SpecialPowers.deleteCategoryEntry("JavaScript-global-property", "testSNSM", false);
   SimpleTest.finish();
--- a/dom/tests/mochitest/bugs/test_bug641552.html
+++ b/dom/tests/mochitest/bugs/test_bug641552.html
@@ -14,20 +14,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 641552 **/
 
 SimpleTest.waitForExplicitFinish();
 
+var contractId = "@mozilla.org/xmlextras/xmlhttprequest;1";
 var categoryEntries = [
-  {category: "JavaScript-global-property", entry: "randomname", contractId: "@mozilla.org/embedcomp/prompt-service;1"},
-  {category: "JavaScript-navigator-property", entry: "randomname1", contractId: "@mozilla.org/embedcomp/prompt-service;1"},
-  {category: "JavaScript-navigator-property", entry: "randomname2", contractId: "@mozilla.org/embedcomp/prompt-service;1"},
+  {category: "JavaScript-global-property", entry: "randomname", contractId: contractId},
+  {category: "JavaScript-navigator-property", entry: "randomname1", contractId: contractId},
+  {category: "JavaScript-navigator-property", entry: "randomname2", contractId: contractId},
 ];
 
 function addCategoryEntries(func) {
   for (var categoryEntry of categoryEntries) {
     SpecialPowers.addCategoryEntry(categoryEntry.category, categoryEntry.entry, categoryEntry.contractId,
                                    false, true);
   }
   SimpleTest.executeSoon(func);
--- a/dom/webidl/IDBCursor.webidl
+++ b/dom/webidl/IDBCursor.webidl
@@ -10,18 +10,17 @@
 enum IDBCursorDirection {
     "next",
     "nextunique",
     "prev",
     "prevunique"
 };
 
 interface IDBCursor {
-    // This should be: readonly    attribute (IDBObjectStore or IDBIndex) source;
-    readonly    attribute nsISupports source;
+    readonly    attribute (IDBObjectStore or IDBIndex) source;
 
     readonly    attribute IDBCursorDirection           direction;
 
     [Throws]
     readonly    attribute any                          key;
 
     [Throws]
     readonly    attribute any                          primaryKey;
--- a/dom/webidl/IDBRequest.webidl
+++ b/dom/webidl/IDBRequest.webidl
@@ -15,17 +15,17 @@ enum IDBRequestReadyState {
 
 interface IDBRequest : EventTarget {
     [Throws]
     readonly    attribute any                  result;
 
     [Throws]
     readonly    attribute DOMError?            error;
 
-    readonly    attribute nsISupports?         source;
+    readonly    attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
     readonly    attribute IDBTransaction?      transaction;
     readonly    attribute IDBRequestReadyState readyState;
 
     [SetterThrows]
                 attribute EventHandler         onsuccess;
 
     [SetterThrows]
                 attribute EventHandler         onerror;
--- a/dom/workers/DOMBindingInlines.h
+++ b/dom/workers/DOMBindingInlines.h
@@ -2,28 +2,24 @@
 /* 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_workers_dombindinginlines_h__
 #define mozilla_dom_workers_dombindinginlines_h__
 
 #include "mozilla/dom/FileReaderSyncBinding.h"
-#include "mozilla/dom/TextDecoderBinding.h"
-#include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/dom/XMLHttpRequestUploadBinding.h"
 #include "mozilla/dom/WorkerLocationBinding.h"
 #include "mozilla/dom/WorkerNavigatorBinding.h"
 
 BEGIN_WORKERS_NAMESPACE
 
 class FileReaderSync;
-class TextDecoder;
-class TextEncoder;
 class XMLHttpRequest;
 class XMLHttpRequestUpload;
 class WorkerLocation;
 class WorkerNavigator;
 
 namespace {
 
 template <class T>
@@ -47,18 +43,16 @@ struct WrapPrototypeTraits
     GetProtoObject(JSContext* aCx, JS::Handle<JSObject*> aGlobal)              \
     {                                                                          \
       using namespace mozilla::dom;                                            \
       return _class##Binding_workers::GetProtoObject(aCx, aGlobal);            \
     }                                                                          \
   };
 
 SPECIALIZE_PROTO_TRAITS(FileReaderSync)
-SPECIALIZE_PROTO_TRAITS(TextDecoder)
-SPECIALIZE_PROTO_TRAITS(TextEncoder)
 SPECIALIZE_PROTO_TRAITS(XMLHttpRequest)
 SPECIALIZE_PROTO_TRAITS(XMLHttpRequestUpload)
 SPECIALIZE_PROTO_TRAITS(WorkerLocation)
 SPECIALIZE_PROTO_TRAITS(WorkerNavigator)
 
 #undef SPECIALIZE_PROTO_TRAITS
 
 } // anonymous namespace
--- a/dom/workers/Events.h
+++ b/dom/workers/Events.h
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_events_h__
 #define mozilla_dom_workers_events_h__
 
 #include "Workers.h"
 
-class JSAutoStructuredCloneBuffer;
+#include "js/StructuredClone.h"
 
 BEGIN_WORKERS_NAMESPACE
 
 namespace events {
 
 bool
 InitClasses(JSContext* aCx, JS::Handle<JSObject*> aGlobal, bool aMainRuntime);
 
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -26,17 +26,17 @@
 #include "DOMBindingInlines.h"
 
 #include "mozilla/Base64.h"
 #include "mozilla/dom/EncodingUtils.h"
 
 USING_WORKERS_NAMESPACE
 using namespace mozilla;
 using mozilla::dom::Optional;
-using mozilla::dom::WorkerGlobalObject;
+using mozilla::dom::GlobalObject;
 
 NS_IMPL_ADDREF_INHERITED(FileReaderSync, DOMBindingBase)
 NS_IMPL_RELEASE_INHERITED(FileReaderSync, DOMBindingBase)
 NS_INTERFACE_MAP_BEGIN(FileReaderSync)
   NS_INTERFACE_MAP_ENTRY(nsICharsetDetectionObserver)
 NS_INTERFACE_MAP_END_INHERITING(DOMBindingBase)
 
 FileReaderSync::FileReaderSync(JSContext* aCx)
@@ -53,17 +53,17 @@ FileReaderSync::_trace(JSTracer* aTrc)
 void
 FileReaderSync::_finalize(JSFreeOp* aFop)
 {
   DOMBindingBase::_finalize(aFop);
 }
 
 // static
 FileReaderSync*
-FileReaderSync::Constructor(const WorkerGlobalObject& aGlobal, ErrorResult& aRv)
+FileReaderSync::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
   nsRefPtr<FileReaderSync> frs = new FileReaderSync(aGlobal.GetContext());
 
   if (!Wrap(aGlobal.GetContext(), aGlobal.Get(), frs)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
--- a/dom/workers/FileReaderSync.h
+++ b/dom/workers/FileReaderSync.h
@@ -31,17 +31,17 @@ class FileReaderSync MOZ_FINAL : public 
 public:
   virtual void
   _trace(JSTracer* aTrc) MOZ_OVERRIDE;
 
   virtual void
   _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
 
   static FileReaderSync*
-  Constructor(const WorkerGlobalObject& aGlobal, ErrorResult& aRv);
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   FileReaderSync(JSContext* aCx);
 
   JSObject* ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aBlob,
                               ErrorResult& aRv);
   void ReadAsBinaryString(JS::Handle<JSObject*> aBlob, nsAString& aResult,
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -17,16 +17,17 @@
 #include "nsITimer.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
 #include "GeckoProfiler.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
+#include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Util.h"
 #include <Navigator.h>
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
@@ -741,16 +742,21 @@ CTypesActivityCallback(JSContext* aCx,
       worker->EndCTypesCallback();
       break;
 
     default:
       MOZ_CRASH("Unknown type flag!");
   }
 }
 
+struct WorkerThreadRuntimePrivate : public PerThreadAtomCache
+{
+  WorkerPrivate* mWorkerPrivate;
+};
+
 JSContext*
 CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   NS_ASSERTION(!aWorkerPrivate->GetJSContext(), "Already has a context!");
 
   JSSettings settings;
   aWorkerPrivate->CopyJSSettings(settings);
@@ -789,17 +795,20 @@ CreateJSContextForWorker(WorkerPrivate* 
   SetDOMCallbacks(aRuntime, &DOMCallbacks);
 
   JSContext* workerCx = JS_NewContext(aRuntime, 0);
   if (!workerCx) {
     NS_WARNING("Could not create new context!");
     return nullptr;
   }
 
-  JS_SetRuntimePrivate(aRuntime, aWorkerPrivate);
+  auto rtPrivate = new WorkerThreadRuntimePrivate();
+  memset(rtPrivate, 0, sizeof(WorkerThreadRuntimePrivate));
+  rtPrivate->mWorkerPrivate = aWorkerPrivate;
+  JS_SetRuntimePrivate(aRuntime, rtPrivate);
 
   JS_SetErrorReporter(workerCx, ErrorReporter);
 
   JS_SetOperationCallback(aRuntime, OperationCallback);
 
   js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback);
 
   JS_SetOptions(workerCx,
@@ -832,16 +841,20 @@ public:
     // the cycle collector shuts down.  Thus all cycles will be broken before
     // the last GC and all finalizers will be run.
     mLastJSContext = JS_NewContext(Runtime(), 0);
     MOZ_ASSERT(mLastJSContext);
   }
 
   ~WorkerJSRuntime()
   {
+    auto rtPrivate = static_cast<WorkerThreadRuntimePrivate*>(JS_GetRuntimePrivate(Runtime()));
+    delete rtPrivate;
+    JS_SetRuntimePrivate(Runtime(), nullptr);
+
     // All JSContexts except mLastJSContext should be destroyed now.  The
     // worker global will be unrooted and the shutdown cycle collection
     // should break all remaining cycles.  Destroying mLastJSContext will run
     // the GC the final time and finalize any JSObjects that were participating
     // in cycles that were broken during CC shutdown.
     nsCycleCollector_shutdown();
 
     // The CC is shutdown, and this will GC, so make sure we don't try to CC
@@ -1095,16 +1108,23 @@ WorkerCrossThreadDispatcher::PostTask(Wo
     return false;
   }
 
   nsRefPtr<WorkerTaskRunnable> runnable = new WorkerTaskRunnable(mPrivate, aTask);
   runnable->Dispatch(nullptr);
   return true;
 }
 
+WorkerPrivate*
+GetWorkerPrivateFromContext(JSContext* aCx)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  return static_cast<WorkerThreadRuntimePrivate*>(JS_GetRuntimePrivate(JS_GetRuntime(aCx)))->mWorkerPrivate;
+}
+
 END_WORKERS_NAMESPACE
 
 // This is only touched on the main thread. Initialized in Init() below.
 JSSettings RuntimeService::sDefaultJSSettings;
 
 RuntimeService::RuntimeService()
 : mMutex("RuntimeService::mMutex"), mObserved(false),
   mShuttingDown(false), mNavigatorStringsLoaded(false)
deleted file mode 100644
--- a/dom/workers/TextDecoder.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- 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 "TextDecoder.h"
-#include "DOMBindingInlines.h"
-
-USING_WORKERS_NAMESPACE
-using mozilla::ErrorResult;
-using mozilla::dom::TextDecoderOptionsWorkers;
-using mozilla::dom::WorkerGlobalObject;
-
-void
-TextDecoder::_trace(JSTracer* aTrc)
-{
-  DOMBindingBase::_trace(aTrc);
-}
-
-void
-TextDecoder::_finalize(JSFreeOp* aFop)
-{
-  DOMBindingBase::_finalize(aFop);
-}
-
-// static
-TextDecoder*
-TextDecoder::Constructor(const WorkerGlobalObject& aGlobal,
-                         const nsAString& aEncoding,
-                         const TextDecoderOptionsWorkers& aOptions,
-                         ErrorResult& aRv)
-{
-  nsRefPtr<TextDecoder> txtDecoder = new TextDecoder(aGlobal.GetContext());
-  txtDecoder->Init(aEncoding, aOptions.mFatal, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  if (!Wrap(aGlobal.GetContext(), aGlobal.Get(), txtDecoder)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  return txtDecoder;
-}
deleted file mode 100644
--- a/dom/workers/TextDecoder.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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_workers_textdecoder_h_
-#define mozilla_dom_workers_textdecoder_h_
-
-#include "mozilla/dom/TextDecoderBase.h"
-#include "mozilla/dom/workers/bindings/DOMBindingBase.h"
-#include "mozilla/dom/TextDecoderBinding.h"
-
-BEGIN_WORKERS_NAMESPACE
-
-class TextDecoder MOZ_FINAL : public DOMBindingBase,
-                              public TextDecoderBase
-{
-protected:
-  TextDecoder(JSContext* aCx)
-  : DOMBindingBase(aCx)
-  {}
-
-  virtual
-  ~TextDecoder()
-  {}
-
-public:
-  virtual void
-  _trace(JSTracer* aTrc) MOZ_OVERRIDE;
-
-  virtual void
-  _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
-
-  static TextDecoder*
-  Constructor(const WorkerGlobalObject& aGlobal,
-              const nsAString& aEncoding,
-              const TextDecoderOptionsWorkers& aOptions,
-              ErrorResult& aRv);
-
-  void
-  Decode(nsAString& aOutDecodedString,
-         ErrorResult& aRv) {
-    TextDecoderBase::Decode(nullptr, 0, false,
-                            aOutDecodedString, aRv);
-  }
-
-  void
-  Decode(const ArrayBufferView& aView,
-         const TextDecodeOptionsWorkers& aOptions,
-         nsAString& aOutDecodedString,
-         ErrorResult& aRv) {
-    TextDecoderBase::Decode(reinterpret_cast<char*>(aView.Data()),
-                            aView.Length(), aOptions.mStream,
-                            aOutDecodedString, aRv);
-  }
-};
-
-END_WORKERS_NAMESPACE
-
-#endif // mozilla_dom_workers_textdecoder_h_
deleted file mode 100644
--- a/dom/workers/TextEncoder.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- 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 "TextEncoder.h"
-#include "DOMBindingInlines.h"
-
-USING_WORKERS_NAMESPACE
-using mozilla::ErrorResult;
-using mozilla::dom::WorkerGlobalObject;
-
-void
-TextEncoder::_trace(JSTracer* aTrc)
-{
-  DOMBindingBase::_trace(aTrc);
-}
-
-void
-TextEncoder::_finalize(JSFreeOp* aFop)
-{
-  DOMBindingBase::_finalize(aFop);
-}
-
-// static
-TextEncoder*
-TextEncoder::Constructor(const WorkerGlobalObject& aGlobal,
-                         const nsAString& aEncoding,
-                         ErrorResult& aRv)
-{
-  nsRefPtr<TextEncoder> txtEncoder = new TextEncoder(aGlobal.GetContext());
-  txtEncoder->Init(aEncoding, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  if (!Wrap(aGlobal.GetContext(), aGlobal.Get(), txtEncoder)) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  return txtEncoder;
-}
deleted file mode 100644
--- a/dom/workers/TextEncoder.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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_workers_textencoder_h_
-#define mozilla_dom_workers_textencoder_h_
-
-#include "mozilla/dom/TextEncoderBase.h"
-#include "mozilla/dom/workers/bindings/DOMBindingBase.h"
-#include "mozilla/dom/TextEncoderBinding.h"
-
-BEGIN_WORKERS_NAMESPACE
-
-class TextEncoder MOZ_FINAL : public DOMBindingBase,
-                              public TextEncoderBase
-{
-protected:
-  TextEncoder(JSContext* aCx)
-  : DOMBindingBase(aCx)
-  {}
-
-  virtual
-  ~TextEncoder()
-  {}
-
-  virtual JSObject*
-  CreateUint8Array(JSContext* aCx, char* aBuf, uint32_t aLen) MOZ_OVERRIDE
-  {
-    return Uint8Array::Create(aCx, this, aLen,
-                              reinterpret_cast<uint8_t*>(aBuf));
-  }
-
-public:
-  virtual void
-  _trace(JSTracer* aTrc) MOZ_OVERRIDE;
-
-  virtual void
-  _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
-
-  static TextEncoder*
-  Constructor(const WorkerGlobalObject& aGlobal,
-              const nsAString& aEncoding,
-              ErrorResult& aRv);
-
-  JSObject*
-  Encode(JSContext* aCx,
-         const nsAString& aString,
-         const TextEncodeOptionsWorkers& aOptions,
-         ErrorResult& aRv) {
-    return TextEncoderBase::Encode(aCx, aString, aOptions.mStream, aRv);
-  }
-};
-
-END_WORKERS_NAMESPACE
-
-#endif // mozilla_dom_workers_textencoder_h_
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -14,17 +14,17 @@
 #include "nsPIDOMWindow.h"
 #include "nsGlobalWindow.h"
 #include "nsHostObjectProtocolHandler.h"
 
 #include "nsIDocument.h"
 #include "nsIDOMFile.h"
 
 USING_WORKERS_NAMESPACE
-using mozilla::dom::WorkerGlobalObject;
+using mozilla::dom::GlobalObject;
 
 // Base class for the Revoke and Create runnable objects.
 class URLRunnable : public nsRunnable
 {
 protected:
   WorkerPrivate* mWorkerPrivate;
   uint32_t mSyncQueueKey;
 
@@ -112,17 +112,17 @@ protected:
 class CreateURLRunnable : public URLRunnable
 {
 private:
   nsIDOMBlob* mBlob;
   nsString& mURL;
 
 public:
   CreateURLRunnable(WorkerPrivate* aWorkerPrivate, nsIDOMBlob* aBlob,
-                    const mozilla::dom::objectURLOptionsWorkers& aOptions,
+                    const mozilla::dom::objectURLOptions& aOptions,
                     nsString& aURL)
   : URLRunnable(aWorkerPrivate),
     mBlob(aBlob),
     mURL(aURL)
   {
     MOZ_ASSERT(aBlob);
   }
 
@@ -222,18 +222,18 @@ public:
     if (!window) {
       mWorkerPrivate->UnregisterHostObjectURI(url);
     }
   }
 };
 
 // static
 void
-URL::CreateObjectURL(const WorkerGlobalObject& aGlobal, JSObject* aBlob,
-                     const mozilla::dom::objectURLOptionsWorkers& aOptions,
+URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject* aBlob,
+                     const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult, mozilla::ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.GetContext();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
 
   nsCOMPtr<nsIDOMBlob> blob = file::GetDOMBlobFromJSObject(aBlob);
   if (!blob) {
     SetDOMStringToNull(aResult);
@@ -249,26 +249,26 @@ URL::CreateObjectURL(const WorkerGlobalO
 
   if (!runnable->Dispatch(cx)) {
     JS_ReportPendingException(cx);
   }
 }
 
 // static
 void
-URL::CreateObjectURL(const WorkerGlobalObject& aGlobal, JSObject& aBlob,
-                     const mozilla::dom::objectURLOptionsWorkers& aOptions,
+URL::CreateObjectURL(const GlobalObject& aGlobal, JSObject& aBlob,
+                     const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult, mozilla::ErrorResult& aRv)
 {
   return CreateObjectURL(aGlobal, &aBlob, aOptions, aResult, aRv);
 }
 
 // static
 void
-URL::RevokeObjectURL(const WorkerGlobalObject& aGlobal, const nsAString& aUrl)
+URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl)
 {
   JSContext* cx = aGlobal.GetContext();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
 
   nsRefPtr<RevokeURLRunnable> runnable =
     new RevokeURLRunnable(workerPrivate, aUrl);
 
   if (!runnable->Dispatch(cx)) {
--- a/dom/workers/URL.h
+++ b/dom/workers/URL.h
@@ -12,24 +12,24 @@
 #include "EventTarget.h"
 
 BEGIN_WORKERS_NAMESPACE
 
 class URL : public EventTarget
 {
 public: // Methods for WebIDL
   static void
-  CreateObjectURL(const WorkerGlobalObject& aGlobal,
-                  JSObject* aArg, const objectURLOptionsWorkers& aOptions,
+  CreateObjectURL(const GlobalObject& aGlobal,
+                  JSObject* aArg, const objectURLOptions& aOptions,
                   nsString& aResult, ErrorResult& aRv);
 
   static void
-  CreateObjectURL(const WorkerGlobalObject& aGlobal,
-                  JSObject& aArg, const objectURLOptionsWorkers& aOptions,
+  CreateObjectURL(const GlobalObject& aGlobal,
+                  JSObject& aArg, const objectURLOptions& aOptions,
                   nsString& aResult, ErrorResult& aRv);
 
   static void
-  RevokeObjectURL(const WorkerGlobalObject& aGlobal, const nsAString& aUrl);
+  RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aUrl);
 };
 
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_url_h__ */
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4395,23 +4395,16 @@ WorkerPrivate::EndCTypesCall()
   mBlockedForMemoryReporter = false;
 }
 
 BEGIN_WORKERS_NAMESPACE
 
 // Force instantiation.
 template class WorkerPrivateParent<WorkerPrivate>;
 
-WorkerPrivate*
-GetWorkerPrivateFromContext(JSContext* aCx)
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-  return static_cast<WorkerPrivate*>(JS_GetRuntimePrivate(JS_GetRuntime(aCx)));
-}
-
 JSStructuredCloneCallbacks*
 WorkerStructuredCloneCallbacks(bool aMainRuntime)
 {
   return aMainRuntime ?
          &gMainThreadWorkerStructuredCloneCallbacks :
          &gWorkerStructuredCloneCallbacks;
 }
 
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -1015,18 +1015,18 @@ CreateDedicatedWorkerGlobalScope(JSConte
       !file::InitClasses(aCx, global) ||
       !exceptions::InitClasses(aCx, global)) {
     return NULL;
   }
 
   // Init other paris-bindings.
   if (!FileReaderSyncBinding_workers::GetConstructorObject(aCx, global) ||
       !ImageDataBinding::GetConstructorObject(aCx, global) ||
-      !TextDecoderBinding_workers::GetConstructorObject(aCx, global) ||
-      !TextEncoderBinding_workers::GetConstructorObject(aCx, global) ||
+      !TextDecoderBinding::GetConstructorObject(aCx, global) ||
+      !TextEncoderBinding::GetConstructorObject(aCx, global) ||
       !XMLHttpRequestBinding_workers::GetConstructorObject(aCx, global) ||
       !XMLHttpRequestUploadBinding_workers::GetConstructorObject(aCx, global) ||
       !URLBinding_workers::GetConstructorObject(aCx, global) ||
       !WorkerLocationBinding_workers::GetConstructorObject(aCx, global) ||
       !WorkerNavigatorBinding_workers::GetConstructorObject(aCx, global)) {
     return NULL;
   }
 
--- a/dom/workers/XMLHttpRequest.cpp
+++ b/dom/workers/XMLHttpRequest.cpp
@@ -1454,18 +1454,18 @@ void
 XMLHttpRequest::_finalize(JSFreeOp* aFop)
 {
   ReleaseProxy(XHRIsGoingAway);
   XMLHttpRequestEventTarget::_finalize(aFop);
 }
 
 // static
 XMLHttpRequest*
-XMLHttpRequest::Constructor(const WorkerGlobalObject& aGlobal,
-                            const MozXMLHttpRequestParametersWorkers& aParams,
+XMLHttpRequest::Constructor(const GlobalObject& aGlobal,
+                            const MozXMLHttpRequestParameters& aParams,
                             ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.GetContext();
   WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
   MOZ_ASSERT(workerPrivate);
 
   nsRefPtr<XMLHttpRequest> xhr = new XMLHttpRequest(cx, workerPrivate);
 
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -10,16 +10,18 @@
 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
 // Need this for XMLHttpRequestResponseType.
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TypedArray.h"
 
+#include "js/StructuredClone.h"
+
 BEGIN_WORKERS_NAMESPACE
 
 class Proxy;
 class XMLHttpRequestUpload;
 class WorkerPrivate;
 
 class XMLHttpRequest : public XMLHttpRequestEventTarget,
                        public WorkerFeature
@@ -68,26 +70,26 @@ protected:
 public:
   virtual void
   _trace(JSTracer* aTrc) MOZ_OVERRIDE;
 
   virtual void
   _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
 
   static XMLHttpRequest*
-  Constructor(const WorkerGlobalObject& aGlobal,
-              const MozXMLHttpRequestParametersWorkers& aParams,
+  Constructor(const GlobalObject& aGlobal,
+              const MozXMLHttpRequestParameters& aParams,
               ErrorResult& aRv);
 
   static XMLHttpRequest*
-  Constructor(const WorkerGlobalObject& aGlobal, const nsAString& ignored,
+  Constructor(const GlobalObject& aGlobal, const nsAString& ignored,
               ErrorResult& aRv)
   {
     // Pretend like someone passed null, so we can pick up the default values
-    MozXMLHttpRequestParametersWorkers params;
+    MozXMLHttpRequestParameters params;
     if (!params.Init(aGlobal.GetContext(), JS::NullHandleValue)) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
 
     return Constructor(aGlobal, params, aRv);
   }
 
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -16,18 +16,16 @@ EXPORTS.mozilla.dom.workers += [
 # Stuff needed for the bindings, not really public though.
 EXPORTS.mozilla.dom.workers.bindings += [
     'DOMBindingBase.h',
     'EventListenerManager.h',
     'EventTarget.h',
     'FileReaderSync.h',
     'Location.h',
     'Navigator.h',
-    'TextDecoder.h',
-    'TextEncoder.h',
     'URL.h',
     'WorkerFeature.h',
     'XMLHttpRequest.h',
     'XMLHttpRequestEventTarget.h',
     'XMLHttpRequestUpload.h',
 ]
 
 CPP_SOURCES += [
@@ -39,18 +37,16 @@ CPP_SOURCES += [
     'Exceptions.cpp',
     'File.cpp',
     'FileReaderSync.cpp',
     'Location.cpp',
     'Navigator.cpp',
     'Principal.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
-    'TextDecoder.cpp',
-    'TextEncoder.cpp',
     'URL.cpp',
     'Worker.cpp',
     'WorkerPrivate.cpp',
     'WorkerScope.cpp',
     'XMLHttpRequest.cpp',
     'XMLHttpRequestEventTarget.cpp',
     'XMLHttpRequestUpload.cpp',
 ]
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -365,17 +365,16 @@ NeedIntermediateSurface(const Pattern& a
 DrawTargetCairo::DrawTargetCairo()
   : mContext(nullptr)
   , mPathObserver(nullptr)
 {
 }
 
 DrawTargetCairo::~DrawTargetCairo()
 {
-  MarkSnapshotIndependent();
   if (mPathObserver) {
     mPathObserver->ForgetDrawTarget();
   }
   cairo_destroy(mContext);
   if (mSurface) {
     cairo_surface_destroy(mSurface);
   }
 }
@@ -1021,16 +1020,19 @@ DrawTargetCairo::Init(cairo_surface_t* a
 }
 
 void *
 DrawTargetCairo::GetNativeSurface(NativeSurfaceType aType)
 {
   if (aType == NATIVE_SURFACE_CAIRO_SURFACE) {
     return cairo_get_target(mContext);
   }
+  if (aType == NATIVE_SURFACE_CAIRO_CONTEXT) {
+    return mContext;
+  }
 
   return nullptr;
 }
 
 void
 DrawTargetCairo::MarkSnapshotIndependent()
 {
   if (mSnapshot) {
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -64,16 +64,17 @@ enum FontType
   FONT_CAIRO,
   FONT_COREGRAPHICS
 };
 
 enum NativeSurfaceType
 {
   NATIVE_SURFACE_D3D10_TEXTURE,
   NATIVE_SURFACE_CAIRO_SURFACE,
+  NATIVE_SURFACE_CAIRO_CONTEXT,
   NATIVE_SURFACE_CGCONTEXT,
   NATIVE_SURFACE_CGCONTEXT_ACCELERATED
 };
 
 enum NativeFontType
 {
   NATIVE_FONT_DWRITE_FONT_FACE,
   NATIVE_FONT_GDI_FONT_FACE,
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -23,16 +23,20 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 
 #ifdef XP_MACOSX
 #include <CoreServices/CoreServices.h>
 #endif
 
+#if defined(MOZ_WIDGET_COCOA)
+#include "nsCocoaFeatures.h"
+#endif
+
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace gl {
 
 #ifdef DEBUG
 unsigned GLContext::sCurrentGLContextTLS = -1;
 #endif
@@ -906,18 +910,20 @@ GLContext::InitExtensions()
 
         // Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it.
         MarkExtensionSupported(OES_EGL_sync);
     }
 
 #ifdef XP_MACOSX
     // The Mac Nvidia driver, for versions up to and including 10.8, don't seem
     // to properly support this.  See 814839
+    // this has been fixed in Mac OS X 10.9. See 907946
     if (WorkAroundDriverBugs() &&
-        Vendor() == gl::GLContext::VendorNVIDIA)
+        Vendor() == gl::GLContext::VendorNVIDIA &&
+        !nsCocoaFeatures::OnMavericksOrLater())
     {
         MarkExtensionUnsupported(gl::GLContext::EXT_packed_depth_stencil);
     }
 #endif
 
 #ifdef DEBUG
     firstRun = false;
 #endif
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -130,17 +130,17 @@ LayerManager::CreateOptimalMaskSurface(c
   return CreateOptimalSurface(aSize, gfxASurface::ImageFormatA8);
 }
 
 TemporaryRef<DrawTarget>
 LayerManager::CreateDrawTarget(const IntSize &aSize,
                                SurfaceFormat aFormat)
 {
   return gfxPlatform::GetPlatform()->
-    CreateOffscreenDrawTarget(aSize, aFormat);
+    CreateOffscreenCanvasDrawTarget(aSize, aFormat);
 }
 
 TextureFactoryIdentifier
 LayerManager::GetTextureFactoryIdentifier()
 {
   //TODO[nrc] make pure virtual when all layer managers use Compositor
   NS_ERROR("Should have been overridden");
   return TextureFactoryIdentifier();
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -403,18 +403,18 @@ public:
    * with this layer manager. In contrast to CreateOptimalSurface, this surface
    * is optimised for drawing alpha only and we assume that drawing the mask
    * is fairly simple.
    */
   virtual already_AddRefed<gfxASurface>
     CreateOptimalMaskSurface(const gfxIntSize &aSize);
 
   /**
-   * Creates a DrawTarget which is optimized for inter-operating with this
-   * layermanager.
+   * Creates a DrawTarget for use with canvas which is optimized for
+   * inter-operating with this layermanager.
    */
   virtual TemporaryRef<mozilla::gfx::DrawTarget>
     CreateDrawTarget(const mozilla::gfx::IntSize &aSize,
                      mozilla::gfx::SurfaceFormat aFormat);
 
   virtual bool CanUseCanvasLayerForSize(const gfxIntSize &aSize) { return true; }
 
   /**
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -272,36 +272,50 @@ ThebesLayerBuffer::DrawTo(ThebesLayer* a
       // and may cause gray lines.
       gfxUtils::ClipToRegionSnapped(aTarget, aLayer->GetEffectiveVisibleRegion());
     }
 
     DrawBufferWithRotation(aTarget, BUFFER_BLACK, aOpacity, aMask, aMaskTransform);
     aTarget->Restore();
   } else {
     RefPtr<DrawTarget> dt = aTarget->GetDrawTarget();
+    bool clipped = false;
 
     // If the entire buffer is valid, we can just draw the whole thing,
     // no need to clip. But we'll still clip if clipping is cheap ---
     // that might let us copy a smaller region of the buffer.
     // Also clip to the visible region if we're told to.
     if (!aLayer->GetValidRegion().Contains(BufferRect()) ||
         (ToData(aLayer)->GetClipToVisibleRegion() &&
          !aLayer->GetVisibleRegion().Contains(BufferRect())) ||
         IsClippingCheap(aTarget, aLayer->GetEffectiveVisibleRegion())) {
       // We don't want to draw invalid stuff, so we need to clip. Might as
       // well clip to the smallest area possible --- the visible region.
       // Bug 599189 if there is a non-integer-translation transform in aTarget,
       // we might sample pixels outside GetEffectiveVisibleRegion(), which is wrong
       // and may cause gray lines.
       gfxUtils::ClipToRegionSnapped(dt, aLayer->GetEffectiveVisibleRegion());
+      clipped = true;
+    }
+
+    RefPtr<SourceSurface> mask;
+    if (aMask) {
+      mask = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aMask);
     }
 
-    DrawBufferWithRotation(aTarget, BUFFER_BLACK, aOpacity, aMask, aMaskTransform);
-    aTarget->Restore();
-   }
+    Matrix maskTransform;
+    if (aMaskTransform) {
+      maskTransform = ToMatrix(*aMaskTransform);
+    }
+
+    DrawBufferWithRotation(dt, BUFFER_BLACK, aOpacity, mask, &maskTransform);
+    if (clipped) {
+      dt->PopClip();
+    }
+  }
 }
 
 static void
 FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
             const nsIntPoint& aOffset, const gfxRGBA& aColor)
 {
   nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
   ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -368,17 +368,17 @@ BasicCompositor::BeginFrame(const gfx::R
   nsIntRect intRect;
   mWidget->GetClientBounds(intRect);
   Rect rect = Rect(0, 0, intRect.width, intRect.height);
   mWidgetSize = intRect.Size();
 
   if (mCopyTarget) {
     // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
     // placeholder so that CreateRenderTarget() works.
-    mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1,1), FORMAT_B8G8R8A8);
+    mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(IntSize(1,1), FORMAT_B8G8R8A8);
   } else {
     mDrawTarget = mWidget->StartRemoteDrawing();
   }
   if (!mDrawTarget) {
     if (aRenderBoundsOut) {
       *aRenderBoundsOut = Rect();
     }
     return;
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -531,16 +531,45 @@ void
 BasicLayerManager::AbortTransaction()
 {
   NS_ASSERTION(InConstruction(), "Should be in construction phase");
   mPhase = PHASE_NONE;
   mUsingDefaultTarget = false;
   mInTransaction = false;
 }
 
+static uint16_t sFrameCount = 0;
+void
+BasicLayerManager::RenderDebugOverlay()
+{
+  if (!gfxPlatform::DrawFrameCounter()) {
+    return;
+  }
+
+  profiler_set_frame_number(sFrameCount);
+
+  uint16_t frameNumber = sFrameCount;
+  const uint16_t bitWidth = 3;
+  for (size_t i = 0; i < 16; i++) {
+
+    gfxRGBA bitColor;
+    if ((frameNumber >> i) & 0x1) {
+      bitColor = gfxRGBA(0, 0, 0, 1.0);
+    } else {
+      bitColor = gfxRGBA(1.0, 1.0, 1.0, 1.0);
+    }
+    mTarget->NewPath();
+    mTarget->SetColor(bitColor);
+    mTarget->Rectangle(gfxRect(bitWidth*i, 0, bitWidth, bitWidth));
+    mTarget->Fill();
+  }
+  // We intentionally overflow at 2^16.
+  sFrameCount++;
+}
+
 bool
 BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
                                           void* aCallbackData,
                                           EndTransactionFlags aFlags)
 {
   PROFILER_LABEL("BasicLayerManager", "EndTransactionInternal");
 #ifdef MOZ_LAYERS_HAVE_LOG
   MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
@@ -608,16 +637,17 @@ BasicLayerManager::EndTransactionInterna
         PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
       }
       // If we're not retained, then don't composite means do nothing at all.
     } else {
       PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
       if (mWidget) {
         FlashWidgetUpdateArea(mTarget);
       }
+      RenderDebugOverlay();
       LayerManager::PostPresent();
     }
 
     if (!mTransactionIncomplete) {
       // Clear out target if we have a complete transaction.
       mTarget = nullptr;
     }
   }
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -173,16 +173,18 @@ protected:
   void ClearLayer(Layer* aLayer);
 
   bool EndTransactionInternal(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
 
   void FlashWidgetUpdateArea(gfxContext* aContext);
 
+  void RenderDebugOverlay();
+
   // Widget whose surface should be used as the basis for ThebesLayer
   // buffers.
   nsIWidget* mWidget;
   // The default context for BeginTransaction.
   nsRefPtr<gfxContext> mDefaultTarget;
   // The context to draw into.
   nsRefPtr<gfxContext> mTarget;
   // When we're doing a transaction in order to draw to a non-default
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -78,16 +78,17 @@ ContentClientBasic::ContentClientBasic(C
 {}
 
 already_AddRefed<gfxASurface>
 ContentClientBasic::CreateBuffer(ContentType aType,
                                  const nsIntRect& aRect,
                                  uint32_t aFlags,
                                  gfxASurface**)
 {
+  MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
   nsRefPtr<gfxASurface> referenceSurface = GetBuffer();
   if (!referenceSurface) {
     gfxContext* defaultTarget = mManager->GetDefaultTarget();
     if (defaultTarget) {
       referenceSurface = defaultTarget->CurrentSurface();
     } else {
       nsIWidget* widget = mManager->GetRetainerWidget();
       if (!widget || !(referenceSurface = widget->GetThebesSurface())) {
@@ -100,19 +101,23 @@ ContentClientBasic::CreateBuffer(Content
 }
 
 TemporaryRef<DrawTarget>
 ContentClientBasic::CreateDTBuffer(ContentType aType,
                                    const nsIntRect& aRect,
                                    uint32_t aFlags,
                                    RefPtr<DrawTarget>* aWhiteDT)
 {
-  NS_RUNTIMEABORT("ContentClientBasic does not support Moz2D drawing yet!");
-  // TODO[Bas] - Implement me!?
-  return nullptr;
+  MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
+  gfxASurface::gfxImageFormat format =
+    gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
+
+  return gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
+    IntSize(aRect.width, aRect.height),
+    ImageFormatToSurfaceFormat(format));
 }
 
 void
 ContentClientRemoteBuffer::DestroyBuffers()
 {
   if (!mDeprecatedTextureClient) {
     return;
   }
@@ -205,16 +210,22 @@ ContentClientRemoteBuffer::BuildDeprecat
     if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClientOnWhite)) {
       return;
     }
     mTextureInfo.mTextureFlags |= TEXTURE_COMPONENT_ALPHA;
   }
 
   CreateFrontBufferAndNotify(aRect);
 }
+
+bool
+ContentClientBasic::SupportsAzureContent() const
+{
+  return gfxPlatform::GetPlatform()->SupportsAzureContent();
+}
  
 bool
 ContentClientRemoteBuffer::SupportsAzureContent() const
 {
   if (!mDeprecatedTextureClient) {
     // Hopefully we don't call this method before we have a texture client. But if
     // we do, then we have no idea if we can support Azure for whatever surface the
     // texture client might come up with.
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -155,16 +155,17 @@ public:
   virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType,
                                                      const nsIntRect& aRect,
                                                      uint32_t aFlags,
                                                      gfxASurface**) MOZ_OVERRIDE;
   virtual TemporaryRef<gfx::DrawTarget> CreateDTBuffer(ContentType aType,
                                                        const nsIntRect& aRect,
                                                        uint32_t aFlags,
                                                        RefPtr<gfx::DrawTarget>* aWhiteDT);
+  virtual bool SupportsAzureContent() const;
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     MOZ_CRASH("Should not be called on non-remote ContentClient");
   }
 
 private:
   BasicLayerManager* mManager;
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -20,16 +20,18 @@
 #include "nsThreadUtils.h"              // for NS_IsMainThread
 
 #define APZC_LOG(...)
 // #define APZC_LOG(args...) printf_stderr(args)
 
 namespace mozilla {
 namespace layers {
 
+float APZCTreeManager::sDPI = 72.0;
+
 APZCTreeManager::APZCTreeManager()
     : mTreeLock("APZCTreeLock")
 {
   MOZ_ASSERT(NS_IsMainThread());
   AsyncPanZoomController::InitializeGlobalState();
 }
 
 APZCTreeManager::~APZCTreeManager()
@@ -224,30 +226,30 @@ APZCTreeManager::ReceiveInputEvent(const
           APZC_LOG("Using APZC %p as the common ancestor\n", mApzcForInputBlock.get());
           // For now, we only ever want to do pinching on the root APZC for a given layers id. So
           // when we find the common ancestor of multiple points, also walk up to the root APZC.
           mApzcForInputBlock = RootAPZCForLayersId(mApzcForInputBlock);
           APZC_LOG("Using APZC %p as the root APZC for multi-touch\n", mApzcForInputBlock.get());
         }
       } else if (mApzcForInputBlock) {
         APZC_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
-        // If we have an mApzcForInputBlock and it's the end of the touch sequence
-        // then null it out so we don't keep a dangling reference and leak things.
-        if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL ||
-            (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END && multiTouchInput.mTouches.Length() == 1)) {
-          mApzcForInputBlock = nullptr;
-        }
       }
       if (mApzcForInputBlock) {
         GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToScreen);
         MultiTouchInput inputForApzc(multiTouchInput);
         for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
           ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
         }
         mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
+        // If we have an mApzcForInputBlock and it's the end of the touch sequence
+        // then null it out so we don't keep a dangling reference and leak things.
+        if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL ||
+            (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END && multiTouchInput.mTouches.Length() == 1)) {
+          mApzcForInputBlock = nullptr;
+        }
       }
       break;
     } case PINCHGESTURE_INPUT: {
       const PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint);
       if (apzc) {
         GetInputTransforms(apzc, transformToApzc, transformToScreen);
         PinchGestureInput inputForApzc(pinchInput);
@@ -295,37 +297,40 @@ APZCTreeManager::ReceiveInputEvent(const
           APZC_LOG("Using APZC %p as the common ancestor\n", mApzcForInputBlock.get());
           // For now, we only ever want to do pinching on the root APZC for a given layers id. So
           // when we find the common ancestor of multiple points, also walk up to the root APZC.
           mApzcForInputBlock = RootAPZCForLayersId(mApzcForInputBlock);
           APZC_LOG("Using APZC %p as the root APZC for multi-touch\n", mApzcForInputBlock.get());
         }
       } else if (mApzcForInputBlock) {
         APZC_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
-        // If we have an mApzcForInputBlock and it's the end of the touch sequence
-        // then null it out so we don't keep a dangling reference and leak things.
-        if (touchEvent.message == NS_TOUCH_CANCEL ||
-            (touchEvent.message == NS_TOUCH_END && touchEvent.touches.Length() == 1)) {
-          mApzcForInputBlock = nullptr;
-        }
       }
       if (mApzcForInputBlock) {
         GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToScreen);
         MultiTouchInput inputForApzc(touchEvent);
         for (size_t i = 0; i < inputForApzc.mTouches.Length(); i++) {
           ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc);
         }
 
         gfx3DMatrix outTransform = transformToApzc * transformToScreen;
         nsTouchEvent* outEvent = static_cast<nsTouchEvent*>(aOutEvent);
         for (size_t i = 0; i < outEvent->touches.Length(); i++) {
           ApplyTransform(&(outEvent->touches[i]->mRefPoint), outTransform);
         }
 
-        return mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
+        nsEventStatus ret = mApzcForInputBlock->ReceiveInputEvent(inputForApzc);
+
+        // If we have an mApzcForInputBlock and it's the end of the touch sequence
+        // then null it out so we don't keep a dangling reference and leak things.
+        if (touchEvent.message == NS_TOUCH_CANCEL ||
+            (touchEvent.message == NS_TOUCH_END && touchEvent.touches.Length() == 1)) {
+          mApzcForInputBlock = nullptr;
+        }
+
+        return ret;
       }
       break;
     } case NS_MOUSE_EVENT: {
       const nsMouseEvent& mouseEvent = static_cast<const nsMouseEvent&>(aEvent);
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(mouseEvent.refPoint.x, mouseEvent.refPoint.y));
       if (apzc) {
         GetInputTransforms(apzc, transformToApzc, transformToScreen);
         MultiTouchInput inputForApzc(mouseEvent);
--- a/gfx/layers/composite/APZCTreeManager.h
+++ b/gfx/layers/composite/APZCTreeManager.h
@@ -230,16 +230,27 @@ public:
    * Calls Destroy() on all APZC instances attached to the tree, and resets the
    * tree back to empty. This function may be called multiple times during the
    * lifetime of this APZCTreeManager, but it must always be called at least once
    * when this APZCTreeManager is no longer needed. Failing to call this function
    * may prevent objects from being freed properly.
    */
   void ClearTree();
 
+  /**
+   * Set the dpi value used by all AsyncPanZoomControllers.
+   * DPI defaults to 72 if not set using SetDPI() at any point.
+   */
+  static void SetDPI(float aDpiValue) { sDPI = aDpiValue; }
+
+  /**
+   * Returns the current dpi value in use.
+   */
+  static float GetDPI() { return sDPI; }
+
 protected:
   /**
    * Debug-build assertion that can be called to ensure code is running on the
    * compositor thread.
    */
   virtual void AssertOnCompositorThread();
 
 public:
@@ -287,14 +298,16 @@ private:
   mozilla::Monitor mTreeLock;
   nsRefPtr<AsyncPanZoomController> mRootApzc;
   /* This tracks the APZC that should receive all inputs for the current input event block.
    * This allows touch points to move outside the thing they started on, but still have the
    * touch events delivered to the same initial APZC. This will only ever be touched on the
    * input delivery thread, and so does not require locking.
    */
   nsRefPtr<AsyncPanZoomController> mApzcForInputBlock;
+
+  static float sDPI;
 };
 
 }
 }
 
 #endif // mozilla_layers_PanZoomController_h
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -216,30 +216,32 @@ CompositorD3D11::Initialize()
       D3D11_COLOR_WRITE_ENABLE_ALL
     };
     blendDesc.RenderTarget[0] = rtBlendNonPremul;
     hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mNonPremulBlendState));
     if (FAILED(hr)) {
       return false;
     }
 
-    D3D11_RENDER_TARGET_BLEND_DESC rtBlendComponent = {
-      TRUE,
-      D3D11_BLEND_ONE,
-      D3D11_BLEND_INV_SRC1_COLOR,
-      D3D11_BLEND_OP_ADD,
-      D3D11_BLEND_ONE,
-      D3D11_BLEND_INV_SRC_ALPHA,
-      D3D11_BLEND_OP_ADD,
-      D3D11_COLOR_WRITE_ENABLE_ALL
-    };
-    blendDesc.RenderTarget[0] = rtBlendComponent;
-    hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mComponentBlendState));
-    if (FAILED(hr)) {
-      return false;
+    if (gfxPlatform::ComponentAlphaEnabled()) {
+      D3D11_RENDER_TARGET_BLEND_DESC rtBlendComponent = {
+        TRUE,
+        D3D11_BLEND_ONE,
+        D3D11_BLEND_INV_SRC1_COLOR,
+        D3D11_BLEND_OP_ADD,
+        D3D11_BLEND_ONE,
+        D3D11_BLEND_INV_SRC_ALPHA,
+        D3D11_BLEND_OP_ADD,
+        D3D11_COLOR_WRITE_ENABLE_ALL
+      };
+      blendDesc.RenderTarget[0] = rtBlendComponent;
+      hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mComponentBlendState));
+      if (FAILED(hr)) {
+        return false;
+      }
     }
   }
 
   nsRefPtr<IDXGIDevice> dxgiDevice;
   nsRefPtr<IDXGIAdapter> dxgiAdapter;
 
   mDevice->QueryInterface(dxgiDevice.StartAssignment());
   dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
@@ -571,16 +573,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
 
       ID3D11ShaderResourceView* srViews[3] = { views[0], views[1], views[2] };
       mContext->PSSetShaderResources(0, 3, srViews);
     }
     break;
   case EFFECT_COMPONENT_ALPHA:
     {
       MOZ_ASSERT(gfxPlatform::ComponentAlphaEnabled());
+      MOZ_ASSERT(mAttachments->mComponentBlendState);
       EffectComponentAlpha* effectComponentAlpha =
         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
       TextureSourceD3D11* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D11();
       TextureSourceD3D11* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D11();
       SetSamplerForFilter(effectComponentAlpha->mFilter);
 
       mVSConstants.textureCoords = effectComponentAlpha->mTextureCoords;
       RefPtr<ID3D11ShaderResourceView> views[2];
@@ -803,17 +806,19 @@ CompositorD3D11::CreateShaders()
   if (FAILED(hr)) { \
     return false; \
   }
 
   LOAD_PIXEL_SHADER(SolidColorShader);
   LOAD_PIXEL_SHADER(RGBShader);
   LOAD_PIXEL_SHADER(RGBAShader);
   LOAD_PIXEL_SHADER(YCbCrShader);
-  LOAD_PIXEL_SHADER(ComponentAlphaShader);
+  if (gfxPlatform::ComponentAlphaEnabled()) {
+    LOAD_PIXEL_SHADER(ComponentAlphaShader);
+  }
 
 #undef LOAD_PIXEL_SHADER
 
   hr = mDevice->CreatePixelShader(RGBAShaderMask3D,
                                   sizeof(RGBAShaderMask3D),
                                   nullptr,
                                   byRef(mAttachments->mRGBAShader[Mask3d]));
   if (FAILED(hr)) {
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -14,20 +14,23 @@
 #include "ThebesLayerD3D9.h"
 #include "gfxPlatform.h"
 
 #include "gfxWindowsPlatform.h"
 #include "gfxTeeSurface.h"
 #include "gfxUtils.h"
 #include "ReadbackProcessor.h"
 #include "ReadbackLayer.h"
+#include "mozilla/gfx/2D.h"
 
 namespace mozilla {
 namespace layers {
 
+using namespace gfx;
+
 ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager)
   : ThebesLayer(aManager, nullptr)
   , LayerD3D9(aManager)
 {
   mImplData = static_cast<LayerD3D9*>(this);
   aManager->deviceManager()->mLayersWithResources.AppendElement(this);
 }
 
@@ -463,17 +466,28 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion 
       }
       break;
     }
   }
 
   if (!destinationSurface)
     return;
 
-  nsRefPtr<gfxContext> context = new gfxContext(destinationSurface);
+  nsRefPtr<gfxContext> context;
+  if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BACKEND_CAIRO)) {
+     RefPtr<DrawTarget> dt =
+        gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface,
+                                                               IntSize(destinationSurface->GetSize().width,
+                                                                       destinationSurface->GetSize().height));
+
+    context = new gfxContext(dt);
+  } else {
+    context = new gfxContext(destinationSurface);
+  }
+
   context->Translate(gfxPoint(-bounds.x, -bounds.y));
   LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
   cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
 
   for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) {
     NS_ASSERTION(aMode == SURFACE_OPAQUE,
                  "Transparent surfaces should not be used for readback");
     const ReadbackProcessor::Update& update = aReadbackUpdates[i];
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -207,28 +207,25 @@ AsyncPanZoomController::AsyncPanZoomCont
      mMinZoom(MIN_ZOOM),
      mMaxZoom(MAX_ZOOM),
      mLastSampleTime(GetFrameTime()),
      mState(NOTHING),
      mLastAsyncScrollTime(GetFrameTime()),
      mLastAsyncScrollOffset(0, 0),
      mCurrentAsyncScrollOffset(0, 0),
      mAsyncScrollTimeoutTask(nullptr),
-     mDPI(72),
      mDisableNextTouchBatch(false),
      mHandlingTouchQueue(false),
      mDelayPanning(false)
 {
   MOZ_COUNT_CTOR(AsyncPanZoomController);
 
   if (aGestures == USE_GESTURE_DETECTOR) {
     mGestureEventListener = new GestureEventListener(this);
   }
-
-  SetDPI(mDPI);
 }
 
 AsyncPanZoomController::~AsyncPanZoomController() {
   MOZ_COUNT_DTOR(AsyncPanZoomController);
 }
 
 already_AddRefed<GeckoContentController>
 AsyncPanZoomController::GetGeckoContentController() {
@@ -427,17 +424,17 @@ nsEventStatus AsyncPanZoomController::On
     case FLING:
     case NOTHING:
     case ANIMATING_ZOOM:
       // May happen if the user double-taps and drags without lifting after the
       // second tap. Ignore the move if this happens.
       return nsEventStatus_eIgnore;
 
     case TOUCHING: {
-      float panThreshold = gTouchStartTolerance * mDPI;
+      float panThreshold = gTouchStartTolerance * APZCTreeManager::GetDPI();
       UpdateWithTouchAtDevicePoint(aEvent);
 
       if (PanDistance() < panThreshold) {
         return nsEventStatus_eIgnore;
       }
 
       StartPanning(aEvent);
 
@@ -945,24 +942,16 @@ const CSSRect AsyncPanZoomController::Ca
   } else if (scrollOffset.y < scrollableRect.y) {
     scrollOffset.y = scrollableRect.y;
   }
 
   CSSRect shiftedDisplayPort = displayPort + scrollOffset;
   return scrollableRect.ClampRect(shiftedDisplayPort) - scrollOffset;
 }
 
-void AsyncPanZoomController::SetDPI(int aDPI) {
-  mDPI = aDPI;
-}
-
-int AsyncPanZoomController::GetDPI() {
-  return mDPI;
-}
-
 void AsyncPanZoomController::ScheduleComposite() {
   if (mCompositorParent) {
     mCompositorParent->ScheduleRenderOnCompositorThread();
   }
 }
 
 void AsyncPanZoomController::RequestContentRepaint() {
   mFrameMetrics.mDisplayPort =
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -203,29 +203,16 @@ public:
    * Returns the incremental transformation corresponding to the async pan/zoom
    * in progress. That is, when this transform is multiplied with the layer's
    * existing transform, it will make the layer appear with the desired pan/zoom
    * amount.
    */
   ViewTransform GetCurrentAsyncTransform();
 
   /**
-   * Sets the DPI of the device for use within panning and zooming logic. It is
-   * a platform responsibility to set this on initialization of this class and
-   * whenever it changes.
-   */
-  void SetDPI(int aDPI);
-
-  /**
-   * Gets the DPI of the device for use outside the panning and zooming logic.
-   * It defaults to 72 if not set using SetDPI() at any point.
-   */
-  int GetDPI();
-
-  /**
    * Recalculates the displayport. Ideally, this should paint an area bigger
    * than the composite-to dimensions so that when you scroll down, you don't
    * checkerboard immediately. This includes a bunch of logic, including
    * algorithms to bias painting in the direction of the velocity.
    */
   static const CSSRect CalculatePendingDisplayPort(
     const FrameMetrics& aFrameMetrics,
     const gfx::Point& aVelocity,
@@ -585,18 +572,16 @@ private:
   // The current offset drawn on the screen, it may not be sent since we have
   // throttling policy for mozbrowserasyncscroll event.
   CSSPoint mCurrentAsyncScrollOffset;
 
   // The delay task triggered by the throttling mozbrowserasyncscroll event
   // ensures the last mozbrowserasyncscroll event is always been fired.
   CancelableTask* mAsyncScrollTimeoutTask;
 
-  int mDPI;
-
   // Flag used to determine whether or not we should disable handling of the
   // next batch of touch events. This is used for sync scrolling of subframes.
   bool mDisableNextTouchBatch;
 
   // Flag used to determine whether or not we should try to enter the
   // WAITING_LISTENERS state. This is used in the case that we are processing a
   // queued up event block. If set, this means that we are handling this queue
   // and we don't want to queue the events back up again.
--- a/gfx/layers/ipc/GestureEventListener.cpp
+++ b/gfx/layers/ipc/GestureEventListener.cpp
@@ -103,17 +103,17 @@ nsEventStatus GestureEventListener::Hand
 
     break;
   }
   case MultiTouchInput::MULTITOUCH_MOVE: {
     // If we move too much, bail out of the tap.
     ScreenIntPoint delta = event.mTouches[0].mScreenPoint - mTouchStartPosition;
     if (mTouches.Length() == 1 &&
         NS_hypot(delta.x, delta.y) >
-          mAsyncPanZoomController->GetDPI() * mAsyncPanZoomController->GetTouchStartTolerance())
+          APZCTreeManager::GetDPI() * mAsyncPanZoomController->GetTouchStartTolerance())
     {
       HandleTapCancel(event);
     }
 
     size_t eventTouchesMatched = 0;
     for (size_t i = 0; i < mTouches.Length(); i++) {
       bool isTouchRemoved = true;
       for (size_t j = 0; j < event.mTouches.Length(); j++) {
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -133,17 +133,29 @@ gfxContext::~gfxContext()
     mDT->Flush();
   }
   MOZ_COUNT_DTOR(gfxContext);
 }
 
 gfxASurface *
 gfxContext::OriginalSurface()
 {
-    return mSurface;
+    if (mCairo || mSurface) {
+        return mSurface;
+    }
+
+    if (mOriginalDT && mOriginalDT->GetType() == BACKEND_CAIRO) {
+        cairo_surface_t *s =
+            (cairo_surface_t*)mOriginalDT->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE);
+        if (s) {
+            mSurface = gfxASurface::Wrap(s);
+            return mSurface;
+        }
+    }
+    return nullptr;
 }
 
 already_AddRefed<gfxASurface>
 gfxContext::CurrentSurface(gfxFloat *dx, gfxFloat *dy)
 {
   if (mCairo) {
     cairo_surface_t *s = cairo_get_group_target(mCairo);
     if (s == mSurface->CairoSurface()) {
@@ -152,31 +164,49 @@ gfxContext::CurrentSurface(gfxFloat *dx,
         nsRefPtr<gfxASurface> ret = mSurface;
         return ret.forget();
     }
 
     if (dx && dy)
         cairo_surface_get_device_offset(s, dx, dy);
     return gfxASurface::Wrap(s);
   } else {
+    if (mDT->GetType() == BACKEND_CAIRO) {
+        cairo_surface_t *s =
+            (cairo_surface_t*)mDT->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE);
+        if (s) {
+            if (dx && dy)
+                cairo_surface_get_device_offset(s, dx, dy);
+            return gfxASurface::Wrap(s);
+        }
+    }
+
     if (dx && dy) {
       *dx = *dy = 0;
     }
     // An Azure context doesn't have a surface backing it.
     return nullptr;
   }
 }
 
 cairo_t *
 gfxContext::GetCairo()
 {
   if (mCairo) {
     return mCairo;
   }
 
+  if (mDT->GetType() == BACKEND_CAIRO) {
+    cairo_t *ctx =
+      (cairo_t*)mOriginalDT->GetNativeSurface(NATIVE_SURFACE_CAIRO_CONTEXT);
+    if (ctx) {
+      return ctx;
+    }
+  }
+
   if (mRefCairo) {
     // Set transform!
     return mRefCairo;
   }
 
   mRefCairo = cairo_create(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->CairoSurface()); 
 
   return mRefCairo;
@@ -1470,16 +1500,37 @@ void
 gfxContext::Paint(gfxFloat alpha)
 {
   PROFILER_LABEL("gfxContext", "Paint");
   if (mCairo) {
     cairo_paint_with_alpha(mCairo, alpha);
   } else {
     AzureState &state = CurrentState();
 
+    if (state.sourceSurface && !state.sourceSurfCairo &&
+        !state.patternTransformChanged && !state.opIsClear)
+    {
+      // This is the case where a PopGroupToSource has been done and this
+      // paint is executed without changing the transform or the source.
+      Matrix oldMat = mDT->GetTransform();
+
+      IntSize surfSize = state.sourceSurface->GetSize();
+
+      Matrix mat;
+      mat.Translate(-state.deviceOffset.x, -state.deviceOffset.y);
+      mDT->SetTransform(mat);
+
+      mDT->DrawSurface(state.sourceSurface,
+                       Rect(state.sourceSurfaceDeviceOffset, Size(surfSize.width, surfSize.height)),
+                       Rect(Point(), Size(surfSize.width, surfSize.height)),
+                       DrawSurfaceOptions(), DrawOptions(alpha, GetOp()));
+      mDT->SetTransform(oldMat);
+      return;
+    }
+
     Matrix mat = mDT->GetTransform();
     mat.Invert();
     Rect paintRect = mat.TransformBounds(Rect(Point(0, 0), Size(mDT->GetSize())));
 
     if (state.opIsClear) {
       mDT->ClearRect(paintRect);
     } else {
       mDT->FillRect(paintRect, GeneralPattern(this),
@@ -1621,16 +1672,17 @@ gfxContext::PopGroupToSource()
   if (mCairo) {
     cairo_pop_group_to_source(mCairo);
   } else {
     RefPtr<SourceSurface> src = mDT->Snapshot();
     Point deviceOffset = CurrentState().deviceOffset;
     Restore();
     CurrentState().sourceSurfCairo = nullptr;
     CurrentState().sourceSurface = src;
+    CurrentState().sourceSurfaceDeviceOffset = deviceOffset;
     CurrentState().pattern = nullptr;
     CurrentState().patternTransformChanged = false;
 
     Matrix mat = mTransform;
     mat.Invert();
 
     Matrix deviceOffsetTranslation;
     deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y);
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -736,16 +736,17 @@ private:
     {}
 
     mozilla::gfx::CompositionOp op;
     bool opIsClear;
     Color color;
     nsRefPtr<gfxPattern> pattern;
     nsRefPtr<gfxASurface> sourceSurfCairo;
     mozilla::RefPtr<SourceSurface> sourceSurface;
+    mozilla::gfx::Point sourceSurfaceDeviceOffset;
     Matrix surfTransform;
     Matrix transform;
     struct PushedClip {
       mozilla::RefPtr<Path> path;
       Rect rect;
       Matrix transform;
     };
     nsTArray<PushedClip> pushedClips;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -871,28 +871,34 @@ gfxPlatform::CreateDrawTargetForBackend(
 
     return CreateDrawTargetForSurface(surf, aSize);
   } else {
     return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
   }
 }
 
 RefPtr<DrawTarget>
-gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
+gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
 {
   NS_ASSERTION(mPreferredCanvasBackend, "No backend.");
   RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
   if (target ||
       mFallbackCanvasBackend == BACKEND_NONE) {
     return target;
   }
 
   return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
 }
 
+RefPtr<DrawTarget>
+gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
+{
+  NS_ASSERTION(mContentBackend, "No backend.");
+  return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
+}
 
 RefPtr<DrawTarget>
 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
 {
   NS_ASSERTION(mPreferredCanvasBackend, "No backend.");
   return Factory::CreateDrawTargetForData(mPreferredCanvasBackend, aData, aSize, aStride, aFormat);
 }
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -229,18 +229,21 @@ public:
       // Overwrite me on platform where GetThebesSurfaceForDrawTarget returns
       // a snapshot of the draw target.
       return GetThebesSurfaceForDrawTarget(aTarget);
     }
 
     virtual already_AddRefed<gfxASurface>
       GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
 
-    virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
-      CreateOffscreenDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
+    mozilla::RefPtr<mozilla::gfx::DrawTarget>
+      CreateOffscreenContentDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
+
+    mozilla::RefPtr<mozilla::gfx::DrawTarget>
+      CreateOffscreenCanvasDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
 
     virtual mozilla::RefPtr<mozilla::gfx::DrawTarget>
       CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize, 
                               int32_t aStride, mozilla::gfx::SurfaceFormat aFormat);
 
     /**
      * Returns true if we will render content using Azure using a gfxPlatform
      * provided DrawTarget.
@@ -580,16 +583,22 @@ public:
     uint32_t GetOrientationSyncMillis() const;
 
     /**
      * Return the layer debugging options to use browser-wide.
      */
     mozilla::layers::DiagnosticTypes GetLayerDiagnosticTypes();
 
     static bool DrawFrameCounter();
+    static nsIntRect FrameCounterBounds() {
+      int bits = 16;
+      int sizeOfBit = 3;
+      return nsIntRect(0, 0, bits * sizeOfBit, sizeOfBit);
+    }
+
     /**
      * Returns true if we should use raw memory to send data to the compositor
      * rather than using shmems.
      *
      * This method should not be called from the compositor thread.
      */
     bool PreferMemoryOverShmem() const;
     bool UseDeprecatedTextures() const { return mLayersUseDeprecated; }
--- a/gfx/thebes/gfxWindowsNativeDrawing.cpp
+++ b/gfx/thebes/gfxWindowsNativeDrawing.cpp
@@ -6,16 +6,17 @@
 #include <windows.h>
 
 #include "nsMathUtils.h"
 
 #include "gfxWindowsNativeDrawing.h"
 #include "gfxWindowsSurface.h"
 #include "gfxAlphaRecovery.h"
 #include "gfxPattern.h"
+#include "mozilla/gfx/2D.h"
 
 enum {
     RENDER_STATE_INIT,
 
     RENDER_STATE_NATIVE_DRAWING,
     RENDER_STATE_NATIVE_DRAWING_DONE,
 
     RENDER_STATE_ALPHA_RECOVERY_BLACK,
@@ -177,17 +178,19 @@ gfxWindowsNativeDrawing::BeginNativeDraw
         NS_ERROR("Bogus render state!");
         return nullptr;
     }
 }
 
 bool
 gfxWindowsNativeDrawing::IsDoublePass()
 {
-    if (!mContext->IsCairo()) {
+    if (!mContext->IsCairo() &&
+        (mContext->GetDrawTarget()->GetType() != mozilla::gfx::BACKEND_CAIRO ||
+         mContext->GetDrawTarget()->IsDualDrawTarget())) {
       return true;
     }
 
     nsRefPtr<gfxASurface> surf = mContext->CurrentSurface(&mDeviceOffset.x, &mDeviceOffset.y);
     if (!surf || surf->CairoStatus())
         return false;
     if (surf->GetType() != gfxASurface::SurfaceTypeWin32 &&
         surf->GetType() != gfxASurface::SurfaceTypeWin32Printing) {
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -497,17 +497,17 @@ gfxWindowsPlatform::UpdateRenderMode()
 
             if (hr == S_OK)
               reporter.SetSuccessful();
         }
     }
 #endif
 
     uint32_t canvasMask = 1 << BACKEND_CAIRO;
-    uint32_t contentMask = 0;
+    uint32_t contentMask = 1 << BACKEND_CAIRO;
     if (mRenderMode == RENDER_DIRECT2D) {
       canvasMask |= 1 << BACKEND_DIRECT2D;
       contentMask |= 1 << BACKEND_DIRECT2D;
     } else {
       canvasMask |= 1 << BACKEND_SKIA;
     }
     InitBackendPrefs(canvasMask, contentMask);
 }
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -55,17 +55,17 @@ class IDXGIAdapter1;
 class nsIMemoryMultiReporter;
 
 // Utility to get a Windows HDC from a thebes context,
 // used by both GDI and Uniscribe font shapers
 struct DCFromContext {
     DCFromContext(gfxContext *aContext) {
         dc = nullptr;
         nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
-        NS_ASSERTION(aSurface, "DCFromContext: null surface");
+        NS_ASSERTION(aSurface || !aContext->IsCairo(), "DCFromContext: null surface");
         if (aSurface &&
             (aSurface->GetType() == gfxASurface::SurfaceTypeWin32 ||
              aSurface->GetType() == gfxASurface::SurfaceTypeWin32Printing))
         {
             dc = static_cast<gfxWindowsSurface*>(aSurface.get())->GetDC();
             needsRelease = false;
             SaveDC(dc);
             cairo_scaled_font_t* scaled =
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -227,18 +227,18 @@ ClippedImage::GetFrameInternal(const nsI
   float frameToDraw = InnerImage()->GetFrameIndex(aWhichFrame);
   if (!mCachedSurface || !mCachedSurface->Matches(aViewportSize,
                                                   aSVGContext,
                                                   frameToDraw,
                                                   aFlags)) {
     // Create a surface to draw into.
     mozilla::RefPtr<mozilla::gfx::DrawTarget> target;
     target = gfxPlatform::GetPlatform()->
-      CreateOffscreenDrawTarget(gfx::IntSize(mClip.width, mClip.height),
-                                gfx::FORMAT_B8G8R8A8);
+      CreateOffscreenCanvasDrawTarget(gfx::IntSize(mClip.width, mClip.height),
+                                      gfx::FORMAT_B8G8R8A8);
     nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
       GetThebesSurfaceForDrawTarget(target);
 
     // Create our callback.
     nsRefPtr<gfxDrawingCallback> drawTileCallback =
       new DrawSingleTileCallback(this, mClip, aViewportSize, aSVGContext, aWhichFrame, aFlags);
     nsRefPtr<gfxDrawable> drawable =
       new gfxCallbackDrawable(drawTileCallback, mClip.Size());
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -17,17 +17,17 @@
 #include "mozilla/Util.h"
 
 #include <stdint.h>
 
 #include "nsID.h"
 #include "nsMemory.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
-#include "jsapi.h"
+#include "js/StructuredClone.h"
 #include "nsCSSProperty.h"
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4800 )
 #endif
 
 #if !defined(OS_POSIX)
 // This condition must be kept in sync with the one in
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -128,10 +128,33 @@ void
 ProtocolErrorBreakpoint(const char* aMsg)
 {
     // Bugs that generate these error messages can be tough to
     // reproduce.  Log always in the hope that someone finds the error
     // message.
     printf_stderr("IPDL protocol error: %s\n", aMsg);
 }
 
+void
+FatalError(const char* aProtocolName, const char* aMsg,
+           ProcessHandle aHandle, bool aIsParent)
+{
+  ProtocolErrorBreakpoint(aMsg);
+
+  nsAutoCString formattedMessage("IPDL error [");
+  formattedMessage.AppendASCII(aProtocolName);
+  formattedMessage.AppendLiteral("]: \"");
+  formattedMessage.AppendASCII(aMsg);
+  if (aIsParent) {
+    formattedMessage.AppendLiteral("\". Killing child side as a result.");
+    NS_ERROR(formattedMessage.get());
+
+    if (!base::KillProcess(aHandle, base::PROCESS_END_KILLED_BY_USER, false)) {
+      NS_ERROR("May have failed to kill child!");
+    }
+  } else {
+    formattedMessage.AppendLiteral("\". abort()ing as a result.");
+    NS_RUNTIMEABORT(formattedMessage.get());
+  }
+}
+
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -10,16 +10,17 @@
 
 #include "base/process.h"
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
 
 #include "prenv.h"
 
 #include "IPCMessageStart.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/Transport.h"
 
 // WARNING: this takes into account the private, special-message-type
 // enum in ipc_channel.h.  They need to be kept in sync.
 namespace {
 // XXX the max message ID is actually kuint32max now ... when this
@@ -107,19 +108,23 @@ LoggingEnabled()
 {
 #if defined(DEBUG)
     return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
 #else
     return false;
 #endif
 }
 
-void
+MOZ_NEVER_INLINE void
 ProtocolErrorBreakpoint(const char* aMsg);
 
+MOZ_NEVER_INLINE void
+FatalError(const char* aProtocolName, const char* aMsg,
+           base::ProcessHandle aHandle, bool aIsParent);
+
 typedef IPCMessageStart ProtocolId;
 
 struct PrivateIPDLInterface {};
 
 bool
 Bridge(const PrivateIPDLInterface&,
        AsyncChannel*, base::ProcessHandle, AsyncChannel*, base::ProcessHandle,
        ProtocolId, ProtocolId);
--- a/ipc/ipdl/ipdl/cxx/ast.py
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -442,57 +442,61 @@ class Inherit(Node):
 class FriendClassDecl(Node):
     def __init__(self, friend):
         Node.__init__(self)
         self.friend = friend
 
 class MethodDecl(Node):
     def __init__(self, name, params=[ ], ret=Type('void'),
                  virtual=0, const=0, pure=0, static=0, warn_unused=0,
-                 inline=0, force_inline=0,
+                 inline=0, force_inline=0, never_inline=0,
                  typeop=None,
                  T=None):
         assert not (virtual and static)
         assert not pure or virtual      # pure => virtual
         assert not (static and typeop)
         assert not (name and typeop)
         assert name is None or isinstance(name, str)
         assert not isinstance(ret, list)
         for decl in params:  assert not isinstance(decl, str)
         assert not isinstance(T, int)
+        assert not (inline and never_inline)
+        assert not (force_inline and never_inline)
 
         if typeop is not None:
             ret = None
 
         Node.__init__(self)
         self.name = name
         self.params = params            # [ Param ]
         self.ret = ret                  # Type or None
         self.virtual = virtual          # bool
         self.const = const              # bool
         self.pure = pure                # bool
         self.static = static            # bool
         self.warn_unused = warn_unused  # bool
         self.force_inline = (force_inline or T) # bool
         self.inline = inline            # bool
+        self.never_inline = never_inline # bool
         self.typeop = typeop            # Type or None
         self.T = T                      # Type or None
 
     def __deepcopy__(self, memo):
         return MethodDecl(
             self.name,
             params=copy.deepcopy(self.params, memo),
             ret=copy.deepcopy(self.ret, memo),
             virtual=self.virtual,
             const=self.const,
             pure=self.pure,
             static=self.static,
             warn_unused=self.warn_unused,
             inline=self.inline,
             force_inline=self.force_inline,
+            never_inline=self.never_inline,
             typeop=copy.deepcopy(self.typeop, memo),
             T=copy.deepcopy(self.T, memo))
 
 class MethodDefn(Block):
     def __init__(self, decl):
         Block.__init__(self)
         self.decl = decl
 
--- a/ipc/ipdl/ipdl/cxx/cgen.py
+++ b/ipc/ipdl/ipdl/cxx/cgen.py
@@ -177,16 +177,18 @@ class CxxCodeGen(CodePrinter, Visitor):
             self.write('template<')
             self.write('typename ')
             md.T.accept(self)
             self.println('>')
             self.printdent()
 
         if md.inline:
             self.write('inline ')
+        if md.inline:
+            self.write('MOZ_NEVER_INLINE ')
         if md.static:
             self.write('static ')
         if md.virtual:
             self.write('virtual ')
         if md.ret:
             md.ret.accept(self)
             self.println()
             self.printdent()
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -376,16 +376,24 @@ def _printErrorMessage(msg):
         ExprCall(ExprVar('NS_ERROR'), args=[ msg ]))
 
 def _protocolErrorBreakpoint(msg):
     if isinstance(msg, str):
         msg = ExprLiteral.String(msg)
     return StmtExpr(ExprCall(ExprVar('mozilla::ipc::ProtocolErrorBreakpoint'),
                              args=[ msg ]))
 
+def _ipcFatalError(name, msg, otherprocess, isparent):
+    if isinstance(name, str):
+        name = ExprLiteral.String(name)
+    if isinstance(msg, str):
+        msg = ExprLiteral.String(msg)
+    return StmtExpr(ExprCall(ExprVar('mozilla::ipc::FatalError'),
+                             args=[ name, msg, otherprocess, isparent ]))
+
 def _printWarningMessage(msg):
     if isinstance(msg, str):
         msg = ExprLiteral.String(msg)
     return StmtExpr(
         ExprCall(ExprVar('NS_WARNING'), args=[ msg ]))
 
 def _fatalError(msg):
     return StmtExpr(
@@ -3204,55 +3212,26 @@ class _GenerateProtocolActorCode(ipdl.as
 
         ## FatalError()       
         msgparam = ExprVar('aMsg')
         msgvar = ExprVar('formattedMessage')
         actorname = _actorName(p.name, self.side)
         fatalerror = MethodDefn(MethodDecl(
             'FatalError',
             params=[ Decl(Type('char', const=1, ptrconst=1), msgparam.name) ],
-            const=1, virtual=1))
-        fatalerror.addstmts([
-            Whitespace('// Virtual method to prevent inlining.\n', indent=1),
-            Whitespace('// This give us better error reporting.\n', indent=1),
-            Whitespace('// See bug 589371\n\n', indent=1),
-            _protocolErrorBreakpoint(msgparam),
-            Whitespace.NL,
-            StmtDecl(Decl(Type('nsAutoCString'), msgvar.name),
-                     initargs=[ExprLiteral.String('IPDL error [' + actorname +
-                                                  ']: \\"')]),
-            StmtExpr(ExprCall(ExprSelect(msgvar, '.', 'AppendASCII'),
-                              args=[msgparam]))
-        ])
+            const=1, never_inline=1))
         if self.side is 'parent':
-            # if the error happens on the parent side, the parent
-            # kills off the child
-            fatalerror.addstmts([
-                StmtExpr(ExprCall(ExprSelect(msgvar, '.', 'AppendLiteral'),
-                                  args=[ExprLiteral.String('\\". Killing ' +
-                                                           'child side as a ' +
-                                                           'result.')])),
-                Whitespace.NL,
-                _printErrorMessage(ExprCall(ExprSelect(msgvar, '.', 'get'))),
-            ])
-
-            ifkill = StmtIf(ExprNot(_killProcess(p.callOtherProcess())))
-            ifkill.addifstmt(
-                _printErrorMessage("May have failed to kill child!"))
-            fatalerror.addstmts([Whitespace.NL, ifkill])
+            otherprocess = p.callOtherProcess()
+            isparent = ExprLiteral.TRUE
         else:
-            # and if it happens on the child side, the child commits
-            # seppuko
-            fatalerror.addstmts([
-                StmtExpr(ExprCall(ExprSelect(msgvar, '.', 'AppendLiteral'),
-                                  args=[ExprLiteral.String('\\". abort()ing ' +
-                                                           'as a result.')])),
-                Whitespace.NL,
-                _runtimeAbort(ExprCall(ExprSelect(msgvar, '.', 'get'))),
-            ])
+            otherprocess = ExprLiteral.NULL
+            isparent = ExprLiteral.FALSE
+        fatalerror.addstmts([
+            _ipcFatalError(actorname, msgparam, otherprocess, isparent)
+        ])
         self.cls.addstmts([ fatalerror, Whitespace.NL ])
 
         ## DestroySubtree(bool normal)
         whyvar = ExprVar('why')
         subtreewhyvar = ExprVar('subtreewhy')
         kidsvar = ExprVar('kids')
         ivar = ExprVar('i')
         ithkid = ExprIndex(kidsvar, ivar)
@@ -5187,16 +5166,17 @@ methodDefns."""
     return cls, defns
 
 def _splitMethodDefn(md, clsname):
     saveddecl = deepcopy(md.decl)
     md.decl.name = (clsname +'::'+ md.decl.name)
     md.decl.virtual = 0
     md.decl.static = 0
     md.decl.warn_unused = 0
+    md.decl.never_inline = 0
     for param in md.decl.params:
         if isinstance(param, Param):
             param.default = None
     return saveddecl, md
 
 
 def _splitFuncDeclDefn(fun):
     assert not fun.decl.inline
--- a/js/ipc/JavaScriptParent.h
+++ b/js/ipc/JavaScriptParent.h
@@ -5,16 +5,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_jsipc_JavaScriptParent__
 #define mozilla_jsipc_JavaScriptParent__
 
 #include "JavaScriptShared.h"
 #include "mozilla/jsipc/PJavaScriptParent.h"
+#include "jsclass.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #undef GetClassInfo
 #endif
 
 namespace mozilla {
 namespace jsipc {
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -30,17 +30,20 @@ namespace js {
 // small to be worth reporting individually.  Under some circumstances, a memory
 // reporter gets tossed into the sundries bucket if it's smaller than
 // MemoryReportingSundriesThreshold() bytes.
 //
 // We need to define this value here, rather than in the code which actually
 // generates the memory reports, because NotableStringInfo uses this value.
 JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold();
 
-struct StringHashPolicy
+// This hash policy avoids flattening ropes (which perturbs the site being
+// measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
+// on every hash and match! Beware.
+struct InefficientNonFlatteningStringHashPolicy
 {
     typedef JSString *Lookup;
     static HashNumber hash(const Lookup &l);
     static bool match(const JSString *const &k, const Lookup &l);
 };
 
 struct ZoneStatsPod
 {
@@ -296,18 +299,20 @@ struct ZoneStats : js::ZoneStatsPod
                 p->value.add(r.front().value);
             } else {
                 // We haven't seen this string before; add it to the hashtable.
                 strings.add(p, r.front().key, r.front().value);
             }
         }
     }
 
-    typedef js::HashMap<JSString*, StringInfo, js::StringHashPolicy, js::SystemAllocPolicy>
-        StringsHashMap;
+    typedef js::HashMap<JSString*,
+                        StringInfo,
+                        js::InefficientNonFlatteningStringHashPolicy,
+                        js::SystemAllocPolicy> StringsHashMap;
 
     StringsHashMap strings;
     js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings;
 
     // The size of all the live things in the GC heap that don't belong to any
     // compartment.
     size_t GCHeapThingsSize();
 };
new file mode 100644
--- /dev/null
+++ b/js/public/ProfilingStack.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 js_ProfilingStack_h
+#define js_ProfilingStack_h
+
+#include "jsbytecode.h"
+#include "jstypes.h"
+
+#include "js/Utility.h"
+
+struct JSRuntime;
+class JSScript;
+
+namespace js {
+
+// A call stack can be specified to the JS engine such that all JS entry/exits
+// to functions push/pop an entry to/from the specified stack.
+//
+// For more detailed information, see vm/SPSProfiler.h.
+//
+class ProfileEntry
+{
+    // All fields are marked volatile to prevent the compiler from re-ordering
+    // instructions. Namely this sequence:
+    //
+    //    entry[size] = ...;
+    //    size++;
+    //
+    // If the size modification were somehow reordered before the stores, then
+    // if a sample were taken it would be examining bogus information.
+    //
+    // A ProfileEntry represents both a C++ profile entry and a JS one. Both use
+    // the string as a description, but JS uses the sp as NULL to indicate that
+    // it is a JS entry. The script_ is then only ever examined for a JS entry,
+    // and the idx is used by both, but with different meanings.
+    //
+    const char * volatile string; // Descriptive string of this entry
+    void * volatile sp;           // Relevant stack pointer for the entry
+    JSScript * volatile script_;  // if js(), non-null script which is running
+    int32_t volatile idx;         // if js(), idx of pc, otherwise line number
+
+  public:
+    // All of these methods are marked with the 'volatile' keyword because SPS's
+    // representation of the stack is stored such that all ProfileEntry
+    // instances are volatile. These methods would not be available unless they
+    // were marked as volatile as well.
+
+    bool js() volatile {
+        JS_ASSERT_IF(sp == NULL, script_ != NULL);
+        return sp == NULL;
+    }
+
+    uint32_t line() volatile { JS_ASSERT(!js()); return idx; }
+    JSScript *script() volatile { JS_ASSERT(js()); return script_; }
+    void *stackAddress() volatile { return sp; }
+    const char *label() volatile { return string; }
+
+    void setLine(uint32_t aLine) volatile { JS_ASSERT(!js()); idx = aLine; }
+    void setLabel(const char *aString) volatile { string = aString; }
+    void setStackAddress(void *aSp) volatile { sp = aSp; }
+    void setScript(JSScript *aScript) volatile { script_ = aScript; }
+
+    // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
+    JS_FRIEND_API(jsbytecode *) pc() volatile;
+    JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
+
+    static size_t offsetOfString() { return offsetof(ProfileEntry, string); }
+    static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); }
+    static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); }
+    static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); }
+
+    // The index used in the entry can either be a line number or the offset of
+    // a pc into a script's code. To signify a NULL pc, use a -1 index. This is
+    // checked against in pc() and setPC() to set/get the right pc.
+    static const int32_t NullPCIndex = -1;
+};
+
+JS_FRIEND_API(void)
+SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
+                         uint32_t max);
+
+JS_FRIEND_API(void)
+EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
+
+JS_FRIEND_API(jsbytecode*)
+ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
+
+} // namespace js
+
+#endif  /* js_ProfilingStack_h */
new file mode 100644
--- /dev/null
+++ b/js/public/StructuredClone.h
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 js_StructuredClone_h
+#define js_StructuredClone_h
+
+#include <stdint.h>
+
+#include "jstypes.h"
+
+struct JSContext;
+class JSObject;
+struct JSRuntime;
+struct JSStructuredCloneReader;
+struct JSStructuredCloneWriter;
+
+namespace JS {
+template <typename T> class Handle;
+class Value;
+}
+
+// API for the HTML5 internal structured cloning algorithm.
+
+// Read structured data from the reader r. This hook is used to read a value
+// previously serialized by a call to the WriteStructuredCloneOp hook.
+//
+// tag and data are the pair of uint32_t values from the header. The callback
+// may use the JS_Read* APIs to read any other relevant parts of the object
+// from the reader r. closure is any value passed to the JS_ReadStructuredClone
+// function. Return the new object on success, NULL on error/exception.
+typedef JSObject *(*ReadStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r,
+                                           uint32_t tag, uint32_t data, void *closure);
+
+// Structured data serialization hook. The engine can write primitive values,
+// Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other
+// type of object requires application support. This callback must first use
+// the JS_WriteUint32Pair API to write an object header, passing a value
+// greater than JS_SCTAG_USER to the tag parameter. Then it can use the
+// JS_Write* APIs to write any other relevant parts of the value v to the
+// writer w. closure is any value passed to the JS_WriteStructuredCLone function.
+//
+// Return true on success, false on error/exception.
+typedef bool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w,
+                                         JS::Handle<JSObject*> obj, void *closure);
+
+// This is called when JS_WriteStructuredClone is given an invalid transferable.
+// To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
+// with error set to one of the JS_SCERR_* values.
+typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid);
+
+// The maximum supported structured-clone serialization format version.
+#define JS_STRUCTURED_CLONE_VERSION 2
+
+struct JSStructuredCloneCallbacks {
+    ReadStructuredCloneOp read;
+    WriteStructuredCloneOp write;
+    StructuredCloneErrorOp reportError;
+};
+
+// Note: if the *data contains transferable objects, it can be read only once.
+JS_PUBLIC_API(bool)
+JS_ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, uint32_t version,
+                       JS::Value *vp, const JSStructuredCloneCallbacks *optionalCallbacks,
+                       void *closure);
+
+// Note: On success, the caller is responsible for calling
+// JS_ClearStructuredClone(*datap, nbytesp).
+JS_PUBLIC_API(bool)
+JS_WriteStructuredClone(JSContext *cx, JS::Value v, uint64_t **datap, size_t *nbytesp,
+                        const JSStructuredCloneCallbacks *optionalCallbacks,
+                        void *closure, JS::Value transferable);
+
+JS_PUBLIC_API(bool)
+JS_ClearStructuredClone(const uint64_t *data, size_t nbytes);
+
+JS_PUBLIC_API(bool)
+JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes, bool *hasTransferable);
+
+JS_PUBLIC_API(bool)
+JS_StructuredClone(JSContext *cx, JS::Value v, JS::Value *vp,
+                   const JSStructuredCloneCallbacks *optionalCallbacks, void *closure);
+
+// RAII sugar for JS_WriteStructuredClone.
+class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
+    uint64_t *data_;
+    size_t nbytes_;
+    uint32_t version_;
+
+  public:
+    JSAutoStructuredCloneBuffer()
+        : data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
+
+    ~JSAutoStructuredCloneBuffer() { clear(); }
+
+    uint64_t *data() const { return data_; }
+    size_t nbytes() const { return nbytes_; }
+
+    void clear();
+
+    // Copy some memory. It will be automatically freed by the destructor.
+    bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
+
+    // Adopt some memory. It will be automatically freed by the destructor.
+    // data must have been allocated by the JS engine (e.g., extracted via
+    // JSAutoStructuredCloneBuffer::steal).
+    void adopt(uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
+
+    // Remove the buffer so that it will not be automatically freed.
+    // After this, the caller is responsible for feeding the memory back to
+    // JSAutoStructuredCloneBuffer::adopt.
+    void steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp=NULL);
+
+    bool read(JSContext *cx, JS::Value *vp,
+              const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
+
+    bool write(JSContext *cx, JS::Value v,
+               const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
+
+    bool write(JSContext *cx, JS::Value v, JS::Value transferable,
+               const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
+
+    // Swap ownership with another JSAutoStructuredCloneBuffer.
+    void swap(JSAutoStructuredCloneBuffer &other);
+
+  private:
+    // Copy and assignment are not supported.
+    JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other);
+    JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
+};
+
+// The range of tag values the application may use for its own custom object types.
+#define JS_SCTAG_USER_MIN  ((uint32_t) 0xFFFF8000)
+#define JS_SCTAG_USER_MAX  ((uint32_t) 0xFFFFFFFF)
+
+#define JS_SCERR_RECURSION 0
+#define JS_SCERR_TRANSFERABLE 1
+
+JS_PUBLIC_API(void)
+JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks);
+
+JS_PUBLIC_API(bool)
+JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
+
+JS_PUBLIC_API(bool)
+JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
+
+JS_PUBLIC_API(bool)
+JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *vp);
+
+JS_PUBLIC_API(bool)
+JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
+
+JS_PUBLIC_API(bool)
+JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
+
+JS_PUBLIC_API(bool)
+JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v);
+
+#endif  /* js_StructuredClone_h */
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1891,12 +1891,30 @@ PRIVATE_TO_JSVAL(void *ptr)
 
 static inline void *
 JSVAL_TO_PRIVATE(jsval v)
 {
     MOZ_ASSERT(JSVAL_IS_DOUBLE(v));
     return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v));
 }
 
+// JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
+// constructing values from scratch (e.g. Int32Value(0)).  These constants are
+// stored in memory and initialized at startup, so testing against them and
+// using them requires memory loads and will be correspondingly slow.
+extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
+
+namespace JS {
+
+extern JS_PUBLIC_DATA(const Handle<Value>) NullHandleValue;
+extern JS_PUBLIC_DATA(const Handle<Value>) UndefinedHandleValue;
+
+}
+
 #undef JS_VALUE_IS_CONSTEXPR
 #undef JS_RETURN_LAYOUT_FROM_BITS
 
 #endif /* js_Value_h */
--- a/js/src/build/cl.py
+++ b/js/src/build/cl.py
@@ -1,18 +1,53 @@
 # 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 ctypes
 import os, os.path
 import subprocess
 import sys
+from mozbuild.makeutil import Makefile
 
 CL_INCLUDES_PREFIX = os.environ.get("CL_INCLUDES_PREFIX", "Note: including file:")
 
+GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW
+GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
+
+
+# cl.exe likes to print inconsistent paths in the showIncludes output
+# (some lowercased, some not, with different directions of slashes),
+# and we need the original file case for make/pymake to be happy.
+# As this is slow and needs to be called a lot of times, use a cache
+# to speed things up.
+_normcase_cache = {}
+
+def normcase(path):
+    # Get*PathName want paths with backslashes
+    path = path.replace('/', os.sep)
+    dir = os.path.dirname(path)
+    # name is fortunately always going to have the right case,
+    # so we can use a cache for the directory part only.
+    name = os.path.basename(path)
+    if dir in _normcase_cache:
+        result = _normcase_cache[dir]
+    else:
+        path = ctypes.create_unicode_buffer(dir)
+        length = GetShortPathName(path, None, 0)
+        shortpath = ctypes.create_unicode_buffer(length)
+        GetShortPathName(path, shortpath, length)
+        length = GetLongPathName(shortpath, None, 0)
+        if length > len(path):
+            path = ctypes.create_unicode_buffer(length)
+        GetLongPathName(shortpath, path, length)
+        result = _normcase_cache[dir] = path.value
+    return os.path.join(result, name)
+
+
 def InvokeClWithDependencyGeneration(cmdline):
     target = ""
     # Figure out what the target is
     for arg in cmdline:
         if arg.startswith("-Fo"):
             target = arg[3:]
             break
 
@@ -24,27 +59,29 @@ def InvokeClWithDependencyGeneration(cmd
     assert not source.startswith('-')
 
     # The deps target lives here
     depstarget = os.path.basename(target) + ".pp"
 
     cmdline += ['-showIncludes']
     cl = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
 
-    deps = set([os.path.normcase(source).replace(os.sep, '/')])
+    mk = Makefile()
+    rule = mk.create_rule(target)
+    rule.add_dependencies([normcase(source)])
     for line in cl.stdout:
         # cl -showIncludes prefixes every header with "Note: including file:"
         # and an indentation corresponding to the depth (which we don't need)
         if line.startswith(CL_INCLUDES_PREFIX):
             dep = line[len(CL_INCLUDES_PREFIX):].strip()
             # We can't handle pathes with spaces properly in mddepend.pl, but
             # we can assume that anything in a path with spaces is a system
             # header and throw it away.
             if ' ' not in dep:
-                deps.add(os.path.normcase(dep).replace(os.sep, '/'))
+                rule.add_dependencies([normcase(dep)])
         else:
             sys.stdout.write(line) # Make sure we preserve the relevant output
                                    # from cl
 
     ret = cl.wait()
     if ret != 0 or target == "":
         sys.exit(ret)
 
@@ -54,17 +91,12 @@ def InvokeClWithDependencyGeneration(cmd
         try:
             os.makedirs(depsdir)
         except OSError:
             pass # This suppresses the error we get when the dir exists, at the
                  # cost of masking failure to create the directory.  We'll just
                  # die on the next line though, so it's not that much of a loss.
 
     with open(depstarget, "w") as f:
-        f.write("%s: %s" % (target, source))
-        for dep in sorted(deps):
-            f.write(" \\\n%s" % dep)
-        f.write('\n')
-        for dep in sorted(deps):
-            f.write("%s:\n" % dep)
+        mk.dump(f)
 
 if __name__ == "__main__":
     InvokeClWithDependencyGeneration(sys.argv[1:])
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -928,24 +928,22 @@ js::testingFunc_inParallelSection(JSCont
     return true;
 }
 
 static const char *ObjectMetadataPropertyName = "__objectMetadataFunction__";
 
 static bool
 ShellObjectMetadataCallback(JSContext *cx, JSObject **pmetadata)
 {
-    Value thisv = UndefinedValue();
-
     RootedValue fun(cx);
     if (!JS_GetProperty(cx, cx->global(), ObjectMetadataPropertyName, &fun))
         return false;
 
     RootedValue rval(cx);
-    if (!Invoke(cx, thisv, fun, 0, NULL, &rval))
+    if (!Invoke(cx, UndefinedValue(), fun, 0, NULL, &rval))
         return false;
 
     if (rval.isObject())
         *pmetadata = &rval.toObject();
 
     return true;
 }
 
--- a/js/src/config/check_spidermonkey_style.py
+++ b/js/src/config/check_spidermonkey_style.py
@@ -297,28 +297,50 @@ def check_style():
 
 
 def module_name(name):
     '''Strip the trailing .cpp, .h, inlines.h or -inl.h from a filename.'''
 
     return name.replace('inlines.h', '').replace('-inl.h', '').replace('.h', '').replace('.cpp', '')
 
 
+def is_module_header(enclosing_inclname, header_inclname):
+    '''Determine if an included name is the "module header", i.e. should be
+    first in the file.'''
+
+    module = module_name(enclosing_inclname)
+
+    # Normal case, e.g. module == "foo/Bar", header_inclname == "foo/Bar.h".
+    if module == module_name(header_inclname):
+        return True
+
+    # A public header, e.g. module == "foo/Bar", header_inclname == "js/Bar.h".
+    m = re.match(r'js\/(.*)\.h', header_inclname)
+    if m is not None and module.endswith('/' + m.group(1)):
+        return True
+
+    # A weird public header case.
+    if module == 'jsmemorymetrics' and header_inclname == 'js/MemoryMetrics.h':
+        return True
+
+    return False
+
+
 class Include(object):
     '''Important information for a single #include statement.'''
 
     def __init__(self, inclname, linenum, is_system):
         self.inclname = inclname
         self.linenum = linenum
         self.is_system = is_system
 
     def isLeaf(self):
         return True
 
-    def section(self, module):
+    def section(self, enclosing_inclname):
         '''Identify which section inclname belongs to.
 
         The section numbers are as follows.
           0. Module header (e.g. jsfoo.h or jsfooinlines.h within jsfoo.cpp)
           1. mozilla/Foo.h
           2. <foo.h> or <foo>
           3. jsfoo.h, prmjtime.h, etc
           4. foo/Bar.h
@@ -328,21 +350,19 @@ class Include(object):
         '''
 
         if self.is_system:
             return 2
 
         if not self.inclname.endswith('.h'):
             return 7
 
-        # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
-        # handling.
-        if module == module_name(self.inclname) or \
-           module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
-           module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h':
+        # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
+        # special handling.
+        if is_module_header(enclosing_inclname, self.inclname):
             return 0
 
         if '/' in self.inclname:
             if self.inclname.startswith('mozilla/'):
                 return 1
 
             if self.inclname.endswith('-inl.h'):
                 return 6
@@ -446,27 +466,25 @@ def do_file(filename, inclname, file_kin
                     error(filename, include.linenum,
                           'vanilla header includes an inline-header file ' + include.quote())
 
                 # Check a file doesn't #include itself.  (We do this here because the cycle
                 # detection below doesn't detect this case.)
                 if inclname == include.inclname:
                     error(filename, include.linenum, 'the file includes itself')
 
-    module = module_name(inclname)
-
     def check_includes_order(include1, include2):
         '''Check the ordering of two #include statements.'''
 
         if include1.inclname in oddly_ordered_inclnames or \
            include2.inclname in oddly_ordered_inclnames:
             return
 
-        section1 = include1.section(module)
-        section2 = include2.section(module)
+        section1 = include1.section(inclname)
+        section2 = include2.section(inclname)
         if (section1 > section2) or \
            ((section1 == section2) and (include1.inclname.lower() > include2.inclname.lower())):
             error(filename, str(include1.linenum) + ':' + str(include2.linenum),
                   include1.quote() + ' should be included after ' + include2.quote())
 
     # The #include statements in the files in assembler/ and yarr/ have all manner of implicit
     # ordering requirements.  Boo.  Ignore them.
     skip_order_checking = inclname.startswith(('assembler/', 'yarr/'))
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -127,18 +127,17 @@ MaybeCheckEvalFreeVariables(ExclusiveCon
 }
 
 inline bool
 CanLazilyParse(ExclusiveContext *cx, const CompileOptions &options)
 {
     return options.canLazilyParse &&
         options.compileAndGo &&
         options.sourcePolicy == CompileOptions::SAVE_SOURCE &&
-        cx->isJSContext() &&
-        !cx->asJSContext()->compartment()->debugMode();
+        !cx->compartment()->debugMode();
 }
 
 void
 frontend::MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options,
                                  const jschar *chars, size_t length)
 {
     JSSourceHandler listener = cx->runtime()->debugHooks.sourceHandler;
     void *listenerData = cx->runtime()->debugHooks.sourceHandlerData;
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1271,16 +1271,18 @@ class MOZ_STACK_CLASS ModuleCompiler
         va_list ap;
         va_start(ap, fmt);
         failfVA(pn, fmt, ap);
         va_end(ap);
         return false;
     }
 
     bool failName(ParseNode *pn, const char *fmt, PropertyName *name) {
+        // This function is invoked without the caller properly rooting its locals.
+        gc::AutoSuppressGC suppress(cx_);
         JSAutoByteString bytes;
         if (AtomToPrintableString(cx_, name, &bytes))
             failf(pn, fmt, bytes.ptr());
         return false;
     }
 
     static const unsigned SLOW_FUNCTION_THRESHOLD_MS = 250;
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -16,17 +16,16 @@
 #include <ctype.h>
 #include <stdarg.h>
 #include <string.h>
 #include <sys/stat.h>
 
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
-#include "jsclone.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
@@ -55,16 +54,17 @@
 #include "builtin/ParallelArray.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FullParseHandler.h"  // for JS_BufferIsCompileableUnit
 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
 #include "gc/Marking.h"
 #include "jit/AsmJSLink.h"
 #include "js/CharacterEncoding.h"
+#include "js/StructuredClone.h"
 #if ENABLE_INTL_API
 #include "unicode/uclean.h"
 #include "unicode/utypes.h"
 #endif // ENABLE_INTL_API
 #include "vm/DateObject.h"
 #include "vm/Debugger.h"
 #include "vm/ErrorObject.h"
 #include "vm/Interpreter.h"
@@ -123,27 +123,16 @@ JS::detail::CallMethodIfWrapped(JSContex
 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
 #endif
 
 #ifdef JS_USE_JSID_STRUCT_TYPES
 const jsid JSID_VOID  = { size_t(JSID_TYPE_VOID) };
 const jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
 #endif
 
-const jsval JSVAL_NULL  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL,      0));
-const jsval JSVAL_ZERO  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32,     0));
-const jsval JSVAL_ONE   = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32,     1));
-const jsval JSVAL_FALSE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN,   false));
-const jsval JSVAL_TRUE  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN,   true));
-const jsval JSVAL_VOID  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
-const HandleValue JS::NullHandleValue =
-    HandleValue::fromMarkedLocation(&JSVAL_NULL);
-const HandleValue JS::UndefinedHandleValue =
-    HandleValue::fromMarkedLocation(&JSVAL_VOID);
-
 const jsid voidIdValue = JSID_VOID;
 const jsid emptyIdValue = JSID_EMPTY;
 const HandleId JS::JSID_VOIDHANDLE = HandleId::fromMarkedLocation(&voidIdValue);
 const HandleId JS::JSID_EMPTYHANDLE = HandleId::fromMarkedLocation(&emptyIdValue);
 
 /* Make sure that jschar is two bytes unsigned integer */
 JS_STATIC_ASSERT((jschar)-1 > 0);
 JS_STATIC_ASSERT(sizeof(jschar) == 2);
@@ -180,28 +169,32 @@ JS_GetEmptyStringValue(JSContext *cx)
 
 JS_PUBLIC_API(JSString *)
 JS_GetEmptyString(JSRuntime *rt)
 {
     JS_ASSERT(rt->hasContexts());
     return rt->emptyString;
 }
 
-static void
+namespace js {
+
+void
 AssertHeapIsIdle(JSRuntime *rt)
 {
     JS_ASSERT(rt->heapState == js::Idle);
 }
 
-static void
+void
 AssertHeapIsIdle(JSContext *cx)
 {
     AssertHeapIsIdle(cx->runtime());
 }
 
+}
+
 static void
 AssertHeapIsIdleOrIterating(JSRuntime *rt)
 {
     JS_ASSERT(!rt->isHeapCollecting());
 }
 
 static void
 AssertHeapIsIdleOrIterating(JSContext *cx)
@@ -5927,230 +5920,16 @@ JS_ParseJSONWithReviver(JSContext *cx, c
     RootedValue reviver(cx, reviverArg), value(cx);
     if (!ParseJSONWithReviver(cx, StableCharPtr(chars, len), len, reviver, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
-JS_PUBLIC_API(bool)
-JS_ReadStructuredClone(JSContext *cx, uint64_t *buf, size_t nbytes,
-                       uint32_t version, jsval *vp,
-                       const JSStructuredCloneCallbacks *optionalCallbacks,
-                       void *closure)
-{
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-
-    if (version > JS_STRUCTURED_CLONE_VERSION) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
-        return false;
-    }
-    const JSStructuredCloneCallbacks *callbacks =
-        optionalCallbacks ?
-        optionalCallbacks :
-        cx->runtime()->structuredCloneCallbacks;
-    return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
-}
-
-JS_PUBLIC_API(bool)
-JS_WriteStructuredClone(JSContext *cx, jsval valueArg, uint64_t **bufp, size_t *nbytesp,
-                        const JSStructuredCloneCallbacks *optionalCallbacks,
-                        void *closure, jsval transferable)
-{
-    RootedValue value(cx, valueArg);
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, value);
-
-    const JSStructuredCloneCallbacks *callbacks =
-        optionalCallbacks ?
-        optionalCallbacks :
-        cx->runtime()->structuredCloneCallbacks;
-    return WriteStructuredClone(cx, value, (uint64_t **) bufp, nbytesp,
-                                callbacks, closure, transferable);
-}
-
-JS_PUBLIC_API(bool)
-JS_ClearStructuredClone(const uint64_t *data, size_t nbytes)
-{
-    return ClearStructuredClone(data, nbytes);
-}
-
-JS_PUBLIC_API(bool)
-JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
-                                   bool *hasTransferable)
-{
-    bool transferable;
-    if (!StructuredCloneHasTransferObjects(data, nbytes, &transferable))
-        return false;
-
-    *hasTransferable = transferable;
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_StructuredClone(JSContext *cx, jsval valueArg, jsval *vp,
-                   const JSStructuredCloneCallbacks *optionalCallbacks,
-                   void *closure)
-{
-    RootedValue value(cx, valueArg);
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, value);
-
-    const JSStructuredCloneCallbacks *callbacks =
-        optionalCallbacks ?
-        optionalCallbacks :
-        cx->runtime()->structuredCloneCallbacks;
-    JSAutoStructuredCloneBuffer buf;
-    return buf.write(cx, value, callbacks, closure) &&
-           buf.read(cx, vp, callbacks, closure);
-}
-
-void
-JSAutoStructuredCloneBuffer::clear()
-{
-    if (data_) {
-        ClearStructuredClone(data_, nbytes_);
-        data_ = NULL;
-        nbytes_ = 0;
-        version_ = 0;
-    }
-}
-
-void
-JSAutoStructuredCloneBuffer::adopt(uint64_t *data, size_t nbytes, uint32_t version)
-{
-    clear();
-    data_ = data;
-    nbytes_ = nbytes;
-    version_ = version;
-}
-
-bool
-JSAutoStructuredCloneBuffer::copy(const uint64_t *srcData, size_t nbytes, uint32_t version)
-{
-    // transferable objects cannot be copied
-    bool hasTransferable;
-    if (!StructuredCloneHasTransferObjects(data_, nbytes_, &hasTransferable) ||
-        hasTransferable)
-        return false;
-
-    uint64_t *newData = static_cast<uint64_t *>(js_malloc(nbytes));
-    if (!newData)
-        return false;
-
-    js_memcpy(newData, srcData, nbytes);
-
-    clear();
-    data_ = newData;
-    nbytes_ = nbytes;
-    version_ = version;
-    return true;
-}
-void
-JSAutoStructuredCloneBuffer::steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp)
-{
-    *datap = data_;
-    *nbytesp = nbytes_;
-    if (versionp)
-        *versionp = version_;
-
-    data_ = NULL;
-    nbytes_ = 0;
-    version_ = 0;
-}
-
-bool
-JSAutoStructuredCloneBuffer::read(JSContext *cx, jsval *vp,
-                                  const JSStructuredCloneCallbacks *optionalCallbacks,
-                                  void *closure)
-{
-    JS_ASSERT(cx);
-    JS_ASSERT(data_);
-    return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
-                                    optionalCallbacks, closure);
-}
-
-bool
-JSAutoStructuredCloneBuffer::write(JSContext *cx, jsval valueArg,
-                                   const JSStructuredCloneCallbacks *optionalCallbacks,
-                                   void *closure)
-{
-    jsval transferable = JSVAL_VOID;
-    return write(cx, valueArg, transferable, optionalCallbacks, closure);
-}
-
-bool
-JSAutoStructuredCloneBuffer::write(JSContext *cx, jsval valueArg,
-                                   jsval transferable,
-                                   const JSStructuredCloneCallbacks *optionalCallbacks,
-                                   void *closure)
-{
-    RootedValue value(cx, valueArg);
-    clear();
-    bool ok = !!JS_WriteStructuredClone(cx, value, &data_, &nbytes_,
-                                        optionalCallbacks, closure,
-                                        transferable);
-    if (!ok) {
-        data_ = NULL;
-        nbytes_ = 0;
-        version_ = JS_STRUCTURED_CLONE_VERSION;
-    }
-    return ok;
-}
-
-void
-JSAutoStructuredCloneBuffer::swap(JSAutoStructuredCloneBuffer &other)
-{
-    uint64_t *data = other.data_;
-    size_t nbytes = other.nbytes_;
-    uint32_t version = other.version_;
-
-    other.data_ = this->data_;
-    other.nbytes_ = this->nbytes_;
-    other.version_ = this->version_;
-
-    this->data_ = data;
-    this->nbytes_ = nbytes;
-    this->version_ = version;
-}
-
-JS_PUBLIC_API(void)
-JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
-{
-    rt->structuredCloneCallbacks = callbacks;
-}
-
-JS_PUBLIC_API(bool)
-JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2)
-{
-    return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
-}
-
-JS_PUBLIC_API(bool)
-JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
-{
-    return r->input().readBytes(p, len);
-}
-
-JS_PUBLIC_API(bool)
-JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data)
-{
-    return w->output().writePair(tag, data);
-}
-
-JS_PUBLIC_API(bool)
-JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
-{
-    return w->output().writeBytes(p, len);
-}
-
 /************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_ReportError(JSContext *cx, const char *format, ...)
 {
     va_list ap;
 
     AssertHeapIsIdle(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1142,64 +1142,18 @@ typedef JSObject *
 
 typedef void
 (* JSDestroyCompartmentCallback)(JSFreeOp *fop, JSCompartment *compartment);
 
 typedef void
 (* JSCompartmentNameCallback)(JSRuntime *rt, JSCompartment *compartment,
                               char *buf, size_t bufsize);
 
-/*
- * Read structured data from the reader r. This hook is used to read a value
- * previously serialized by a call to the WriteStructuredCloneOp hook.
- *
- * tag and data are the pair of uint32_t values from the header. The callback
- * may use the JS_Read* APIs to read any other relevant parts of the object
- * from the reader r. closure is any value passed to the JS_ReadStructuredClone
- * function. Return the new object on success, NULL on error/exception.
- */
-typedef JSObject *(*ReadStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r,
-                                           uint32_t tag, uint32_t data, void *closure);
-
-/*
- * Structured data serialization hook. The engine can write primitive values,
- * Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other
- * type of object requires application suppor