Merge m-c to fx-team
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 22 Sep 2013 09:16:05 -0700
changeset 148261 41047800c65ce71666af17a284b9fb62f9a60432
parent 148260 a9fd089aeefba233b34806a91eca9757d6c6b7dc (current diff)
parent 148216 f97307cb4c957a69271657a3c3c6ef3797814768 (diff)
child 148262 0cd9c60fd6749232a4e970c2e2cf3de979f1f307
push id25332
push usercbook@mozilla.com
push dateMon, 23 Sep 2013 11:07:56 +0000
treeherdermozilla-central@00bf153a66e4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team
build/virtualenv/packages.txt
build/virtualenv/populate_virtualenv.py
js/src/jsscript.cpp
js/src/jsscript.h
js/src/shell/js.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/src/Sandbox.cpp
modules/zlib/src/Makefile.in
modules/zlib/src/objs.mk
python/mozbuild/README.rst
python/mozbuild/dumbmake/README.rst
python/mozbuild/mozbuild/frontend/README.rst
--- a/Makefile.in
+++ b/Makefile.in
@@ -99,17 +99,17 @@ endif
 export:: install-dist-sdk
 
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
 endif
 
 default all::
-	$(call BUILDSTATUS,TIERS export compile libs tools)
+	$(call BUILDSTATUS,TIERS export $(if $(MOZ_PSEUDO_DERECURSE),compile )libs tools)
 
 include $(topsrcdir)/config/rules.mk
 
 distclean::
 	$(RM) $(DIST_GARBAGE)
 
 ifeq ($(OS_ARCH),WINNT)
 # we want to copy PDB files on Windows
@@ -174,17 +174,20 @@ ifdef MOZ_CRASHREPORTER
           zip -r9D "../$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip" . -i "*.sym" -i "*.txt"  -x "*test*" -x "*Test*"
 endif # MOZ_CRASHREPORTER
 
 uploadsymbols:
 ifdef MOZ_CRASHREPORTER
 	$(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(SYMBOL_INDEX_NAME) "$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip"
 endif
 
-# defined in package-name.mk
+# MOZ_SOURCE_STAMP is defined in package-name.mk with a deferred assignment.
+# exporting it makes make run its $(shell) command for each invoked submake,
+# so transform it to an immediate assignment.
+MOZ_SOURCE_STAMP := $(MOZ_SOURCE_STAMP)
 export MOZ_SOURCE_STAMP
 
 #XXX: this is a hack, since we don't want to clobber for MSVC
 # PGO support, but we can't do this test in client.mk
 ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
 # No point in clobbering if PGO has been explicitly disabled.
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 maybe_clobber_profiledbuild: clean
@@ -209,8 +212,15 @@ endif
 js/src/Makefile: subsrcdir := js/src
 
 ifdef ENABLE_TESTS
 # Incorporate static tier directories into tests. This should be incorporated
 # into moz.build files someday.
 check::
 	$(call SUBMAKE,$@,js/src)
 endif
+
+ifdef MOZ_PSEUDO_DERECURSE
+# Interdependencies for parallel export.
+js/xpconnect/src/export: config/makefiles/precompile/export
+accessible/src/xpcom/export: config/makefiles/precompile/export
+js/src/export: mfbt/export
+endif
--- a/accessible/src/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/DocAccessibleWrap.cpp
@@ -1,246 +1,84 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/dom/TabChild.h"
+#include "DocAccessibleWrap.h"
 
 #include "Compatibility.h"
-#include "DocAccessibleWrap.h"
-#include "ISimpleDOMDocument_i.c"
-#include "nsCoreUtils.h"
-#include "nsIAccessibilityService.h"
 #include "nsWinUtils.h"
+#include "mozilla/dom/TabChild.h"
 #include "Role.h"
 #include "RootAccessible.h"
+#include "sdnDocAccessible.h"
 #include "Statistics.h"
 
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeNode.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsISelectionController.h"
-#include "nsIServiceManager.h"
-#include "nsIURI.h"
-#include "nsViewManager.h"
-#include "nsIWebNavigation.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
-/* For documentation of the accessibility architecture, 
- * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
- */
-
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
 DocAccessibleWrap::
   DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
                     nsIPresShell* aPresShell) :
   DocAccessible(aDocument, aRootContent, aPresShell), mHWND(nullptr)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
-//-----------------------------------------------------
-// IUnknown interface methods - see iunknown.h for documentation
-//-----------------------------------------------------
-STDMETHODIMP_(ULONG)
-DocAccessibleWrap::AddRef()
-{
-  return nsAccessNode::AddRef();
-}
-
-STDMETHODIMP_(ULONG) DocAccessibleWrap::Release()
-{
-  return nsAccessNode::Release();
-}
-
-// Microsoft COM QueryInterface
-STDMETHODIMP
-DocAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
-{
-  if (!ppv)
-    return E_INVALIDARG;
-
-  *ppv = nullptr;
-
-  if (IID_ISimpleDOMDocument != iid)
-    return HyperTextAccessibleWrap::QueryInterface(iid, ppv);
-
-  statistics::ISimpleDOMUsed();
-  *ppv = static_cast<ISimpleDOMDocument*>(this);
-  (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
-  return S_OK;
-}
+IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWrap)
+  if (aIID == IID_ISimpleDOMDocument) {
+    statistics::ISimpleDOMUsed();
+    *aInstancePtr = static_cast<ISimpleDOMDocument*>(new sdnDocAccessible(this));
+    static_cast<IUnknown*>(*aInstancePtr)->AddRef();
+    return S_OK;
+  }
+IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(HyperTextAccessibleWrap)
 
 STDMETHODIMP
-DocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)
-{
-  A11Y_TRYBLOCK_BEGIN
-
-  if (!aURL)
-    return E_INVALIDARG;
-
-  *aURL = nullptr;
-
-  nsAutoString URL;
-  nsresult rv = GetURL(URL);
-  if (NS_FAILED(rv))
-    return E_FAIL;
-
-  if (URL.IsEmpty())
-    return S_FALSE;
-
-  *aURL = ::SysAllocStringLen(URL.get(), URL.Length());
-  return *aURL ? S_OK : E_OUTOFMEMORY;
-
-  A11Y_TRYBLOCK_END
-}
-
-STDMETHODIMP
-DocAccessibleWrap::get_title( /* [out] */ BSTR __RPC_FAR *aTitle)
-{
-  A11Y_TRYBLOCK_BEGIN
-
-  if (!aTitle)
-    return E_INVALIDARG;
-
-  *aTitle = nullptr;
-
-  nsAutoString title;
-  nsresult rv = GetTitle(title);
-  if (NS_FAILED(rv))
-    return E_FAIL;
-
-  *aTitle = ::SysAllocStringLen(title.get(), title.Length());
-  return *aTitle ? S_OK : E_OUTOFMEMORY;
-
-  A11Y_TRYBLOCK_END
-}
-
-STDMETHODIMP
-DocAccessibleWrap::get_mimeType(/* [out] */ BSTR __RPC_FAR *aMimeType)
+DocAccessibleWrap::get_accValue(VARIANT aVarChild, BSTR __RPC_FAR* aValue)
 {
   A11Y_TRYBLOCK_BEGIN
 
-  if (!aMimeType)
-    return E_INVALIDARG;
-
-  *aMimeType = nullptr;
-
-  nsAutoString mimeType;
-  nsresult rv = GetMimeType(mimeType);
-  if (NS_FAILED(rv))
-    return E_FAIL;
-
-  if (mimeType.IsEmpty())
-    return S_FALSE;
-
-  *aMimeType = ::SysAllocStringLen(mimeType.get(), mimeType.Length());
-  return *aMimeType ? S_OK : E_OUTOFMEMORY;
-
-  A11Y_TRYBLOCK_END
-}
-
-STDMETHODIMP
-DocAccessibleWrap::get_docType(/* [out] */ BSTR __RPC_FAR *aDocType)
-{
-  A11Y_TRYBLOCK_BEGIN
-
-  if (!aDocType)
+  if (!aValue)
     return E_INVALIDARG;
-
-  *aDocType = nullptr;
-
-  nsAutoString docType;
-  nsresult rv = GetDocType(docType);
-  if (NS_FAILED(rv))
-    return E_FAIL;
-
-  if (docType.IsEmpty())
-    return S_FALSE;
-
-  *aDocType = ::SysAllocStringLen(docType.get(), docType.Length());
-  return *aDocType ? S_OK : E_OUTOFMEMORY;
-
-  A11Y_TRYBLOCK_END
-}
-
-STDMETHODIMP
-DocAccessibleWrap::get_nameSpaceURIForID(/* [in] */  short aNameSpaceID,
-  /* [out] */ BSTR __RPC_FAR *aNameSpaceURI)
-{
-  A11Y_TRYBLOCK_BEGIN
-
-  if (!aNameSpaceURI)
-    return E_INVALIDARG;
-
-  *aNameSpaceURI = nullptr;
-
-  if (aNameSpaceID < 0)
-    return E_INVALIDARG;  // -1 is kNameSpaceID_Unknown
-
-  nsAutoString nameSpaceURI;
-  nsresult rv = GetNameSpaceURIForID(aNameSpaceID, nameSpaceURI);
-  if (NS_FAILED(rv))
-    return E_FAIL;
-
-  if (nameSpaceURI.IsEmpty())
-    return S_FALSE;
-
-  *aNameSpaceURI = ::SysAllocStringLen(nameSpaceURI.get(),
-                                       nameSpaceURI.Length());
-
-  return *aNameSpaceURI ? S_OK : E_OUTOFMEMORY;
-
-  A11Y_TRYBLOCK_END
-}
-
-STDMETHODIMP
-DocAccessibleWrap::put_alternateViewMediaTypes( /* [in] */ BSTR __RPC_FAR *aCommaSeparatedMediaTypes)
-{
-  A11Y_TRYBLOCK_BEGIN
-
-  if (!aCommaSeparatedMediaTypes)
-    return E_INVALIDARG;
-
-  *aCommaSeparatedMediaTypes = nullptr;
-  return E_NOTIMPL;
-
-  A11Y_TRYBLOCK_END
-}
-
-STDMETHODIMP
-DocAccessibleWrap::get_accValue(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR *pszValue)
-{
-  if (!pszValue)
-    return E_INVALIDARG;
+  *aValue = nullptr;
 
   // For backwards-compat, we still support old MSAA hack to provide URL in accValue
-  *pszValue = nullptr;
   // Check for real value first
-  HRESULT hr = AccessibleWrap::get_accValue(varChild, pszValue);
-  if (FAILED(hr) || *pszValue || varChild.lVal != CHILDID_SELF)
+  HRESULT hr = AccessibleWrap::get_accValue(aVarChild, aValue);
+  if (FAILED(hr) || *aValue || aVarChild.lVal != CHILDID_SELF)
     return hr;
+
   // If document is being used to create a widget, don't use the URL hack
   roles::Role role = Role();
   if (role != roles::DOCUMENT && role != roles::APPLICATION && 
       role != roles::DIALOG && role != roles::ALERT) 
     return hr;
 
-  return get_URL(pszValue);
+  nsAutoString URL;
+  nsresult rv = GetURL(URL);
+  if (URL.IsEmpty())
+    return S_FALSE;
+
+  *aValue = ::SysAllocStringLen(URL.get(), URL.Length());
+  return *aValue ? S_OK : E_OUTOFMEMORY;
+
+  A11Y_TRYBLOCK_END
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode
 
 void
 DocAccessibleWrap::Shutdown()
 {
--- a/accessible/src/windows/msaa/DocAccessibleWrap.h
+++ b/accessible/src/windows/msaa/DocAccessibleWrap.h
@@ -1,62 +1,32 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/* For documentation of the accessibility architecture, 
- * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
- */
-
 #ifndef mozilla_a11y_DocAccessibleWrap_h__
 #define mozilla_a11y_DocAccessibleWrap_h__
 
-#include "ISimpleDOMDocument.h"
-
 #include "DocAccessible.h"
-#include "nsIDocShellTreeItem.h"
 
 namespace mozilla {
 namespace a11y {
 
-class DocAccessibleWrap : public DocAccessible,
-                          public ISimpleDOMDocument
+class DocAccessibleWrap : public DocAccessible
 {
 public:
   DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
                     nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
-    // IUnknown
-    STDMETHODIMP_(ULONG) AddRef();
-    STDMETHODIMP_(ULONG) Release();
-    STDMETHODIMP      QueryInterface(REFIID, void**);
+  DECL_IUNKNOWN_INHERITED
 
-    // ISimpleDOMDocument
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_URL( 
-        /* [out] */ BSTR __RPC_FAR *url);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_title( 
-        /* [out] */ BSTR __RPC_FAR *title);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_mimeType( 
-        /* [out] */ BSTR __RPC_FAR *mimeType);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_docType( 
-        /* [out] */ BSTR __RPC_FAR *docType);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_nameSpaceURIForID( 
-        /* [in] */ short nameSpaceID,
-        /* [out] */ BSTR __RPC_FAR *nameSpaceURI);
-
-    virtual /* [id] */ HRESULT STDMETHODCALLTYPE put_alternateViewMediaTypes( 
-        /* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes);
-
-    // IAccessible
+  // IAccessible
 
     // Override get_accValue to provide URL when no other value is available
     virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue( 
         /* [optional][in] */ VARIANT varChild,
         /* [retval][out] */ BSTR __RPC_FAR *pszValue);
 
   // nsAccessNode
   virtual void Shutdown();
--- a/accessible/src/windows/msaa/TextLeafAccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/TextLeafAccessibleWrap.cpp
@@ -10,12 +10,12 @@
 #include "Statistics.h"
 
 using namespace mozilla::a11y;
 
 IMPL_IUNKNOWN_QUERY_HEAD(TextLeafAccessibleWrap)
   if (aIID == IID_ISimpleDOMText) {
     statistics::ISimpleDOMUsed();
     *aInstancePtr = static_cast<ISimpleDOMText*>(new sdnTextAccessible(this));
-    AddRef();
+    static_cast<IUnknown*>(*aInstancePtr)->AddRef();
     return S_OK;
   }
 IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(AccessibleWrap)
--- a/accessible/src/windows/sdn/moz.build
+++ b/accessible/src/windows/sdn/moz.build
@@ -3,16 +3,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MODULE = 'accessibility'
 
 CPP_SOURCES += [
     'sdnAccessible.cpp',
+    'sdnDocAccessible.cpp',
     'sdnTextAccessible.cpp',
 ]
 
 LIBXUL_LIBRARY = True
 
 LOCAL_INCLUDES += [
     '../../base',
     '../../generic',
copy from accessible/src/windows/msaa/DocAccessibleWrap.cpp
copy to accessible/src/windows/sdn/sdnDocAccessible.cpp
--- a/accessible/src/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/src/windows/sdn/sdnDocAccessible.cpp
@@ -1,319 +1,167 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/dom/TabChild.h"
+#include "sdnDocAccessible.h"
 
-#include "Compatibility.h"
-#include "DocAccessibleWrap.h"
 #include "ISimpleDOMDocument_i.c"
-#include "nsCoreUtils.h"
-#include "nsIAccessibilityService.h"
-#include "nsWinUtils.h"
-#include "Role.h"
-#include "RootAccessible.h"
-#include "Statistics.h"
-
-#include "nsIDocShell.h"
-#include "nsIDocShellTreeNode.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsISelectionController.h"
-#include "nsIServiceManager.h"
-#include "nsIURI.h"
-#include "nsViewManager.h"
-#include "nsIWebNavigation.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
-/* For documentation of the accessibility architecture, 
- * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
- */
-
 ////////////////////////////////////////////////////////////////////////////////
-// DocAccessibleWrap
+// sdnDocAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
-DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell) :
-  DocAccessible(aDocument, aRootContent, aPresShell), mHWND(nullptr)
-{
-}
-
-DocAccessibleWrap::~DocAccessibleWrap()
-{
-}
-
-//-----------------------------------------------------
-// IUnknown interface methods - see iunknown.h for documentation
-//-----------------------------------------------------
-STDMETHODIMP_(ULONG)
-DocAccessibleWrap::AddRef()
-{
-  return nsAccessNode::AddRef();
-}
-
-STDMETHODIMP_(ULONG) DocAccessibleWrap::Release()
-{
-  return nsAccessNode::Release();
-}
-
-// Microsoft COM QueryInterface
-STDMETHODIMP
-DocAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
-{
-  if (!ppv)
-    return E_INVALIDARG;
-
-  *ppv = nullptr;
-
-  if (IID_ISimpleDOMDocument != iid)
-    return HyperTextAccessibleWrap::QueryInterface(iid, ppv);
-
-  statistics::ISimpleDOMUsed();
-  *ppv = static_cast<ISimpleDOMDocument*>(this);
-  (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
-  return S_OK;
-}
+IMPL_IUNKNOWN_QUERY_HEAD(sdnDocAccessible)
+  IMPL_IUNKNOWN_QUERY_IFACE(ISimpleDOMDocument)
+IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAccessible)
 
 STDMETHODIMP
-DocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)
+sdnDocAccessible::get_URL(BSTR __RPC_FAR* aURL)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!aURL)
     return E_INVALIDARG;
-
   *aURL = nullptr;
 
+  if (mAccessible->IsDefunct())
+    return CO_E_OBJNOTCONNECTED;
+
   nsAutoString URL;
-  nsresult rv = GetURL(URL);
+  nsresult rv = mAccessible->GetURL(URL);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   if (URL.IsEmpty())
     return S_FALSE;
 
   *aURL = ::SysAllocStringLen(URL.get(), URL.Length());
   return *aURL ? S_OK : E_OUTOFMEMORY;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
-DocAccessibleWrap::get_title( /* [out] */ BSTR __RPC_FAR *aTitle)
+sdnDocAccessible::get_title(BSTR __RPC_FAR* aTitle)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!aTitle)
     return E_INVALIDARG;
-
   *aTitle = nullptr;
 
+  if (mAccessible->IsDefunct())
+    return CO_E_OBJNOTCONNECTED;
+
   nsAutoString title;
-  nsresult rv = GetTitle(title);
+  nsresult rv = mAccessible->GetTitle(title);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   *aTitle = ::SysAllocStringLen(title.get(), title.Length());
   return *aTitle ? S_OK : E_OUTOFMEMORY;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
-DocAccessibleWrap::get_mimeType(/* [out] */ BSTR __RPC_FAR *aMimeType)
+sdnDocAccessible::get_mimeType(BSTR __RPC_FAR* aMimeType)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!aMimeType)
     return E_INVALIDARG;
-
   *aMimeType = nullptr;
 
+  if (mAccessible->IsDefunct())
+    return CO_E_OBJNOTCONNECTED;
+
   nsAutoString mimeType;
-  nsresult rv = GetMimeType(mimeType);
+  nsresult rv = mAccessible->GetMimeType(mimeType);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   if (mimeType.IsEmpty())
     return S_FALSE;
 
   *aMimeType = ::SysAllocStringLen(mimeType.get(), mimeType.Length());
   return *aMimeType ? S_OK : E_OUTOFMEMORY;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
-DocAccessibleWrap::get_docType(/* [out] */ BSTR __RPC_FAR *aDocType)
+sdnDocAccessible::get_docType(BSTR __RPC_FAR* aDocType)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!aDocType)
     return E_INVALIDARG;
-
   *aDocType = nullptr;
 
+  if (mAccessible->IsDefunct())
+    return CO_E_OBJNOTCONNECTED;
+
   nsAutoString docType;
-  nsresult rv = GetDocType(docType);
+  nsresult rv = mAccessible->GetDocType(docType);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   if (docType.IsEmpty())
     return S_FALSE;
 
   *aDocType = ::SysAllocStringLen(docType.get(), docType.Length());
   return *aDocType ? S_OK : E_OUTOFMEMORY;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
-DocAccessibleWrap::get_nameSpaceURIForID(/* [in] */  short aNameSpaceID,
-  /* [out] */ BSTR __RPC_FAR *aNameSpaceURI)
+sdnDocAccessible::get_nameSpaceURIForID(short aNameSpaceID,
+                                        BSTR __RPC_FAR* aNameSpaceURI)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!aNameSpaceURI)
     return E_INVALIDARG;
+  *aNameSpaceURI = nullptr;
 
-  *aNameSpaceURI = nullptr;
+  if (mAccessible->IsDefunct())
+    return CO_E_OBJNOTCONNECTED;
 
   if (aNameSpaceID < 0)
     return E_INVALIDARG;  // -1 is kNameSpaceID_Unknown
 
   nsAutoString nameSpaceURI;
-  nsresult rv = GetNameSpaceURIForID(aNameSpaceID, nameSpaceURI);
+  nsresult rv = mAccessible->GetNameSpaceURIForID(aNameSpaceID, nameSpaceURI);
   if (NS_FAILED(rv))
     return E_FAIL;
 
   if (nameSpaceURI.IsEmpty())
     return S_FALSE;
 
   *aNameSpaceURI = ::SysAllocStringLen(nameSpaceURI.get(),
                                        nameSpaceURI.Length());
 
   return *aNameSpaceURI ? S_OK : E_OUTOFMEMORY;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
-DocAccessibleWrap::put_alternateViewMediaTypes( /* [in] */ BSTR __RPC_FAR *aCommaSeparatedMediaTypes)
+sdnDocAccessible::put_alternateViewMediaTypes(BSTR __RPC_FAR* aCommaSeparatedMediaTypes)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!aCommaSeparatedMediaTypes)
     return E_INVALIDARG;
+  *aCommaSeparatedMediaTypes = nullptr;
 
-  *aCommaSeparatedMediaTypes = nullptr;
-  return E_NOTIMPL;
+  return mAccessible->IsDefunct() ? CO_E_OBJNOTCONNECTED : E_NOTIMPL;
 
   A11Y_TRYBLOCK_END
 }
-
-STDMETHODIMP
-DocAccessibleWrap::get_accValue(
-      /* [optional][in] */ VARIANT varChild,
-      /* [retval][out] */ BSTR __RPC_FAR *pszValue)
-{
-  if (!pszValue)
-    return E_INVALIDARG;
-
-  // For backwards-compat, we still support old MSAA hack to provide URL in accValue
-  *pszValue = nullptr;
-  // Check for real value first
-  HRESULT hr = AccessibleWrap::get_accValue(varChild, pszValue);
-  if (FAILED(hr) || *pszValue || varChild.lVal != CHILDID_SELF)
-    return hr;
-  // If document is being used to create a widget, don't use the URL hack
-  roles::Role role = Role();
-  if (role != roles::DOCUMENT && role != roles::APPLICATION && 
-      role != roles::DIALOG && role != roles::ALERT) 
-    return hr;
-
-  return get_URL(pszValue);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsAccessNode
-
-void
-DocAccessibleWrap::Shutdown()
-{
-  // Do window emulation specific shutdown if emulation was started.
-  if (nsWinUtils::IsWindowEmulationStarted()) {
-    // Destroy window created for root document.
-    if (mDocFlags & eTabDocument) {
-      nsWinUtils::sHWNDCache->Remove(mHWND);
-      ::DestroyWindow(static_cast<HWND>(mHWND));
-    }
-
-    mHWND = nullptr;
-  }
-
-  DocAccessible::Shutdown();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DocAccessible public
-
-void*
-DocAccessibleWrap::GetNativeWindow() const
-{
-  return mHWND ? mHWND : DocAccessible::GetNativeWindow();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DocAccessible protected
-
-void
-DocAccessibleWrap::DoInitialUpdate()
-{
-  DocAccessible::DoInitialUpdate();
-
-  if (nsWinUtils::IsWindowEmulationStarted()) {
-    // Create window for tab document.
-    if (mDocFlags & eTabDocument) {
-      mozilla::dom::TabChild* tabChild =
-        mozilla::dom::TabChild::GetFrom(mDocumentNode->GetShell());
-
-      a11y::RootAccessible* rootDocument = RootAccessible();
-
-      mozilla::WindowsHandle nativeData = 0;
-      if (tabChild)
-        tabChild->SendGetWidgetNativeData(&nativeData);
-      else
-        nativeData = reinterpret_cast<mozilla::WindowsHandle>(
-          rootDocument->GetNativeWindow());
-
-      bool isActive = true;
-      int32_t x = CW_USEDEFAULT, y = CW_USEDEFAULT, width = 0, height = 0;
-      if (Compatibility::IsDolphin()) {
-        GetBounds(&x, &y, &width, &height);
-        int32_t rootX = 0, rootY = 0, rootWidth = 0, rootHeight = 0;
-        rootDocument->GetBounds(&rootX, &rootY, &rootWidth, &rootHeight);
-        x = rootX - x;
-        y -= rootY;
-
-        nsCOMPtr<nsISupports> container = mDocumentNode->GetContainer();
-        nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
-        docShell->GetIsActive(&isActive);
-      }
-
-      HWND parentWnd = reinterpret_cast<HWND>(nativeData);
-      mHWND = nsWinUtils::CreateNativeWindow(kClassNameTabContent, parentWnd,
-                                             x, y, width, height, isActive);
-
-      nsWinUtils::sHWNDCache->Put(mHWND, this);
-
-    } else {
-      DocAccessible* parentDocument = ParentDocument();
-      if (parentDocument)
-        mHWND = parentDocument->GetNativeWindow();
-    }
-  }
-}
copy from accessible/src/windows/msaa/DocAccessibleWrap.h
copy to accessible/src/windows/sdn/sdnDocAccessible.h
--- a/accessible/src/windows/msaa/DocAccessibleWrap.h
+++ b/accessible/src/windows/sdn/sdnDocAccessible.h
@@ -1,78 +1,53 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/* For documentation of the accessibility architecture, 
- * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
- */
-
-#ifndef mozilla_a11y_DocAccessibleWrap_h__
-#define mozilla_a11y_DocAccessibleWrap_h__
+#ifndef mozilla_a11y_sdnDocAccessible_h_
+#define mozilla_a11y_sdnDocAccessible_h_
 
 #include "ISimpleDOMDocument.h"
+#include "IUnknownImpl.h"
 
-#include "DocAccessible.h"
-#include "nsIDocShellTreeItem.h"
+#include "DocAccessibleWrap.h"
 
 namespace mozilla {
 namespace a11y {
 
-class DocAccessibleWrap : public DocAccessible,
-                          public ISimpleDOMDocument
+class sdnDocAccessible MOZ_FINAL : public ISimpleDOMDocument
 {
 public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell);
-  virtual ~DocAccessibleWrap();
+  sdnDocAccessible(DocAccessibleWrap* aAccessible) : mAccessible(aAccessible) {};
+  ~sdnDocAccessible() { };
+
+  DECL_IUNKNOWN
 
-    // IUnknown
-    STDMETHODIMP_(ULONG) AddRef();
-    STDMETHODIMP_(ULONG) Release();
-    STDMETHODIMP      QueryInterface(REFIID, void**);
+  // ISimpleDOMDocument
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_URL(
+    /* [out] */ BSTR __RPC_FAR *url);
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_title(
+    /* [out] */ BSTR __RPC_FAR *title);
 
-    // ISimpleDOMDocument
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_URL( 
-        /* [out] */ BSTR __RPC_FAR *url);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_title( 
-        /* [out] */ BSTR __RPC_FAR *title);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_mimeType( 
-        /* [out] */ BSTR __RPC_FAR *mimeType);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_docType( 
-        /* [out] */ BSTR __RPC_FAR *docType);
-    
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_nameSpaceURIForID( 
-        /* [in] */ short nameSpaceID,
-        /* [out] */ BSTR __RPC_FAR *nameSpaceURI);
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_mimeType(
+    /* [out] */ BSTR __RPC_FAR *mimeType);
+
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_docType(
+    /* [out] */ BSTR __RPC_FAR *docType);
 
-    virtual /* [id] */ HRESULT STDMETHODCALLTYPE put_alternateViewMediaTypes( 
-        /* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes);
-
-    // IAccessible
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_nameSpaceURIForID(
+    /* [in] */ short nameSpaceID,
+    /* [out] */ BSTR __RPC_FAR *nameSpaceURI);
 
-    // Override get_accValue to provide URL when no other value is available
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue( 
-        /* [optional][in] */ VARIANT varChild,
-        /* [retval][out] */ BSTR __RPC_FAR *pszValue);
-
-  // nsAccessNode
-  virtual void Shutdown();
-
-  // DocAccessible
-  virtual void* GetNativeWindow() const;
+  virtual /* [id] */ HRESULT STDMETHODCALLTYPE put_alternateViewMediaTypes(
+    /* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes);
 
 protected:
-  // DocAccessible
-  virtual void DoInitialUpdate();
-
-protected:
-  void* mHWND;
+  nsRefPtr<DocAccessibleWrap> mAccessible;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -20,16 +20,18 @@ pref("browser.cache.disk.capacity", 5500
 pref("browser.cache.disk.parent_directory", "/cache");
 #endif
 pref("browser.cache.disk.smart_size.enabled", false);
 pref("browser.cache.disk.smart_size.first_run", false);
 
 pref("browser.cache.memory.enable", true);
 pref("browser.cache.memory.capacity", 1024); // kilobytes
 
+pref("browser.cache.memory_limit", 2048); // 2 MB
+
 /* image cache prefs */
 pref("image.cache.size", 1048576); // bytes
 pref("image.high_quality_downscaling.enabled", false);
 pref("canvas.image.cache.limit", 10485760); // 10 MB
 
 /* offline cache prefs */
 pref("browser.offline-apps.notify", false);
 pref("browser.cache.offline.enable", true);
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "2815b6670938908c94b8e927401fa8895c12d794", 
+    "revision": "c8947b9d62eeff57eee9e4ba1677006d837efb83", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -249,16 +249,17 @@
 @BINPATH@/components/layout_xul.xpt
 @BINPATH@/components/locale.xpt
 @BINPATH@/components/lwbrk.xpt
 @BINPATH@/components/migration.xpt
 @BINPATH@/components/mimetype.xpt
 @BINPATH@/components/mozfind.xpt
 @BINPATH@/components/necko_about.xpt
 @BINPATH@/components/necko_cache.xpt
+@BINPATH@/components/necko_cache2.xpt
 @BINPATH@/components/necko_cookie.xpt
 @BINPATH@/components/necko_dns.xpt
 @BINPATH@/components/necko_file.xpt
 @BINPATH@/components/necko_ftp.xpt
 @BINPATH@/components/necko_http.xpt
 @BINPATH@/components/necko_res.xpt
 @BINPATH@/components/necko_socket.xpt
 @BINPATH@/components/necko_strconv.xpt
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,14 +1,16 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1379114379000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1379696114000">
   <emItems>
-      <emItem  blockID="i350" id="sqlmoz@facebook.com">
+      <emItem  blockID="i454" id="sqlmoz@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
+                                <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
                   </emItem>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i402" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -175,16 +177,20 @@
       <emItem  blockID="i19" id="{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}">
                         <versionRange  minVersion="1.1b1" maxVersion="1.1b1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i438" id="{02edb56b-9b33-435b-b7df-b2843273a694}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i450" id="{dff137ae-1ffd-11e3-8277-b8ac6f996f26}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i111" os="WINNT" id="{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}">
                         <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i136" id="Adobe@flash.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
@@ -334,18 +340,18 @@
       <emItem  blockID="i44" id="sigma@labs.mozilla">
                         </emItem>
       <emItem  blockID="i246" id="support@vide1flash2.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i48" id="admin@youtubespeedup.com">
                         </emItem>
-      <emItem  blockID="i104" id="yasd@youasdr3.com">
-                        <versionRange  minVersion="0" maxVersion="*">
+      <emItem  blockID="i218" id="ffxtlbr@claro.com">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i79" id="GifBlock@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i69" id="{977f3b97-5461-4346-92c8-a14c749b77c9}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
@@ -386,16 +392,20 @@
       <emItem  blockID="i16" id="{27182e60-b5f3-411c-b545-b44205977502}">
                         <versionRange  minVersion="1.0" maxVersion="1.0">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i92" id="play5@vide04flash.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i453" id="/^brasilescape.*\@facebook\.com$/">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i286" id="{58bd07eb-0ee0-4df0-8121-dc9b693373df}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
@@ -432,18 +442,18 @@
       <emItem  blockID="i448" id="{0134af61-7a0c-4649-aeca-90d776060cb3}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i83" id="flash@adobee.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i218" id="ffxtlbr@claro.com">
-                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+      <emItem  blockID="i104" id="yasd@youasdr3.com">
+                        <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i10" id="{8CE11043-9A15-4207-A565-0C94C42D590D}">
                         </emItem>
       <emItem  blockID="i76" id="crossriderapp3924@crossrider.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
@@ -466,16 +476,20 @@
       <emItem  blockID="i6" id="{3f963a5b-e555-4543-90e2-c3908898db71}">
                         <versionRange  minVersion=" " maxVersion="8.5">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i56" id="flash@adobe.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i451" id="{e44a1809-4d10-4ab8-b343-3326b64c7cdd}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i216" id="fdm_ffext@freedownloadmanager.org">
                         <versionRange  minVersion="1.0" maxVersion="1.3.1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                                 <versionRange  minVersion="1.5.7.5" maxVersion="1.5.7.5" severity="1">
                     </versionRange>
@@ -559,30 +573,30 @@
       <emItem  blockID="i304" id="{f0e59437-6148-4a98-b0a6-60d557ef57f4}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i86" id="{45147e67-4020-47e2-8f7a-55464fb535aa}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i431" id="chinaescapeone@facebook.com">
-                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+      <emItem  blockID="i318" id="ffxtlbr@incredibar.com">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i312" id="extension21804@extension21804.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i324" id="/^((34qEOefiyYtRJT@IM5Munavn\.com)|(Mro5Fm1Qgrmq7B@ByrE69VQfZvZdeg\.com)|(KtoY3KGxrCe5ie@yITPUzbBtsHWeCdPmGe\.com)|(9NgIdLK5Dq4ZMwmRo6zk@FNt2GCCLGyUuOD\.com)|(NNux7bWWW@RBWyXdnl6VGls3WAwi\.com)|(E3wI2n@PEHTuuNVu\.com)|(2d3VuWrG6JHBXbQdbr@3BmSnQL\.com))$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i318" id="ffxtlbr@incredibar.com">
-                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+      <emItem  blockID="i431" id="chinaescapeone@facebook.com">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i108" id="{28bfb930-7620-11e1-b0c4-0800200c9a66}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i262" id="{167d9323-f7cc-48f5-948a-6f012831a69f}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
@@ -680,16 +694,20 @@
       <emItem  blockID="i441" id="{49c53dce-afa0-49a1-a08b-2eb8e8444128}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i282" id="{33e0daa6-3af3-d8b5-6752-10e949c61516}">
                         <versionRange  minVersion="0" maxVersion="1.1.999" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i452" id="{77beece6-3997-403a-92fa-0055bfcf88e5}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i45" id="{22119944-ED35-4ab1-910B-E619EA06A115}">
                         <versionRange  minVersion="0.1" maxVersion="7.6.1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="8.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i82" id="{8f42fb8b-b6f6-45de-81c0-d6d39f54f971}">
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -1,12 +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/. */
 
+const Cu = Components.utils;
+Cu.import("resource://gre/modules/LoadContextInfo.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
 //******** define a js object to implement nsITreeView
 function pageInfoTreeView(treeid, copycol)
 {
   // copycol is the index number for the column that we want to add to
   // the copy-n-paste buffer when the user hits accel-c
   this.treeid = treeid;
   this.copycol = copycol;
   this.rows = 0;
@@ -211,23 +215,25 @@ var gStrings = { };
 var gBundle;
 
 const PERMISSION_CONTRACTID     = "@mozilla.org/permissionmanager;1";
 const PREFERENCES_CONTRACTID    = "@mozilla.org/preferences-service;1";
 const ATOM_CONTRACTID           = "@mozilla.org/atom-service;1";
 
 // a number of services I'll need later
 // the cache services
-const nsICacheService = Components.interfaces.nsICacheService;
-const ACCESS_READ     = Components.interfaces.nsICache.ACCESS_READ;
-const cacheService = Components.classes["@mozilla.org/network/cache-service;1"].getService(nsICacheService);
-var httpCacheSession = cacheService.createSession("HTTP", 0, true);
-httpCacheSession.doomEntriesIfExpired = false;
-var ftpCacheSession = cacheService.createSession("FTP", 0, true);
-ftpCacheSession.doomEntriesIfExpired = false;
+const nsICacheStorageService = Components.interfaces.nsICacheStorageService;
+const nsICacheStorage = Components.interfaces.nsICacheStorage;
+const cacheService = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"].getService(nsICacheStorageService);
+
+var loadContextInfo = LoadContextInfo.fromLoadContext(
+  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+        .getInterface(Components.interfaces.nsIWebNavigation)
+        .QueryInterface(Components.interfaces.nsILoadContext), false);
+var diskStorage = cacheService.diskCacheStorage(loadContextInfo, false);
 
 const nsICookiePermission  = Components.interfaces.nsICookiePermission;
 const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
 
 const nsICertificateDialogs = Components.interfaces.nsICertificateDialogs;
 const CERTIFICATEDIALOGS_CONTRACTID = "@mozilla.org/nsCertificateDialogs;1"
 
 // clipboard helper
@@ -458,29 +464,26 @@ function toggleGroupbox(id)
       elt.flexWhenOpened = elt.flex;
       elt.flex = 0;
     }
   }
 }
 
 function openCacheEntry(key, cb)
 {
-  var tries = 0;
   var checkCacheListener = {
-    onCacheEntryAvailable: function(entry, access, status) {
-      if (entry || tries == 1) {
-        cb(entry);
-      }
-      else {
-        tries++;
-        ftpCacheSession.asyncOpenCacheEntry(key, ACCESS_READ, this, true);
-      }
-    }
+    onCacheEntryCheck: function(entry, appCache) {
+      return nsICacheEntryOpenCallback.ENTRY_VALID;
+    },
+    onCacheEntryAvailable: function(entry, isNew, appCache, status) {
+      cb(entry);
+    },
+    get mainThreadOnly() { return true; }
   };
-  httpCacheSession.asyncOpenCacheEntry(key, ACCESS_READ, checkCacheListener, true);
+  diskStorage.asyncOpenURI(Services.io.newURI(key, null, null), "", nsICacheStorage.OPEN_READONLY, checkCacheListener);
 }
 
 function makeGeneralTab()
 {
   var title = (gDocument.title) ? gBundle.getFormattedString("pageTitle", [gDocument.title]) : gBundle.getString("noPageTitle");
   document.getElementById("titletext").value = title;
 
   var url = gDocument.location.toString();
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -108,22 +108,22 @@ Sanitizer.prototype = {
   // pref to determine a range
   ignoreTimespan : true,
   range : null,
 
   items: {
     cache: {
       clear: function ()
       {
-        var cacheService = Cc["@mozilla.org/network/cache-service;1"].
-                          getService(Ci.nsICacheService);
+        var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].
+                    getService(Ci.nsICacheStorageService);
         try {
           // Cache doesn't consult timespan, nor does it have the
           // facility for timespan-based eviction.  Wipe it.
-          cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+          cache.clear();
         } catch(er) {}
 
         var imageCache = Cc["@mozilla.org/image/tools;1"].
                          getService(Ci.imgITools).getImgCacheForDocument(null);
         try {
           imageCache.clearCache(false); // true=chrome, false=content
         } catch(er) {}
       },
--- a/browser/base/content/test/general/browser_bookmark_titles.js
+++ b/browser/base/content/test/general/browser_bookmark_titles.js
@@ -54,17 +54,17 @@ function generatorTest() {
     let proxy = Services.prefs.getIntPref('network.proxy.type');
     Services.prefs.setIntPref('network.proxy.type', 0);
     registerCleanupFunction(function () {
         BrowserOffline.toggleOfflineStatus();
         Services.prefs.setIntPref('network.proxy.type', proxy);
     });
 
     // LOAD_FLAGS_BYPASS_CACHE isn't good enough. So clear the cache.
-    Services.cache.evictEntries(Services.cache.STORE_ANYWHERE);
+    Services.cache2.clear();
 
     let [uri, title] = tests[0];
     content.location = uri;
     yield undefined;
     // The offline mode test is only good if the page failed to load.
     is(content.document.documentURI.substring(0, 14), 'about:neterror',
         "Offline mode successfully simulated network outage.");
     checkBookmark(uri, title);
--- a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
+++ b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
@@ -1,39 +1,48 @@
 /* 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/. */
+
+let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", null);
+
 function test() {
   // initialization
   waitForExplicitFinish();
   let windowsToClose = [];
   let testURI = "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517.html";
   let fileName;
   let MockFilePicker = SpecialPowers.MockFilePicker;
-  let cache = Cc["@mozilla.org/network/cache-service;1"]
-              .getService(Ci.nsICacheService);
+  let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+              .getService(Ci.nsICacheStorageService);
 
-  function checkDiskCacheFor(filename) {
-    let visitor = {
-      visitDevice: function(deviceID, deviceInfo) {
-        if (deviceID == "disk")
-          info(deviceID + " device contains " + deviceInfo.entryCount + " entries");
-        return deviceID == "disk";
+  function checkDiskCacheFor(filename, goon) {
+    Visitor.prototype = {
+      onCacheStorageInfo: function(num, consumption)
+      {
+        info("disk storage contains " + num + " entries");
       },
-
-      visitEntry: function(deviceID, entryInfo) {
-        info(entryInfo.key);
-        is(entryInfo.key.contains(filename), false, "web content present in disk cache");
+      onCacheEntryInfo: function(entry)
+      {
+        info(entry.key);
+        is(entry.key.contains(filename), false, "web content present in disk cache");
+      },
+      onCacheEntryVisitCompleted: function()
+      {
+        goon();
       }
     };
-    cache.visitEntries(visitor);
+    function Visitor() {}
+
+    var storage = cache.diskCacheStorage(LoadContextInfo.default, false);
+    storage.asyncVisitStorage(new Visitor(), true /* Do walk entries */);
   }
 
   function contextMenuOpened(aWindow, event) {
-    cache.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+    cache.clear();
 
     event.currentTarget.removeEventListener("popupshown", contextMenuOpened);
 
     // Create the folder the image will be saved into.
     var destDir = createTemporarySaveDirectory();
     var destFile = destDir.clone();
 
     MockFilePicker.displayDirectory = destDir;
@@ -60,18 +69,17 @@ function test() {
     event.target.hidePopup();
   }
 
   function onTransferComplete(downloadSuccess) {
     ok(downloadSuccess, "Image file should have been downloaded successfully");
 
     // Give the request a chance to finish and create a cache entry
     executeSoon(function() {
-      checkDiskCacheFor(fileName);
-      finish();
+      checkDiskCacheFor(fileName, finish);
     });
   }
 
   function createTemporarySaveDirectory() {
     var saveDir = Cc["@mozilla.org/file/directory_service;1"]
                     .getService(Ci.nsIProperties)
                     .get("TmpD", Ci.nsIFile);
     saveDir.append("testsavedir");
--- a/browser/base/content/test/social/browser_social_errorPage.js
+++ b/browser/base/content/test/social/browser_social_errorPage.js
@@ -15,17 +15,17 @@ let origProxyType = Services.prefs.getIn
 
 function goOffline() {
   // Simulate a network outage with offline mode. (Localhost is still
   // accessible in offline mode, so disable the test proxy as well.)
   if (!Services.io.offline)
     BrowserOffline.toggleOfflineStatus();
   Services.prefs.setIntPref('network.proxy.type', 0);
   // LOAD_FLAGS_BYPASS_CACHE isn't good enough. So clear the cache.
-  Services.cache.evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
+  Services.cache2.clear();
 }
 
 function goOnline(callback) {
   Services.prefs.setIntPref('network.proxy.type', origProxyType);
   if (Services.io.offline)
     BrowserOffline.toggleOfflineStatus();
   if (callback)
     callback();
--- a/browser/components/places/tests/unit/head_bookmarks.js
+++ b/browser/components/places/tests/unit/head_bookmarks.js
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/LoadContextInfo.jsm");
 
 // Import common head.
 let (commonFile = do_get_file("../../../../../toolkit/components/places/tests/head_common.js", false)) {
   let uri = Services.io.newFileURI(commonFile);
   Services.scriptloader.loadSubScript(uri.spec, this);
 }
 
 // Put any other stuff relative to this test folder below.
--- a/browser/components/places/tests/unit/test_clearHistory_shutdown.js
+++ b/browser/components/places/tests/unit/test_clearHistory_shutdown.js
@@ -129,23 +129,25 @@ function run_test_continue()
 }
 
 function getDistinctNotifications() {
   let ar = EXPECTED_NOTIFICATIONS.concat(UNEXPECTED_NOTIFICATIONS);
   return [ar[i] for (i in ar) if (ar.slice(0, i).indexOf(ar[i]) == -1)];
 }
 
 function storeCache(aURL, aContent) {
-  let cache = Cc["@mozilla.org/network/cache-service;1"].
-              getService(Ci.nsICacheService);
-  let session = cache.createSession("FTP", Ci.nsICache.STORE_ANYWHERE,
-                                    Ci.nsICache.STREAM_BASED);
+  let cache = Services.cache2;
+  let storage = cache.diskCacheStorage(LoadContextInfo.default, false);
 
   var storeCacheListener = {
-    onCacheEntryAvailable: function (entry, access, status) {
+    onCacheEntryCheck: function (entry, appcache) {
+      return nsICacheEntryOpenCallback.ENTRY_VALID;
+    },
+
+    onCacheEntryAvailable: function (entry, isnew, appcache, status) {
       do_check_eq(status, Cr.NS_OK);
 
       entry.setMetaDataElement("servertype", "0");
       var os = entry.openOutputStream(0);
 
       var written = os.write(aContent, aContent.length);
       if (written != aContent.length) {
         do_throw("os.write has not written all data!\n" +
@@ -153,31 +155,29 @@ function storeCache(aURL, aContent) {
                  "  Actual: " + aContent.length + "\n");
       }
       os.close();
       entry.close();
       do_execute_soon(run_test_continue);
     }
   };
 
-  session.asyncOpenCacheEntry(aURL,
-                              Ci.nsICache.ACCESS_READ_WRITE,
-                              storeCacheListener);
+  storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "",
+                       Ci.nsICacheStorage.OPEN_NORMALLY,
+                       storeCacheListener);
 }
 
 
 function checkCache(aURL) {
-  let cache = Cc["@mozilla.org/network/cache-service;1"].
-              getService(Ci.nsICacheService);
-  let session = cache.createSession("FTP", Ci.nsICache.STORE_ANYWHERE,
-                                    Ci.nsICache.STREAM_BASED);
+  let cache = Services.cache2;
+  let storage = cache.diskCacheStorage(LoadContextInfo.default, false);
 
   var checkCacheListener = {
-    onCacheEntryAvailable: function (entry, access, status) {
+    onCacheEntryAvailable: function (entry, isnew, appcache, status) {
       do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
       do_test_finished();
     }
   };
 
-  session.asyncOpenCacheEntry(aURL,
-                              Ci.nsICache.ACCESS_READ,
-                              checkCacheListener);
+  storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "",
+                       Ci.nsICacheStorage.OPEN_READONLY,
+                       checkCacheListener);
 }
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -2,16 +2,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/.
 
 // Load DownloadUtils module for convertByteUnits
 Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
 Components.utils.import("resource://gre/modules/ctypes.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
 
 var gAdvancedPane = {
   _inited: false,
 
   /**
    * Brings the appropriate tab to the front and initializes various bits of UI.
    */
   init: function ()
@@ -72,18 +73,18 @@ var gAdvancedPane = {
 #ifdef MOZ_CRASHREPORTER
     this.initSubmitCrashes();
 #endif
     this.initTelemetry();
 #ifdef MOZ_SERVICES_HEALTHREPORT
     this.initSubmitHealthReport();
 #endif
 
-    this.updateActualCacheSize("disk");
-    this.updateActualCacheSize("offline");
+    this.updateActualCacheSize();
+    this.updateActualAppCacheSize();
 
     // Notify observers that the UI is now ready
     Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
   },
 
   /**
    * Stores the identity of the current tab in preferences so that the selected
    * tab can be persisted between openings of the preferences window.
@@ -291,32 +292,74 @@ var gAdvancedPane = {
    * Displays a dialog in which proxy settings may be changed.
    */
   showConnections: function ()
   {
     document.documentElement.openSubDialog("chrome://browser/content/preferences/connection.xul",
                                            "", null);
   },
 
-  // Retrieves the amount of space currently used by disk or offline cache
-  updateActualCacheSize: function (device)
+  // Retrieves the amount of space currently used by disk cache
+  updateActualCacheSize: function ()
+  {
+    var sum = 0;
+    function updateUI(consumption) {
+      var actualSizeLabel = document.getElementById("actualDiskCacheSize");
+      var sizeStrings = DownloadUtils.convertByteUnits(consumption);
+      var prefStrBundle = document.getElementById("bundlePreferences");
+      var sizeStr = prefStrBundle.getFormattedString("actualDiskCacheSize", sizeStrings);
+      actualSizeLabel.value = sizeStr;
+    }
+
+    Visitor.prototype = {
+      expected: 0,
+      sum: 0,
+      QueryInterface: function listener_qi(iid) {
+        if (iid.equals(Ci.nsISupports) ||
+            iid.equals(Ci.nsICacheStorageVisitor)) {
+          return this;
+        }
+        throw Components.results.NS_ERROR_NO_INTERFACE;
+      },
+      onCacheStorageInfo: function(num, consumption)
+      {
+        this.sum += consumption;
+        if (!--this.expected)
+          updateUI(this.sum);
+      }
+    };
+    function Visitor(callbacksExpected) {
+      this.expected = callbacksExpected;
+    }
+
+    var cacheService =
+      Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
+                .getService(Components.interfaces.nsICacheStorageService);
+    // non-anonymous
+    var storage1 = cacheService.diskCacheStorage(LoadContextInfo.default, false);
+    // anonymous
+    var storage2 = cacheService.diskCacheStorage(LoadContextInfo.anonymous, false);
+
+    // expect 2 callbacks
+    var visitor = new Visitor(2);
+    storage1.asyncVisitStorage(visitor, false /* Do not walk entries */);
+    storage2.asyncVisitStorage(visitor, false /* Do not walk entries */);
+  },
+
+  // Retrieves the amount of space currently used by offline cache
+  updateActualAppCacheSize: function ()
   {
     var visitor = {
       visitDevice: function (deviceID, deviceInfo)
       {
-        if (deviceID == device) {
-          var actualSizeLabel = document.getElementById(device == "disk" ?
-                                                        "actualDiskCacheSize" :
-                                                        "actualAppCacheSize");
+        if (deviceID == "offline") {
+          var actualSizeLabel = document.getElementById("actualAppCacheSize");
           var sizeStrings = DownloadUtils.convertByteUnits(deviceInfo.totalSize);
           var prefStrBundle = document.getElementById("bundlePreferences");
-          var sizeStr = prefStrBundle.getFormattedString(device == "disk" ?
-                                                         "actualDiskCacheSize" :
-                                                         "actualAppCacheSize",
-                                                         sizeStrings);
+          var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
           actualSizeLabel.value = sizeStr;
         }
         // Do not enumerate entries
         return false;
       },
 
       visitEntry: function (deviceID, entryInfo)
       {
@@ -367,33 +410,33 @@ var gAdvancedPane = {
     return isNaN(intValue) ? 0 : intValue * 1024;
   },
 
   /**
    * Clears the cache.
    */
   clearCache: function ()
   {
-    var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
-                                 .getService(Components.interfaces.nsICacheService);
+    var cache = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
+                                 .getService(Components.interfaces.nsICacheStorageService);
     try {
-      cacheService.evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
+      cache.clear();
     } catch(ex) {}
-    this.updateActualCacheSize("disk");
+    this.updateActualCacheSize();
   },
 
   /**
    * Clears the application cache.
    */
   clearOfflineAppCache: function ()
   {
     Components.utils.import("resource:///modules/offlineAppCache.jsm");
     OfflineAppCacheHelper.clear();
 
-    this.updateActualCacheSize("offline");
+    this.updateActualAppCacheSize();
     this.updateOfflineApps();
   },
 
   readOfflineNotify: function()
   {
     var pref = document.getElementById("browser.offline-apps.notify");
     var button = document.getElementById("offlineNotifyExceptions");
     button.disabled = !pref.value;
@@ -528,17 +571,17 @@ var gAdvancedPane = {
                        .getService(Components.interfaces.nsIPermissionManager);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
     list.removeChild(item);
     gAdvancedPane.offlineAppSelected();
-    this.updateActualCacheSize("offline");
+    this.updateActualAppCacheSize();
   },
 
   // UPDATE TAB
 
   /*
    * Preferences:
    *
    * app.update.enabled
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Load DownloadUtils module for convertByteUnits
 Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
+Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
 
 var gAdvancedPane = {
   _inited: false,
 
   /**
    * Brings the appropriate tab to the front and initializes various bits of UI.
    */
   init: function ()
@@ -62,18 +63,18 @@ var gAdvancedPane = {
     this.updateOfflineApps();
 #ifdef MOZ_CRASHREPORTER
     this.initSubmitCrashes();
 #endif
     this.initTelemetry();
 #ifdef MOZ_SERVICES_HEALTHREPORT
     this.initSubmitHealthReport();
 #endif
-    this.updateActualCacheSize("disk");
-    this.updateActualCacheSize("offline");
+    this.updateActualCacheSize();
+    this.updateActualAppCacheSize();
   },
 
   /**
    * Stores the identity of the current tab in preferences so that the selected
    * tab can be persisted between openings of the preferences window.
    */
   tabSelectionChanged: function ()
   {
@@ -273,32 +274,77 @@ var gAdvancedPane = {
   showConnections: function ()
   {
     openDialog("chrome://browser/content/preferences/connection.xul",
                "mozilla:connectionmanager",
                "model=yes",
                null);
   },
 
-  // Retrieves the amount of space currently used by disk or offline cache
-  updateActualCacheSize: function (device)
+  // Retrieves the amount of space currently used by disk cache
+  updateActualCacheSize: function ()
+  {
+    var sum = 0;
+    function updateUI(consumption) {
+      var actualSizeLabel = document.getElementById("actualDiskCacheSize");
+      var sizeStrings = DownloadUtils.convertByteUnits(consumption);
+      var prefStrBundle = document.getElementById("bundlePreferences");
+      var sizeStr = prefStrBundle.getFormattedString("actualDiskCacheSize", sizeStrings);
+      actualSizeLabel.value = sizeStr;
+    }
+
+    Visitor.prototype = {
+      expected: 0,
+      sum: 0,
+      QueryInterface: function listener_qi(iid) {
+        if (iid.equals(Ci.nsISupports) ||
+            iid.equals(Ci.nsICacheStorageVisitor)) {
+          return this;
+        }
+        throw Components.results.NS_ERROR_NO_INTERFACE;
+      },
+      onCacheStorageInfo: function(num, consumption)
+      {
+        this.sum += consumption;
+        if (!--this.expected)
+          updateUI(this.sum);
+      },
+      onCacheEntryInfo: function(entry)
+      {
+      }
+    };
+    function Visitor(callbacksExpected) {
+      this.expected = callbacksExpected;
+    }
+
+    var cacheService =
+      Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
+                .getService(Components.interfaces.nsICacheStorageService);
+    // non-anonymous
+    var storage1 = cacheService.diskCacheStorage(LoadContextInfo.default, false);
+    // anonymous
+    var storage2 = cacheService.diskCacheStorage(LoadContextInfo.anonymous, false);
+
+    // expect 2 callbacks
+    var visitor = new Visitor(2);
+    storage1.asyncVisitStorage(visitor, false /* Do not walk entries */);
+    storage2.asyncVisitStorage(visitor, false /* Do not walk entries */);
+  },
+
+  // Retrieves the amount of space currently used by offline cache
+  updateActualAppCacheSize: function ()
   {
     var visitor = {
       visitDevice: function (deviceID, deviceInfo)
       {
-        if (deviceID == device) {
-          var actualSizeLabel = document.getElementById(device == "disk" ?
-                                                        "actualDiskCacheSize" :
-                                                        "actualAppCacheSize");
+        if (deviceID == "offline") {
+          var actualSizeLabel = document.getElementById("actualAppCacheSize");
           var sizeStrings = DownloadUtils.convertByteUnits(deviceInfo.totalSize);
           var prefStrBundle = document.getElementById("bundlePreferences");
-          var sizeStr = prefStrBundle.getFormattedString(device == "disk" ?
-                                                         "actualDiskCacheSize" :
-                                                         "actualAppCacheSize",
-                                                         sizeStrings);
+          var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
           actualSizeLabel.value = sizeStr;
         }
         // Do not enumerate entries
         return false;
       },
 
       visitEntry: function (deviceID, entryInfo)
       {
@@ -354,28 +400,28 @@ var gAdvancedPane = {
    */
   clearCache: function ()
   {
     var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
                                  .getService(Components.interfaces.nsICacheService);
     try {
       cacheService.evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
     } catch(ex) {}
-    this.updateActualCacheSize("disk");
+    this.updateActualCacheSize();
   },
 
   /**
    * Clears the application cache.
    */
   clearOfflineAppCache: function ()
   {
     Components.utils.import("resource:///modules/offlineAppCache.jsm");
     OfflineAppCacheHelper.clear();
 
-    this.updateActualCacheSize("offline");
+    this.updateActualAppCacheSize();
     this.updateOfflineApps();
   },
 
   readOfflineNotify: function()
   {
     var pref = document.getElementById("browser.offline-apps.notify");
     var button = document.getElementById("offlineNotifyExceptions");
     button.disabled = !pref.value;
@@ -511,17 +557,17 @@ var gAdvancedPane = {
                        .getService(Components.interfaces.nsIPermissionManager);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
     pm.remove(host, "offline-app",
               Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
     list.removeChild(item);
     gAdvancedPane.offlineAppSelected();
-    this.updateActualCacheSize("offline");
+    this.updateActualAppCacheSize();
   },
 
   // UPDATE TAB
 
   /*
    * Preferences:
    *
    * app.update.enabled
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js
@@ -1,34 +1,37 @@
 /* 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/. */
 
 // Check about:cache after private browsing
 // This test covers MozTrap test 6047
 // bug 880621
 
+let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", null);
+
 let tmp = {};
 
 Cc["@mozilla.org/moz/jssubscript-loader;1"]
   .getService(Ci.mozIJSSubScriptLoader)
   .loadSubScript("chrome://browser/content/sanitize.js", tmp);
 
 let Sanitizer = tmp.Sanitizer;
 
 function test() {
 
   waitForExplicitFinish();
 
   sanitizeCache();
 
-  let nrEntriesR1 = get_device_entry_count("disk");
-  is (nrEntriesR1, 0, "Disk cache reports 0KB and has no entries");
+  let nrEntriesR1 = getStorageEntryCount("regular", function(nrEntriesR1) {
+    is(nrEntriesR1, 0, "Disk cache reports 0KB and has no entries");
 
-  get_cache_for_private_window();
+    get_cache_for_private_window();
+  });
 }
 
 function cleanup() {
   let prefs = Services.prefs.getBranch("privacy.cpd.");
 
   prefs.clearUserPref("history");
   prefs.clearUserPref("downloads");
   prefs.clearUserPref("cache");
@@ -56,39 +59,52 @@ function sanitizeCache() {
   prefs.setBoolPref("passwords", false);
   prefs.setBoolPref("sessions", false);
   prefs.setBoolPref("siteSettings", false);
 
   s.sanitize();
 }
 
 function get_cache_service() {
-  return Components.classes["@mozilla.org/network/cache-service;1"]
-                   .getService(Components.interfaces.nsICacheService);
+  return Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
+                   .getService(Components.interfaces.nsICacheStorageService);
 }
 
-function get_device_entry_count(device) {
+function getStorageEntryCount(device, goon) {
   var cs = get_cache_service();
-  var entry_count = -1;
+
+  var storage;
+  switch (device) {
+  case "private":
+    storage = cs.diskCacheStorage(LoadContextInfo.private, false);
+    break;
+  case "regular":
+    storage = cs.diskCacheStorage(LoadContextInfo.default, false);
+    break;
+  default:
+    throw "Unknown device " + device + " at getStorageEntryCount";
+  }
 
   var visitor = {
-    visitDevice: function (deviceID, deviceInfo) {
-      if (device == deviceID) {
-        entry_count = deviceInfo.entryCount;
-      }
-      return false;
+    entryCount: 0,
+    onCacheStorageInfo: function (aEntryCount, aConsumption) {
     },
-    visitEntry: function (deviceID, entryInfo) {
-      do_throw("nsICacheVisitor.visitEntry should not be called " +
-               "when checking the availability of devices");
+    onCacheEntryInfo: function(entry)
+    {
+      info(device + ":" + entry.key + "\n");
+      if (entry.key.match(/^http:\/\/example.org\//))
+        ++this.entryCount;
+    },
+    onCacheEntryVisitCompleted: function()
+    {
+      goon(this.entryCount);
     }
   };
 
-  cs.visitEntries(visitor);
-  return entry_count;
+  storage.asyncVisitStorage(visitor, true);
 }
 
 function get_cache_for_private_window () {
   let win = OpenBrowserWindow({private: true});
   win.addEventListener("load", function () {
     win.removeEventListener("load", arguments.callee, false);
 
     executeSoon(function() {
@@ -99,23 +115,25 @@ function get_cache_for_private_window ()
       win.gBrowser.selectedTab = tab;
       let newTabBrowser = win.gBrowser.getBrowserForTab(tab);
 
       newTabBrowser.addEventListener("load", function eventHandler() {
         newTabBrowser.removeEventListener("load", eventHandler, true);
 
         executeSoon(function() {
 
-          let nrEntriesP = get_device_entry_count("memory");
-          is (nrEntriesP, 1, "Memory cache reports some entries from example.org domain");
+          getStorageEntryCount("private", function(nrEntriesP) {
+            ok(nrEntriesP >= 1, "Memory cache reports some entries from example.org domain");
+
+            getStorageEntryCount("regular", function(nrEntriesR2) {
+              is(nrEntriesR2, 0, "Disk cache reports 0KB and has no entries");
 
-          let nrEntriesR2 = get_device_entry_count("disk");
-          is (nrEntriesR2, 0, "Disk cache reports 0KB and has no entries");
+              cleanup();
 
-          cleanup();
-
-          win.close();
-          finish();
+              win.close();
+              finish();
+            });
+          });
         });
       }, true);
     });
   }, false);
 }
--- a/browser/devtools/debugger/DebuggerProcess.jsm
+++ b/browser/devtools/debugger/DebuggerProcess.jsm
@@ -45,79 +45,95 @@ BrowserDebuggerProcess.init = function(a
   return new BrowserDebuggerProcess(aOnClose, aOnRun);
 };
 
 BrowserDebuggerProcess.prototype = {
   /**
    * Initializes the debugger server.
    */
   _initServer: function() {
+    dumpn("Initializing the chrome debugger server.");
+
     if (!this.loader) {
       // Create a separate loader instance, so that we can be sure to receive a
       // separate instance of the DebuggingServer from the rest of the devtools.
       // This allows us to safely use the tools against even the actors and
       // DebuggingServer itself.
       this.loader = new DevToolsLoader();
       this.loader.main("devtools/server/main");
       this.debuggerServer = this.loader.DebuggerServer;
+      dumpn("Created a separate loader instance for the DebuggerServer.");
     }
 
     if (!this.debuggerServer.initialized) {
       this.debuggerServer.init();
       this.debuggerServer.addBrowserActors();
+      dumpn("initialized and added the browser actors for the DebuggerServer.");
     }
+
     this.debuggerServer.openListener(Prefs.chromeDebuggingPort);
+
+    dumpn("Finished initializing the chrome debugger server.");
+    dumpn("Started listening on port: " + Prefs.chromeDebuggingPort);
   },
 
   /**
    * Initializes a profile for the remote debugger process.
    */
   _initProfile: function() {
+    dumpn("Initializing the chrome debugger user profile.");
+
     let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
       .createInstance(Ci.nsIToolkitProfileService);
 
     let profileName;
     try {
       // Attempt to get the required chrome debugging profile name string.
       profileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME;
+      dumpn("Using chrome debugger profile name: " + profileName);
     } catch (e) {
       // Requested profile string could not be retrieved.
       profileName = CHROME_DEBUGGER_PROFILE_NAME;
       let msg = "Querying the current profile failed. " + e.name + ": " + e.message;
       dumpn(msg);
       Cu.reportError(msg);
     }
 
     let profileObject;
     try {
       // Attempt to get the required chrome debugging profile toolkit object.
       profileObject = profileService.getProfileByName(profileName);
+      dumpn("Using chrome debugger profile object: " + profileObject);
 
       // The profile exists but the corresponding folder may have been deleted.
       var enumerator = Services.dirsvc.get("ProfD", Ci.nsIFile).parent.directoryEntries;
       while (enumerator.hasMoreElements()) {
         let profileDir = enumerator.getNext().QueryInterface(Ci.nsIFile);
         if (profileDir.leafName.contains(profileName)) {
           // Requested profile was found and the folder exists.
           this._dbgProfile = profileObject;
           return;
         }
       }
       // Requested profile was found but the folder was deleted. Cleanup needed.
       profileObject.remove(true);
+      dumpn("The already existing chrome debugger profile was invalid.");
     } catch (e) {
       // Requested profile object was not found.
       let msg = "Creating a profile failed. " + e.name + ": " + e.message;
       dumpn(msg);
       Cu.reportError(msg);
     }
 
     // Create a new chrome debugging profile.
     this._dbgProfile = profileService.createProfile(null, null, profileName);
     profileService.flush();
+
+    dumpn("Finished creating the chrome debugger user profile.");
+    dumpn("Flushed profile service with: " + profileName);
   },
 
   /**
    * Creates and initializes the profile & process for the remote debugger.
    */
   _create: function() {
     dumpn("Initializing chrome debugging process.");
     let process = this._dbgProcess = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
@@ -134,23 +150,23 @@ BrowserDebuggerProcess.prototype = {
       this._runCallback.call({}, this);
     }
   },
 
   /**
    * Closes the remote debugger, removing the profile and killing the process.
    */
   close: function() {
+    dumpn("Cleaning up the chrome debugging process.");
+
     if (this._dbgProcess.isRunning) {
-      dumpn("Killing chrome debugging process...");
       this._dbgProcess.kill();
     }
 
     this._telemetry.toolClosed("jsbrowserdebugger");
-
     this.debuggerServer.destroy();
 
     dumpn("Chrome debugger is now closed...");
     if (typeof this._closeCallback == "function") {
       this._closeCallback.call({}, this);
     }
   }
 };
@@ -169,8 +185,12 @@ let Prefs = new ViewHelpers.Prefs("devto
  */
 function dumpn(str) {
   if (wantLogging) {
     dump("DBG-FRONTEND: " + str + "\n");
   }
 }
 
 let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
+
+Services.prefs.addObserver("devtools.debugger.log", {
+  observe: (...args) => wantLogging = Services.prefs.getBoolPref(args.pop())
+}, false);
--- a/browser/devtools/debugger/test/browser_dbg_chrome-create.js
+++ b/browser/devtools/debugger/test/browser_dbg_chrome-create.js
@@ -1,15 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that a chrome debugger can be created in a new process.
  */
 
+// Enable logging for this test, bug 860349.
+Services.prefs.setBoolPref("devtools.debugger.log", true);
+
 let gProcess;
 
 function test() {
   // Windows XP test slaves are terribly slow at this test.
   requestLongerTimeout(4);
 
   initChromeDebugger(aOnClose).then(aProcess => {
     gProcess = aProcess;
--- a/browser/devtools/styleeditor/test/browser_styleeditor_private_perwindowpb.js
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_private_perwindowpb.js
@@ -8,26 +8,26 @@
 let gUI;
 
 function test() {
   waitForExplicitFinish();
   let windowsToClose = [];
   let testURI = 'http://' + TEST_HOST + '/browser/browser/devtools/styleeditor/test/test_private.html';
 
   function checkCache() {
-    checkDiskCacheFor(TEST_HOST);
-
-    gUI = null;
-    finish();
+    checkDiskCacheFor(TEST_HOST, function() {
+      gUI = null;
+      finish();
+    });
   }
 
   function doTest(aWindow) {
     aWindow.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
       aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
-      cache.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+      cache.clear();
       openStyleEditorInWindow(aWindow, function(panel) {
         gUI = panel.UI;
         gUI.on("editor-added", onEditorAdded);
       });
     }, true);
 
     aWindow.gBrowser.selectedBrowser.loadURI(testURI);
   }
--- a/browser/devtools/styleeditor/test/head.js
+++ b/browser/devtools/styleeditor/test/head.js
@@ -4,22 +4,24 @@
 const TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/styleeditor/test/";
 const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/styleeditor/test/";
 const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleeditor/test/";
 const TEST_HOST = 'mochi.test:8888';
 
 let tempScope = {};
 Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
 let TargetFactory = tempScope.devtools.TargetFactory;
-Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
+Cu.import("resource://gre/modules/LoadContextInfo.jsm", tempScope);
+let LoadContextInfo = tempScope.LoadContextInfo;
+Cu.import("resource://gre/modules/devtools/Console.jsm", tempScope);
 let console = tempScope.console;
 
 let gPanelWindow;
-let cache = Cc["@mozilla.org/network/cache-service;1"]
-              .getService(Ci.nsICacheService);
+let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+              .getService(Ci.nsICacheStorageService);
 
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
 function cleanup()
 {
@@ -79,30 +81,35 @@ function addTabAndLaunchStyleEditorChrom
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
     gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
     launchStyleEditorChrome(aCallback, aSheet, aLine, aCol);
   }, true);
 }
 */
 
-function checkDiskCacheFor(host)
+function checkDiskCacheFor(host, done)
 {
   let foundPrivateData = false;
 
-  let visitor = {
-    visitDevice: function(deviceID, deviceInfo) {
-      if (deviceID == "disk")
-        info("disk device contains " + deviceInfo.entryCount + " entries");
-      return deviceID == "disk";
+  Visitor.prototype = {
+    onCacheStorageInfo: function(num, consumption)
+    {
+      info("disk storage contains " + num + " entries");
     },
-
-    visitEntry: function(deviceID, entryInfo) {
-      info(entryInfo.key);
-      foundPrivateData |= entryInfo.key.contains(host);
+    onCacheEntryInfo: function(entry)
+    {
+      info(entry.key);
+      foundPrivateData |= entry.key.contains(host);
+    },
+    onCacheEntryVisitCompleted: function()
+    {
       is(foundPrivateData, false, "web content present in disk cache");
+      done();
     }
   };
-  cache.visitEntries(visitor);
-  is(foundPrivateData, false, "private data present in disk cache");
+  function Visitor() {}
+
+  var storage = cache.diskCacheStorage(LoadContextInfo.default, false);
+  storage.asyncVisitStorage(new Visitor(), true /* Do walk entries */);
 }
 
 registerCleanupFunction(cleanup);
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -258,16 +258,17 @@
 @BINPATH@/components/layout_xul.xpt
 @BINPATH@/components/locale.xpt
 @BINPATH@/components/lwbrk.xpt
 @BINPATH@/browser/components/migration.xpt
 @BINPATH@/components/mimetype.xpt
 @BINPATH@/components/mozfind.xpt
 @BINPATH@/components/necko_about.xpt
 @BINPATH@/components/necko_cache.xpt
+@BINPATH@/components/necko_cache2.xpt
 @BINPATH@/components/necko_cookie.xpt
 @BINPATH@/components/necko_dns.xpt
 @BINPATH@/components/necko_file.xpt
 @BINPATH@/components/necko_ftp.xpt
 @BINPATH@/components/necko_http.xpt
 @BINPATH@/components/necko_res.xpt
 @BINPATH@/components/necko_socket.xpt
 @BINPATH@/components/necko_strconv.xpt
@@ -792,8 +793,12 @@ bin/libfreebl_32int64_3.so
 @BINPATH@/metro/chrome/@AB_CD@@JAREXT@
 @BINPATH@/metro/chrome/@AB_CD@.manifest
 @BINPATH@/metro/chrome/pdfjs.manifest
 @BINPATH@/metro/chrome/pdfjs/*
 @BINPATH@/metro/components
 @BINPATH@/metro/defaults
 @BINPATH@/metro/modules
 #endif
+
+#ifdef MOZ_ASAN
+@BINPATH@/llvm-symbolizer
+#endif
--- a/browser/metro/base/content/sanitize.js
+++ b/browser/metro/base/content/sanitize.js
@@ -1,13 +1,15 @@
 // -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 /* 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/. */
 
+XPCOMUtils.defineLazyModuleGetter(this, "LoadContextInfo",
+                                  "resource://gre/modules/LoadContextInfo.jsm");
 function Sanitizer() {}
 
 Sanitizer.prototype = {
   // warning to the caller: this one may raise an exception (e.g. bug #265028)
   clearItem: function (aItemName)
   {
     if (this.items[aItemName].canClear)
       this.items[aItemName].clear();
@@ -80,19 +82,19 @@ Sanitizer.prototype = {
       {
         return (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED);
       }
     },
 
     cache: {
       clear: function ()
       {
-        var cacheService = Cc["@mozilla.org/network/cache-service;1"].getService(Ci.nsICacheService);
+        var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
         try {
-          cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+          cache.clear();
         } catch(er) {}
 
         let imageCache = Cc["@mozilla.org/image/cache;1"].getService(Ci.imgICache);
         try {
           imageCache.clearCache(false); // true=chrome, false=content
         } catch(er) {}
       },
 
@@ -138,19 +140,20 @@ Sanitizer.prototype = {
       {
         return true;
       }
     },
 
     offlineApps: {
       clear: function ()
       {
-        var cacheService = Cc["@mozilla.org/network/cache-service;1"].getService(Ci.nsICacheService);
+        var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
+        var appCacheStorage = cacheService.appCacheStorage(LoadContextInfo.default, null);
         try {
-          cacheService.evictEntries(Ci.nsICache.STORE_OFFLINE);
+          appCacheStorage.asyncEvictStorage(null);
         } catch(er) {}
       },
 
       get canClear()
       {
           return true;
       }
     },
--- a/browser/modules/offlineAppCache.jsm
+++ b/browser/modules/offlineAppCache.jsm
@@ -1,18 +1,20 @@
 /* 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.EXPORTED_SYMBOLS = ["OfflineAppCacheHelper"];
 
+Components.utils.import('resource://gre/modules/LoadContextInfo.jsm');
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 this.OfflineAppCacheHelper = {
   clear: function() {
-    var cacheService = Cc["@mozilla.org/network/cache-service;1"].
-                       getService(Ci.nsICacheService);
+    var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
+    var appCacheStorage = cacheService.appCacheStorage(LoadContextInfo.default, null);
     try {
-      cacheService.evictEntries(Ci.nsICache.STORE_OFFLINE);
+      appCacheStorage.asyncEvictStorage(null);
     } catch(er) {}
   }
 };
--- a/build/autoconf/config.status.m4
+++ b/build/autoconf/config.status.m4
@@ -176,8 +176,10 @@ changequote([, ])
 chmod +x $CONFIG_STATUS
 rm -fr confdefs* $ac_clean_files
 dnl Execute config.status, unless --no-create was passed to configure.
 if test "$no_create" != yes && ! ${PYTHON} $CONFIG_STATUS; then
     trap '' EXIT
     exit 1
 fi
 ])
+
+AC_SUBST([MOZ_PSEUDO_DERECURSE])
--- a/build/autoconf/python-virtualenv.m4
+++ b/build/autoconf/python-virtualenv.m4
@@ -19,17 +19,17 @@ fi
 
 _virtualenv_topsrcdir=
 _virtualenv_populate_path=
 
 dnl If this is a mozilla-central, we'll find the virtualenv in the top
 dnl source directory. If this is a SpiderMonkey build, we assume we're at
 dnl js/src and try to find the virtualenv from the mozilla-central root.
 for base in $MOZILLA_CENTRAL_PATH $_topsrcdir $_topsrcdir/../..; do
-  possible=$base/build/virtualenv/populate_virtualenv.py
+  possible=$base/python/mozbuild/mozbuild/virtualenv.py
 
   if test -e $possible; then
     _virtualenv_topsrcdir=$base
     _virtualenv_populate_path=$possible
     break
   fi
 done
 
@@ -48,17 +48,18 @@ mozilla-central and relaunch configure.]
 fi
 
 if test -z $DONT_POPULATE_VIRTUALENV; then
   AC_MSG_RESULT([Creating Python environment])
   dnl This verifies our Python version is sane and ensures the Python
   dnl virtualenv is present and up to date. It sanitizes the environment
   dnl for us, so we don't need to clean anything out.
   $PYTHON $_virtualenv_populate_path \
-    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv || exit 1
+    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv \
+    $_virtualenv_topsrcdir/build/virtualenv_packages.txt || exit 1
 
   case "$host_os" in
   mingw*)
     PYTHON=`cd $MOZ_BUILD_ROOT && pwd -W`/_virtualenv/Scripts/python.exe
     ;;
   *)
     PYTHON=$MOZ_BUILD_ROOT/_virtualenv/bin/python
     ;;
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -507,16 +507,22 @@ class Automation(object):
     if 'NSPR_LOG_MODULES' not in env:
       env['NSPR_LOG_MODULES'] = 'signaling:5,mtransport:3'
     env['R_LOG_LEVEL'] = '5'
     env['R_LOG_DESTINATION'] = 'stderr'
     env['R_LOG_VERBOSE'] = '1'
 
     # ASan specific environment stuff
     if self.IS_ASAN and (self.IS_LINUX or self.IS_MAC):
+      # Symbolizer support
+      llvmsym = os.path.join(xrePath, "llvm-symbolizer")
+      if os.path.isfile(llvmsym):
+        env["ASAN_SYMBOLIZER_PATH"] = llvmsym
+        self.log.info("INFO | automation.py | ASan using symbolizer at %s", llvmsym)
+
       try:
         totalMemory = int(os.popen("free").readlines()[1].split()[1])
 
         # Only 2 GB RAM or less available? Use custom ASan options to reduce
         # the amount of resources required to do the tests. Standard options 
         # will otherwise lead to OOM conditions on the current test slaves.
         # 
         # If we have more than 2 GB or RAM but still less than 4 GB, we need
new file mode 100644
--- /dev/null
+++ b/build/docs/conf.py
@@ -0,0 +1,49 @@
+# 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/.
+
+from __future__ import unicode_literals
+
+import os
+import re
+
+from datetime import datetime
+
+
+here = os.path.abspath(os.path.dirname(__file__))
+mozilla_dir = os.path.normpath(os.path.join(here, '..', '..'))
+
+import mdn_theme
+
+extensions = [
+    'sphinx.ext.autodoc',
+]
+
+templates_path = ['_templates']
+source_suffix = '.rst'
+master_doc = 'index'
+project = u'Mozilla Build System'
+year = datetime.now().year
+copyright = u'%s, Mozilla Foundation, CC BY-SA 3.0' % year
+
+# Grab the version from the source tree's milestone.
+with open(os.path.join(mozilla_dir, 'config', 'milestone.txt'), 'rt') as fh:
+    for line in fh:
+        line = line.strip()
+
+        if not line or line.startswith('#'):
+            continue
+
+        release = line
+        break
+
+version = re.sub(r'[ab]\d+$', '', release)
+
+exclude_patterns = ['_build']
+pygments_style = 'sphinx'
+
+html_theme_path = [mdn_theme.get_theme_dir()]
+html_theme = 'mdn'
+
+html_static_path = ['_static']
+htmlhelp_basename = 'MozillaBuildSystemdoc'
new file mode 100644
--- /dev/null
+++ b/build/docs/glossary.rst
@@ -0,0 +1,28 @@
+========
+Glossary
+========
+
+.. glossary::
+   :sorted:
+
+   object directory
+       A directory holding the output of the build system. The build
+       system attempts to isolate all file modifications to this
+       directory. By convention, object directories are commonly
+       directories under the source directory prefixed with **obj-**.
+       e.g. **obj-firefox**.
+
+   mozconfig
+       A shell script used to configure the build system.
+
+   configure
+       A generated shell script which detects the current system
+       environment, applies a requested set of build configuration
+       options, and writes out metadata to be consumed by the build
+       system.
+
+   config.status
+       An executable file produced by **configure** that takes the
+       generated build config and writes out files used to build the
+       tree. Traditionally, config.status writes out a bunch of
+       Makefiles.
new file mode 100644
--- /dev/null
+++ b/build/docs/index.rst
@@ -0,0 +1,41 @@
+==================================
+Mozilla Build System Documentation
+==================================
+
+Overview
+========
+
+.. toctree::
+   :maxdepth: 1
+
+   glossary
+
+Important Concepts
+==================
+.. toctree::
+   :maxdepth: 1
+
+   Mozconfig Files <mozconfigs>
+   Profile Guided Optimization <pgo>
+
+mozbuild
+========
+
+mozbuild is a Python package containing a lot of the code for the
+Mozilla build system.
+
+.. toctree::
+   :maxdepth: 1
+
+   mozbuild/index
+   mozbuild/frontend
+   mozbuild/dumbmake
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
rename from python/mozbuild/dumbmake/README.rst
rename to build/docs/mozbuild/dumbmake.rst
rename from python/mozbuild/mozbuild/frontend/README.rst
rename to build/docs/mozbuild/frontend.rst
rename from python/mozbuild/README.rst
rename to build/docs/mozbuild/index.rst
new file mode 100644
--- /dev/null
+++ b/build/docs/mozconfigs.rst
@@ -0,0 +1,68 @@
+===============
+mozconfig Files
+===============
+
+mozconfig files are used to configure how a build works.
+
+mozconfig files are actually shell scripts. They are executed in a
+special context with specific variables and functions exposed to them.
+
+API
+===
+
+Functions
+---------
+
+The following special functions are available to a mozconfig script.
+
+ac_add_options
+^^^^^^^^^^^^^^
+
+This function is used to declare extra options/arguments to pass into
+configure.
+
+e.g.::
+
+    ac_add_options --disable-tests
+    ac_add_options --enable-optimize
+
+mk_add_options
+^^^^^^^^^^^^^^
+
+This function is used to inject statements into client.mk for execution.
+It is typically used to define variables, notably the object directory.
+
+e.g.::
+
+    mk_add_options AUTOCLOBBER=1
+
+ac_add_options
+^^^^^^^^^^^^^^
+
+This is a variant of ac_add_options() which only adds configure options
+for a specified application. This is only used when building multiple
+applications through client.mk. This function is typically not needed.
+
+Special mk_add_options Variables
+--------------------------------
+
+For historical reasons, the method for communicating certain
+well-defined variables is via mk_add_options(). In this section, we
+document what those special variables are.
+
+MOZ_OBJDIR
+^^^^^^^^^^
+
+This variable is used to define the :term:`object directory` for the current
+build.
+
+Finding the active mozconfig
+============================
+
+Multiple mozconfig files can exist to provide different configuration
+options for different tasks. The rules for finding the active mozconfig
+are defined in the
+:py:func:`mozbuild.mozconfig.MozconfigLoader.find_mozconfig` method:
+
+.. autoclass:: mozbuild.mozconfig.MozconfigLoader
+   :members: find_mozconfig
new file mode 100644
--- /dev/null
+++ b/build/docs/pgo.rst
@@ -0,0 +1,40 @@
+.. _pgo:
+
+===========================
+Profile Guided Optimization
+===========================
+
+:abbr:`PGO (Profile Guided Optimization)` is the process of adding
+probes to a compiled binary, running said binary, then using the
+run-time information to *recompile* the binary to (hopefully) make it
+faster.
+
+How PGO Builds Work
+===================
+
+The supported interface for invoking a PGO build is to evaluate the
+*build* target of client.mk with *MOZ_PGO* defined. e.g.::
+
+    $ make -f client.mk MOZ_PGO=1
+
+This is equivalent to::
+
+    $ make -f client.mk profiledbuild
+
+Which is roughly equivalent to:
+
+#. Perform a build with *MOZ_PROFILE_GENERATE=1* and *MOZ_PGO_INSTRUMENTED=1*
+#. Package with *MOZ_PGO_INSTRUMENTED=1*
+#. Performing a run of the instrumented binaries
+#. $ make maybe_clobber_profiledbuild
+#. Perform a build with *MOZ_PROFILE_USE=1*
+
+Differences between toolchains
+==============================
+
+There are some implementation differences depending on the compiler
+toolchain being used.
+
+The *maybe_clobber_profiledbuild* step gets its name because of a
+difference. On Windows, this step merely moves some *.pgc* files around.
+Using GCC or Clang, it is equivalent to a *make clean*.
--- a/build/unix/Makefile.in
+++ b/build/unix/Makefile.in
@@ -1,14 +1,22 @@
 # -*- makefile -*-
 #
 # 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/.
 
 SDK_BINARY = run-mozilla.sh
 
+ifneq ($(LLVM_SYMBOLIZER),)
+# Install a copy of the llvm-symbolizer binary to dist/bin, so it can
+# be used for symbolizing traces for e.g. AddressSanitizer
+LLVMSYM_EXECUTABLES=$(LLVM_SYMBOLIZER)
+LLVMSYM_DEST=$(FINAL_TARGET)
+INSTALL_TARGETS += LLVMSYM
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 libs:: $(srcdir)/run-mozilla.sh
 	$(INSTALL) $< $(DIST)/bin
 
 # EOF
--- a/build/unix/elfhack/Makefile.in
+++ b/build/unix/elfhack/Makefile.in
@@ -7,20 +7,16 @@ INTERNAL_TOOLS = 1
 
 HOST_PROGRAM = elfhack
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 
 VPATH += $(topsrcdir)/build
 
 OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
 
-ifndef CROSS_COMPILE
-CSRCS += dummy.c
-endif
-
 WRAP_LDFLAGS=
 
 include $(topsrcdir)/config/rules.mk
 
 test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack $(filter inject/%,$(CSRCS:.c=.$(OBJ_SUFFIX)))
 	$(MKSHLIB) $(LDFLAGS) $< -nostartfiles
 	@echo ===
 	@echo === If you get failures below, please file a bug describing the error
--- a/build/unix/elfhack/inject/Makefile.in
+++ b/build/unix/elfhack/inject/Makefile.in
@@ -11,21 +11,16 @@ CPU := x86
 else
 ifneq (,$(filter arm%,$(TARGET_CPU)))
 CPU := arm
 else
 CPU := $(TARGET_CPU)
 endif
 endif
 
-CSRCS := \
-  $(CPU).c \
-  $(CPU)-noinit.c \
-  $(NULL)
-
 include $(topsrcdir)/config/rules.mk
 
 export:: $(CSRCS:.c=.$(OBJ_SUFFIX))
 
 $(CSRCS): %.c: ../inject.c
 	cp $< $@
 
 GARBAGE += $(CSRCS)
--- a/build/unix/elfhack/inject/moz.build
+++ b/build/unix/elfhack/inject/moz.build
@@ -1,7 +1,20 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 NO_DIST_INSTALL = True
+
+
+if CONFIG['TARGET_CPU'].endswith('86'):
+    cpu = 'x86'
+elif CONFIG['TARGET_CPU'].startswith('arm'):
+    cpu = 'arm'
+else:
+    cpu = CONFIG['TARGET_CPU']
+
+CSRCS += [
+    "%s-noinit.c" % (cpu),
+    "%s.c" % (cpu),
+]
--- a/build/unix/elfhack/moz.build
+++ b/build/unix/elfhack/moz.build
@@ -7,12 +7,17 @@
 NO_DIST_INSTALL = True
 DIRS += ['inject']
 
 CSRCS += [
     'test-array.c',
     'test-ctors.c',
 ]
 
+if not CONFIG['CROSS_COMPILE']:
+    CSRCS += [
+        'dummy.c',
+    ]
+
 HOST_CPPSRCS += [
     'elf.cpp',
     'elfhack.cpp',
 ]
--- a/build/unix/mozconfig.asan
+++ b/build/unix/mozconfig.asan
@@ -1,13 +1,14 @@
 . "$topsrcdir/build/mozconfig.common"
 
 # Use Clang as specified in manifest
 export CC="$topsrcdir/clang/bin/clang -fgnu89-inline"
 export CXX="$topsrcdir/clang/bin/clang++"
+export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
 
 # Mandatory flags for ASan
 export ASANFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC"
 export CFLAGS="$ASANFLAGS"
 export CXXFLAGS="$ASANFLAGS"
 export LDFLAGS="-fsanitize=address"
 
 # Enable ASan specific code and build workarounds
rename from build/virtualenv/packages.txt
rename to build/virtualenv_packages.txt
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -475,17 +475,17 @@ nsScriptSecurityManager::ContentSecurity
         return true; // fail open to not break sites.
     }
 
     if (reportViolation) {
         nsAutoString fileName;
         unsigned lineNum = 0;
         NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
 
-        JSScript *script;
+        JS::RootedScript script(cx);
         if (JS_DescribeScriptedCaller(cx, &script, &lineNum)) {
             if (const char *file = JS_GetScriptFilename(cx, script)) {
                 CopyUTF8toUTF16(nsDependentCString(file), fileName);
             }
         }
         csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
                                  fileName,
                                  scriptSample,
--- a/client.mk
+++ b/client.mk
@@ -320,18 +320,18 @@ EXTRA_CONFIG_DEPS := \
 CONFIG_STATUS_DEPS := \
   $(wildcard $(TOPSRCDIR)/*/confvars.sh) \
   $(CONFIGURES) \
   $(TOPSRCDIR)/CLOBBER \
   $(TOPSRCDIR)/nsprpub/configure \
   $(TOPSRCDIR)/config/milestone.txt \
   $(TOPSRCDIR)/js/src/config/milestone.txt \
   $(TOPSRCDIR)/browser/config/version.txt \
-  $(TOPSRCDIR)/build/virtualenv/packages.txt \
-  $(TOPSRCDIR)/build/virtualenv/populate_virtualenv.py \
+  $(TOPSRCDIR)/build/virtualenv_packages.txt \
+  $(TOPSRCDIR)/python/mozbuild/mozbuild/virtualenv.py \
   $(TOPSRCDIR)/testing/mozbase/packages.txt \
   $(NULL)
 
 CONFIGURE_ENV_ARGS += \
   MAKE="$(MAKE)" \
   $(NULL)
 
 # configure uses the program name to determine @srcdir@. Calling it without
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -1,25 +1,123 @@
 # 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 INCLUDED_RULES_MK
 include $(topsrcdir)/config/rules.mk
 endif
 
+# The traditional model of directory traversal with make is as follows:
+#   make -C foo
+#     Entering foo
+#     make -C bar
+#       Entering foo/bar
+#     make -C baz
+#       Entering foo/baz
+#   make -C qux
+#     Entering qux
+#
+# Pseudo derecurse transforms the above into:
+#   make -C foo
+#   make -C foo/bar
+#   make -C foo/baz
+#   make -C qux
+
+# MOZ_PSEUDO_DERECURSE can have values other than 1.
+ifeq (1_.,$(if $(MOZ_PSEUDO_DERECURSE),1)_$(DEPTH))
+
+include root.mk
+
+# Disable build status for mach in top directories without TIERS.
+# In practice this disables it when recursing under js/src, which confuses mach.
+ifndef TIERS
+BUILDSTATUS =
+endif
+
+# Main rules (export, compile, libs and tools) call recurse_* rules.
+# This wrapping is only really useful for build status.
+compile libs export tools::
+	$(call BUILDSTATUS,TIER_START $@ $($@_subtiers))
+	+$(MAKE) recurse_$@
+	$(call BUILDSTATUS,TIER_FINISH $@)
+
+# Carefully avoid $(eval) type of rule generation, which makes pymake slower
+# than necessary.
+# Get current tier and corresponding subtiers from the data in root.mk.
+CURRENT_TIER := $(filter $(foreach tier,compile libs export tools,recurse_$(tier)),$(MAKECMDGOALS))
+ifneq (,$(filter-out 0 1,$(words $(CURRENT_TIER))))
+$(error $(CURRENT_TIER) not supported on the same make command line)
+endif
+CURRENT_TIER := $(subst recurse_,,$(CURRENT_TIER))
+CURRENT_SUBTIERS := $($(CURRENT_TIER)_subtiers)
+
+# The rules here are doing directory traversal, so we don't want further
+# recursion to happen when running make -C subdir $tier. But some make files
+# further call make -C something else, and sometimes expect recursion to
+# happen in that case (see browser/metro/locales/Makefile.in for example).
+# Conveniently, every invocation of make increases MAKELEVEL, so only stop
+# recursion from happening at current MAKELEVEL + 1.
+ifdef CURRENT_TIER
+ifeq (0,$(MAKELEVEL))
+export NO_RECURSE_MAKELEVEL=1
+else
+export NO_RECURSE_MAKELEVEL=$(word $(MAKELEVEL),2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
+endif
+endif
+
+# Get all directories traversed for all subtiers in the current tier, or use
+# directly the $(*_dirs) variables available in root.mk when there is no
+# TIERS (like for js/src).
+CURRENT_DIRS := $(or $($(CURRENT_TIER)_dirs),$(foreach subtier,$(CURRENT_SUBTIERS),$($(CURRENT_TIER)_subtier_$(subtier))))
+
+# Subtier delimiter rules
+$(addprefix subtiers/,$(addsuffix _start/$(CURRENT_TIER),$(CURRENT_SUBTIERS))): subtiers/%_start/$(CURRENT_TIER):
+	$(call BUILDSTATUS,SUBTIER_START $(CURRENT_TIER) $* $(if $(BUG_915535_FIXED),$($(CURRENT_TIER)_subtier_$*)))
+
+$(addprefix subtiers/,$(addsuffix _finish/$(CURRENT_TIER),$(CURRENT_SUBTIERS))): subtiers/%_finish/$(CURRENT_TIER):
+	$(call BUILDSTATUS,SUBTIER_FINISH $(CURRENT_TIER) $*)
+
+# Recursion rule for all directories traversed for all subtiers in the
+# current tier.
+# root.mk defines subtier_of_* variables, that map a normalized subdir path to
+# a subtier name (e.g. subtier_of_memory_jemalloc = base)
+$(addsuffix /$(CURRENT_TIER),$(CURRENT_DIRS)): %/$(CURRENT_TIER):
+ifdef BUG_915535_FIXED
+	$(call BUILDSTATUS,TIERDIR_START $(CURRENT_TIER) $(subtier_of_$(subst /,_,$*)) $*)
+endif
+	+@$(MAKE) -C $* $(if $(filter $*,$(tier_$(subtier_of_$(subst /,_,$*))_staticdirs)),,$(CURRENT_TIER))
+ifdef BUG_915535_FIXED
+	$(call BUILDSTATUS,TIERDIR_FINISH $(CURRENT_TIER) $(subtier_of_$(subst /,_,$*)) $*)
+endif
+
+# The export tier requires nsinstall, which is built from config. So every
+# subdirectory traversal needs to happen after traversing config.
+ifeq ($(CURRENT_TIER),export)
+$(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CURRENT_TIER)
+endif
+
+else
+
+# Don't recurse if MAKELEVEL is NO_RECURSE_MAKELEVEL as defined above, but
+# still recurse for externally managed make files (gyp-generated ones).
+ifeq ($(EXTERNALLY_MANAGED_MAKE_FILE)_$(NO_RECURSE_MAKELEVEL),_$(MAKELEVEL))
+
+compile libs export tools::
+
+else
 #########################
 # Tier traversal handling
 #########################
 
 ifdef TIERS
 
-compile libs export tools::
+libs export tools::
 	$(call BUILDSTATUS,TIER_START $@ $(filter-out $(if $(filter export,$@),,precompile),$(TIERS)))
-	$(foreach tier,$(TIERS), $(if $(filter-out compile_precompile libs_precompile tools_precompile,$@_$(tier)), \
+	$(foreach tier,$(TIERS), $(if $(filter-out libs_precompile tools_precompile,$@_$(tier)), \
 		$(call BUILDSTATUS,SUBTIER_START $@ $(tier) $(if $(filter libs,$@),$(tier_$(tier)_staticdirs)) $(tier_$(tier)_dirs)) \
 		$(if $(filter libs,$@),$(foreach dir, $(tier_$(tier)_staticdirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),,1))) \
 		$(foreach dir, $(tier_$(tier)_dirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),$@)) \
 		$(call BUILDSTATUS,SUBTIER_FINISH $@ $(tier))))
 	$(call BUILDSTATUS,TIER_FINISH $@)
 
 else
 
@@ -36,14 +134,18 @@ endif
 $(1):: $$(SUBMAKEFILES)
 ifdef PARALLEL_DIRS
 	+@$(MAKE) $$(PARALLEL_DIRS_$(1))
 endif
 	$$(LOOP_OVER_DIRS)
 
 endef
 
-$(foreach subtier,export compile libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
+$(foreach subtier,export libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
 
-compile export tools:: $(SUBMAKEFILES)
+tools export:: $(SUBMAKEFILES)
 	$(LOOP_OVER_TOOL_DIRS)
 
-endif
+endif # ifdef TIERS
+
+endif # ifeq ($(EXTERNALLY_MANAGED_MAKE_FILE)_$(NO_RECURSE_MAKELEVEL),_$(MAKELEVEL))
+
+endif # ifeq (1_.,$(MOZ_PSEUDO_DERECURSE)_$(DEPTH))
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -690,17 +690,19 @@ SUBMAKEFILES += $(addsuffix /Makefile, $
 
 # The root makefile doesn't want to do a plain export/libs, because
 # of the tiers and because of libxul. Suppress the default rules in favor
 # of something else. Makefiles which use this var *must* provide a sensible
 # default rule before including rules.mk
 ifndef SUPPRESS_DEFAULT_RULES
 default all::
 	$(MAKE) export
+ifdef MOZ_PSEUDO_DERECURSE
 	$(MAKE) compile
+endif
 	$(MAKE) libs
 	$(MAKE) tools
 endif # SUPPRESS_DEFAULT_RULES
 
 ifeq ($(findstring s,$(filter-out --%, $(MAKEFLAGS))),)
 ECHO := echo
 QUIET :=
 else
--- a/config/stl-headers
+++ b/config/stl-headers
@@ -16,16 +16,17 @@ new
 
 # FIXME: these headers haven't been reviewed yet, but we use them
 # unsafely in Gecko, so we might as well prevent them from
 # throwing exceptions
 algorithm
 atomic
 deque
 ios
+iosfwd
 iostream
 iterator
 limits
 list
 map
 memory
 ostream
 set
--- a/config/system-headers
+++ b/config/system-headers
@@ -464,16 +464,17 @@ intshcut.h
 inttypes.h
 iodef.h
 io.h
 IOKit/IOKitLib.h
 IOKit/IOMessage.h
 IOKit/pwr_mgt/IOPMLib.h
 iomanip
 ios
+iosfwd
 iostream
 iostream.h
 iterator
 JavaControl.h
 JavaEmbedding/JavaControl.h
 JavaVM/jni.h
 JManager.h
 JNIEnvTests.h
--- a/configure.in
+++ b/configure.in
@@ -1207,18 +1207,20 @@ dnl = Use Address Sanitizer
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(address-sanitizer,
 [  --enable-address-sanitizer       Enable Address Sanitizer (default=no)],
     MOZ_ASAN=1,
     MOZ_ASAN= )
 if test -n "$MOZ_ASAN"; then
     MOZ_LLVM_HACKS=1
     AC_DEFINE(MOZ_ASAN)
+    MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
 AC_SUBST(MOZ_ASAN)
+AC_SUBST(LLVM_SYMBOLIZER)
 
 dnl ========================================================
 dnl = Enable hacks required for LLVM instrumentations
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(llvm-hacks,
 [  --enable-llvm-hacks       Enable workarounds required for several LLVM instrumentations (default=no)],
     MOZ_LLVM_HACKS=1,
     MOZ_LLVM_HACKS= )
@@ -1230,17 +1232,22 @@ AC_SUBST(MOZ_NO_WLZDEFS)
 AC_SUBST(MOZ_CFLAGS_NSS)
 
 dnl ========================================================
 dnl GNU specific defaults
 dnl ========================================================
 if test "$GNU_CC"; then
     # Per bug 719659 comment 2, some of the headers on ancient build machines
     # may require gnu89 inline semantics.  But otherwise, we use C99.
-    CFLAGS="$CFLAGS -std=gnu99 -fgnu89-inline"
+    # But on OS X we just use C99 plus GNU extensions, in order to fix
+    # bug 917526.
+    CFLAGS="$CFLAGS -std=gnu99"
+    if test "${OS_ARCH}" != Darwin; then
+        CFLAGS="$CFLAGS -fgnu89-inline"
+    fi
     # FIXME: Let us build with strict aliasing. bug 414641.
     CFLAGS="$CFLAGS -fno-strict-aliasing"
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     DSO_LDOPTS='-shared'
     if test "$GCC_USE_GNU_LD"; then
         # Some tools like ASan use a runtime library that is only
         # linked against executables, so we must allow undefined
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -666,17 +666,17 @@ WebSocket::Init(JSContext* aCx,
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   NS_ENSURE_STATE(os);
   rv = os->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, true);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = os->AddObserver(this, DOM_WINDOW_FROZEN_TOPIC, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   unsigned lineno;
-  JSScript* script;
+  JS::RootedScript script(aCx);
   if (JS_DescribeScriptedCaller(aCx, &script, &lineno)) {
     mScriptFile = JS_GetScriptFilename(aCx, script);
     mScriptLine = lineno;
   }
 
   // Get WindowID
   mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(aCx);
 
--- a/content/base/test/test_bug482935.html
+++ b/content/base/test/test_bug482935.html
@@ -6,19 +6,19 @@
   <link rel="stylesheet" type="text/css" href="	/tests/SimpleTest/test.css" />
 </head>
 <body onload="onWindowLoad()">
 <script class="testbody" type="text/javascript">
 
 var url = "bug482935.sjs";
 
 function clearCache() {
-    SpecialPowers.Cc["@mozilla.org/network/cache-service;1"].
-               getService(SpecialPowers.Ci.nsICacheService).
-               evictEntries(SpecialPowers.Ci.nsICache.STORE_ANYWHERE);
+    SpecialPowers.Cc["@mozilla.org/netwerk/cache-storage-service;1"].
+               getService(SpecialPowers.Ci.nsICacheStorageService).
+               clear();
 }
 
 // Tests that the response is cached if the request is cancelled
 // after it has reached state 4
 function testCancelInPhase4() {
 
   clearCache();
 
--- a/content/media/Latency.cpp
+++ b/content/media/Latency.cpp
@@ -8,28 +8,29 @@
 #define FORCE_PR_LOG
 
 #include "Latency.h"
 #include "nsThreadUtils.h"
 #include <prlog.h>
 #include <cmath>
 #include <algorithm>
 
+#include <mozilla/StaticPtr.h>
 
 using namespace mozilla;
 
 const char* LatencyLogIndex2Strings[] = {
   "Audio MediaStreamTrack",
   "Video MediaStreamTrack",
   "Cubeb",
   "AudioStream",
   "NetStat"
 };
 
-static nsRefPtr<AsyncLatencyLogger> gAsyncLogger;
+static StaticRefPtr<AsyncLatencyLogger> gAsyncLogger;
 
 PRLogModuleInfo*
 GetLatencyLog()
 {
   static PRLogModuleInfo* sLog;
   if (!sLog) {
     sLog = PR_NewLogModule("MediaLatency");
   }
--- a/docshell/test/navigation/NavigationUtils.js
+++ b/docshell/test/navigation/NavigationUtils.js
@@ -88,20 +88,16 @@ function isInaccessible(wnd, message) {
   try {
     wnd.document.body.innerHTML;
     ok(false, message);
   } catch(ex) {
     ok(true, message);
   }
 }
 
-function getSubframe(win, i) {
-  return SpecialPowers.unwrap(SpecialPowers.wrap(win)[i]);
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Functions that require UniversalXPConnect privilege
 ///////////////////////////////////////////////////////////////////////////
 
 function xpcEnumerateContentWindows(callback) {
 
   var Ci = SpecialPowers.Ci;
   var ww = SpecialPowers.Cc["@mozilla.org/embedcomp/window-watcher;1"]
--- a/docshell/test/navigation/test_bug13871.html
+++ b/docshell/test/navigation/test_bug13871.html
@@ -4,28 +4,27 @@
     <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     <script type="text/javascript" src="NavigationUtils.js"></script>        
     <style type="text/css">
       iframe { width: 90%; height: 50px; }
     </style>
 <script>
-
 window.onload = function () {
-  navigateByLocation(getSubframe(window0, 0));
+  navigateByLocation(window0.frames[0]);
   navigateByOpen("window1_child0");
   navigateByForm("window2_child0");
   navigateByHyperlink("window3_child0");
 
   xpcWaitForFinishedFrames(function() {
-    isInaccessible(getSubframe(window0, 0), "Should not be able to navigate off-domain frame by setting location.");
-    isInaccessible(getSubframe(window1, 0), "Should not be able to navigate off-domain frame by calling window.open.");
-    isInaccessible(getSubframe(window2, 0), "Should not be able to navigate off-domain frame by submitting form.");
-    isInaccessible(getSubframe(window3, 0), "Should not be able to navigate off-domain frame by targeted hyperlink.");
+    isInaccessible(window0.frames[0], "Should not be able to navigate off-domain frame by setting location.");
+    isInaccessible(window1.frames[0], "Should not be able to navigate off-domain frame by calling window.open.");
+    isInaccessible(window2.frames[0], "Should not be able to navigate off-domain frame by submitting form.");
+    isInaccessible(window3.frames[0], "Should not be able to navigate off-domain frame by targeted hyperlink.");
 
     window0.close();
     window1.close();
     window2.close();
     window3.close();
 
     xpcCleanupWindows();
     SimpleTest.finish();
--- a/docshell/test/navigation/test_grandchild.html
+++ b/docshell/test/navigation/test_grandchild.html
@@ -9,26 +9,26 @@
       iframe { width: 90%; height: 200px; }
     </style>
 <script>
 if (!navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 1);
 }
 
 window.onload = function () {
-  navigateByLocation(getSubframe(getSubframe(frames, 0), 0));
+  navigateByLocation(frames[0].frames[0]);
   navigateByOpen("child1_child0");
   navigateByForm("child2_child0");
   navigateByHyperlink("child3_child0");
 
   xpcWaitForFinishedFrames(function() {
-    isNavigated(getSubframe(getSubframe(frames, 0), 0), "Should be able to navigate off-domain grandchild by setting location.");
-    isNavigated(getSubframe(getSubframe(frames, 1), 0), "Should be able to navigate off-domain grandchild by calling window.open.");
-    isNavigated(getSubframe(getSubframe(frames, 2), 0), "Should be able to navigate off-domain grandchild by submitting form.");
-    isNavigated(getSubframe(getSubframe(frames, 3), 0), "Should be able to navigate off-domain grandchild by targeted hyperlink.");
+    isNavigated(frames[0].frames[0], "Should be able to navigate off-domain grandchild by setting location.");
+    isNavigated(frames[1].frames[0], "Should be able to navigate off-domain grandchild by calling window.open.");
+    isNavigated(frames[2].frames[0], "Should be able to navigate off-domain grandchild by submitting form.");
+    isNavigated(frames[3].frames[0], "Should be able to navigate off-domain grandchild by targeted hyperlink.");
 
     xpcCleanupWindows();
     SimpleTest.finish();
   }, 4);
 }
 </script>
 </head>
 <body>
--- a/docshell/test/navigation/test_sibling-off-domain.html
+++ b/docshell/test/navigation/test_sibling-off-domain.html
@@ -6,17 +6,17 @@
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     <script type="text/javascript" src="NavigationUtils.js"></script>        
     <style type="text/css">
       iframe { width: 90%; height: 50px; }
     </style>
 <script>
 window.onload = function () {
   document.getElementById('active').innerHTML =
-      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#SpecialPowers.unwrap(SpecialPowers.wrap(parent).frames[0]),location"></iframe>' +
+      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#parent.frames[0],location"></iframe>' +
       '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child1,open"></iframe>' +
       '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child2,form"></iframe>' +
       '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child3,hyperlink"></iframe>';
 
   xpcWaitForFinishedFrames(function() {
     isBlank(frames[0], "Should not be able to navigate off-domain sibling by setting location.");
     isBlank(frames[1], "Should not be able to navigate off-domain sibling by calling window.open.");
     isBlank(frames[2], "Should not be able to navigate off-domain sibling by submitting form.");
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -22,26 +22,16 @@ WindowNamedPropertiesHandler::getOwnProp
                                                        unsigned aFlags)
 {
   if (!JSID_IS_STRING(aId)) {
     // Nothing to do if we're resolving a non-string property.
     return true;
   }
 
   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
-  nsresult rv =
-    nsDOMClassInfo::ScriptSecurityManager()->CheckPropertyAccess(aCx, global,
-                                                                 "Window", aId,
-                                                                 nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
-  if (NS_FAILED(rv)) {
-    // The security check failed. The security manager set a JS exception for
-    // us.
-    return false;
-  }
-
   if (HasPropertyOnPrototype(aCx, aProxy, aId)) {
     return true;
   }
 
   nsDependentJSString str(aId);
 
   // Grab the DOM window.
   XPCWrappedNative* wrapper = XPCWrappedNative::Get(global);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9432,17 +9432,17 @@ nsGlobalWindow::ShowSlowScriptDialog()
   nsCOMPtr<nsIDocShell> ds = GetDocShell();
   NS_ENSURE_TRUE(ds, KillSlowScript);
   nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
   NS_ENSURE_TRUE(prompt, KillSlowScript);
 
   // Check if we should offer the option to debug
   JS::RootedScript script(cx);
   unsigned lineno;
-  bool hasFrame = JS_DescribeScriptedCaller(cx, script.address(), &lineno);
+  bool hasFrame = JS_DescribeScriptedCaller(cx, &script, &lineno);
 
   bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx);
 #ifdef MOZ_JSDEBUGGER
   // Get the debugger service if necessary.
   if (debugPossible) {
     bool jsds_IsOn = false;
     const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
     nsCOMPtr<jsdIExecutionHook> jsdHook;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -504,17 +504,18 @@ void
 NS_ScriptErrorReporter(JSContext *cx,
                        const char *message,
                        JSErrorReport *report)
 {
   // We don't want to report exceptions too eagerly, but warnings in the
   // absence of werror are swallowed whole, so report those now.
   if (!JSREPORT_IS_WARNING(report->flags)) {
     nsIXPConnect* xpc = nsContentUtils::XPConnect();
-    if (JS_DescribeScriptedCaller(cx, nullptr, nullptr)) {
+    JS::RootedScript script(cx);
+    if (JS_DescribeScriptedCaller(cx, &script, nullptr)) {
       xpc->MarkErrorUnreported(cx);
       return;
     }
 
     if (xpc) {
       nsAXPCNativeCallContext *cc = nullptr;
       xpc->GetCurrentNativeCallContext(&cc);
       if (cc) {
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -26,17 +26,17 @@
 #include "nsJSPrincipals.h"
 #include "xpcpublic.h"
 #include "nsContentUtils.h"
 
 bool
 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
                               uint32_t* aLineno)
 {
-  JSScript* script = nullptr;
+  JS::RootedScript script(aContext);
   unsigned lineno = 0;
 
   if (!JS_DescribeScriptedCaller(aContext, &script, &lineno)) {
     return false;
   }
 
   *aFilename = ::JS_GetScriptFilename(aContext, script);
   *aLineno = lineno;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -21,16 +21,18 @@
 #   * headerFile - The file in which the nativeType is declared (defaults
 #                  to an educated guess).
 #   * concrete - Indicates whether there exist JS objects with this interface as
 #                their primary interface (and hence whose prototype is this
 #                interface's prototype object).  Always False for callback
 #                interfaces.  Defaults to True otherwise.
 #   * workers - Indicates whether the descriptor is intended to be used for
 #               worker threads (defaults to false).
+#   * customTrace - The native class will use a custom trace hook (defaults to
+#                   true for workers, false otherwise).
 #   * customFinalize - The native class will use a custom finalize hook
 #                      (defaults to true for workers, false otherwise).
 #   * wantsQI - Indicates whether the interface should have a QueryInterface
 #               method available to chrome.
 #   * notflattened - The native type does not have nsIClassInfo, so when
 #                    wrapping it the right IID needs to be passed in.
 #   * register - True if this binding should be registered.  Defaults to true.
 #   * binaryNames - Dict for mapping method and attribute names to different
@@ -182,17 +184,17 @@ DOMInterfaces = {
 
 'CameraManager': {
     'nativeType': 'nsDOMCameraManager',
     'headerFile': 'DOMCameraManager.h'
 },
 
 'CanvasRenderingContext2D': {
     'implicitJSContext': [
-        'createImageData', 'getImageData', 'mozDash'
+        'createImageData', 'getImageData'
     ],
     'resultNotAddRefed': [ 'canvas', 'measureText' ],
     'binaryNames': {
         'mozImageSmoothingEnabled': 'imageSmoothingEnabled',
         'mozFillRule': 'fillRule'
     }
 },
 
@@ -839,17 +841,16 @@ DOMInterfaces = {
 },
 
 'OfflineAudioCompletionEvent': {
     'resultNotAddRefed': [ 'renderedBuffer' ],
 },
 
 'OfflineAudioContext': {
     'nativeType': 'mozilla::dom::AudioContext',
-    'implicitJSContext': [ 'createBuffer' ],
     'resultNotAddRefed': [ 'destination', 'listener' ],
 },
 
 'OfflineResourceList': {
     'nativeType': 'nsDOMOfflineResourceList',
 },
 
 'OscillatorNode': {
@@ -1241,17 +1242,16 @@ DOMInterfaces = {
     'implicitJSContext' : [ 'undo', 'redo', 'transact' ],
 },
 
 'URL' : [{
     'wrapperCache' : False,
     'nativeOwnership': 'refcounted',
 },
 {
-    'implicitJSContext': [ 'createObjectURL', 'revokeObjectURL' ],
     'workers': True,
 }],
 
 'VTTCue': {
     'nativeType': 'mozilla::dom::TextTrackCue'
 },
 
 'WebGLActiveInfo': {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -13,16 +13,17 @@ import itertools
 
 from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute
 from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
 
 AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
+TRACE_HOOK_NAME = '_trace'
 CONSTRUCT_HOOK_NAME = '_constructor'
 LEGACYCALLER_HOOK_NAME = '_legacycaller'
 HASINSTANCE_HOOK_NAME = '_hasInstance'
 NEWRESOLVE_HOOK_NAME = '_newResolve'
 ENUMERATE_HOOK_NAME= '_enumerate'
 ENUM_ENTRY_VARIABLE_NAME = 'strings'
 
 def replaceFileIfChanged(filename, newContents):
@@ -170,20 +171,17 @@ class CGDOMJSClass(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
         # Our current reserved slot situation is unsafe for globals. Fix bug 760095!
         assert "Window" not in descriptor.interface.identifier.name
     def declare(self):
         return ""
     def define(self):
-        # Custom tracehooks are a footgun, so avoid supporting them. For instance,
-        # you have to be careful about barriers, and if you don't set a JSClass flag,
-        # then you'll end up permanently disabling incremental GC.
-        traceHook = 'nullptr'
+        traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'nullptr'
         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
         classFlags = "JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3)"
         if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
             classFlags += " | JSCLASS_NEW_RESOLVE"
             enumerateHook = ENUMERATE_HOOK_NAME
         else:
             newResolveHook = "JS_ResolveStub"
@@ -378,16 +376,18 @@ class CGList(CGThing):
         # generator we won't be able to both declare and define ourselves, or
         # define ourselves more than once!
         self.children = list(children)
         self.joiner = joiner
     def append(self, child):
         self.children.append(child)
     def prepend(self, child):
         self.children.insert(0, child)
+    def extend(self, kids):
+        self.children.extend(kids)
     def join(self, generator):
         return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
     def declare(self):
         return self.join(child.declare() for child in self.children if child is not None)
     def define(self):
         return self.join(child.define() for child in self.children if child is not None)
     def deps(self):
         deps = set()
@@ -1066,16 +1066,30 @@ class CGClassFinalizeHook(CGAbstractClas
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
                                      'void', args)
 
     def generate_code(self):
         return CGIndenter(finalizeHook(self.descriptor, self.name, self.args[0].name)).define()
 
+class CGClassTraceHook(CGAbstractClassHook):
+    """
+    A hook to trace through our native object; used for GC and CC
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSTracer*', 'trc'), Argument('JSObject*', 'obj')]
+        CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
+                                     args)
+
+    def generate_code(self):
+        return """  if (self) {
+    self->%s(%s);
+  }""" % (self.name, self.args[0].name)
+
 class CGClassConstructor(CGAbstractStaticMethod):
     """
     JS-visible constructor for our objects
     """
     def __init__(self, descriptor, ctor, name=CONSTRUCT_HOOK_NAME):
         args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'), Argument('JS::Value*', 'vp')]
         CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
         self._ctor = ctor
@@ -2865,17 +2879,17 @@ for (uint32_t i = 0; i < length; ++i) {
                         }
                     ))).define()
 
         templateBody += "\n}"
         templateBody = wrapObjectTemplate(templateBody, type,
                                           "${declName}.SetNull()", notSequence)
         # Sequence arguments that might contain traceable things need
         # to get traced
-        if not isMember and typeNeedsRooting(elementType, descriptorProvider):
+        if not isMember and typeNeedsRooting(elementType):
             holderType = CGTemplatedType("SequenceRooter", elementInfo.declType)
             # If our sequence is nullable, this will set the Nullable to be
             # not-null, but that's ok because we make an explicit SetNull() call
             # on it as needed if our JS value is actually null.
             holderArgs = "cx, &%s" % arrayRef
         else:
             holderType = None
             holderArgs = None
@@ -3495,38 +3509,23 @@ for (uint32_t i = 0; i < length; ++i) {
                                            getEnumValueName(defaultValue.value))))
         return JSToNativeConversionInfo(template, declType=CGGeneric(declType),
                                         dealWithOptional=isOptional)
 
     if type.isCallback():
         assert not isEnforceRange and not isClamp
         assert not type.treatNonCallableAsNull() or type.nullable()
 
-        if descriptorProvider.workers:
-            if isMember:
-                raise NoSuchDescriptorError("Can't handle member callbacks in "
-                                            "workers; need to sort out rooting"
-                                            "issues")
-            if isOptional:
-                # We have a specialization of Optional that will use a
-                # Rooted for the storage here.
-                declType = CGGeneric("JS::Handle<JSObject*>")
-            else:
-                declType = CGGeneric("JS::Rooted<JSObject*>")            
-            conversion = "  ${declName} = &${val}.toObject();\n"
-            declArgs = "cx"
-        else:
-            name = type.unroll().identifier.name
-            if type.nullable():
-                declType = CGGeneric("nsRefPtr<%s>" % name);
-            else:
-                declType = CGGeneric("OwningNonNull<%s>" % name)
-            conversion = (
-                "  ${declName} = new %s(&${val}.toObject());\n" % name)
-            declArgs = None
+        name = type.unroll().identifier.name
+        if type.nullable():
+            declType = CGGeneric("nsRefPtr<%s>" % name);
+        else:
+            declType = CGGeneric("OwningNonNull<%s>" % name)
+        conversion = (
+            "  ${declName} = new %s(&${val}.toObject());\n" % name)
 
         if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
             haveCallable = "JS_ObjectIsCallable(cx, &${val}.toObject())"
             if not isDefinitelyObject:
                 haveCallable = "${val}.isObject() && " + haveCallable
             if defaultValue is not None:
                 assert(isinstance(defaultValue, IDLNullValue))
                 haveCallable = "${haveValue} && " + haveCallable
@@ -3542,18 +3541,17 @@ for (uint32_t i = 0; i < length; ++i) {
                 conversion +
                 "} else {\n"
                 "%s"
                 "}" % CGIndenter(onFailureNotCallable(failureCode)).define(),
                 type,
                 "${declName} = nullptr",
                 failureCode)
         return JSToNativeConversionInfo(template, declType=declType,
-                                        dealWithOptional=isOptional,
-                                        declArgs=declArgs)
+                                        dealWithOptional=isOptional)
 
     if type.isAny():
         assert not isEnforceRange and not isClamp
 
         declArgs = None
         if (isMember == "Variadic" or isMember == "Sequence" or
             isMember == "Dictionary"):
             # Rooting is handled by the sequence and dictionary tracers.
@@ -3621,17 +3619,17 @@ for (uint32_t i = 0; i < length; ++i) {
 
         template += ('if (!${declName}.Init(cx, %s, "%s")) {\n'
                      "%s\n"
                      "}" % (val, firstCap(sourceDescription),
                             exceptionCodeIndented.define()))
 
         # Dictionary arguments that might contain traceable things need to get
         # traced
-        if not isMember and typeNeedsRooting(type, descriptorProvider):
+        if not isMember and typeNeedsRooting(type):
             declType = CGTemplatedType("RootedDictionary", declType);
             declArgs = "cx"
         else:
             declArgs = None
 
         return JSToNativeConversionInfo(template, declType=declType,
                                         declArgs=declArgs)
 
@@ -3927,17 +3925,17 @@ class CGArgumentConverter(CGThing):
         if typeConversion.dealWithOptional:
             raise TypeError("Shouldn't have optional things in variadics")
         if typeConversion.holderType is not None:
             raise TypeError("Shouldn't need holders for variadics")
 
         replacer = dict(self.argcAndIndex, **self.replacementVariables)
         replacer["seqType"] = CGTemplatedType("AutoSequence",
                                               typeConversion.declType).define()
-        if typeNeedsRooting(self.argument.type, self.descriptorProvider):
+        if typeNeedsRooting(self.argument.type):
             rooterDecl = ("SequenceRooter<%s> ${holderName}(cx, &${declName});\n" %
                           typeConversion.declType.define())
         else:
             rooterDecl = ""
         replacer["elemType"] = typeConversion.declType.define()
 
         # NOTE: Keep this in sync with sequence conversions as needed
         variadicConversion = string.Template("${seqType} ${declName};\n" +
@@ -4197,24 +4195,16 @@ if (!returnArray) {
         if type.nullable():
             conversion = CGIfElseWrapper(
                 "%s.IsNull()" % result,
                 CGGeneric(setValue("JS::NullValue()", False)),
                 CGGeneric(conversion)).define()
         return conversion, False
 
     if type.isCallback() or type.isCallbackInterface():
-        # See comments in WrapNewBindingObject explaining why we need
-        # to wrap here.
-        # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
-        if descriptorProvider.workers:
-            return (setValue("JS::ObjectOrNullValue(%s)" % result,
-                             "objectOrNull"),
-                    False)
-
         wrapCode = setValue(
             "JS::ObjectValue(*GetCallbackFromCallbackObject(%(result)s))",
             "object")
         if type.nullable():
             wrapCode = (
                 "if (%(result)s) {\n" +
                 CGIndenter(CGGeneric(wrapCode)).define() + "\n"
                 "} else {\n" +
@@ -4357,39 +4347,37 @@ def infallibleForMember(member, type, de
     CURRENT ASSUMPTIONS:
         We assume that successCode for wrapping up return values cannot contain
         failure conditions.
     """
     return getWrapTemplateForType(type, descriptorProvider, 'result', None,\
                                   memberIsCreator(member), "return false;",
                                   False)[1]
 
-def leafTypeNeedsCx(type, descriptorProvider, retVal):
+def leafTypeNeedsCx(type, 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):
+            (retVal and type.isSpiderMonkeyInterface()))
+
+def leafTypeNeedsScopeObject(type, retVal):
+    return retVal and type.isSpiderMonkeyInterface()
+
+def leafTypeNeedsRooting(type):
+    return leafTypeNeedsCx(type, False) or type.isSpiderMonkeyInterface()
+
+def typeNeedsRooting(type):
     return typeMatchesLambda(type,
-                             lambda t: leafTypeNeedsRooting(t, descriptorProvider))
-
-def typeNeedsCx(type, descriptorProvider, retVal=False):
+                             lambda t: leafTypeNeedsRooting(t))
+
+def typeNeedsCx(type, retVal=False):
     return typeMatchesLambda(type,
-                             lambda t: leafTypeNeedsCx(t, descriptorProvider, retVal))
-
-def typeNeedsScopeObject(type, descriptorProvider, retVal=False):
+                             lambda t: leafTypeNeedsCx(t, retVal))
+
+def typeNeedsScopeObject(type, retVal=False):
     return typeMatchesLambda(type,
-                             lambda t: leafTypeNeedsScopeObject(t, descriptorProvider, retVal))
+                             lambda t: leafTypeNeedsScopeObject(t, 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)
@@ -4451,62 +4439,60 @@ def getRetvalDeclarationForType(returnTy
             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
     if returnType.isAny():
         return CGGeneric("JS::Value"), False, None, None
     if returnType.isObject() or returnType.isSpiderMonkeyInterface():
         return CGGeneric("JSObject*"), False, None, None
     if returnType.isSequence():
         nullable = returnType.nullable()
         if nullable:
             returnType = returnType.inner
         # If our result is already addrefed, use the right type in the
         # sequence argument here.
         (result, _, _, _) = getRetvalDeclarationForType(returnType.inner,
                                                         descriptorProvider,
                                                         resultAlreadyAddRefed,
                                                         isMember="Sequence")
         # While we have our inner type, set up our rooter, if needed
-        if not isMember and typeNeedsRooting(returnType, descriptorProvider):
+        if not isMember and typeNeedsRooting(returnType):
             rooter = CGGeneric("SequenceRooter<%s > resultRooter(cx, &result);" %
                                result.define())
         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) +
                     "Initializer")
         result = CGGeneric(dictName)
-        if not isMember and typeNeedsRooting(returnType, descriptorProvider):
+        if not isMember and typeNeedsRooting(returnType):
             if nullable:
                 result = CGTemplatedType("NullableRootedDictionary", result)
             else:
                 result = CGTemplatedType("RootedDictionary", result)
             resultArgs = "cx"
         else:
             if nullable:
                 result = CGTemplatedType("Nullable", result)
             resultArgs = None
         return result, True, None, resultArgs
     if returnType.isUnion():
         result = CGGeneric("Owning" + returnType.unroll().name)
-        if not isMember and typeNeedsRooting(returnType, descriptorProvider):
+        if not isMember and typeNeedsRooting(returnType):
             if returnType.nullable():
                 result = CGTemplatedType("NullableRootedUnion", result)
             else:
                 result = CGTemplatedType("RootedUnion", result)
             resultArgs = "cx"
         else:
             if returnType.nullable():
                 result = CGTemplatedType("Nullable", result)
@@ -4519,40 +4505,39 @@ def getRetvalDeclarationForType(returnTy
         return result, False, None, None
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
     return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
 
-def needCx(returnType, arguments, extendedAttributes, descriptorProvider,
-           considerTypes):
+def needCx(returnType, arguments, extendedAttributes, considerTypes):
     return (considerTypes and
-            (typeNeedsCx(returnType, descriptorProvider, True) or
-             any(typeNeedsCx(a.type, descriptorProvider) for a in arguments)) or
+            (typeNeedsCx(returnType, True) or
+             any(typeNeedsCx(a.type) for a in arguments)) or
             'implicitJSContext' in extendedAttributes)
 
 def needScopeObject(returnType, arguments, extendedAttributes,
-                    descriptorProvider, isWrapperCached, considerTypes):
+                    isWrapperCached, considerTypes):
     return (considerTypes and not isWrapperCached and
-            (typeNeedsScopeObject(returnType, descriptorProvider, True) or
-             any(typeNeedsScopeObject(a.type, descriptorProvider) for a in arguments)))
+            (typeNeedsScopeObject(returnType, True) or
+             any(typeNeedsScopeObject(a.type) 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.
     """
     def __init__(self, errorReport, arguments, argsPre, returnType,
                  extendedAttributes, descriptorProvider, nativeMethodName,
-                 static, object="self"):
+                 static, object="self", argsPost=[]):
         CGThing.__init__(self)
 
         assert errorReport is None or isinstance(errorReport, CGThing)
 
         isFallible = errorReport is not None
 
         resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
                                                         extendedAttributes)
@@ -4597,16 +4582,17 @@ class CGCallGenerator(CGThing):
                 arg = CGWrapper(arg, pre="NonNullHelper(", post=")")
             args.append(arg)
 
         # Return values that go in outparams go here
         if resultOutParam:
             args.append(CGGeneric("result"))
         if isFallible:
             args.append(CGGeneric("rv"))
+        args.extend(CGGeneric(arg) for arg in argsPost)
 
         # Build up our actual call
         self.cgRoot = CGList([], "\n")
 
         call = CGGeneric(nativeMethodName)
         if not static:
             call = CGWrapper(call, pre="%s->" % object)
         call = CGList([call, CGWrapper(args, pre="(", post=");")])
@@ -4815,31 +4801,32 @@ if (global.Failed()) {
 }
 """))
             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())
+                         not descriptor.interface.isJSImplemented())
         if needsCx and not (static and descriptor.workers):
             argsPre.append("cx")
 
         needsUnwrap = False
+        argsPost = []
         if isConstructor:
             needsUnwrap = True
             needsUnwrappedVar = False
             unwrappedVar = "obj"
         elif descriptor.interface.isJSImplemented():
             needsUnwrap = True
             needsUnwrappedVar = True
-            argsPre.append("js::GetObjectCompartment(unwrappedObj.empty() ? obj : unwrappedObj.ref())")
+            argsPost.append("js::GetObjectCompartment(unwrappedObj.empty() ? obj : unwrappedObj.ref())")
         elif needScopeObject(returnType, arguments, self.extendedAttributes,
-                             descriptor, descriptor.wrapperCache, True):
+                             descriptor.wrapperCache, True):
             needsUnwrap = True
             needsUnwrappedVar = True
             argsPre.append("unwrappedObj.empty() ? obj : unwrappedObj.ref()")
 
         if needsUnwrap and needsUnwrappedVar:
             # 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;"))
@@ -4902,17 +4889,17 @@ if (!${obj}) {
             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,
-                    static))
+                    static, argsPost=argsPost))
         self.cgRoot = CGList(cgThings, "\n")
 
     def getArguments(self):
         return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
 
     def isFallible(self):
         return not 'infallible' in self.extendedAttributes
 
@@ -6322,17 +6309,17 @@ class CGUnionStruct(CGThing):
                                                "m${name}").substitute(vars))
             enumValues.append("e" + vars["name"])
 
             toJSValCases.append(CGCase("e" + vars["name"],
                                        self.getConversionToJS(vars, t)))
             destructorCases.append(CGCase("e" + vars["name"],
                                           CGGeneric("Destroy%s();"
                                                      % vars["name"])))
-            if self.ownsMembers and typeNeedsRooting(t, self.descriptorProvider):
+            if self.ownsMembers and typeNeedsRooting(t):
                 if t.isObject():
                     traceCases.append(
                         CGCase("e" + vars["name"],
                                CGGeneric('JS_CallObjectTracer(trc, %s, "%s");' %
                                          ("&mValue.m" + vars["name"] + ".Value()",
                                           "mValue.m" + vars["name"]))))
                 else:
                     assert t.isSpiderMonkeyInterface()
@@ -8011,16 +7998,20 @@ class CGDescriptor(CGThing):
         if descriptor.concrete and not descriptor.proxy:
             if not descriptor.workers and descriptor.wrapperCache:
                 cgThings.append(CGAddPropertyHook(descriptor))
 
             # Always have a finalize hook, regardless of whether the class
             # wants a custom hook.
             cgThings.append(CGClassFinalizeHook(descriptor))
 
+            # Only generate a trace hook if the class wants a custom hook.
+            if (descriptor.customTrace):
+                cgThings.append(CGClassTraceHook(descriptor))
+
         properties = PropertyArrays(descriptor)
         cgThings.append(CGGeneric(define=str(properties)))
         cgThings.append(CGNativeProperties(descriptor, properties))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
         if not descriptor.workers and descriptor.concrete and descriptor.proxy:
             cgThings.append(CGResolveOwnProperty(descriptor))
@@ -8338,17 +8329,17 @@ if (""",
     def traceDictionaryMethod(self):
         body = ""
         if self.dictionary.parent:
             cls = self.makeClassName(self.dictionary.parent)
             body += "%s::TraceDictionary(trc);\n" % cls
 
         memberTraces = [self.getMemberTrace(m)
                         for m in self.dictionary.members
-                        if typeNeedsRooting(m.type, self.descriptorProvider)]
+                        if typeNeedsRooting(m.type)]
 
         body += "\n\n".join(memberTraces)
 
         return ClassMethod("TraceDictionary", "void", [
             Argument("JSTracer*", "trc"),
         ], body=body)
 
     def assignmentOperator(self):
@@ -8543,17 +8534,17 @@ if (""",
             post="\n} while(0);")
         if not member.defaultValue:
             # Only do the conversion if we have a value
             conversion = CGIfWrapper(conversion, "%s.WasPassed()" % memberLoc)
         return conversion
 
     def getMemberTrace(self, member):
         type = member.type;
-        assert typeNeedsRooting(type, self.descriptorProvider)
+        assert typeNeedsRooting(type)
         memberLoc = self.makeMemberName(member.identifier.name)
         if member.defaultValue:
             memberData = memberLoc
         else:
             # The data is inside the Optional<>
             memberData = "%s.Value()" % memberLoc
 
         memberName = "%s.%s" % (self.makeClassName(self.dictionary),
@@ -9192,20 +9183,20 @@ 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.passJSBitsAsNeeded):
+                  self.passJSBitsAsNeeded):
             args.insert(0, Argument("JSContext*", "cx"))
             if needScopeObject(returnType, argList, self.extendedAttrs,
-                               self.descriptorProvider, 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():
             args.insert(0, Argument("const GlobalObject&", "global"))
         return args
 
     def doGetArgType(self, type, optional, isMember):
@@ -9655,17 +9646,17 @@ class CGJSImplMember(CGNativeMember):
                                 passJSBitsAsNeeded=passJSBitsAsNeeded,
                                 visibility=visibility,
                                 jsObjectsArePtr=jsObjectsArePtr,
                                 variadicIsSequence=variadicIsSequence)
         self.body = self.getImpl()
 
     def getArgs(self, returnType, argList):
         args = CGNativeMember.getArgs(self, returnType, argList)
-        args.insert(0, Argument("JSCompartment*", "aCompartment"))
+        args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
         return args
 
 class CGJSImplMethod(CGJSImplMember):
     """
     Class for generating code for the methods for a JS-implemented WebIDL
     interface.
     """
     def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
@@ -9697,17 +9688,17 @@ class CGJSImplMethod(CGJSImplMember):
         if self.name != 'Constructor':
             raise TypeError("Named constructors are not supported for JS implemented WebIDL. See bug 851287.")
         if len(self.signature[1]) != 0:
             # The first two arguments to the constructor implementation are not
             # arguments to the WebIDL constructor, so don't pass them to __Init()
             assert args[0].argType == 'const GlobalObject&'
             assert args[1].argType == 'JSContext*'
             constructorArgs = [arg.name for arg in args[2:]]
-            constructorArgs.insert(0, "js::GetObjectCompartment(scopeObj)")
+            constructorArgs.append("js::GetObjectCompartment(scopeObj)")
             initCall = """
 // Wrap the object before calling __Init so that __DOM_IMPL__ is available.
 nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(window);
 JS::Rooted<JSObject*> scopeObj(cx, globalHolder->GetGlobalJSObject());
 JS::Rooted<JS::Value> wrappedVal(cx);
 if (!WrapNewBindingObject(cx, scopeObj, impl, &wrappedVal)) {
   MOZ_ASSERT(JS_IsExceptionPending(cx));
   aRv.Throw(NS_ERROR_UNEXPECTED);
@@ -10275,17 +10266,17 @@ class CallbackMember(CGNativeMember):
         return default
 
     def getArgs(self, returnType, argList):
         args = CGNativeMember.getArgs(self, returnType, argList)
         if not self.needThisHandling:
             # Since we don't need this handling, we're the actual method that
             # will be called, so we need an aRethrowExceptions argument.
             if self.rethrowContentException:
-                args.insert(0, Argument("JSCompartment*", "aCompartment"))
+                args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
             else:
                 args.append(Argument("ExceptionHandling", "aExceptionHandling",
                                      "eReportExceptions"))
             return args
         # We want to allow the caller to pass in a "this" object, as
         # well as a JSContext.
         return [Argument("JSContext*", "cx"),
                 Argument("JS::Handle<JSObject*>", "aThisObj")] + args
@@ -10765,18 +10756,17 @@ class CGEventGetter(CGNativeMember):
                         type)
 
     def getArgs(self, returnType, argList):
         args = [self.getArg(arg) for arg in argList]
         if returnType.isDOMString():
             args.append(Argument("nsString&", "aRetVal"))
         elif returnType.isByteString():
             args.append(Argument("nsCString&", "aRetVal"))
-        if needCx(returnType, argList, self.extendedAttrs,
-                  self.descriptorProvider, True):
+        if needCx(returnType, argList, self.extendedAttrs, True):
             args.insert(0, Argument("JSContext*", "aCx"))
         if not 'infallible' in self.extendedAttrs:
             raise TypeError("Event code generator does not support [Throws]!")
         return args
 
     def getMethodBody(self):
         type = self.member.type
         memberName = CGDictionary.makeMemberName(self.member.identifier.name)
@@ -10836,17 +10826,17 @@ class CGEventMethod(CGNativeMember):
         name = "a" + name[0].upper() + name[1:]
         return Argument(decl.define(), name)
 
     def declare(self, cgClass):
         self.args = list(self.originalArgs)
         self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
         constructorForNativeCaller = CGNativeMember.declare(self, cgClass) + "\n"
         self.args = list(self.originalArgs)
-        if needCx(None, self.descriptorProvider.interface.members, [], self.descriptorProvider, True):
+        if needCx(None, self.descriptorProvider.interface.members, [], True):
             self.args.insert(0, Argument("JSContext*", "aCx"))
         self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
         self.args.append(Argument('ErrorResult&', 'aRv'))
         return constructorForNativeCaller + CGNativeMember.declare(self, cgClass)
 
     def define(self, cgClass):
         self.args = list(self.originalArgs)
         members = ""
@@ -10881,17 +10871,17 @@ class CGEventMethod(CGNativeMember):
 
         self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
         constructorForNativeCaller = CGNativeMember.define(self, cgClass) + "\n"
         self.args = list(self.originalArgs)
         self.body = (
             "nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());\n"
             "return Constructor(owner, %s, %s);" % (self.args[0].name, self.args[1].name)
             )
-        if needCx(None, self.descriptorProvider.interface.members, [], self.descriptorProvider, True):
+        if needCx(None, self.descriptorProvider.interface.members, [], True):
             self.args.insert(0, Argument("JSContext*", "aCx"))
         self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
         self.args.append(Argument('ErrorResult&', 'aRv'))
         return constructorForNativeCaller + CGNativeMember.define(self, cgClass)
 
 class CGEventClass(CGBindingImplClass):
     """
     Codegen for the actual Event class implementation for this descriptor
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -349,16 +349,17 @@ class Descriptor(DescriptorProvider):
         if self.workers and desc.get('nativeOwnership', 'worker') == 'worker':
             self.nativeOwnership = "worker"
         else:
             self.nativeOwnership = desc.get('nativeOwnership', 'refcounted')
             if not self.nativeOwnership in ['owned', 'refcounted']:
                 raise TypeError("Descriptor for %s has unrecognized value (%s) "
                                 "for nativeOwnership" %
                                 (self.interface.identifier.name, self.nativeOwnership))
+        self.customTrace = desc.get('customTrace', self.workers)
         self.customFinalize = desc.get('customFinalize', self.workers)
         if desc.get('wantsQI', None) != None:
             self._wantsQI = desc.get('wantsQI', None)
         self.wrapperCache = (not self.interface.isCallback() and
                              (self.nativeOwnership == 'worker' or
                               (self.nativeOwnership != 'owned' and
                                desc.get('wrapperCache', True))))
 
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "mozilla/dom/PCrashReporterParent.h"
 #include "mozilla/dom/TabMessageUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsIFile.h"
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
+#include "nsDataHashtable.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 class ProcessReporter;
 
 class CrashReporterParent :
     public PCrashReporterParent
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -357,52 +357,49 @@ this.PushService = {
           // The most likely reason for a registration request timing out is
           // that the socket has disconnected. Best to reconnect.
           if (requestTimedOut) {
             this._shutdownWS();
             this._reconnectAfterBackoff();
           }
         }
         break;
-      case "webapps-uninstall":
-        debug("webapps-uninstall");
+      case "webapps-clear-data":
+        debug("webapps-clear-data");
 
-        let data;
-        try {
-          data = JSON.parse(aData);
-        } catch (ex) {
-          debug("webapps-uninstall: JSON parsing error: " + aData);
+        let data = aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
+        if (!data) {
+          debug("webapps-clear-data: Failed to get information about application");
           return;
         }
 
-        let manifestURL = data.manifestURL;
         let appsService = Cc["@mozilla.org/AppsService;1"]
                             .getService(Ci.nsIAppsService);
-        if (appsService.getAppLocalIdByManifestURL(manifestURL) ==
-            Ci.nsIScriptSecurityManager.NO_APP_ID) {
-          debug("webapps-uninstall: No app found " + manifestURL);
+        let manifestURL = appsService.getManifestURLByLocalId(data.appId);
+        if (!manifestURL) {
+          debug("webapps-clear-data: No manifest URL found for " + data.appId);
           return;
         }
 
         this._db.getAllByManifestURL(manifestURL, function(records) {
           debug("Got " + records.length);
           for (let i = 0; i < records.length; i++) {
             this._db.delete(records[i].channelID, null, function() {
-              debug("app uninstall: " + manifestURL +
+              debug("webapps-clear-data: " + manifestURL +
                     " Could not delete entry " + records[i].channelID);
             });
             // courtesy, but don't establish a connection
             // just for it
             if (this._ws) {
               debug("Had a connection, so telling the server");
-              this._sendRequest("unregister", {channelID: records[i].channelID});
+              this._send("unregister", {channelID: records[i].channelID});
             }
           }
         }.bind(this), function() {
-          debug("Error in getAllByManifestURL: url " + manifestURL);
+          debug("webapps-clear-data: Error in getAllByManifestURL(" + manifestURL + ")");
         });
 
         break;
     }
   },
 
   get _UAID() {
     return prefs.get("userAgentID");
@@ -457,17 +454,17 @@ this.PushService = {
 
     this._requestTimeout = prefs.get("requestTimeout");
 
     this._udpPort = prefs.get("udp.port");
 
     this._startListeningIfChannelsPresent();
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
-    Services.obs.addObserver(this, "webapps-uninstall", false);
+    Services.obs.addObserver(this, "webapps-clear-data", false);
 
     // On B2G the NetworkManager interface fires a network-active-changed
     // event.
     //
     // The "active network" is based on priority - i.e. Wi-Fi has higher
     // priority than data. The PushService should just use the preferred
     // network, and not care about all interface changes.
     // network-active-changed is not fired when the network goes offline, but
@@ -516,17 +513,17 @@ this.PushService = {
       return;
 
     debug("uninit()");
 
     prefs.ignore("debug", this);
     prefs.ignore("connection.enabled", this);
     prefs.ignore("serverURL", this);
     Services.obs.removeObserver(this, this._getNetworkStateChangeEventName());
-    Services.obs.removeObserver(this, "webapps-uninstall", false);
+    Services.obs.removeObserver(this, "webapps-clear-data", false);
     Services.obs.removeObserver(this, "xpcom-shutdown", false);
 
     if (this._db) {
       this._db.close();
       this._db = null;
     }
 
     if (this._udpServer) {
--- a/dom/src/offline/nsDOMOfflineResourceList.cpp
+++ b/dom/src/offline/nsDOMOfflineResourceList.cpp
@@ -798,19 +798,26 @@ nsDOMOfflineResourceList::CacheKeys()
 
   if (mCachedKeys)
     return NS_OK;
 
   nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetOwner());
   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
 
+  uint32_t appId = 0;
+  bool inBrowser = false;
+  if (loadContext) {
+    loadContext->GetAppId(&appId);
+    loadContext->GetIsInBrowserElement(&inBrowser);
+  }
+
   nsAutoCString groupID;
-  mApplicationCacheService->BuildGroupID(
-      mManifestURI, loadContext, groupID);
+  mApplicationCacheService->BuildGroupIDForApp(
+      mManifestURI, appId, inBrowser, groupID);
 
   nsCOMPtr<nsIApplicationCache> appCache;
   mApplicationCacheService->GetActiveCache(groupID,
                                            getter_AddRefs(appCache));
 
   if (!appCache) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
--- a/dom/tests/mochitest/ajax/offline/foreign2.html
+++ b/dom/tests/mochitest/ajax/offline/foreign2.html
@@ -9,17 +9,17 @@
 <script class="testbody" type="text/javascript">
 
 function manifestUpdated()
 {
   var appCacheService = SpecialPowers.Cc["@mozilla.org/network/application-cache-service;1"]
     .getService(SpecialPowers.Ci.nsIApplicationCacheService);
 
   var foreign2cache = appCacheService.chooseApplicationCache(
-    "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContext());
+    "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContextInfo());
 
   window.opener.OfflineTest.ok(foreign2cache, "Foreign 2 cache present, chosen for foreign2.html");
   window.opener.OfflineTest.is(foreign2cache.manifestURI.asciiSpec, "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest")
 
   var foreign1cache = OfflineTest.getActiveCache(
     "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest");
   window.opener.OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
   foreign1cache.discard();
@@ -36,17 +36,17 @@ function onLoaded()
     "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest");
   window.opener.OfflineTest.ok(foreign1cache, "Foreign 1 cache loaded");
 
   var foreign2cache = window.opener.OfflineTest.getActiveCache(
     "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.cacheManifest");
   window.opener.OfflineTest.ok(!foreign2cache, "Foreign 2 cache not present");
 
   foreign1cache = appCacheService.chooseApplicationCache(
-    "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", window.opener.OfflineTest.loadContext());
+    "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", window.opener.OfflineTest.loadContextInfo());
   window.opener.OfflineTest.ok(!foreign1cache, "foreign2.html not chosen from foreign1 cache");
 
   try
   {
     window.opener.OfflineTest.ok(applicationCache.status == SpecialPowers.Ci.nsIDOMOfflineResourceList.UNCACHED,
         "there is no associated application cache");
   }
   catch (ex)
--- a/dom/tests/mochitest/ajax/offline/offlineTests.js
+++ b/dom/tests/mochitest/ajax/offline/offlineTests.js
@@ -1,11 +1,13 @@
 // Utility functions for offline tests.
 var Cc = SpecialPowers.Cc;
 var Ci = SpecialPowers.Ci;
+var Cu = SpecialPowers.Cu;
+var LoadContextInfo = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {}).LoadContextInfo;
 
 const kNetBase = 2152398848; // 0x804B0000
 var NS_ERROR_CACHE_KEY_NOT_FOUND = kNetBase + 61;
 var NS_ERROR_CACHE_KEY_WAIT_FOR_VALIDATION = kNetBase + 64;
 
 // Reading the contents of multiple cache entries asynchronously
 function OfflineCacheContents(urls) {
   this.urls = urls;
@@ -330,23 +332,28 @@ manifestURL: function(overload)
 loadContext: function()
 {
   return SpecialPowers.wrap(window).QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
                                    .getInterface(SpecialPowers.Ci.nsIWebNavigation)
                                    .QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
                                    .getInterface(SpecialPowers.Ci.nsILoadContext);
 },
 
+loadContextInfo: function()
+{
+  return LoadContextInfo.fromLoadContext(this.loadContext(), false);
+},
+
 getActiveCache: function(overload)
 {
   // Note that this is the current active cache in the cache stack, not the
   // one associated with this window.
   var serv = Cc["@mozilla.org/network/application-cache-service;1"]
              .getService(Ci.nsIApplicationCacheService);
-  var groupID = serv.buildGroupID(this.manifestURL(overload), this.loadContext());
+  var groupID = serv.buildGroupID(this.manifestURL(overload), this.loadContextInfo());
   return serv.getActiveCache(groupID);
 },
 
 getActiveSession: function()
 {
   var cache = this.getActiveCache();
   if (!cache) {
     return null;
--- a/dom/tests/mochitest/ajax/offline/test_foreign.html
+++ b/dom/tests/mochitest/ajax/offline/test_foreign.html
@@ -22,17 +22,17 @@
 var win;
 
 function manifestUpdated()
 {
   var appCacheService = SpecialPowers.Cc["@mozilla.org/network/application-cache-service;1"]
     .getService(SpecialPowers.Ci.nsIApplicationCacheService);
 
   foreign1cache = appCacheService.chooseApplicationCache(
-    "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContext());
+    "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html", OfflineTest.loadContextInfo());
 
   OfflineTest.ok(foreign1cache, "foreign2.html chosen from foreign1 cache");
   OfflineTest.is(foreign1cache.manifestURI.asciiSpec, "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign1.cacheManifest")
 
   win = window.open("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/foreign2.html");
 }
 
 function onDone() // called by the open window after stuff is finished
--- a/dom/tests/mochitest/ajax/offline/test_offlineMode.html
+++ b/dom/tests/mochitest/ajax/offline/test_offlineMode.html
@@ -18,16 +18,23 @@
 
 var gImplicitWindow = null;
 var gCompleteTimeout = null;
 var gGotExplicitVersion = 0;
 var gGotImplicitVersion = 0;
 var gGotDynamicVersion = 0;
 var gGotOnError = false;
 
+function createURI(urispec)
+{
+  var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
+                         .getService(Components.interfaces.nsIIOService);
+  return ioServ.newURI(urispec, null, null);
+}
+
 // test
 
 function manifestUpdated()
 {
   applicationCache.mozAdd("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/notonwhitelist.html");
   OfflineTest.waitForAdd("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/notonwhitelist.html", dynamicAdded);
 }
 
@@ -107,22 +114,22 @@ function goOffline()
 {
   var listener = {
     onCacheEntryDoomed: function (status) {
       OfflineTest.priv(goOfflineContinue)();
     }
   };
 
   // Delete HTTP cache to ensure we are going from offline cache
-  var sessionServ = Cc["@mozilla.org/network/cache-service;1"]
-      .getService(Ci.nsICacheService);
-  cacheSession = sessionServ.createSession("HTTP", Ci.nsICache.STORE_ANYWHERE, Ci.nsICache.STREAM_BASED);
-  cacheSession.doomEntry("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/notonwhitelist.html", null);
-  cacheSession.doomEntry("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingIframe.sjs", null);
-  cacheSession.doomEntry("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html", listener);
+  var cache = Cc["@mozilla.org/network/cache-storage-service;1"]
+      .getService(Ci.nsICacheStorageService);
+  var storage = cache.diskCacheStorage(LoadContextInfo.default, false);
+  storage.asyncDoomURI(createURI("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/notonwhitelist.html"), "", null);
+  storage.asyncDoomURI(createURI("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingIframe.sjs"), "", null);
+  storage.asyncDoomURI(createURI("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html"), "", listener);
 }
 
 function goOfflineContinue()
 {
   var ioserv = Cc["@mozilla.org/network/io-service;1"]
       .getService(Ci.nsIIOService);
 
   ioserv.offline = true;
--- a/dom/tests/mochitest/bugs/iframe_bug440572.html
+++ b/dom/tests/mochitest/bugs/iframe_bug440572.html
@@ -1,16 +1,16 @@
 <html>
 <body>
 <script>
 
 var success = 0;
 
 try {
-  SpecialPowers.unwrap(SpecialPowers.wrap(parent)[name]).success = 1;
+  parent[name].success = 1;
 } catch (e) {
   parent.postMessage(e, "http://mochi.test:8888");
 }
 
 parent.postMessage(success ? "success" : "failure", "http://mochi.test:8888");
 </script>
 <p>Move on, nothing to see here...</p>
 </body>
--- a/dom/tests/mochitest/bugs/test_bug850517.html
+++ b/dom/tests/mochitest/bugs/test_bug850517.html
@@ -11,27 +11,28 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript">
 
   /** Test for live updating of named child resolution. **/
   SimpleTest.waitForExplicitFinish();
 
   function go() {
     var ifrA = $('a');
     var ifrB = $('b');
-    var sb = new SpecialPowers.Cu.Sandbox(SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal());
+    var sb = new SpecialPowers.Cu.Sandbox('http://www.example.com');
     sb.win = window;
     sb.childA = ifrA.contentWindow;
     sb.childB = ifrB.contentWindow;
     sb.is = is;
     sb.ok = ok;
     is(window.theoneandonly.frameElement, ifrA, "Named child resolution works");
     SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childA, "Named child resolution works via Xray");', sb);
     ifrA.removeAttribute('name');
     is(typeof window.theoneandonly, 'undefined', "Revocation works");
-    SpecialPowers.Cu.evalInSandbox('is(typeof win.theoneandonly, "undefined", "Revocation works via Xray");', sb);
+    SpecialPowers.Cu.evalInSandbox('try { win.theoneandonly; ok(false, "Should have thrown"); } ' +
+                                   'catch (e) {ok(!!/denied/.exec(e) && !!/theoneandonly/.exec(e), "Revocation works via Xray");};', sb);
     ifrB.setAttribute('name', 'theoneandonly');
     is(window.theoneandonly.frameElement, ifrB, "Another mule kicking in the same old stall");
     SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childB, "Another mule via Xray");', sb);
     SimpleTest.finish();
   }
 
   </script>
 </head>
--- a/dom/tests/mochitest/whatwg/postMessage_onOther.html
+++ b/dom/tests/mochitest/whatwg/postMessage_onOther.html
@@ -45,55 +45,52 @@
     //   http://test1.example.com
     //
     // and not
     //
     //   http://example.com
 
     function receiveSubDomain(evt)
     {
-      var topframe =
-        SpecialPowers.unwrap(SpecialPowers.wrap(window).parent.topDomainFrame);
       if (evt.origin !== "http://mochi.test:8888")
       {
         fail("wrong top-domain origin: " + evt.origin);
         return;
       }
       if (evt.data !== "start-test")
       {
         fail("wrong top-domain message: " + evt.origin);
         return;
       }
 
       document.domain = "example.com";
-      topframe.postMessage("domain-switch", "http://example.com");
+      window.parent.topDomainFrame.postMessage("domain-switch",
+                                               "http://example.com");
     }
     
     function receiveTopDomain(evt)
     {
-      var subframe =
-        SpecialPowers.unwrap(SpecialPowers.wrap(window).parent.subDomainFrame);
       if (evt.origin !== "http://test1.example.com")
       {
         fail("wrong subdomain origin: " + evt.origin);
         return;
       }
       if (evt.data !== "domain-switch")
       {
         fail("wrong subdomain message: " + evt.origin);
         return;
       }
-      if (evt.source !== subframe)
+      if (evt.source !== window.parent.subDomainFrame)
       {
         fail("wrong source on message from subdomain");
         return;
       }
 
       document.domain = "example.com";
-      subframe.testSiblingPostMessage();
+      window.parent.subDomainFrame.testSiblingPostMessage();
     }
 
     function testSiblingPostMessage()
     {
       window.parent.postMessage("test-finished", "http://mochi.test:8888");
     }
 
     function setup()
--- a/dom/workers/EventListenerManager.cpp
+++ b/dom/workers/EventListenerManager.cpp
@@ -382,17 +382,17 @@ EventListenerManager::DispatchEvent(JSCo
     // to the next listener rather than bailing out. If something fails and
     // does not set an exception then we bail out entirely as we've either run
     // out of memory or the operation callback has indicated that we should
     // stop running.
 
     JS::Rooted<JS::Value> listenerVal(aCx, listeners[index]);
 
     JS::Rooted<JSObject*> listenerObj(aCx);
-    if (!JS_ValueToObject(aCx, listenerVal, listenerObj.address())) {
+    if (!JS_ValueToObject(aCx, listenerVal, &listenerObj)) {
       if (!JS_ReportPendingException(aCx)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       continue;
     }
 
     static const char sHandleEventChars[] = "handleEvent";
--- a/dom/workers/EventTarget.cpp
+++ b/dom/workers/EventTarget.cpp
@@ -1,66 +1,79 @@
 /* -*- 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/. */
 
 #include "EventTarget.h"
 #include "mozilla/dom/EventListenerBinding.h"
+#include "mozilla/dom/EventHandlerBinding.h"
 
 USING_WORKERS_NAMESPACE
 using mozilla::ErrorResult;
 using mozilla::dom::EventListener;
 using mozilla::dom::Nullable;
+using mozilla::dom::EventHandlerNonNull;
 
 void
 EventTarget::_trace(JSTracer* aTrc)
 {
   mListenerManager._trace(aTrc);
   DOMBindingBase::_trace(aTrc);
 }
 
 void
 EventTarget::_finalize(JSFreeOp* aFop)
 {
   mListenerManager._finalize(aFop);
   DOMBindingBase::_finalize(aFop);
 }
 
-JSObject*
+already_AddRefed<EventHandlerNonNull>
 EventTarget::GetEventListener(const nsAString& aType, ErrorResult& aRv) const
 {
   JSContext* cx = GetJSContext();
 
   JS::RootedString type(cx,
     JS_NewUCStringCopyN(cx, aType.BeginReading(), aType.Length()));
   if (!type || !(type = JS_InternJSString(cx, type))) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return NULL;
+    return nullptr;
   }
 
-  return mListenerManager.GetEventListener(INTERNED_STRING_TO_JSID(cx, type));
+  JS::RootedObject listener(
+    cx, mListenerManager.GetEventListener(INTERNED_STRING_TO_JSID(cx, type)));
+  if (!listener) {
+    return nullptr;
+  }
+
+  nsRefPtr<EventHandlerNonNull> handler = new EventHandlerNonNull(listener);
+  return handler.forget();
 }
 
 void
 EventTarget::SetEventListener(const nsAString& aType,
-                              JS::Handle<JSObject*> aListener,
+                              EventHandlerNonNull* aListener,
                               ErrorResult& aRv)
 {
   JSContext* cx = GetJSContext();
 
   JS::RootedString type(cx,
     JS_NewUCStringCopyN(cx, aType.BeginReading(), aType.Length()));
   if (!type || !(type = JS_InternJSString(cx, type))) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
+  JS::RootedObject listener(cx);
+  if (aListener) {
+    listener = aListener->Callable();
+  }
   mListenerManager.SetEventListener(cx, INTERNED_STRING_TO_JSID(cx, type),
-                                    aListener, aRv);
+                                    listener, aRv);
 }
 
 void
 EventTarget::AddEventListener(const nsAString& aType,
                               EventListener* aListener,
                               bool aCapturing, Nullable<bool> aWantsUntrusted,
                               ErrorResult& aRv)
 {
--- a/dom/workers/EventTarget.h
+++ b/dom/workers/EventTarget.h
@@ -12,16 +12,17 @@
 #include "mozilla/dom/workers/bindings/EventListenerManager.h"
 
 #include "mozilla/dom/Nullable.h"
 #include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 class EventListener;
+class EventHandlerNonNull;
 } // namespace mozilla
 } // namespace dom
 
 BEGIN_WORKERS_NAMESPACE
 
 class EventTarget : public DOMBindingBase
 {
   EventListenerManager mListenerManager;
@@ -51,36 +52,37 @@ public:
                       bool aCapture, ErrorResult& aRv);
 
   bool
   DispatchEvent(JS::Handle<JSObject*> aEvent, ErrorResult& aRv) const
   {
     return mListenerManager.DispatchEvent(GetJSContext(), *this, aEvent, aRv);
   }
 
-  JSObject*
+  already_AddRefed<EventHandlerNonNull>
   GetEventListener(const nsAString& aType, ErrorResult& aRv) const;
 
   void
-  SetEventListener(const nsAString& aType, JS::Handle<JSObject*> aListener,
+  SetEventListener(const nsAString& aType, EventHandlerNonNull* aListener,
                    ErrorResult& aRv);
 
   bool
   HasListeners() const
   {
     return mListenerManager.HasListeners();
   }
 
-  void SetEventHandler(JSContext*, const nsAString& aType, JSObject* aHandler,
+  void SetEventHandler(const nsAString& aType, EventHandlerNonNull* aHandler,
                        ErrorResult& rv)
   {
     rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
   }
 
-  JSObject* GetEventHandler(JSContext*, const nsAString& aType)
+  EventHandlerNonNull*
+  GetEventHandler(const nsAString& aType)
   {
     return nullptr;
   }
 
   JSObject* GetOwnerGlobal() const
   {
     // We have no windows
     return nullptr;
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -693,17 +693,17 @@ ContentSecurityPolicyAllows(JSContext* a
 {
   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
   worker->AssertIsOnWorkerThread();
 
   if (worker->GetReportCSPViolations()) {
     nsString fileName;
     uint32_t lineNum = 0;
 
-    JSScript* script;
+    JS::RootedScript script(aCx);
     const char* file;
     if (JS_DescribeScriptedCaller(aCx, &script, &lineNum) &&
         (file = JS_GetScriptFilename(aCx, script))) {
       fileName.AssignASCII(file);
     } else {
       JS_ReportPendingException(aCx);
     }
 
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -2,16 +2,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/. */
 
 #include "Worker.h"
 
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/EventHandlerBinding.h"
 
 #include "jsapi.h"
 #include "EventTarget.h"
 #include "RuntimeService.h"
 #include "WorkerPrivate.h"
 
 #include "WorkerInlines.h"
 
@@ -174,24 +175,29 @@ private:
                    const nsAString &aNameStr)
   {
     WorkerPrivate* worker =
       GetInstancePrivate(aCx, &aArgs.thisv().toObject(),
                          NS_ConvertUTF16toUTF8(aNameStr).get());
     MOZ_ASSERT(worker);
 
     ErrorResult rv;
-    JS::Rooted<JSObject*> listener(aCx, worker->GetEventListener(Substring(aNameStr, 2), rv));
+    nsRefPtr<EventHandlerNonNull> handler =
+      worker->GetEventListener(Substring(aNameStr, 2), rv);
 
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to get listener!");
       return false;
     }
 
-    aArgs.rval().setObjectOrNull(listener);
+    if (!handler) {
+      aArgs.rval().setNull();
+    } else {
+      aArgs.rval().setObject(*handler->Callable());
+    }
     return true;
   }
 
   static bool
   GetOnerrorImpl(JSContext* aCx, JS::CallArgs aArgs)
   {
     return GetEventListener(aCx, aArgs, NS_LITERAL_STRING("onerror"));
   }
@@ -221,22 +227,28 @@ private:
                    const nsAString& aNameStr)
   {
     WorkerPrivate* worker =
       GetInstancePrivate(aCx, &aArgs.thisv().toObject(),
                          NS_ConvertUTF16toUTF8(aNameStr).get());
     MOZ_ASSERT(worker);
 
     JS::Rooted<JSObject*> listener(aCx);
-    if (!JS_ValueToObject(aCx, aArgs.get(0), listener.address())) {
+    if (!JS_ValueToObject(aCx, aArgs.get(0), &listener)) {
       return false;
     }
 
+    nsRefPtr<EventHandlerNonNull> handler;
+    if (listener && JS_ObjectIsCallable(aCx, listener)) {
+      handler = new EventHandlerNonNull(listener);
+    } else {
+      handler = nullptr;
+    }
     ErrorResult rv;
-    worker->SetEventListener(Substring(aNameStr, 2), listener, rv);
+    worker->SetEventListener(Substring(aNameStr, 2), handler, rv);
 
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to set listener!");
       return false;
     }
 
     aArgs.rval().setUndefined();
     return true;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2682,17 +2682,17 @@ WorkerPrivate::Create(JSContext* aCx, JS
     else {
       // Not a window
       NS_ASSERTION(isChrome, "Should be chrome only!");
 
       parentContext = nullptr;
 
       // We're being created outside of a window. Need to figure out the script
       // that is creating us in order for us to use relative URIs later on.
-      JSScript *script;
+      JS::RootedScript script(aCx);
       if (JS_DescribeScriptedCaller(aCx, &script, nullptr)) {
         if (NS_FAILED(NS_NewURI(getter_AddRefs(baseURI),
                                 JS_GetScriptFilename(aCx, script)))) {
           JS_ReportError(aCx, "Failed to construct base URI!");
           return nullptr;
         }
       }
 
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -6,16 +6,17 @@
 
 #include "WorkerScope.h"
 
 #include "jsapi.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/EventBinding.h"
+#include "mozilla/dom/EventHandlerBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMExceptionBinding.h"
 #include "mozilla/dom/FileReaderSyncBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
@@ -158,26 +159,29 @@ private:
   static bool
   GetOnCloseImpl(JSContext* aCx, JS::CallArgs aArgs)
   {
     const char* name = sEventStrings[STRING_onclose];
     WorkerGlobalScope* scope = GetInstancePrivate(aCx, &aArgs.thisv().toObject(), name);
     MOZ_ASSERT(scope);
 
     ErrorResult rv;
-
-    JSObject* listener =
+    nsRefPtr<EventHandlerNonNull> handler =
       scope->GetEventListener(NS_ConvertASCIItoUTF16(name + 2), rv);
 
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to get event listener!");
       return false;
     }
 
-    aArgs.rval().setObjectOrNull(listener);
+    if (!handler) {
+      aArgs.rval().setNull();
+    } else {
+      aArgs.rval().setObject(*handler->Callable());
+    }
     return true;
   }
 
   static bool
   GetOnClose(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   {
     JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
     return JS::CallNonGenericMethod<IsWorkerGlobalScope, GetOnCloseImpl>(aCx, args);
@@ -186,25 +190,31 @@ private:
   static bool
   SetOnCloseImpl(JSContext* aCx, JS::CallArgs aArgs)
   {
     const char* name = sEventStrings[STRING_onclose];
     WorkerGlobalScope* scope =
       GetInstancePrivate(aCx, &aArgs.thisv().toObject(), name);
     MOZ_ASSERT(scope);
 
-    if (aArgs.length() == 0 || !aArgs[0].isObject()) {
+    if (aArgs.length() == 0 || !aArgs[0].isObjectOrNull()) {
       JS_ReportError(aCx, "Not an event listener!");
       return false;
     }
 
     ErrorResult rv;
-    JS::Rooted<JSObject*> listenerObj(aCx, &aArgs[0].toObject());
+    JS::Rooted<JSObject*> listenerObj(aCx, aArgs[0].toObjectOrNull());
+    nsRefPtr<EventHandlerNonNull> handler;
+    if (listenerObj && JS_ObjectIsCallable(aCx, listenerObj)) {
+      handler = new EventHandlerNonNull(listenerObj);
+    } else {
+      handler = nullptr;
+    }
     scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2),
-                            listenerObj, rv);
+                            handler, rv);
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to set event listener!");
       return false;
     }
 
     aArgs.rval().setUndefined();
     return true;
   }
@@ -314,31 +324,31 @@ private:
   static bool
   GetOnErrorListenerImpl(JSContext* aCx, JS::CallArgs aArgs)
   {
     const char* name = sEventStrings[STRING_onerror];
     WorkerGlobalScope* scope = GetInstancePrivate(aCx, &aArgs.thisv().toObject(), name);
     MOZ_ASSERT(scope);
 
     ErrorResult rv;
-
-    JSObject* adaptor =
+    nsRefPtr<EventHandlerNonNull> adaptor =
       scope->GetEventListener(NS_ConvertASCIItoUTF16(name + 2), rv);
 
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to get event listener!");
       return false;
     }
 
     if (!adaptor) {
       aArgs.rval().setNull();
       return true;
     }
 
-    aArgs.rval().set(js::GetFunctionNativeReserved(adaptor, SLOT_wrappedFunction));
+    aArgs.rval().set(js::GetFunctionNativeReserved(adaptor->Callable(),
+                                                   SLOT_wrappedFunction));
     MOZ_ASSERT(aArgs.rval().isObject());
     return true;
   }
 
   static bool
   GetOnErrorListener(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   {
     JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
@@ -370,18 +380,18 @@ private:
       return false;
     }
 
     js::SetFunctionNativeReserved(listener, SLOT_wrappedScope,
                                   JS::ObjectValue(*obj));
     js::SetFunctionNativeReserved(listener, SLOT_wrappedFunction, aArgs[0]);
 
     ErrorResult rv;
-
-    scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2), listener, rv);
+    nsRefPtr<EventHandlerNonNull> handler = new EventHandlerNonNull(listener);
+    scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2), handler, rv);
 
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to set event listener!");
       return false;
     }
 
     aArgs.rval().setUndefined();
     return true;
@@ -782,26 +792,29 @@ private:
   GetOnMessageImpl(JSContext* aCx, JS::CallArgs aArgs)
   {
     const char* name = sEventStrings[STRING_onmessage];
     DedicatedWorkerGlobalScope* scope =
       GetInstancePrivate(aCx, &aArgs.thisv().toObject(), name);
     MOZ_ASSERT(scope);
 
     ErrorResult rv;
-
-    JSObject* listener =
+    nsRefPtr<EventHandlerNonNull> handler =
       scope->GetEventListener(NS_ConvertASCIItoUTF16(name + 2), rv);
 
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to get event listener!");
       return false;
     }
 
-    aArgs.rval().setObjectOrNull(listener);
+    if (!handler) {
+      aArgs.rval().setNull();
+    } else {
+      aArgs.rval().setObject(*handler->Callable());
+    }
     return true;
   }
 
   static bool
   GetOnMessage(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   {
     JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
     return JS::CallNonGenericMethod<IsDedicatedWorkerGlobalScope, GetOnMessageImpl>(aCx, args);
@@ -810,26 +823,32 @@ private:
   static bool
   SetOnMessageImpl(JSContext* aCx, JS::CallArgs aArgs)
   {
     const char* name = sEventStrings[STRING_onmessage];
     DedicatedWorkerGlobalScope* scope =
       GetInstancePrivate(aCx, &aArgs.thisv().toObject(), name);
     MOZ_ASSERT(scope);
 
-    if (aArgs.length() == 0 || !aArgs[0].isObject()) {
+    if (aArgs.length() == 0 || !aArgs[0].isObjectOrNull()) {
       JS_ReportError(aCx, "Not an event listener!");
       return false;
     }
 
     ErrorResult rv;
 
-    JS::Rooted<JSObject*> listenerObj(aCx, &aArgs[0].toObject());
+    JS::Rooted<JSObject*> listenerObj(aCx, aArgs[0].toObjectOrNull());
+    nsRefPtr<EventHandlerNonNull> handler;
+    if (listenerObj && JS_ObjectIsCallable(aCx, listenerObj)) {
+      handler = new EventHandlerNonNull(listenerObj);
+    } else {
+      handler = nullptr;
+    }
     scope->SetEventListener(NS_ConvertASCIItoUTF16(name + 2),
-                            listenerObj, rv);
+                            handler, rv);
 
     if (rv.Failed()) {
       JS_ReportError(aCx, "Failed to set event listener!");
       return false;
     }
 
     aArgs.rval().setUndefined();
     return true;
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -94,25 +94,24 @@ public:
 
   void
   Unpin();
 
   bool
   Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
 
 #define IMPL_GETTER_AND_SETTER(_type)                                          \
-  JSObject*                                                                    \
-  GetOn##_type(JSContext* /* unused */, ErrorResult& aRv)                      \
+  already_AddRefed<EventHandlerNonNull>                                        \
+  GetOn##_type(ErrorResult& aRv)                                               \
   {                                                                            \
     return GetEventListener(NS_LITERAL_STRING(#_type), aRv);                   \
   }                                                                            \
                                                                                \
   void                                                                         \
-  SetOn##_type(JSContext* /* unused */,  JS::Handle<JSObject*> aListener,      \
-               ErrorResult& aRv)                                               \
+  SetOn##_type(EventHandlerNonNull* aListener,  ErrorResult& aRv)              \
   {                                                                            \
     SetEventListener(NS_LITERAL_STRING(#_type), aListener, aRv);               \
   }
 
   IMPL_GETTER_AND_SETTER(readystatechange)
 
 #undef IMPL_GETTER_AND_SETTER
 
--- a/dom/workers/XMLHttpRequestEventTarget.h
+++ b/dom/workers/XMLHttpRequestEventTarget.h
@@ -23,25 +23,24 @@ protected:
 public:
   virtual void
   _trace(JSTracer* aTrc) MOZ_OVERRIDE;
 
   virtual void
   _finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
 
 #define IMPL_GETTER_AND_SETTER(_type)                                          \
-  JSObject*                                                                    \
-  GetOn##_type(JSContext* /* unused */, ErrorResult& aRv)                      \
+  already_AddRefed<EventHandlerNonNull>                                        \
+  GetOn##_type(ErrorResult& aRv)                                               \
   {                                                                            \
     return GetEventListener(NS_LITERAL_STRING(#_type), aRv);                   \
   }                                                                            \
                                                                                \
   void                                                                         \
-  SetOn##_type(JSContext* /* unused */, JS::Handle<JSObject*> aListener,       \
-               ErrorResult& aRv)                                               \
+  SetOn##_type(EventHandlerNonNull* aListener,  ErrorResult& aRv)              \
   {                                                                            \
     SetEventListener(NS_LITERAL_STRING(#_type), aListener, aRv);               \
   }
 
   IMPL_GETTER_AND_SETTER(loadstart)
   IMPL_GETTER_AND_SETTER(progress)
   IMPL_GETTER_AND_SETTER(abort)
   IMPL_GETTER_AND_SETTER(error)
--- a/gfx/2d/QuartzSupport.h
+++ b/gfx/2d/QuartzSupport.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsCoreAnimationSupport_h__
 #define nsCoreAnimationSupport_h__
 #ifdef XP_MACOSX
 
 #import <OpenGL/OpenGL.h>
+#import <OpenGL/gl.h>
 #import "ApplicationServices/ApplicationServices.h"
 #include "gfxTypes.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/gfx/MacIOSurface.h"
 #include "nsError.h"
 
 // Get the system color space.
 CGColorSpaceRef CreateSystemColorSpace();
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -231,14 +231,16 @@ pixman-dither.patch: Add dithering of 16
 quartz-support-color-emoji-font.patch: support Apple Color Emoji font in cairo-quartz backend
 
 use-show-text-glyphs-if-glyph-path-fails.patch: fall back to show_text_glyphs even at huge sizes if scaled_font_glyph_path didn't work
 
 pixman-enable-altivec-acceleration.patch: enable building the altivec acceleration
 
 win32-d3dsurface9.patch: Create a win32 d3d9 surface to support LockRect
 
+win32-avoid-extend-pad-fallback: Avoid falling back to pixman when using EXTEND_PAD
+
 ==== disable printing patch ====
 
 disable-printing.patch:  allows us to use NS_PRINTING to disable printing.
 
 ==== cairo clamp bounday patch ====
 cairo-clamp-boundary.patch: don't call pixman_fill with negative starts or negative sizes
--- a/gfx/cairo/cairo/src/cairo-win32-surface.c
+++ b/gfx/cairo/cairo/src/cairo-win32-surface.c
@@ -1114,17 +1114,17 @@ static cairo_int_status_t
     cairo_win32_surface_t *dst = abstract_dst;
     cairo_win32_surface_t *src;
     cairo_surface_pattern_t *src_surface_pattern;
     int alpha;
     double scalex, scaley;
     cairo_fixed_t x0_fixed, y0_fixed;
     cairo_int_status_t status;
 
-    cairo_bool_t needs_alpha, needs_scale, needs_repeat;
+    cairo_bool_t needs_alpha, needs_scale, needs_repeat, needs_pad;
     cairo_image_surface_t *src_image = NULL;
 
     cairo_format_t src_format;
     cairo_rectangle_int_t src_extents;
 
     cairo_rectangle_int_t src_r = { src_x, src_y, width, height };
     cairo_rectangle_int_t dst_r = { dst_x, dst_y, width, height };
 
@@ -1145,17 +1145,18 @@ static cairo_int_status_t
     {
 	goto UNSUPPORTED;
     }
 
     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
 	goto UNSUPPORTED;
 
     if (pattern->extend != CAIRO_EXTEND_NONE &&
-	pattern->extend != CAIRO_EXTEND_REPEAT)
+	pattern->extend != CAIRO_EXTEND_REPEAT &&
+	pattern->extend != CAIRO_EXTEND_PAD)
 	goto UNSUPPORTED;
 
     if (mask_pattern) {
 	/* FIXME: When we fully support RENDER style 4-channel
 	 * masks we need to check r/g/b != 1.0.
 	 */
 	if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1252,16 +1253,17 @@ static cairo_int_status_t
 
     /* If the src rectangle doesn't wholly lie within the src extents,
      * fudge things.  We really need to do fixup on the unpainted
      * region -- e.g. the SOURCE operator is broken for areas outside
      * of the extents, because it won't clear that area to transparent
      * black.
      */
 
+    needs_pad = FALSE;
     if (pattern->extend != CAIRO_EXTEND_REPEAT) {
 	needs_repeat = FALSE;
 
 	/* If the src rect and the extents of the source image don't overlap at all,
 	 * we can't do anything useful here.
 	 */
 	if (src_r.x > src_extents.width || src_r.y > src_extents.height ||
 	    (src_r.x + src_r.width) < 0 || (src_r.y + src_r.height) < 0)
@@ -1273,40 +1275,48 @@ static cairo_int_status_t
 
 	if (src_r.x < 0) {
 	    src_r.width += src_r.x;
 
 	    dst_r.width += src_r.x;
 	    dst_r.x -= src_r.x;
 
             src_r.x = 0;
+            needs_pad = TRUE;
 	}
 
 	if (src_r.y < 0) {
 	    src_r.height += src_r.y;
 
 	    dst_r.height += src_r.y;
 	    dst_r.y -= src_r.y;
 	    
             src_r.y = 0;
+            needs_pad = TRUE;
 	}
 
 	if (src_r.x + src_r.width > src_extents.width) {
 	    src_r.width = src_extents.width - src_r.x;
 	    dst_r.width = src_r.width;
+            needs_pad = TRUE;
 	}
 
 	if (src_r.y + src_r.height > src_extents.height) {
 	    src_r.height = src_extents.height - src_r.y;
 	    dst_r.height = src_r.height;
+            needs_pad = TRUE;
 	}
     } else {
 	needs_repeat = TRUE;
     }
 
+    if (pattern->extend == CAIRO_EXTEND_PAD && needs_pad) {
+        goto UNSUPPORTED;
+    }
+
     /*
      * Operations that we can do:
      *
      * AlphaBlend uses the following formula for alpha when not use the per-pixel alpha (AlphaFormat = 0)
      *   Dst.Alpha = Src.Alpha * (SCA/255.0) + Dst.Alpha * (1.0 - (SCA/255.0))
      * This turns into Dst.Alpha = Src.Alpha when SCA = 255.
      * (http://msdn.microsoft.com/en-us/library/aa921335.aspx)
      *
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/win32-avoid-extend-pad-fallback.patch
@@ -0,0 +1,109 @@
+diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c
+--- a/gfx/cairo/cairo/src/cairo-win32-surface.c
++++ b/gfx/cairo/cairo/src/cairo-win32-surface.c
+@@ -1114,17 +1114,17 @@ static cairo_int_status_t
+     cairo_win32_surface_t *dst = abstract_dst;
+     cairo_win32_surface_t *src;
+     cairo_surface_pattern_t *src_surface_pattern;
+     int alpha;
+     double scalex, scaley;
+     cairo_fixed_t x0_fixed, y0_fixed;
+     cairo_int_status_t status;
+ 
+-    cairo_bool_t needs_alpha, needs_scale, needs_repeat;
++    cairo_bool_t needs_alpha, needs_scale, needs_repeat, needs_pad;
+     cairo_image_surface_t *src_image = NULL;
+ 
+     cairo_format_t src_format;
+     cairo_rectangle_int_t src_extents;
+ 
+     cairo_rectangle_int_t src_r = { src_x, src_y, width, height };
+     cairo_rectangle_int_t dst_r = { dst_x, dst_y, width, height };
+ 
+@@ -1145,17 +1145,18 @@ static cairo_int_status_t
+     {
+ 	goto UNSUPPORTED;
+     }
+ 
+     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+ 	goto UNSUPPORTED;
+ 
+     if (pattern->extend != CAIRO_EXTEND_NONE &&
+-	pattern->extend != CAIRO_EXTEND_REPEAT)
++	pattern->extend != CAIRO_EXTEND_REPEAT &&
++	pattern->extend != CAIRO_EXTEND_PAD)
+ 	goto UNSUPPORTED;
+ 
+     if (mask_pattern) {
+ 	/* FIXME: When we fully support RENDER style 4-channel
+ 	 * masks we need to check r/g/b != 1.0.
+ 	 */
+ 	if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
+ 	    return CAIRO_INT_STATUS_UNSUPPORTED;
+@@ -1252,16 +1253,17 @@ static cairo_int_status_t
+ 
+     /* If the src rectangle doesn't wholly lie within the src extents,
+      * fudge things.  We really need to do fixup on the unpainted
+      * region -- e.g. the SOURCE operator is broken for areas outside
+      * of the extents, because it won't clear that area to transparent
+      * black.
+      */
+ 
++    needs_pad = FALSE;
+     if (pattern->extend != CAIRO_EXTEND_REPEAT) {
+ 	needs_repeat = FALSE;
+ 
+ 	/* If the src rect and the extents of the source image don't overlap at all,
+ 	 * we can't do anything useful here.
+ 	 */
+ 	if (src_r.x > src_extents.width || src_r.y > src_extents.height ||
+ 	    (src_r.x + src_r.width) < 0 || (src_r.y + src_r.height) < 0)
+@@ -1273,40 +1275,48 @@ static cairo_int_status_t
+ 
+ 	if (src_r.x < 0) {
+ 	    src_r.width += src_r.x;
+ 
+ 	    dst_r.width += src_r.x;
+ 	    dst_r.x -= src_r.x;
+ 
+             src_r.x = 0;
++            needs_pad = TRUE;
+ 	}
+ 
+ 	if (src_r.y < 0) {
+ 	    src_r.height += src_r.y;
+ 
+ 	    dst_r.height += src_r.y;
+ 	    dst_r.y -= src_r.y;
+ 	    
+             src_r.y = 0;
++            needs_pad = TRUE;
+ 	}
+ 
+ 	if (src_r.x + src_r.width > src_extents.width) {
+ 	    src_r.width = src_extents.width - src_r.x;
+ 	    dst_r.width = src_r.width;
++            needs_pad = TRUE;
+ 	}
+ 
+ 	if (src_r.y + src_r.height > src_extents.height) {
+ 	    src_r.height = src_extents.height - src_r.y;
+ 	    dst_r.height = src_r.height;
++            needs_pad = TRUE;
+ 	}
+     } else {
+ 	needs_repeat = TRUE;
+     }
+ 
++    if (pattern->extend == CAIRO_EXTEND_PAD && needs_pad) {
++        goto UNSUPPORTED;
++    }
++
+     /*
+      * Operations that we can do:
+      *
+      * AlphaBlend uses the following formula for alpha when not use the per-pixel alpha (AlphaFormat = 0)
+      *   Dst.Alpha = Src.Alpha * (SCA/255.0) + Dst.Alpha * (1.0 - (SCA/255.0))
+      * This turns into Dst.Alpha = Src.Alpha when SCA = 255.
+      * (http://msdn.microsoft.com/en-us/library/aa921335.aspx)
+      *
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -170,19 +170,19 @@ public:
     mTarget->SetMatrix(mTransform);
   }
 
   // Set the opaque rect to match the bounds of the visible region.
   void AnnotateOpaqueRect()
   {
     const nsIntRegion& visibleRegion = mLayer->GetEffectiveVisibleRegion();
     const nsIntRect& bounds = visibleRegion.GetBounds();
-    nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
 
     if (mTarget->IsCairo()) {
+      nsRefPtr<gfxASurface> currentSurface = mTarget->CurrentSurface();
       const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
 
       // Try to annotate currentSurface with a region of pixels that have been
       // (or will be) painted opaque, if no such region is currently set.
       if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
           (mLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
           !mTransform.HasNonAxisAlignedTransform()) {
         currentSurface->SetOpaqueRect(
@@ -317,25 +317,27 @@ BasicLayerManager::PushGroupWithCachedSu
   return ctx.forget();
 }
 
 void
 BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed)
 {
   if (!aTarget)
     return;
-  nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
-  if (aTarget->IsCairo() && mCachedSurface.IsSurface(current)) {
-    gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
-    aTarget->IdentityMatrix();
-    aTarget->SetSource(current);
-    mCachedSurfaceInUse = false;
-  } else {
-    aTarget->PopGroupToSource();
+  if (aTarget->IsCairo()) {
+    nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
+    if (mCachedSurface.IsSurface(current)) {
+      gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
+      aTarget->IdentityMatrix();
+      aTarget->SetSource(current);
+      mCachedSurfaceInUse = false;
+      return;
+    }
   }
+  aTarget->PopGroupToSource();
 }
 
 void
 BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
 {
   mInTransaction = true;
 
 #ifdef MOZ_LAYERS_HAVE_LOG
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -82,17 +82,16 @@ BasicThebesLayer::PaintThebes(gfxContext
                               Layer* aMaskLayer,
                               LayerManager::DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               ReadbackProcessor* aReadback)
 {
   PROFILER_LABEL("BasicThebesLayer", "PaintThebes");
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
-  nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface();
 
   if (!mContentClient) {
     // we pass a null pointer for the Forwarder argument, which means
     // this will not have a ContentHost on the other side.
     mContentClient = new ContentClientBasic(nullptr, BasicManager());
   }
 
   nsTArray<ReadbackProcessor::Update> readbackUpdates;
--- a/gfx/thebes/gfxDrawable.cpp
+++ b/gfx/thebes/gfxDrawable.cpp
@@ -129,16 +129,22 @@ gfxSurfaceDrawable::Draw(gfxContext* aCo
     pattern->SetMatrix(gfxMatrix(aTransform).Multiply(mTransform));
     aContext->NewPath();
     aContext->SetPattern(pattern);
     aContext->Rectangle(aFillRect);
     aContext->Fill();
     return true;
 }
 
+already_AddRefed<gfxImageSurface>
+gfxSurfaceDrawable::GetAsImageSurface()
+{
+    return mSurface->GetAsImageSurface();
+}
+
 gfxCallbackDrawable::gfxCallbackDrawable(gfxDrawingCallback* aCallback,
                                          const gfxIntSize aSize)
  : gfxDrawable(aSize)
  , mCallback(aCallback)
 {
 }
 
 already_AddRefed<gfxSurfaceDrawable>
--- a/gfx/thebes/gfxDrawable.h
+++ b/gfx/thebes/gfxDrawable.h
@@ -10,16 +10,17 @@
 #include "nsAutoPtr.h"
 #include "gfxTypes.h"
 #include "gfxRect.h"
 #include "gfxColor.h"
 #include "gfxMatrix.h"
 #include "gfxPattern.h"
 
 class gfxASurface;
+class gfxImageSurface;
 class gfxContext;
 
 /**
  * gfxDrawable
  * An Interface representing something that has an intrinsic size and can draw
  * itself repeatedly.
  */
 class gfxDrawable {
@@ -36,16 +37,17 @@ public:
      * pattern prior to rendering it.
      *  @return whether drawing was successful
      */
     virtual bool Draw(gfxContext* aContext,
                         const gfxRect& aFillRect,
                         bool aRepeat,
                         const gfxPattern::GraphicsFilter& aFilter,
                         const gfxMatrix& aTransform = gfxMatrix()) = 0;
+    virtual already_AddRefed<gfxImageSurface> GetAsImageSurface() { return nullptr; }
     virtual gfxIntSize Size() { return mSize; }
 
 protected:
     const gfxIntSize mSize;
 };
 
 /**
  * gfxSurfaceDrawable
@@ -57,16 +59,18 @@ public:
                        const gfxMatrix aTransform = gfxMatrix());
     virtual ~gfxSurfaceDrawable() {}
 
     virtual bool Draw(gfxContext* aContext,
                         const gfxRect& aFillRect,
                         bool aRepeat,
                         const gfxPattern::GraphicsFilter& aFilter,
                         const gfxMatrix& aTransform = gfxMatrix());
+    
+    virtual already_AddRefed<gfxImageSurface> GetAsImageSurface();
 
 protected:
     nsRefPtr<gfxASurface> mSurface;
     const gfxMatrix mTransform;
 };
 
 /**
  * gfxDrawingCallback
--- a/gfx/thebes/gfxImageSurface.cpp
+++ b/gfx/thebes/gfxImageSurface.cpp
@@ -292,31 +292,42 @@ gfxImageSurface::CopyFrom(gfxImageSurfac
     return true;
 }
 
 already_AddRefed<gfxSubimageSurface>
 gfxImageSurface::GetSubimage(const gfxRect& aRect)
 {
     gfxRect r(aRect);
     r.Round();
+    MOZ_ASSERT(gfxRect(0, 0, mSize.width, mSize.height).Contains(r));
+
+    gfxImageFormat format = Format();
+
     unsigned char* subData = Data() +
         (Stride() * (int)r.Y()) +
         (int)r.X() * gfxASurface::BytePerPixelFromFormat(Format());
 
+    if (format == ImageFormatARGB32 &&
+        GetOpaqueRect().Contains(aRect)) {
+        format = ImageFormatRGB24;
+    }
+
     nsRefPtr<gfxSubimageSurface> image =
         new gfxSubimageSurface(this, subData,
-                               gfxIntSize((int)r.Width(), (int)r.Height()));
+                               gfxIntSize((int)r.Width(), (int)r.Height()),
+                               format);
 
     return image.forget();
 }
 
 gfxSubimageSurface::gfxSubimageSurface(gfxImageSurface* aParent,
                                        unsigned char* aData,
-                                       const gfxIntSize& aSize)
-  : gfxImageSurface(aData, aSize, aParent->Stride(), aParent->Format())
+                                       const gfxIntSize& aSize,
+                                       gfxImageFormat aFormat)
+  : gfxImageSurface(aData, aSize, aParent->Stride(), aFormat)
   , mParent(aParent)
 {
 }
 
 already_AddRefed<gfxImageSurface>
 gfxImageSurface::GetAsImageSurface()
 {
   nsRefPtr<gfxImageSurface> surface = this;
--- a/gfx/thebes/gfxImageSurface.h
+++ b/gfx/thebes/gfxImageSurface.h
@@ -144,14 +144,15 @@ protected:
     long mStride;
 };
 
 class gfxSubimageSurface : public gfxImageSurface {
 protected:
     friend class gfxImageSurface;
     gfxSubimageSurface(gfxImageSurface* aParent,
                        unsigned char* aData,
-                       const gfxIntSize& aSize);
+                       const gfxIntSize& aSize,
+                       gfxImageFormat aFormat);
 private:
     nsRefPtr<gfxImageSurface> mParent;
 };
 
 #endif /* GFX_IMAGESURFACE_H */
--- a/gfx/thebes/gfxQPainterSurface.cpp
+++ b/gfx/thebes/gfxQPainterSurface.cpp
@@ -67,11 +67,12 @@ gfxQPainterSurface::GetAsImageSurface()
 
     cairo_surface_t *isurf = cairo_qt_surface_get_image(CairoSurface());
     if (!isurf)
         return nullptr;
 
     assert(cairo_surface_get_type(isurf) == CAIRO_SURFACE_TYPE_IMAGE);
 
     nsRefPtr<gfxImageSurface> asurf = new gfxImageSurface(isurf);
+    asurf->SetOpaqueRect(GetOpaqueRect());
     return asurf.forget();
 }
 #endif
--- a/gfx/thebes/gfxQuartzImageSurface.cpp
+++ b/gfx/thebes/gfxQuartzImageSurface.cpp
@@ -62,10 +62,13 @@ gfxQuartzImageSurface::GetAsImageSurface
         return nullptr;
 
     cairo_surface_t *isurf = cairo_quartz_image_surface_get_image (CairoSurface());
     if (!isurf) {
         NS_WARNING ("Couldn't obtain an image surface from a QuartzImageSurface?!");
         return nullptr;
     }
 
-    return gfxASurface::Wrap(isurf).downcast<gfxImageSurface>();
+    nsRefPtr<gfxImageSurface> result = gfxASurface::Wrap(isurf).downcast<gfxImageSurface>();
+    result->SetOpaqueRect(GetOpaqueRect());
+
+    return result.forget();
 }
--- a/gfx/thebes/gfxQuartzSurface.cpp
+++ b/gfx/thebes/gfxQuartzSurface.cpp
@@ -189,15 +189,17 @@ already_AddRefed<gfxImageSurface> gfxQua
     nsRefPtr<gfxASurface> img = Wrap(surface);
 
     // cairo_quartz_surface_get_image returns a referenced image, and thebes
     // shares the refcounts of Cairo surfaces. However, Wrap also adds a
     // reference to the image. We need to remove one of these references
     // explicitly so we don't leak.
     img->Release();
 
+    img->SetOpaqueRect(GetOpaqueRect());
+
     return img.forget().downcast<gfxImageSurface>();
 }
 
 gfxQuartzSurface::~gfxQuartzSurface()
 {
     CGContextRelease(mCGContext);
 }
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -240,26 +240,33 @@ CreateSamplingRestrictedDrawable(gfxDraw
 
     // if 'needed' is empty, nothing will be drawn since aFill
     // must be entirely outside the clip region, so it doesn't
     // matter what we do here, but we should avoid trying to
     // create a zero-size surface.
     if (needed.IsEmpty())
         return nullptr;
 
+    nsRefPtr<gfxASurface> temp;
     gfxIntSize size(int32_t(needed.Width()), int32_t(needed.Height()));
-    nsRefPtr<gfxASurface> temp =
-        gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::ContentFromFormat(aFormat));
-    if (!temp || temp->CairoStatus())
-        return nullptr;
 
-    nsRefPtr<gfxContext> tmpCtx = new gfxContext(temp);
-    tmpCtx->SetOperator(OptimalFillOperator());
-    aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true,
-                    gfxPattern::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft()));
+    nsRefPtr<gfxImageSurface> image = aDrawable->GetAsImageSurface();
+    if (image && gfxRect(0, 0, image->GetSize().width, image->GetSize().height).Contains(needed)) {
+      temp = image->GetSubimage(needed);
+    } else {
+      temp =
+          gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::ContentFromFormat(aFormat));
+      if (!temp || temp->CairoStatus())
+          return nullptr;
+
+      nsRefPtr<gfxContext> tmpCtx = new gfxContext(temp);
+      tmpCtx->SetOperator(OptimalFillOperator());
+      aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true,
+                      gfxPattern::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft()));
+    }
 
     nsRefPtr<gfxDrawable> drawable = 
         new gfxSurfaceDrawable(temp, size, gfxMatrix().Translate(-needed.TopLeft()));
     return drawable.forget();
 }
 #endif // !MOZ_GFX_OPTIMIZE_MOBILE
 
 // working around cairo/pixman bug (bug 364968)
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -501,17 +501,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/gfxWindowsSurface.cpp
+++ b/gfx/thebes/gfxWindowsSurface.cpp
@@ -188,17 +188,20 @@ gfxWindowsSurface::GetAsImageSurface()
 
     if (mForPrinting)
         return nullptr;
 
     cairo_surface_t *isurf = cairo_win32_surface_get_image(CairoSurface());
     if (!isurf)
         return nullptr;
 
-	return gfxASurface::Wrap(isurf).downcast<gfxImageSurface>();
+    nsRefPtr<gfxImageSurface> result = gfxASurface::Wrap(isurf).downcast<gfxImageSurface>();
+    result->SetOpaqueRect(GetOpaqueRect());
+
+    return result.forget();
 }
 
 already_AddRefed<gfxWindowsSurface>
 gfxWindowsSurface::OptimizeToDDB(HDC dc, const gfxIntSize& size, gfxImageFormat format)
 {
     if (mForPrinting)
         return nullptr;
 
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -809,16 +809,17 @@ bool imgFrame::ImageComplete() const
 // after Optimize() is called, though in all cases it will be just a
 // performance win -- the pixels are still correct and have the A byte
 // set to 0xff.
 void imgFrame::SetHasNoAlpha()
 {
   if (mFormat == gfxASurface::ImageFormatARGB32) {
       mFormat = gfxASurface::ImageFormatRGB24;
       mFormatChanged = true;
+      ThebesSurface()->SetOpaqueRect(gfxRect(0, 0, mSize.width, mSize.height));
   }
 }
 
 void imgFrame::SetAsNonPremult(bool aIsNonPremult)
 {
   mNonPremult = aIsNonPremult;
 }
 
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -21,17 +21,17 @@
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsMimeTypes.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIScriptSecurityManager.h"
 
-#include "nsICacheVisitor.h"
+#include "nsICacheEntry.h"
 
 #include "plstr.h" // PL_strcasestr(...)
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 #include "imgIRequest.h"
 
 using namespace mozilla;
 using namespace mozilla::image;
@@ -334,17 +334,17 @@ void imgRequest::SetCacheValidation(imgC
 {
   /* get the expires info */
   if (aCacheEntry) {
     nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aRequest));
     if (cacheChannel) {
       nsCOMPtr<nsISupports> cacheToken;
       cacheChannel->GetCacheToken(getter_AddRefs(cacheToken));
       if (cacheToken) {
-        nsCOMPtr<nsICacheEntryInfo> entryDesc(do_QueryInterface(cacheToken));
+        nsCOMPtr<nsICacheEntry> entryDesc(do_QueryInterface(cacheToken));
         if (entryDesc) {
           uint32_t expiration;
           /* get the expiration time from the caching channel's token */
           entryDesc->GetExpirationTime(&expiration);
 
           // Expiration time defaults to 0. We set the expiration time on our
           // entry if it hasn't been set yet.
           if (aCacheEntry->GetExpiryTime() == 0)
--- a/image/test/unit/test_private_channel.js
+++ b/image/test/unit/test_private_channel.js
@@ -93,18 +93,19 @@ function run_loadImage_tests() {
             server.stop(do_test_finished);
           });
         });
       });
     });
   }
 
   Services.obs.addObserver(observer, "cacheservice:empty-cache", false);
-  let cs = Cc["@mozilla.org/network/cache-service;1"].getService(Ci.nsICacheService);
-  cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+  let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+             .getService(Ci.nsICacheStorageService);
+  cs.clear();
 }
 
 function cleanup()
 {
   for (var i = 0; i < requests.length; ++i) {
     requests[i].cancelAndForgetObserver(0);
   }
 }
--- a/js/jsd/jsd_val.cpp
+++ b/js/jsd/jsd_val.cpp
@@ -567,17 +567,18 @@ jsd_GetValueFunction(JSDContext* jsdc, J
     JS::RootedObject obj(cx);
     JS::RootedFunction fun(cx);
 
     if (JSVAL_IS_PRIMITIVE(jsdval->val))
         return nullptr;
 
     obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val));
     JSAutoCompartment ac(cx, obj);
-    fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj));
+    JS::RootedValue funval(cx, JS::ObjectValue(*obj));
+    fun = JS_ValueToFunction(cx, funval);
 
     return fun;
 }
 
 JSDValue*
 jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
 {
     AutoSafeJSContext cx;
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -201,17 +201,17 @@ endif
 
 INSTALL_TARGETS += jsconfig
 jsconfig_FILES = $(export_files)
 jsconfig_DEST = $(DIST)/include
 jsconfig_TARGET := export
 
 .PHONY: buildffi buildicu
 buildffi buildicu:
-compile:: buildffi buildicu
+$(if $(MOZ_PSEUDO_DERECURSE),compile,export):: buildffi buildicu
 
 include $(topsrcdir)/config/rules.mk
 
 ifdef JS_HAS_CTYPES
 ifndef MOZ_NATIVE_FFI
 buildffi:
 		$(call SUBMAKE,,ctypes/libffi)
 
@@ -293,21 +293,28 @@ ifeq ($(MOZ_DEBUG),1)
 endif
 
 ifdef MOZ_VALGRIND
 ifndef MOZ_ASAN
 JITTEST_VALGRIND_FLAG = --valgrind
 endif
 endif
 
+ifdef MOZ_ASAN
+ifneq ($(LLVM_SYMBOLIZER),)
+# Use the LLVM symbolizer when running jit-tests under ASan, if available
+JITTEST_ASAN_ENV=ASAN_SYMBOLIZER_PATH='$(LLVM_SYMBOLIZER)'
+endif
+endif
+
 check-style::
 	(cd $(srcdir) && $(PYTHON) config/check_spidermonkey_style.py);
 
 check-jit-test::
-	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
+	$(JITTEST_ASAN_ENV) $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
 	        --no-slow --no-progress --tinderbox --tbpl $(JITTEST_VALGRIND_FLAG) \
 	        $(DIST)/bin/$(JS_SHELL_NAME)$(BIN_SUFFIX)
 
 check:: check-style check-jit-test
 
 # jstests doesn't have a --jitflags option, so we need to loop, updating the
 # exit code (RC) after each invocation.
 # FIXME: MethodJIT doesn't work for 1 test case (bug 644393), so
--- a/js/src/build/autoconf/config.status.m4
+++ b/js/src/build/autoconf/config.status.m4
@@ -176,8 +176,10 @@ changequote([, ])
 chmod +x $CONFIG_STATUS
 rm -fr confdefs* $ac_clean_files
 dnl Execute config.status, unless --no-create was passed to configure.
 if test "$no_create" != yes && ! ${PYTHON} $CONFIG_STATUS; then
     trap '' EXIT
     exit 1
 fi
 ])
+
+AC_SUBST([MOZ_PSEUDO_DERECURSE])
--- a/js/src/build/autoconf/python-virtualenv.m4
+++ b/js/src/build/autoconf/python-virtualenv.m4
@@ -19,17 +19,17 @@ fi
 
 _virtualenv_topsrcdir=
 _virtualenv_populate_path=
 
 dnl If this is a mozilla-central, we'll find the virtualenv in the top
 dnl source directory. If this is a SpiderMonkey build, we assume we're at
 dnl js/src and try to find the virtualenv from the mozilla-central root.
 for base in $MOZILLA_CENTRAL_PATH $_topsrcdir $_topsrcdir/../..; do
-  possible=$base/build/virtualenv/populate_virtualenv.py
+  possible=$base/python/mozbuild/mozbuild/virtualenv.py
 
   if test -e $possible; then
     _virtualenv_topsrcdir=$base
     _virtualenv_populate_path=$possible
     break
   fi
 done
 
@@ -48,17 +48,18 @@ mozilla-central and relaunch configure.]
 fi
 
 if test -z $DONT_POPULATE_VIRTUALENV; then
   AC_MSG_RESULT([Creating Python environment])
   dnl This verifies our Python version is sane and ensures the Python
   dnl virtualenv is present and up to date. It sanitizes the environment
   dnl for us, so we don't need to clean anything out.
   $PYTHON $_virtualenv_populate_path \
-    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv || exit 1
+    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv \
+    $_virtualenv_topsrcdir/build/virtualenv_packages.txt || exit 1
 
   case "$host_os" in
   mingw*)
     PYTHON=`cd $MOZ_BUILD_ROOT && pwd -W`/_virtualenv/Scripts/python.exe
     ;;
   *)
     PYTHON=$MOZ_BUILD_ROOT/_virtualenv/bin/python
     ;;
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -432,19 +432,19 @@ function DefaultLocale() {
     var locale = RuntimeDefaultLocale();
     if (!IsStructurallyValidLanguageTag(locale))
         return localeOfLastResort;
 
     locale = CanonicalizeLanguageTag(locale);
     if (callFunction(std_Object_hasOwnProperty, oldStyleLanguageTagMappings, locale))
         locale = oldStyleLanguageTagMappings[locale];
 
-    if (!(collatorInternalProperties.availableLocales[locale] &&
-          numberFormatInternalProperties.availableLocales[locale] &&
-          dateTimeFormatInternalProperties.availableLocales[locale]))
+    if (!(collatorInternalProperties.availableLocales()[locale] &&
+          numberFormatInternalProperties.availableLocales()[locale] &&
+          dateTimeFormatInternalProperties.availableLocales()[locale]))
     {
         locale = localeOfLastResort;
     }
     return locale;
 }
 
 
 /**
@@ -1036,17 +1036,17 @@ function InitializeCollator(collator, lo
         }
     }
 
     // Compute effective locale.
     // Step 14.
     var relevantExtensionKeys = Collator.relevantExtensionKeys;
 
     // Step 15.
-    var r = ResolveLocale(Collator.availableLocales,
+    var r = ResolveLocale(Collator.availableLocales(),
                           requestedLocales, opt,
                           relevantExtensionKeys,
                           localeData);
     // Step 16.
     internals.locale = r.locale;
 
     // Steps 17-19.
     var i = 0, len = relevantExtensionKeys.length;
@@ -1109,31 +1109,39 @@ function InitializeCollator(collator, lo
  * matching (possibly fallback) locale. Locales appear in the same order in the
  * returned list as in the input list.
  *
  * Spec: ECMAScript Internationalization API Specification, 10.2.2.
  */
 function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
     var options = arguments.length > 1 ? arguments[1] : undefined;
 
-    var availableLocales = collatorInternalProperties.availableLocales;
+    var availableLocales = collatorInternalProperties.availableLocales();
     var requestedLocales = CanonicalizeLocaleList(locales);
     return SupportedLocales(availableLocales, requestedLocales, options);
 }
 
 
 /**
  * Collator internal properties.
  *
  * Spec: ECMAScript Internationalization API Specification, 9.1 and 10.2.3.
  */
 var collatorInternalProperties = {
     sortLocaleData: collatorSortLocaleData,
     searchLocaleData: collatorSearchLocaleData,
-    availableLocales: addOldStyleLanguageTags(intl_Collator_availableLocales()),
+    _availableLocales: null,
+    availableLocales: function()
+    {
+        var locales = this._availableLocales;
+        if (locales)
+            return locales;
+        return (this._availableLocales =
+          addOldStyleLanguageTags(intl_Collator_availableLocales()));
+    },
     relevantExtensionKeys: ["co", "kn"]
 };
 
 
 function collatorSortLocaleData(locale) {
     var collations = intl_availableCollations(locale);
     callFunction(std_Array_unshift, collations, null);
     return {
@@ -1262,17 +1270,17 @@ function InitializeNumberFormat(numberFo
     // Compute effective locale.
     // Step 9.
     var NumberFormat = numberFormatInternalProperties;
 
     // Step 10.
     var localeData = NumberFormat.localeData;
 
     // Step 11.
-    var r = ResolveLocale(NumberFormat.availableLocales,
+    var r = ResolveLocale(NumberFormat.availableLocales(),
                           requestedLocales, opt,
                           NumberFormat.relevantExtensionKeys,
                           localeData);
 
     // Steps 12-14.
     internals.locale = r.locale;
     internals.numberingSystem = r.nu;
     var dataLocale = r.dataLocale;
@@ -1405,30 +1413,38 @@ function CurrencyDigits(currency) {
  * matching (possibly fallback) locale. Locales appear in the same order in the
  * returned list as in the input list.
  *
  * Spec: ECMAScript Internationalization API Specification, 11.2.2.
  */
 function Intl_NumberFormat_supportedLocalesOf(locales /*, options*/) {
     var options = arguments.length > 1 ? arguments[1] : undefined;
 
-    var availableLocales = numberFormatInternalProperties.availableLocales;
+    var availableLocales = numberFormatInternalProperties.availableLocales();
     var requestedLocales = CanonicalizeLocaleList(locales);
     return SupportedLocales(availableLocales, requestedLocales, options);
 }
 
 
 /**
  * NumberFormat internal properties.
  *
  * Spec: ECMAScript Internationalization API Specification, 9.1 and 11.2.3.
  */
 var numberFormatInternalProperties = {
     localeData: numberFormatLocaleData,
-    availableLocales: addOldStyleLanguageTags(intl_NumberFormat_availableLocales()),
+    _availableLocales: null,
+    availableLocales: function()
+    {
+        var locales = this._availableLocales;
+        if (locales)
+            return locales;
+        return (this._availableLocales =
+          addOldStyleLanguageTags(intl_NumberFormat_availableLocales()));
+    },
     relevantExtensionKeys: ["nu"]
 };
 
 
 function getNumberingSystems(locale) {
     // ICU doesn't have an API to determine the set of numbering systems
     // supported for a locale; it generally pretends that any numbering system
     // can be used with any locale. Supporting a decimal numbering system
@@ -1591,17 +1607,17 @@ function InitializeDateTimeFormat(dateTi
     // Compute effective locale.
     // Step 8.
     var DateTimeFormat = dateTimeFormatInternalProperties;
 
     // Step 9.
     var localeData = DateTimeFormat.localeData;
 
     // Step 10.
-    var r = ResolveLocale(DateTimeFormat.availableLocales,
+    var r = ResolveLocale(DateTimeFormat.availableLocales(),
                           requestedLocales, opt,
                           DateTimeFormat.relevantExtensionKeys,
                           localeData);
 
     // Steps 11-13.
     internals.locale = r.locale;
     internals.calendar = r.ca;
     internals.numberingSystem = r.nu;
@@ -2001,30 +2017,38 @@ function BestFitFormatMatcher(options, f
  * matching (possibly fallback) locale. Locales appear in the same order in the
  * returned list as in the input list.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.2.2.
  */
 function Intl_DateTimeFormat_supportedLocalesOf(locales /*, options*/) {
     var options = arguments.length > 1 ? arguments[1] : undefined;
 
-    var availableLocales = dateTimeFormatInternalProperties.availableLocales;
+    var availableLocales = dateTimeFormatInternalProperties.availableLocales();
     var requestedLocales = CanonicalizeLocaleList(locales);
     return SupportedLocales(availableLocales, requestedLocales, options);
 }
 
 
 /**
  * DateTimeFormat internal properties.
  *
  * Spec: ECMAScript Internationalization API Specification, 9.1 and 12.2.3.
  */
 var dateTimeFormatInternalProperties = {
     localeData: dateTimeFormatLocaleData,
-    availableLocales: addOldStyleLanguageTags(intl_DateTimeFormat_availableLocales()),
+    _availableLocales: null,
+    availableLocales: function()
+    {
+        var locales = this._availableLocales;
+        if (locales)
+            return locales;
+        return (this._availableLocales =
+          addOldStyleLanguageTags(intl_DateTimeFormat_availableLocales()));
+    },
     relevantExtensionKeys: ["ca", "nu"]
 };
 
 
 function dateTimeFormatLocaleData(locale) {
     return {
         ca: intl_availableCalendars(locale),
         nu: getNumberingSystems(locale)
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -255,17 +255,17 @@ StructTypeRepresentation::init(JSContext
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Interning
 
 JSObject *
 TypeRepresentation::addToTableOrFree(JSContext *cx,
-                                     TypeRepresentationSet::AddPtr &p)
+                                     TypeRepresentationHash::AddPtr &p)
 {
     JS_ASSERT(!ownerObject_);
 
     JSCompartment *comp = cx->compartment();
 
     if (!comp->typeReprs.add(p, this)) {
         js_ReportOutOfMemory(cx);
         js_free(this); // do not finalize, not present in the table
@@ -293,17 +293,17 @@ TypeRepresentation::addToTableOrFree(JSC
 /*static*/
 JSObject *
 ScalarTypeRepresentation::Create(JSContext *cx,
                                  ScalarTypeRepresentation::Type type)
 {
     JSCompartment *comp = cx->compartment();
 
     ScalarTypeRepresentation sample(type);
-    TypeRepresentationSet::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
+    TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
     if (p)
         return (*p)->ownerObject();
 
     // Note: cannot use cx->new_ because constructor is private.
     ScalarTypeRepresentation *ptr =
         (ScalarTypeRepresentation *) cx->malloc_(
             sizeof(ScalarTypeRepresentation));
     if (!ptr)
@@ -327,17 +327,17 @@ ArrayTypeRepresentation::Create(JSContex
     int32_t temp;
     if (!SafeMul(element->size(), length, &temp)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_TYPEDOBJECT_TOO_BIG);
         return NULL;
     }
 
     ArrayTypeRepresentation sample(element, length);
-    TypeRepresentationSet::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
+    TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
     if (p)
         return (*p)->ownerObject();
 
     // Note: cannot use cx->new_ because constructor is private.
     ArrayTypeRepresentation *ptr =
         (ArrayTypeRepresentation *) cx->malloc_(
             sizeof(ArrayTypeRepresentation));
     if (!ptr)
@@ -359,17 +359,17 @@ StructTypeRepresentation::Create(JSConte
     // Note: cannot use cx->new_ because constructor is private.
     size_t size = sizeof(StructTypeRepresentation) + count * sizeof(StructField);
     StructTypeRepresentation *ptr =
         (StructTypeRepresentation *) cx->malloc_(size);
     new(ptr) StructTypeRepresentation();
     if (!ptr->init(cx, ids, typeReprOwners))
         return NULL;
 
-    TypeRepresentationSet::AddPtr p = comp->typeReprs.lookupForAdd(ptr);
+    TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(ptr);
     if (p) {
         js_free(ptr); // do not finalize, not present in the table
         return (*p)->ownerObject();
     }
 
     return ptr->addToTableOrFree(cx, p);
 }
 
@@ -535,20 +535,20 @@ StructTypeRepresentation::appendStringSt
 
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Misc
 
 const StructField *
-StructTypeRepresentation::fieldNamed(HandleId id) const
+StructTypeRepresentation::fieldNamed(jsid id) const
 {
     for (size_t i = 0; i < fieldCount(); i++) {
-        if (field(i).id.get() == id.get())
+        if (field(i).id.get() == id)
             return &field(i);
     }
     return NULL;
 }
 
 /*static*/ bool
 TypeRepresentation::isTypeRepresentationOwnerObject(JSObject *obj)
 {
--- a/js/src/builtin/TypeRepresentation.h
+++ b/js/src/builtin/TypeRepresentation.h
@@ -80,34 +80,34 @@ struct TypeRepresentationHasher
     static bool matchStructs(StructTypeRepresentation *key1,
                              StructTypeRepresentation *key2);
     static bool matchArrays(ArrayTypeRepresentation *key1,
                             ArrayTypeRepresentation *key2);
 };
 
 typedef js::HashSet<TypeRepresentation *,
                     TypeRepresentationHasher,
-                    RuntimeAllocPolicy> TypeRepresentationSet;
+                    RuntimeAllocPolicy> TypeRepresentationHash;
 
 class TypeRepresentation {
   public:
     enum Kind {
         Scalar,
         Struct,
         Array
     };
 
   protected:
     TypeRepresentation(Kind kind, size_t size, size_t align);
 
     size_t size_;
     size_t alignment_;
     Kind kind_;
 
-    JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationSet::AddPtr &p);
+    JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationHash::AddPtr &p);
 
   private:
     static const Class class_;
     static void obj_trace(JSTracer *trace, JSObject *object);
     static void obj_finalize(js::FreeOp *fop, JSObject *object);
 
     js::HeapPtrObject ownerObject_;
     void traceFields(JSTracer *tracer);
@@ -285,17 +285,17 @@ class StructTypeRepresentation : public 
         return fieldCount_;
     }
 
     const StructField &field(size_t i) const {
         JS_ASSERT(i < fieldCount());
         return fields()[i];
     }
 
-    const StructField *fieldNamed(HandleId id) const;
+    const StructField *fieldNamed(jsid id) const;
 
     static JSObject *Create(JSContext *cx,
                             AutoIdVector &ids,
                             AutoObjectVector &typeReprOwners);
 };
 
 } // namespace js
 
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -969,25 +969,25 @@ ArrayType::create(JSContext *cx, HandleO
     SetFunctionNativeReserved(fillFun, 0, ObjectValue(*obj));
 
     return obj;
 }
 
 bool
 ArrayType::construct(JSContext *cx, unsigned argc, Value *vp)
 {
-    if (!JS_IsConstructing(cx, vp)) {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (!args.isConstructing()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_NOT_FUNCTION, "ArrayType");
         return false;
     }
 
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    if (argc != 2 ||
+    if (args.length() != 2 ||
         !args[0].isObject() ||
         !args[1].isNumber() ||
         args[1].toNumber() < 0)
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS);
         return false;
     }
@@ -1241,25 +1241,25 @@ StructType::create(JSContext *cx, Handle
         return NULL;
 
     return obj;
 }
 
 bool
 StructType::construct(JSContext *cx, unsigned int argc, Value *vp)
 {
-    if (!JS_IsConstructing(cx, vp)) {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (!args.isConstructing()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_NOT_FUNCTION, "StructType");
         return false;
     }
 
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    if (argc >= 1 && args[0].isObject()) {
+    if (args.length() >= 1 && args[0].isObject()) {
         RootedObject structTypeGlobal(cx, &args.callee());
         RootedObject fields(cx, &args[0].toObject());
         RootedObject obj(cx, create(cx, structTypeGlobal, fields));
         if (!obj)
             return false;
         args.rval().setObject(*obj);
         return true;
     }
@@ -2361,8 +2361,15 @@ BinaryBlock::obj_enumerate(JSContext *cx
             statep.setNull();
             break;
         }
         break;
     }
 
     return true;
 }
+
+/* static */ size_t
+BinaryBlock::dataOffset()
+{
+    return JSObject::getPrivateDataOffset(BLOCK_RESERVED_SLOTS + 1);
+}
+
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -192,16 +192,20 @@ class BinaryBlock
                                     bool *succeeded);
 
     static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
                                 MutableHandleValue statep, MutableHandleId idp);
 
   public:
     static const Class class_;
 
+    // Returns the offset in bytes within the object where the `void*`
+    // pointer can be found.
+    static size_t dataOffset();
+
     static bool isBlock(HandleObject val);
     static uint8_t *mem(HandleObject val);
 
     // creates zeroed memory of size of type
     static JSObject *createZeroed(JSContext *cx, HandleObject type);
 
     // creates a block that aliases the memory owned by `owner` at the
     // given offset
--- a/js/src/config/recurse.mk
+++ b/js/src/config/recurse.mk
@@ -1,25 +1,123 @@
 # 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 INCLUDED_RULES_MK
 include $(topsrcdir)/config/rules.mk
 endif
 
+# The traditional model of directory traversal with make is as follows:
+#   make -C foo
+#     Entering foo
+#     make -C bar
+#       Entering foo/bar
+#     make -C baz
+#       Entering foo/baz
+#   make -C qux
+#     Entering qux
+#
+# Pseudo derecurse transforms the above into:
+#   make -C foo
+#   make -C foo/bar
+#   make -C foo/baz
+#   make -C qux
+
+# MOZ_PSEUDO_DERECURSE can have values other than 1.
+ifeq (1_.,$(if $(MOZ_PSEUDO_DERECURSE),1)_$(DEPTH))
+
+include root.mk
+
+# Disable build status for mach in top directories without TIERS.
+# In practice this disables it when recursing under js/src, which confuses mach.
+ifndef TIERS
+BUILDSTATUS =
+endif
+
+# Main rules (export, compile, libs and tools) call recurse_* rules.
+# This wrapping is only really useful for build status.
+compile libs export tools::
+	$(call BUILDSTATUS,TIER_START $@ $($@_subtiers))
+	+$(MAKE) recurse_$@
+	$(call BUILDSTATUS,TIER_FINISH $@)
+
+# Carefully avoid $(eval) type of rule generation, which makes pymake slower
+# than necessary.
+# Get current tier and corresponding subtiers from the data in root.mk.
+CURRENT_TIER := $(filter $(foreach tier,compile libs export tools,recurse_$(tier)),$(MAKECMDGOALS))
+ifneq (,$(filter-out 0 1,$(words $(CURRENT_TIER))))
+$(error $(CURRENT_TIER) not supported on the same make command line)
+endif
+CURRENT_TIER := $(subst recurse_,,$(CURRENT_TIER))
+CURRENT_SUBTIERS := $($(CURRENT_TIER)_subtiers)
+
+# The rules here are doing directory traversal, so we don't want further
+# recursion to happen when running make -C subdir $tier. But some make files
+# further call make -C something else, and sometimes expect recursion to
+# happen in that case (see browser/metro/locales/Makefile.in for example).
+# Conveniently, every invocation of make increases MAKELEVEL, so only stop
+# recursion from happening at current MAKELEVEL + 1.
+ifdef CURRENT_TIER
+ifeq (0,$(MAKELEVEL))
+export NO_RECURSE_MAKELEVEL=1
+else
+export NO_RECURSE_MAKELEVEL=$(word $(MAKELEVEL),2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20)
+endif
+endif
+
+# Get all directories traversed for all subtiers in the current tier, or use
+# directly the $(*_dirs) variables available in root.mk when there is no
+# TIERS (like for js/src).
+CURRENT_DIRS := $(or $($(CURRENT_TIER)_dirs),$(foreach subtier,$(CURRENT_SUBTIERS),$($(CURRENT_TIER)_subtier_$(subtier))))
+
+# Subtier delimiter rules
+$(addprefix subtiers/,$(addsuffix _start/$(CURRENT_TIER),$(CURRENT_SUBTIERS))): subtiers/%_start/$(CURRENT_TIER):
+	$(call BUILDSTATUS,SUBTIER_START $(CURRENT_TIER) $* $(if $(BUG_915535_FIXED),$($(CURRENT_TIER)_subtier_$*)))
+
+$(addprefix subtiers/,$(addsuffix _finish/$(CURRENT_TIER),$(CURRENT_SUBTIERS))): subtiers/%_finish/$(CURRENT_TIER):
+	$(call BUILDSTATUS,SUBTIER_FINISH $(CURRENT_TIER) $*)
+
+# Recursion rule for all directories traversed for all subtiers in the
+# current tier.
+# root.mk defines subtier_of_* variables, that map a normalized subdir path to
+# a subtier name (e.g. subtier_of_memory_jemalloc = base)
+$(addsuffix /$(CURRENT_TIER),$(CURRENT_DIRS)): %/$(CURRENT_TIER):
+ifdef BUG_915535_FIXED
+	$(call BUILDSTATUS,TIERDIR_START $(CURRENT_TIER) $(subtier_of_$(subst /,_,$*)) $*)
+endif
+	+@$(MAKE) -C $* $(if $(filter $*,$(tier_$(subtier_of_$(subst /,_,$*))_staticdirs)),,$(CURRENT_TIER))
+ifdef BUG_915535_FIXED
+	$(call BUILDSTATUS,TIERDIR_FINISH $(CURRENT_TIER) $(subtier_of_$(subst /,_,$*)) $*)
+endif
+
+# The export tier requires nsinstall, which is built from config. So every
+# subdirectory traversal needs to happen after traversing config.
+ifeq ($(CURRENT_TIER),export)
+$(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CURRENT_TIER)
+endif
+
+else
+
+# Don't recurse if MAKELEVEL is NO_RECURSE_MAKELEVEL as defined above, but
+# still recurse for externally managed make files (gyp-generated ones).
+ifeq ($(EXTERNALLY_MANAGED_MAKE_FILE)_$(NO_RECURSE_MAKELEVEL),_$(MAKELEVEL))
+
+compile libs export tools::
+
+else
 #########################
 # Tier traversal handling
 #########################
 
 ifdef TIERS
 
-compile libs export tools::
+libs export tools::
 	$(call BUILDSTATUS,TIER_START $@ $(filter-out $(if $(filter export,$@),,precompile),$(TIERS)))
-	$(foreach tier,$(TIERS), $(if $(filter-out compile_precompile libs_precompile tools_precompile,$@_$(tier)), \
+	$(foreach tier,$(TIERS), $(if $(filter-out libs_precompile tools_precompile,$@_$(tier)), \
 		$(call BUILDSTATUS,SUBTIER_START $@ $(tier) $(if $(filter libs,$@),$(tier_$(tier)_staticdirs)) $(tier_$(tier)_dirs)) \
 		$(if $(filter libs,$@),$(foreach dir, $(tier_$(tier)_staticdirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),,1))) \
 		$(foreach dir, $(tier_$(tier)_dirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),$@)) \
 		$(call BUILDSTATUS,SUBTIER_FINISH $@ $(tier))))
 	$(call BUILDSTATUS,TIER_FINISH $@)
 
 else
 
@@ -36,14 +134,18 @@ endif
 $(1):: $$(SUBMAKEFILES)
 ifdef PARALLEL_DIRS
 	+@$(MAKE) $$(PARALLEL_DIRS_$(1))
 endif
 	$$(LOOP_OVER_DIRS)
 
 endef
 
-$(foreach subtier,export compile libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
+$(foreach subtier,export libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
 
-compile export tools:: $(SUBMAKEFILES)
+tools export:: $(SUBMAKEFILES)
 	$(LOOP_OVER_TOOL_DIRS)
 
-endif
+endif # ifdef TIERS
+
+endif # ifeq ($(EXTERNALLY_MANAGED_MAKE_FILE)_$(NO_RECURSE_MAKELEVEL),_$(MAKELEVEL))
+
+endif # ifeq (1_.,$(MOZ_PSEUDO_DERECURSE)_$(DEPTH))
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -690,17 +690,19 @@ SUBMAKEFILES += $(addsuffix /Makefile, $
 
 # The root makefile doesn't want to do a plain export/libs, because
 # of the tiers and because of libxul. Suppress the default rules in favor
 # of something else. Makefiles which use this var *must* provide a sensible
 # default rule before including rules.mk
 ifndef SUPPRESS_DEFAULT_RULES
 default all::
 	$(MAKE) export
+ifdef MOZ_PSEUDO_DERECURSE
 	$(MAKE) compile
+endif
 	$(MAKE) libs
 	$(MAKE) tools
 endif # SUPPRESS_DEFAULT_RULES
 
 ifeq ($(findstring s,$(filter-out --%, $(MAKEFLAGS))),)
 ECHO := echo
 QUIET :=
 else
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -464,16 +464,17 @@ intshcut.h
 inttypes.h
 iodef.h
 io.h
 IOKit/IOKitLib.h
 IOKit/IOMessage.h
 IOKit/pwr_mgt/IOPMLib.h
 iomanip
 ios
+iosfwd
 iostream
 iostream.h
 iterator
 JavaControl.h
 JavaEmbedding/JavaControl.h
 JavaVM/jni.h
 JManager.h
 JNIEnvTests.h
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1056,17 +1056,22 @@ if test -n "$MOZ_LLVM_HACKS"; then
 fi
 
 dnl ========================================================
 dnl GNU specific defaults
 dnl ========================================================
 if test "$GNU_CC"; then
     # Per bug 719659 comment 2, some of the headers on ancient build machines
     # may require gnu89 inline semantics.  But otherwise, we use C99.
-    CFLAGS="$CFLAGS -std=gnu99 -fgnu89-inline"
+    # But on OS X we just use C99 plus GNU extensions, in order to fix
+    # bug 917526.
+    CFLAGS="$CFLAGS -std=gnu99"
+    if test "${OS_ARCH}" != Darwin; then
+        CFLAGS="$CFLAGS -fgnu89-inline"
+    fi
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     DSO_LDOPTS='-shared'
     if test "$GCC_USE_GNU_LD"; then
         # Some tools like ASan use a runtime library that is only
         # linked against executables, so we must allow undefined
         # symbols for shared objects in some cases.
         if test -z "$MOZ_NO_WLZDEFS"; then
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -3969,17 +3969,17 @@ PointerType::ConstructData(JSContext* cx
   // the given js function. Callers may leave this blank, or pass null if they
   // wish to pass the third argument.
   RootedObject thisObj(cx, NULL);
   if (args.length() >= 2) {
     if (args[1].isNull()) {
       thisObj = NULL;
     } else if (!JSVAL_IS_PRIMITIVE(args[1])) {
       thisObj = &args[1].toObject();
-    } else if (!JS_ValueToObject(cx, args[1], thisObj.address())) {
+    } else if (!JS_ValueToObject(cx, args[1], &thisObj)) {
       return false;
     }
   }
 
   // The third argument is an optional error sentinel that js-ctypes will return
   // if an exception is raised while executing the closure. The type must match
   // the return type of the callback.
   jsval errVal = JSVAL_VOID;
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -129,26 +129,20 @@ class gcstats::StatisticsSerializer
         size_t nchars = strlen(buf);
         jschar *out = js_pod_malloc<jschar>(nchars + 1);
         if (!out) {
             oom_ = true;
             js_free(buf);
             return NULL;
         }
 
-        size_t outlen = nchars;
-        bool ok = InflateStringToBuffer(NULL, buf, nchars, out, &outlen);
+        InflateStringToBuffer(buf, nchars, out);
         js_free(buf);
-        if (!ok) {
-            oom_ = true;
-            js_free(out);
-            return NULL;
-        }
+
         out[nchars] = 0;
-
         return out;
     }
 
     char *finishCString() {
         if (oom_)
             return NULL;
 
         buf_.append('\0');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/jit-complex.js
@@ -0,0 +1,30 @@
+// Test that we can optimize stuff like line.target.x without
+// creating an intermediate object.
+
+if (!this.hasOwnProperty("Type"))
+  quit();
+
+var PointType = new StructType({x: float64,
+                                y: float64});
+var LineType = new StructType({source: PointType,
+                               target: PointType});
+
+function manhattenDistance(line) {
+  return (Math.abs(line.target.x - line.source.x) +
+          Math.abs(line.target.y - line.source.y));
+}
+
+function foo() {
+  var N = 30000;
+  var points = [];
+  var obj;
+  var s;
+
+  var fromAToB = new LineType({source: {x: 22, y: 44},
+                               target: {x: 66, y: 88}});
+
+  for (var i = 0; i < N; i++)
+    assertEq(manhattenDistance(fromAToB), 88);
+}
+
+foo();
--- a/js/src/jit-test/tests/TypedObject/jit-prefix.js
+++ b/js/src/jit-test/tests/TypedObject/jit-prefix.js
@@ -7,22 +7,31 @@ var PointType2 = new StructType({x: floa
 var PointType3 = new StructType({x: float64,
                                  y: float64,
                                  z: float64});
 
 function xPlusY(p) {
   return p.x + p.y;
 }
 
+function xPlusYTweak(p) {
+  p.x = 22;
+  return xPlusY(p);
+}
+
 function foo() {
   var N = 30000;
   var points = [];
+  var obj;
+  var s;
+
   for (var i = 0; i < N; i++) {
-    var s;
     if ((i % 2) == 0 || true)
-      s = xPlusY(new PointType2({x: i, y: i+1}));
+      obj = new PointType2({x: i, y: i+1});
     else
-      s = xPlusY(new PointType3({x: i, y: i+1, z: i+2}));
-    assertEq(s, i + i + 1);
+      obj = new PointType3({x: i, y: i+1, z: i+2});
+
+    assertEq(xPlusY(obj), i + i + 1);
+    assertEq(xPlusYTweak(obj), 22 + i + 1);
   }
 }
 
 foo();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/arguments/bug-917585-relax-aliasing-constraints.js
@@ -0,0 +1,18 @@
+
+function foo(a, b) {
+    blah(function (x) { a = x; }, b);
+    return arguments[0];
+}
+
+function blah(f, b) {
+    f(b);
+}
+
+function main() {
+    for (var i = 0; i < 1500; i++) {
+        var x = foo(i, i*2);
+        assertEq(x, i*2);
+    }
+}
+
+main();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/offThreadCompileScript.js
@@ -0,0 +1,21 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+// Test off-thread parsing.
+
+load(libdir + 'asserts.js');
+
+if (!getBuildConfiguration().threadsafe)
+  quit(0);
+
+offThreadCompileScript('Math.sin(Math.PI/2)');
+assertEq(runOffThreadScript(), 1);
+
+offThreadCompileScript('a string which cannot be reduced to the start symbol');
+assertThrowsInstanceOf(runOffThreadScript, SyntaxError);
+
+offThreadCompileScript('smerg;');
+assertThrowsInstanceOf(runOffThreadScript, ReferenceError);
+
+offThreadCompileScript('throw "blerg";');
+assertThrowsValue(runOffThreadScript, 'blerg');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onNewScript-off-main-thread.js
@@ -0,0 +1,18 @@
+// We still get onNewScript notifications for code compiled off the main thread.
+
+if (!getBuildConfiguration().threadsafe)
+  quit(0);
+
+var g = newGlobal();
+var dbg = new Debugger(g);
+
+var log;
+dbg.onNewScript = function (s) {
+  log += 's';
+  assertEq(s.source.text, '"t" + "wine"');
+}
+
+log = '';
+g.offThreadCompileScript('"t" + "wine"');
+assertEq(runOffThreadScript(), 'twine');
+assertEq(log, 's');
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -6357,16 +6357,18 @@ GenerateStubs(ModuleCompiler &m)
     for (unsigned i = 0; i < m.module().numExportedFunctions(); i++) {
         m.setEntryOffset(i);
         if (!GenerateEntry(m, m.module().exportedFunction(i)))
             return false;
     }
 
     Label throwLabel;
 
+    // The order of the iterations here is non-deterministic, since
+    // m.allExits() is a hash keyed by pointer values!
     for (ModuleCompiler::ExitMap::Range r = m.allExits(); !r.empty(); r.popFront()) {
         GenerateFFIExit(m, r.front().key, r.front().value, &throwLabel);
         if (m.masm().oom())
             return false;
     }
 
     if (m.stackOverflowLabel().used()) {
         if (!GenerateStackOverflowExit(m, &throwLabel))
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -75,17 +75,17 @@ SetElemICInspector::sawTypedArrayWrite()
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_TypedArray())
             return true;
     }
     return false;
 }
 
 bool
-BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, Vector<Shape *> &shapes)
+BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
 {
     // Return a list of shapes seen by the baseline IC for the current op.
     // An empty list indicates no shapes are known, or there was an uncacheable
     // access.
     JS_ASSERT(shapes.empty());
 
     if (!hasBaselineScript())
         return true;
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -89,17 +89,18 @@ class BaselineInspector
         }
         return ICInspectorType(this, pc, ent);
     }
 
     ICStub *monomorphicStub(jsbytecode *pc);
     bool dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond);
 
   public:
-    bool maybeShapesForPropertyOp(jsbytecode *pc, Vector<Shape *> &shapes);
+    typedef Vector<Shape *, 4, IonAllocPolicy> ShapeVector;
+    bool maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes);
 
     SetElemICInspector setElemICInspector(jsbytecode *pc) {
         return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
     }
 
     MIRType expectedResultType(jsbytecode *pc);
     MCompare::CompareType expectedCompareType(jsbytecode *pc);
     MIRType expectedBinaryArithSpecialization(jsbytecode *pc);
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -239,28 +239,29 @@ BaselineCompile(JSContext *cx, HandleScr
         script->setBaselineScript(BASELINE_DISABLED_SCRIPT);
 
     return status;
 }
 
 static MethodStatus
 CanEnterBaselineJIT(JSContext *cx, HandleScript script, bool osr)
 {
+    // Limit the locals on a given script so that stack check on baseline frames        
+    // doesn't overflow a uint32_t value.
+    static_assert(sizeof(script->nslots) == sizeof(uint16_t), "script->nslots may get too large!");
+
     JS_ASSERT(jit::IsBaselineEnabled(cx));
 
     // Skip if the script has been disabled.
     if (!script->canBaselineCompile())
         return Method_Skipped;
 
     if (script->length > BaselineScript::MAX_JSSCRIPT_LENGTH)
         return Method_CantCompile;
 
-    if (script->nslots > BaselineScript::MAX_JSSCRIPT_SLOTS)
-        return Method_CantCompile;
-
     if (!cx->compartment()->ensureIonCompartmentExists(cx))
         return Method_Error;
 
     if (script->hasBaselineScript())
         return Method_Compiled;
 
     // Check script use count. However, always eagerly compile scripts if JSD
     // is enabled, so that we don't have to OSR and don't have to update the
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -95,21 +95,16 @@ struct PCMappingIndexEntry
     uint32_t bufferOffset;
 };
 
 struct BaselineScript
 {
   public:
     static const uint32_t MAX_JSSCRIPT_LENGTH = 0x0fffffffu;
 
-    // Limit the locals on a given script so that stack check on baseline frames
-    // doesn't overflow a uint32_t value.
-    // (MAX_JSSCRIPT_SLOTS * sizeof(Value)) must fit within a uint32_t.
-    static const uint32_t MAX_JSSCRIPT_SLOTS = 0xfffffu;
-
   private:
     // Code pointer containing the actual method.
     HeapPtr<IonCode> method_;
 
     // Allocated space for fallback stubs.
     FallbackICStubSpace fallbackStubSpace_;
 
     // Native code offset right before the scope chain is initialized.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Util.h"
 
 #include "jslibmath.h"
 #include "jsmath.h"
 #include "jsnum.h"
 
 #include "builtin/Eval.h"
+#include "builtin/TypedObject.h"
 #include "gc/Nursery.h"
 #include "jit/ExecutionModeInlines.h"
 #include "jit/IonLinker.h"
 #include "jit/IonSpewer.h"
 #include "jit/Lowering.h"
 #include "jit/MIRGenerator.h"
 #include "jit/MoveEmitter.h"
 #include "jit/ParallelFunctions.h"
@@ -716,81 +717,82 @@ CodeGenerator::visitRegExpTest(LRegExpTe
 typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject);
 static const VMFunction LambdaInfo =
     FunctionInfo<LambdaFn>(js::Lambda);
 
 bool
 CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir)
 {
     pushArg(ToRegister(lir->scopeChain()));
-    pushArg(ImmGCPtr(lir->mir()->fun()));
+    pushArg(ImmGCPtr(lir->mir()->info().fun));
     return callVM(LambdaInfo, lir);
 }
 
 bool
 CodeGenerator::visitLambda(LLambda *lir)
 {
     Register scopeChain = ToRegister(lir->scopeChain());
     Register output = ToRegister(lir->output());
-    JSFunction *fun = lir->mir()->fun();
-
-    OutOfLineCode *ool = oolCallVM(LambdaInfo, lir, (ArgList(), ImmGCPtr(fun), scopeChain),
+    const LambdaFunctionInfo &info = lir->mir()->info();
+
+    OutOfLineCode *ool = oolCallVM(LambdaInfo, lir, (ArgList(), ImmGCPtr(info.fun), scopeChain),
                                    StoreRegisterTo(output));
     if (!ool)
         return false;
 
-    JS_ASSERT(gen->compartment == fun->compartment());
-    JS_ASSERT(!fun->hasSingletonType());
-
-    masm.newGCThing(output, fun, ool->entry());
-    masm.initGCThing(output, fun);
-
-    emitLambdaInit(output, scopeChain, fun);
+    JS_ASSERT(gen->compartment == info.fun->compartment());
+    JS_ASSERT(!info.singletonType);
+
+    masm.newGCThing(output, info.fun, ool->entry());
+    masm.initGCThing(output, info.fun);
+
+    emitLambdaInit(output, scopeChain, info);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 void
-CodeGenerator::emitLambdaInit(const Register &output, const Register &scopeChain, JSFunction *fun)
+CodeGenerator::emitLambdaInit(const Register &output, const Register &scopeChain,
+                              const LambdaFunctionInfo &info)
 {
     // Initialize nargs and flags. We do this with a single uint32 to avoid
     // 16-bit writes.
     union {
         struct S {
             uint16_t nargs;
             uint16_t flags;
         } s;
         uint32_t word;
     } u;
-    u.s.nargs = fun->nargs;
-    u.s.flags = fun->flags & ~JSFunction::EXTENDED;
+    u.s.nargs = info.fun->nargs;
+    u.s.flags = info.flags & ~JSFunction::EXTENDED;
 
     JS_STATIC_ASSERT(offsetof(JSFunction, flags) == offsetof(JSFunction, nargs) + 2);
     masm.store32(Imm32(u.word), Address(output, offsetof(JSFunction, nargs)));
-    masm.storePtr(ImmGCPtr(fun->nonLazyScript()),
+    masm.storePtr(ImmGCPtr(info.scriptOrLazyScript),
                   Address(output, JSFunction::offsetOfNativeOrScript()));
     masm.storePtr(scopeChain, Address(output, JSFunction::offsetOfEnvironment()));
-    masm.storePtr(ImmGCPtr(fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
+    masm.storePtr(ImmGCPtr(info.fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
 }
 
 bool
 CodeGenerator::visitLambdaPar(LLambdaPar *lir)
 {
     Register resultReg = ToRegister(lir->output());
     Register sliceReg = ToRegister(lir->forkJoinSlice());
     Register scopeChainReg = ToRegister(lir->scopeChain());
     Register tempReg1 = ToRegister(lir->getTemp0());
     Register tempReg2 = ToRegister(lir->getTemp1());
-    JSFunction *fun = lir->mir()->fun();
+    const LambdaFunctionInfo &info = lir->mir()->info();
 
     JS_ASSERT(scopeChainReg != resultReg);
 
-    emitAllocateGCThingPar(lir, resultReg, sliceReg, tempReg1, tempReg2, fun);
-    emitLambdaInit(resultReg, scopeChainReg, fun);
+    emitAllocateGCThingPar(lir, resultReg, sliceReg, tempReg1, tempReg2, info.fun);
+    emitLambdaInit(resultReg, scopeChainReg, info);
     return true;
 }
 
 bool
 CodeGenerator::visitLabel(LLabel *lir)
 {
     masm.bind(lir->label());
     return true;
@@ -1910,40 +1912,16 @@ CodeGenerator::visitCallKnown(LCallKnown
     JS_ASSERT(!target->isNative());
     // Missing arguments must have been explicitly appended by the IonBuilder.
     JS_ASSERT(target->nargs <= call->numStackArgs());
 
     JS_ASSERT_IF(call->mir()->isConstructing(), target->isInterpretedConstructor());
 
     masm.checkStackAlignment();
 
-    // If the function is known to be uncompilable, just emit the call to
-    // Invoke in sequential mode, else mark as cannot compile.
-    JS_ASSERT(call->mir()->hasRootedScript());
-    JSScript *targetScript = target->nonLazyScript();
-    if (GetIonScript(targetScript, executionMode) == ION_DISABLED_SCRIPT &&
-        (executionMode == ParallelExecution || !targetScript->canBaselineCompile()))
-    {
-        if (executionMode == ParallelExecution)
-            return false;
-
-        if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
-            return false;
-
-        if (call->mir()->isConstructing()) {
-            Label notPrimitive;
-            masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
-            masm.loadValue(Address(StackPointer, unusedStack), JSReturnOperand);
-            masm.bind(&notPrimitive);
-        }
-
-        dropArguments(call->numStackArgs() + 1);
-        return true;
-    }
-
     // The calleereg is known to be a non-native function, but might point to
     // a LazyScript instead of a JSScript.
     masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
 
     // Knowing that calleereg is a non-native function, load the JSScript.
     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
 
     // Load script jitcode.
@@ -2508,17 +2486,17 @@ CodeGenerator::visitCheckOverRecursedFai
         return false;
 
     // Avoid saving/restoring the temp register since we will put the
     // ReturnReg into it below and we don't want to clobber that
     // during PopRegsInMask():
     LCheckOverRecursedPar *lir = ool->lir();
     Register tempReg = ToRegister(lir->getTempReg());
     RegisterSet saveSet(lir->safepoint()->liveRegs());
-    saveSet.maybeTake(tempReg);
+    saveSet.takeUnchecked(tempReg);
 
     masm.PushRegsInMask(saveSet);
     masm.movePtr(ToRegister(lir->forkJoinSlice()), CallTempReg0);
     masm.setupUnalignedABICall(1, CallTempReg1);
     masm.passABIArg(CallTempReg0);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CheckOverRecursedPar));
     masm.movePtr(ReturnReg, tempReg);
     masm.PopRegsInMask(saveSet);
@@ -2570,17 +2548,17 @@ CodeGenerator::visitOutOfLineCheckInterr
         return false;
 
     // Avoid saving/restoring the temp register since we will put the
     // ReturnReg into it below and we don't want to clobber that
     // during PopRegsInMask():
     LCheckInterruptPar *lir = ool->lir;
     Register tempReg = ToRegister(lir->getTempReg());
     RegisterSet saveSet(lir->safepoint()->liveRegs());
-    saveSet.maybeTake(tempReg);
+    saveSet.takeUnchecked(tempReg);
 
     masm.PushRegsInMask(saveSet);
     masm.movePtr(ToRegister(ool->lir->forkJoinSlice()), CallTempReg0);
     masm.setupUnalignedABICall(1, CallTempReg1);
     masm.passABIArg(CallTempReg0);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CheckInterruptPar));
     masm.movePtr(ReturnReg, tempReg);
     masm.PopRegsInMask(saveSet);
@@ -2879,16 +2857,35 @@ CodeGenerator::visitNewArrayCallVM(LNewA
     if (ReturnReg != objReg)
         masm.movePtr(ReturnReg, objReg);
 
     restoreLive(lir);
 
     return true;
 }
 
+typedef JSObject *(*NewDerivedTypedObjectFn)(JSContext *,
+                                             HandleObject type,
+                                             HandleObject owner,
+                                             int32_t offset);
+static const VMFunction CreateDerivedTypedObjInfo =
+    FunctionInfo<NewDerivedTypedObjectFn>(CreateDerivedTypedObj);
+
+bool
+CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
+{
+    // Not yet made safe for par exec:
+    JS_ASSERT(gen->info().executionMode() == SequentialExecution);
+
+    pushArg(ToRegister(lir->offset()));
+    pushArg(ToRegister(lir->owner()));
+    pushArg(ToRegister(lir->type()));
+    return callVM(CreateDerivedTypedObjInfo, lir);
+}
+
 bool
 CodeGenerator::visitNewSlots(LNewSlots *lir)
 {
     Register temp1 = ToRegister(lir->temp1());
     Register temp2 = ToRegister(lir->temp2());
     Register temp3 = ToRegister(lir->temp3());
     Register output = ToRegister(lir->output());
 
@@ -3289,17 +3286,17 @@ CodeGenerator::visitOutOfLineNewGCThingP
     // that must not be clobbered but which are not technically
     // considered live.
     RegisterSet saveSet(RegisterSet::Volatile());
 
     // Also preserve the temps we're about to overwrite,
     // but don't bother to save the objReg.
     saveSet.addUnchecked(CallTempReg0);
     saveSet.addUnchecked(CallTempReg1);
-    saveSet.maybeTake(AnyRegister(ool->objReg));
+    saveSet.takeUnchecked(AnyRegister(ool->objReg));
 
     masm.PushRegsInMask(saveSet);
     masm.move32(Imm32(ool->allocKind), CallTempReg0);
     masm.setupUnalignedABICall(1, CallTempReg1);
     masm.passABIArg(CallTempReg0);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewGCThingPar));
     masm.movePtr(ReturnReg, ool->objReg);
     masm.PopRegsInMask(saveSet);
@@ -3596,16 +3593,25 @@ CodeGenerator::visitTypedArrayElements(L
 {
     Register obj = ToRegister(lir->object());
     Register out = ToRegister(lir->output());
     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), out);
     return true;
 }
 
 bool
+CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
+{
+    Register obj = ToRegister(lir->object());
+    Register out = ToRegister(lir->output());
+    masm.loadPtr(Address(obj, BinaryBlock::dataOffset()), out);
+    return true;
+}
+
+bool
 CodeGenerator::visitStringLength(LStringLength *lir)
 {
     Register input = ToRegister(lir->string());
     Register output = ToRegister(lir->output());
 
     masm.loadStringLength(input, output);
     return true;
 }
@@ -4924,17 +4930,17 @@ CodeGenerator::visitOutOfLineStoreElemen
         // instruction we don't want to do that.  So instead we push
         // the volatile registers but we don't save the register
         // `object`.  We will copy the ReturnReg into `object`.  The
         // function we are calling (`PushPar`) agrees to either return
         // `object` unchanged or NULL.  This way after we restore the
         // registers, we can examine `object` to know whether an error
         // occurred.
         RegisterSet saveSet(ins->safepoint()->liveRegs());
-        saveSet.maybeTake(object);
+        saveSet.takeUnchecked(object);
 
         masm.PushRegsInMask(saveSet);
         masm.reserveStack(sizeof(PushParArgs));
         masm.storePtr(object, Address(StackPointer, offsetof(PushParArgs, object)));
         masm.storeConstantOrRegister(value, Address(StackPointer,
                                                     offsetof(PushParArgs, value)));
         masm.movePtr(StackPointer, CallTempReg0);
         masm.setupUnalignedABICall(1, CallTempReg1);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -127,32 +127,34 @@ class CodeGenerator : public CodeGenerat
     bool visitNewObject(LNewObject *lir);
     bool visitOutOfLineNewObject(OutOfLineNewObject *ool);
     bool visitNewDeclEnvObject(LNewDeclEnvObject *lir);
     bool visitNewCallObject(LNewCallObject *lir);
     bool visitNewCallObjectPar(LNewCallObjectPar *lir);
     bool visitNewStringObject(LNewStringObject *lir);
     bool visitNewPar(LNewPar *lir);
     bool visitNewDenseArrayPar(LNewDenseArrayPar *lir);
+    bool visitNewDerivedTypedObject(LNewDerivedTypedObject *lir);
     bool visitAbortPar(LAbortPar *lir);
     bool visitInitElem(LInitElem *lir);
     bool visitInitElemGetterSetter(LInitElemGetterSetter *lir);
     bool visitInitProp(LInitProp *lir);
     bool visitInitPropGetterSetter(LInitPropGetterSetter *lir);
     bool visitCreateThis(LCreateThis *lir);
     bool visitCreateThisWithProto(LCreateThisWithProto *lir);
     bool visitCreateThisWithTemplate(LCreateThisWithTemplate *lir);
     bool visitCreateArgumentsObject(LCreateArgumentsObject *lir);
     bool visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir);
     bool visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir);
     bool visitReturnFromCtor(LReturnFromCtor *lir);
     bool visitComputeThis(LComputeThis *lir);
     bool visitArrayLength(LArrayLength *lir);
     bool visitTypedArrayLength(LTypedArrayLength *lir);
     bool visitTypedArrayElements(LTypedArrayElements *lir);
+    bool visitTypedObjectElements(LTypedObjectElements *lir);
     bool visitStringLength(LStringLength *lir);
     bool visitInitializedLength(LInitializedLength *lir);
     bool visitSetInitializedLength(LSetInitializedLength *lir);
     bool visitNotO(LNotO *ins);
     bool visitNotV(LNotV *ins);
     bool visitBoundsCheck(LBoundsCheck *lir);
     bool visitBoundsCheckRange(LBoundsCheckRange *lir);
     bool visitBoundsCheckLower(LBoundsCheckLower *lir);
@@ -331,17 +333,18 @@ class CodeGenerator : public CodeGenerat
     bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
 
     bool emitAllocateGCThingPar(LInstruction *lir, const Register &objReg, const Register &sliceReg,
                                 const Register &tempReg1, const Register &tempReg2,
                                 JSObject *templateObj);
 
     bool emitCallToUncompiledScriptPar(LInstruction *lir, Register calleeReg);
 
-    void emitLambdaInit(const Register &resultReg, const Register &scopeChainReg, JSFunction *fun);
+    void emitLambdaInit(const Register &resultReg, const Register &scopeChainReg,
+                        const LambdaFunctionInfo &info);
 
     IonScriptCounts *maybeCreateScriptCounts();
 
     // Test whether value is truthy or not and jump to the corresponding label.
     // If the value can be an object that emulates |undefined|, |ool| must be
     // non-null; otherwise it may be null (and the scratch definitions should
     // be bogus), in which case an object encountered here will always be
     // truthy.
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -914,27 +914,17 @@ TypeAnalyzer::checkFloatCoherency()
         for (MDefinitionIterator def(*block); def; def++) {
             if (def->type() != MIRType_Float32)
                 continue;
             if (def->isPassArg()) // no check for PassArg as it is broken, see bug 915479
                 continue;
 
             for (MUseDefIterator use(*def); use; use++) {
                 MDefinition *consumer = use.def();
-                // The only valid uses of a Float32 are:
-                // - an operation that can consume Float32
-                // - an operation that has been specialized to Float32 (for instance, an add)
-                // - a conversion to Double
-                if (consumer->canConsumeFloat32())
-                    continue;
-                if (consumer->type() == MIRType_Float32)
-                    continue;
-                if (consumer->isToDouble())
-                    continue;
-                MOZ_ASSUME_UNREACHABLE("Float32 flowing into a non float specialized operation");
+                JS_ASSERT(consumer->isConsistentFloat32Use());
             }
         }
     }
 #endif
     return true;
 }
 
 bool
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6,16 +6,17 @@
 
 #include "jit/IonBuilder.h"
 
 #include "mozilla/DebugOnly.h"
 
 #include "jsautooplen.h"
 
 #include "builtin/Eval.h"
+#include "builtin/TypedObject.h"
 #include "builtin/TypeRepresentation.h"
 #include "frontend/SourceNotes.h"
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineInspector.h"
 #include "jit/ExecutionModeInlines.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
 #include "jit/IonSpewer.h"
@@ -157,17 +158,17 @@ IonBuilder::getSingleCallTarget(types::T
     if (!obj || !obj->is<JSFunction>())
         return NULL;
 
     return &obj->as<JSFunction>();
 }
 
 bool
 IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
-                               AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda)
+                               ObjectVector &targets, uint32_t maxTargets, bool *gotLambda)
 {
     JS_ASSERT(targets.length() == 0);
     JS_ASSERT(gotLambda);
     *gotLambda = false;
 
     if (!calleeTypes)
         return true;
 
@@ -197,19 +198,16 @@ IonBuilder::getPolyCallTargets(types::Te
                 targets.clear();
                 return true;
             }
 
             fun = typeObj->interpretedFunction;
             *gotLambda = true;
         }
 
-        if (fun->isInterpreted() && !fun->getOrCreateScript(cx))
-            return false;
-
         // Don't optimize if we're constructing and the callee is not a
         // constructor, so that CallKnown does not have to handle this case
         // (it should always throw).
         if (constructing && !fun->isInterpretedConstructor() && !fun->isNativeConstructor()) {
             targets.clear();
             return true;
         }
 
@@ -1137,18 +1135,18 @@ IonBuilder::traverseBytecode()
         // popped by this opcode either:
         //
         //   (1) Have the Folded flag set on them.
         //   (2) Have more uses than before compiling this op (the value is
         //       used as operand of a new MIR instruction).
         //
         // This is used to catch problems where IonBuilder pops a value without
         // adding any SSA uses and doesn't call setFoldedUnchecked on it.
-        Vector<MDefinition *> popped(cx);
-        Vector<size_t> poppedUses(cx);
+        Vector<MDefinition *, 4, IonAllocPolicy> popped;
+        Vector<size_t, 4, IonAllocPolicy> poppedUses;
         unsigned nuses = GetUseCount(script_, pc - script_->code);
 
         for (unsigned i = 0; i < nuses; i++) {
             MDefinition *def = current->peek(-int32_t(i + 1));
             if (!popped.append(def) || !poppedUses.append(def->defUseCount()))
                 return false;
         }
 #endif
@@ -1184,17 +1182,25 @@ IonBuilder::traverseBytecode()
                 // we may replace it with |undefined|, but the difference is
                 // not observable.
                 JS_ASSERT(i == 0);
                 if (current->peek(-1) == popped[0])
                     break;
                 // FALL THROUGH
 
               default:
-                JS_ASSERT(popped[i]->isFolded() || popped[i]->defUseCount() > poppedUses[i]);
+                JS_ASSERT(popped[i]->isFolded() ||
+
+                          // MNewDerivedTypedObject instances are
+                          // often dead unless they escape from the
+                          // fn. See IonBuilder::loadTypedObjectData()
+                          // for more details.
+                          popped[i]->isNewDerivedTypedObject() ||
+
+                          popped[i]->defUseCount() > poppedUses[i]);
                 break;
             }
         }
 #endif
 
         pc += js_CodeSpec[op].length;
         current->updateTrackedPc(pc);
     }
@@ -3987,17 +3993,17 @@ IonBuilder::makeInliningDecision(JSFunct
 
     // TI calls ObjectStateChange to trigger invalidation of the caller.
     types::HeapTypeSet::WatchObjectStateChange(cx, targetType);
 
     return true;
 }
 
 uint32_t
-IonBuilder::selectInliningTargets(AutoObjectVector &targets, CallInfo &callInfo, Vector<bool> &choiceSet)
+IonBuilder::selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, BoolVector &choiceSet)
 {
     uint32_t totalSize = 0;
     uint32_t numInlineable = 0;
 
     // For each target, ask whether it may be inlined.
     if (!choiceSet.reserve(targets.length()))
         return false;
     for (size_t i = 0; i < targets.length(); i++) {
@@ -4093,17 +4099,17 @@ IonBuilder::inlineSingleCall(CallInfo &c
         return inlineNativeCall(callInfo, target->native());
 
     if (!inlineScriptedCall(callInfo, target))
         return InliningStatus_Error;
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineCallsite(AutoObjectVector &targets, AutoObjectVector &originals,
+IonBuilder::inlineCallsite(ObjectVector &targets, ObjectVector &originals,
                            bool lambda, CallInfo &callInfo)
 {
     if (!inliningEnabled())
         return InliningStatus_NotInlined;
 
     if (targets.length() == 0)
         return InliningStatus_NotInlined;
 
@@ -4133,17 +4139,17 @@ IonBuilder::inlineCallsite(AutoObjectVec
             current->add(constFun);
             callInfo.setFun(constFun);
         }
 
         return inlineSingleCall(callInfo, target);
     }
 
     // Choose a subset of the targets for polymorphic inlining.
-    Vector<bool> choiceSet(cx);
+    BoolVector choiceSet;
     uint32_t numInlined = selectInliningTargets(targets, callInfo, choiceSet);
     if (numInlined == 0)
         return InliningStatus_NotInlined;
 
     // Perform a polymorphic dispatch.
     if (!inlineCalls(callInfo, targets, originals, choiceSet, propCache))
         return InliningStatus_Error;
 
@@ -4155,17 +4161,17 @@ IonBuilder::inlineGenericFallback(JSFunc
                                   bool clonedAtCallsite)
 {
     // Generate a new block with all arguments on-stack.
     MBasicBlock *fallbackBlock = newBlock(dispatchBlock, pc);
     if (!fallbackBlock)
         return false;
 
     // Create a new CallInfo to track modified state within this block.
-    CallInfo fallbackInfo(cx, callInfo.constructing());
+    CallInfo fallbackInfo(callInfo.constructing());
     if (!fallbackInfo.init(callInfo))
         return false;
     fallbackInfo.popFormals(fallbackBlock);
     fallbackInfo.wrapArgs(fallbackBlock);
 
     // Generate an MCall, which uses stateful |current|.
     setCurrentAndSpecializePhis(fallbackBlock);
     if (!makeCall(target, fallbackInfo, clonedAtCallsite))
@@ -4193,17 +4199,17 @@ IonBuilder::inlineTypeObjectFallback(Cal
     JS_ASSERT_IF(callInfo.fun()->isGetPropertyCache(), !cache->hasUses());
     JS_ASSERT_IF(callInfo.fun()->isTypeBarrier(), cache->hasOneUse());
 
     // This means that no resume points yet capture the MGetPropertyCache,
     // so everything from the MGetPropertyCache up until the call is movable.
     // We now move the MGetPropertyCache and friends into a fallback path.
 
     // Create a new CallInfo to track modified state within the fallback path.
-    CallInfo fallbackInfo(cx, callInfo.constructing());
+    CallInfo fallbackInfo(callInfo.constructing());
     if (!fallbackInfo.init(callInfo))
         return false;
 
     // Capture stack prior to the call operation. This captures the function.
     MResumePoint *preCallResumePoint =
         MResumePoint::New(dispatchBlock, pc, callerResumePoint_, MResumePoint::ResumeAt);
     if (!preCallResumePoint)
         return false;
@@ -4267,18 +4273,18 @@ IonBuilder::inlineTypeObjectFallback(Cal
 
     // inlineGenericFallback() set the return block as |current|.
     preCallBlock->end(MGoto::New(current));
     *fallbackTarget = prepBlock;
     return true;
 }
 
 bool
-IonBuilder::inlineCalls(CallInfo &callInfo, AutoObjectVector &targets,
-                        AutoObjectVector &originals, Vector<bool> &choiceSet,
+IonBuilder::inlineCalls(CallInfo &callInfo, ObjectVector &targets,
+                        ObjectVector &originals, BoolVector &choiceSet,
                         MGetPropertyCache *maybeCache)
 {
     // Only handle polymorphic inlining.
     JS_ASSERT(IsIonInlinablePC(pc));
     JS_ASSERT(choiceSet.length() == targets.length());
     JS_ASSERT_IF(!maybeCache, targets.length() >= 2);
     JS_ASSERT_IF(maybeCache, targets.length() >= 1);
 
@@ -4375,17 +4381,17 @@ IonBuilder::inlineCalls(CallInfo &callIn
         dispatchBlock->add(funcDef);
 
         // Use the MConstant in the inline resume point and on stack.
         int funIndex = inlineBlock->entryResumePoint()->numOperands() - callInfo.numFormals();
         inlineBlock->entryResumePoint()->replaceOperand(funIndex, funcDef);
         inlineBlock->rewriteSlot(funIndex, funcDef);
 
         // Create a new CallInfo to track modified state within the inline block.
-        CallInfo inlineInfo(cx, callInfo.constructing());
+        CallInfo inlineInfo(callInfo.constructing());
         if (!inlineInfo.init(callInfo))
             return false;
         inlineInfo.popFormals(inlineBlock);
         inlineInfo.setFun(funcDef);
         inlineInfo.wrapArgs(inlineBlock);
 
         if (maybeCache) {
             JS_ASSERT(callInfo.thisArg() == maybeCache->object());
@@ -4718,17 +4724,17 @@ IonBuilder::jsop_funcall(uint32_t argc)
 
     int calleeDepth = -((int)argc + 2);
     int funcDepth = -((int)argc + 1);
 
     // If |Function.prototype.call| may be overridden, don't optimize callsite.
     types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction *native = getSingleCallTarget(calleeTypes);
     if (!native || !native->isNative() || native->native() != &js_fun_call) {
-        CallInfo callInfo(cx, false);
+        CallInfo callInfo(false);
         if (!callInfo.init(current, argc))
             return false;
         return makeCall(native, callInfo, false);
     }
     current->peek(calleeDepth)->setFoldedUnchecked();
 
     // Extract call target.
     types::TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
@@ -4753,17 +4759,17 @@ IonBuilder::jsop_funcall(uint32_t argc)
         MPassArg *pass = MPassArg::New(undef);
         current->add(pass);
         current->push(pass);
     } else {
         // |this| becomes implicit in the call.
         argc -= 1;
     }
 
-    CallInfo callInfo(cx, false);
+    CallInfo callInfo(false);
     if (!callInfo.init(current, argc))
         return false;
 
     // Try inlining call
     if (argc > 0 && makeInliningDecision(target, callInfo) && target->isInterpreted())
         return inlineScriptedCall(callInfo, target);
 
     // Call without inlining.
@@ -4773,17 +4779,17 @@ IonBuilder::jsop_funcall(uint32_t argc)
 bool
 IonBuilder::jsop_funapply(uint32_t argc)
 {
     int calleeDepth = -((int)argc + 2);
 
     types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction *native = getSingleCallTarget(calleeTypes);
     if (argc != 2) {
-        CallInfo callInfo(cx, false);
+        CallInfo callInfo(false);
         if (!callInfo.init(current, argc))
             return false;
         return makeCall(native, callInfo, false);
     }
 
     // Disable compilation if the second argument to |apply| cannot be guaranteed
     // to be either definitely |arguments| or definitely not |arguments|.
     MDefinition *argument = current->peek(-1);
@@ -4791,17 +4797,17 @@ IonBuilder::jsop_funapply(uint32_t argc)
         argument->mightBeType(MIRType_Magic) &&
         argument->type() != MIRType_Magic)
     {
         return abort("fun.apply with MaybeArguments");
     }
 
     // Fallback to regular call if arg 2 is not definitely |arguments|.
     if (argument->type() != MIRType_Magic) {
-        CallInfo callInfo(cx, false);
+        CallInfo callInfo(false);
         if (!callInfo.init(current, argc))
             return false;
         return makeCall(native, callInfo, false);
     }
 
     if (!native ||
         !native->isNative() ||
         native->native() != js_fun_apply)
@@ -4869,26 +4875,26 @@ IonBuilder::jsop_funapplyarguments(uint3
     }
 
     // When inlining we have the arguments the function gets called with
     // and can optimize even more, by just calling the functions with the args.
     // We also try this path when doing the definite properties analysis, as we
     // can inline the apply() target and don't care about the actual arguments
     // that were passed in.
 
-    CallInfo callInfo(cx, false);
+    CallInfo callInfo(false);
 
     // Vp
     MPassArg *passVp = current->pop()->toPassArg();
     passVp->getArgument()->setFoldedUnchecked();
     passVp->replaceAllUsesWith(passVp->getArgument());
     passVp->block()->discard(passVp);
 
     // Arguments
-    Vector<MDefinition *> args(cx);
+    MDefinitionVector args;
     if (inliningDepth_) {
         if (!args.append(inlineCallInfo_->argv().begin(), inlineCallInfo_->argv().end()))
             return false;
     }
     callInfo.setArgs(&args);
 
     // This
     MPassArg *passThis = current->pop()->toPassArg();
@@ -4931,44 +4937,44 @@ IonBuilder::jsop_call(uint32_t argc, boo
             // See bug 870847.
             observed->addType(cx, types::Type::DoubleType());
         }
     }
 
     int calleeDepth = -((int)argc + 2);
 
     // Acquire known call target if existent.
-    AutoObjectVector originals(cx);
+    ObjectVector originals;
     bool gotLambda = false;
     types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     if (calleeTypes) {
         if (!getPolyCallTargets(calleeTypes, constructing, originals, 4, &gotLambda))
             return false;
     }
     JS_ASSERT_IF(gotLambda, originals.length() <= 1);
 
     // If any call targets need to be cloned, clone them. Keep track of the
     // originals as we need to case on them for poly inline.
     bool hasClones = false;
-    AutoObjectVector targets(cx);
+    ObjectVector targets;
     RootedFunction fun(cx);
     RootedScript scriptRoot(cx, script());
     for (uint32_t i = 0; i < originals.length(); i++) {
         fun = &originals[i]->as<JSFunction>();
-        if (fun->isInterpreted() && fun->nonLazyScript()->shouldCloneAtCallsite) {
+        if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite) {
             fun = CloneFunctionAtCallsite(cx, fun, scriptRoot, pc);
             if (!fun)
                 return false;
             hasClones = true;
         }
         if (!targets.append(fun))
             return false;
     }
 
-    CallInfo callInfo(cx, constructing);
+    CallInfo callInfo(constructing);
     if (!callInfo.init(current, argc))
         return false;
 
     // Try inlining
     InliningStatus status = inlineCallsite(targets, originals, gotLambda, callInfo);
     if (status == InliningStatus_Inlined)
         return true;
     if (status == InliningStatus_Error)
@@ -5098,17 +5104,17 @@ ArgumentTypesMatch(MDefinition *def, typ
 }
 
 bool
 IonBuilder::testNeedsArgumentCheck(JSContext *cx, JSFunction *target, CallInfo &callInfo)
 {
     // If we have a known target, check if the caller arg types are a subset of callee.
     // Since typeset accumulates and can't decrease that means we don't need to check
     // the arguments anymore.
-    if (!target->isInterpreted())
+    if (!target->hasScript())
         return true;
 
     JSScript *targetScript = target->nonLazyScript();
     if (!targetScript->types)
         return true;
 
     if (!ArgumentTypesMatch(callInfo.thisArg(), cloneTypeSet(types::TypeScript::ThisTypes(targetScript))))
         return true;
@@ -5140,23 +5146,16 @@ IonBuilder::makeCallHelper(JSFunction *t
     if (target && !target->isNative())
         targetArgs = Max<uint32_t>(target->nargs, callInfo.argc());
 
     MCall *call =
         MCall::New(target, targetArgs + 1, callInfo.argc(), callInfo.constructing());
     if (!call)
         return NULL;
 
-    // Save the script for inspection by visitCallKnown().
-    if (target && target->isInterpreted()) {
-        if (!target->getOrCreateScript(cx))
-            return NULL;
-        call->rootTargetScript(target);
-    }
-
     // Explicitly pad any missing arguments with |undefined|.
     // This permits skipping the argumentsRectifier.
     for (int i = targetArgs; i > (int)callInfo.argc(); i--) {
         JS_ASSERT_IF(target, !target->isNative());
         MConstant *undef = MConstant::New(UndefinedValue());
         current->add(undef);
         MPassArg *pass = MPassArg::New(undef);
         current->add(pass);
@@ -5301,17 +5300,17 @@ IonBuilder::jsop_eval(uint32_t argc)
         // The 'this' value for the outer and eval scripts must be the
         // same. This is not guaranteed if a primitive string/number/etc.
         // is passed through to the eval invoke as the primitive may be
         // boxed into different objects if accessed via 'this'.
         JSValueType type = thisTypes->getKnownTypeTag();
         if (type != JSVAL_TYPE_OBJECT && type != JSVAL_TYPE_NULL && type != JSVAL_TYPE_UNDEFINED)
             return abort("Direct eval from script with maybe-primitive 'this'");
 
-        CallInfo callInfo(cx, /* constructing = */ false);
+        CallInfo callInfo(/* constructing = */ false);
         if (!callInfo.init(current, argc))
             return false;
         callInfo.unwrapArgs();
 
         callInfo.fun()->setFoldedUnchecked();
 
         MDefinition *scopeChain = current->scopeChain();
         MDefinition *string = callInfo.getArg(0);
@@ -5337,17 +5336,17 @@ IonBuilder::jsop_eval(uint32_t argc)
                 current->add(dynamicName);
 
                 MInstruction *thisv = MPassArg::New(thisValue);
                 current->add(thisv);
 
                 current->push(dynamicName);
                 current->push(thisv);
 
-                CallInfo evalCallInfo(cx, /* constructing = */ false);
+                CallInfo evalCallInfo(/* constructing = */ false);
                 if (!evalCallInfo.init(current, /* argc = */ 0))
                     return false;
 
                 return makeCall(NULL, evalCallInfo, false);
             }
         }
 
         MInstruction *filterArguments = MFilterArguments::New(string);
@@ -7006,16 +7005,38 @@ IonBuilder::convertShiftToMaskForStaticT
     JS_ASSERT(!ptr->isEffectful());
 
     current->add(mask);
     current->add(ptr);
 
     return ptr;
 }
 
+static MIRType
+MIRTypeForTypedArrayRead(ScalarTypeRepresentation::Type arrayType,
+                         bool observedDouble)
+{
+    switch (arrayType) {
+      case ScalarTypeRepresentation::TYPE_INT8:
+      case ScalarTypeRepresentation::TYPE_UINT8:
+      case ScalarTypeRepresentation::TYPE_UINT8_CLAMPED:
+      case ScalarTypeRepresentation::TYPE_INT16:
+      case ScalarTypeRepresentation::TYPE_UINT16:
+      case ScalarTypeRepresentation::TYPE_INT32:
+        return MIRType_Int32;
+      case ScalarTypeRepresentation::TYPE_UINT32:
+        return observedDouble ? MIRType_Double : MIRType_Int32;
+      case ScalarTypeRepresentation::TYPE_FLOAT32:
+        return (LIRGenerator::allowFloat32Optimizations()) ? MIRType_Float32 : MIRType_Double;
+      case ScalarTypeRepresentation::TYPE_FLOAT64:
+        return MIRType_Double;
+    }
+    MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
+}
+
 bool
 IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
                                ScalarTypeRepresentation::Type arrayType)
 {
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
 
     bool maybeUndefined = types->hasType(types::Type::UndefinedType());
 
@@ -7032,38 +7053,17 @@ IonBuilder::jsop_getelem_typed(MDefiniti
     if (!maybeUndefined) {
         // Assume the index is in range, so that we can hoist the length,
         // elements vector and bounds check.
 
         // If we are reading in-bounds elements, we can use knowledge about
         // the array type to determine the result type, even if the opcode has
         // never executed. The known pushed type is only used to distinguish
         // uint32 reads that may produce either doubles or integers.
-        MIRType knownType;
-        switch (arrayType) {
-          case ScalarTypeRepresentation::TYPE_INT8:
-          case ScalarTypeRepresentation::TYPE_UINT8:
-          case ScalarTypeRepresentation::TYPE_UINT8_CLAMPED:
-          case ScalarTypeRepresentation::TYPE_INT16:
-          case ScalarTypeRepresentation::TYPE_UINT16:
-          case ScalarTypeRepresentation::TYPE_INT32:
-            knownType = MIRType_Int32;
-            break;
-          case ScalarTypeRepresentation::TYPE_UINT32:
-            knownType = allowDouble ? MIRType_Double : MIRType_Int32;
-            break;
-          case ScalarTypeRepresentation::TYPE_FLOAT32:
-            knownType = (LIRGenerator::allowFloat32Optimizations()) ? MIRType_Float32 : MIRType_Double;
-            break;
-          case ScalarTypeRepresentation::TYPE_FLOAT64:
-            knownType = MIRType_Double;
-            break;
-          default:
-            MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
-        }
+        MIRType knownType = MIRTypeForTypedArrayRead(arrayType, allowDouble);
 
         // Get the length.
         MInstruction *length = getTypedArrayLength(obj);
         current->add(length);
 
         // Bounds check.
         index = addBoundsCheck(index, length);
 
@@ -8155,16 +8155,20 @@ IonBuilder::jsop_getprop(PropertyName *n
     if (info().executionMode() == DefinitePropertiesAnalysis) {
         MDefinition *obj = current->pop();
         MCallGetProperty *call = MCallGetProperty::New(obj, name);
         current->add(call);
         current->push(call);
         return resumeAfter(call);
     }
 
+    // Try to emit loads from known binary data blocks
+    if (!getPropTryTypedObject(&emitted, id, types) || emitted)
+        return emitted;
+
     // Try to emit loads from definite slots.
     if (!getPropTryDefiniteSlot(&emitted, name, barrier, types) || emitted)
         return emitted;
 
     // Try to inline a common property getter, or make a call.
     if (!getPropTryCommonGetter(&emitted, id, barrier, types) || emitted)
         return emitted;
 
@@ -8237,16 +8241,131 @@ IonBuilder::getPropTryConstant(bool *emi
     current->add(known);
     current->push(known);
 
     *emitted = true;
     return true;
 }
 
 bool
+IonBuilder::getPropTryTypedObject(bool *emitted,
+                                  jsid id,
+                                  types::TemporaryTypeSet *resultTypes)
+{
+    TypeRepresentationSet fieldTypeReprs;
+    int32_t fieldOffset;
+    size_t fieldIndex;
+    if (!lookupTypedObjectField(current->peek(-1), id, &fieldOffset,
+                                &fieldTypeReprs, &fieldIndex))
+        return false;
+    if (fieldTypeReprs.empty())
+        return true;
+
+    switch (fieldTypeReprs.kind()) {
+      case TypeRepresentation::Struct:
+      case TypeRepresentation::Array:
+        return getPropTryComplexPropOfTypedObject(emitted,
+                                                  fieldOffset,
+                                                  fieldTypeReprs,
+                                                  fieldIndex,
+                                                  resultTypes);
+
+      case TypeRepresentation::Scalar:
+        return getPropTryScalarPropOfTypedObject(emitted,
+                                                 fieldOffset,
+                                                 fieldTypeReprs,
+                                                 resultTypes);
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Bad kind");
+}
+
+bool
+IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
+                                              int32_t fieldOffset,
+                                              TypeRepresentationSet fieldTypeReprs,
+                                              types::TemporaryTypeSet *resultTypes)
+{
+    // Must always be loading the same scalar type
+    if (fieldTypeReprs.length() != 1)
+        return true;
+    ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
+
+    // OK!
+    *emitted = true;
+
+    MDefinition *typedObj = current->pop();
+
+    // Find location within the owner object.
+    MDefinition *owner, *ownerOffset;
+    loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
+
+    // Load the element data.
+    MTypedObjectElements *elements = MTypedObjectElements::New(owner);
+    current->add(elements);
+
+    // Reading from an Uint32Array will result in a double for values
+    // that don't fit in an int32. We have to bailout if this happens
+    // and the instruction is not known to return a double.
+    bool allowDouble = resultTypes->hasType(types::Type::DoubleType());
+    MIRType knownType = MIRTypeForTypedArrayRead(fieldTypeRepr->type(), allowDouble);
+
+    // Typed array offsets are expressed in units of the alignment,
+    // and the binary data API guarantees all offsets are properly
+    // aligned. So just do the divide.
+    MConstant *alignment = MConstant::New(Int32Value(fieldTypeRepr->alignment()));
+    current->add(alignment);
+    MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, alignment, MIRType_Int32);
+    current->add(scaledOffset);
+
+    MLoadTypedArrayElement *load =
+        MLoadTypedArrayElement::New(elements, scaledOffset,
+                                    fieldTypeRepr->type());
+    load->setResultType(knownType);
+    load->setResultTypeSet(resultTypes);
+    current->add(load);
+    current->push(load);
+    return true;
+}
+
+bool
+IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
+                                               int32_t fieldOffset,
+                                               TypeRepresentationSet fieldTypeReprs,
+                                               size_t fieldIndex,
+                                               types::TemporaryTypeSet *resultTypes)
+{
+    // Must know the field index so that we can load the new type
+    // object for the derived value
+    if (fieldIndex == SIZE_MAX)
+        return true;
+
+    *emitted = true;
+    MDefinition *typedObj = current->pop();
+
+    // Identify the type object for the field.
+    MDefinition *type = loadTypedObjectType(typedObj);
+    MDefinition *fieldType = typeObjectForFieldFromStructType(type, fieldIndex);
+
+    // Find location within the owner object.
+    MDefinition *owner, *ownerOffset;
+    loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
+
+    // Create the derived type object.
+    MInstruction *derived = new MNewDerivedTypedObject(fieldTypeReprs,
+                                                       fieldType,
+                                                       owner,
+                                                       ownerOffset);
+    derived->setResultTypeSet(resultTypes);
+    current->add(derived);
+    current->push(derived);
+    return true;
+}
+
+bool
 IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
                                    bool barrier, types::TemporaryTypeSet *types)
 {
     JS_ASSERT(*emitted == false);
     types::TypeSet *propTypes = GetDefiniteSlot(cx, current->peek(-1)->resultTypeSet(), name);
     if (!propTypes)
         return true;
 
@@ -8316,17 +8435,17 @@ IonBuilder::getPropTryCommonGetter(bool 
 
     // Spoof stack to expected state for call.
     pushConstant(ObjectValue(*commonGetter));
 
     MPassArg *wrapper = MPassArg::New(obj);
     current->add(wrapper);
     current->push(wrapper);
 
-    CallInfo callInfo(cx, false);
+    CallInfo callInfo(false);
     if (!callInfo.init(current, 0))
         return false;
 
     // Inline if we can, otherwise, forget it and just generate a call.
     if (makeInliningDecision(commonGetter, callInfo) && commonGetter->isInterpreted()) {
         if (!inlineScriptedCall(callInfo, commonGetter))
             return false;
     } else {
@@ -8334,17 +8453,17 @@ IonBuilder::getPropTryCommonGetter(bool 
             return false;
     }
 
     *emitted = true;
     return true;
 }
 
 static bool
-CanInlinePropertyOpShapes(const Vector<Shape *> &shapes)
+CanInlinePropertyOpShapes(const BaselineInspector::ShapeVector &shapes)
 {
     for (size_t i = 0; i < shapes.length(); i++) {
         // We inline the property access as long as the shape is not in
         // dictionary made. We cannot be sure that the shape is still a
         // lastProperty, and calling Shape::search() on dictionary mode
         // shapes that aren't lastProperty is invalid.
         if (shapes[i]->inDictionary())
             return false;
@@ -8356,17 +8475,17 @@ CanInlinePropertyOpShapes(const Vector<S
 bool
 IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name, jsid id,
                                    bool barrier, types::TemporaryTypeSet *types)
 {
     JS_ASSERT(*emitted == false);
     if (current->peek(-1)->type() != MIRType_Object)
         return true;
 
-    Vector<Shape *> shapes(cx);
+    BaselineInspector::ShapeVector shapes;
     if (!inspector->maybeShapesForPropertyOp(pc, shapes))
         return false;
 
     if (shapes.empty() || !CanInlinePropertyOpShapes(shapes))
         return true;
 
     MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
     if (barrier || IsNullOrUndefined(rvalType))
@@ -8526,16 +8645,20 @@ IonBuilder::jsop_setprop(PropertyName *n
     types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
     bool barrier;
     if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value,
                                        /* canModify = */ true, &barrier))
     {
         return false;
     }
 
+    // Try to emit stores to known binary data blocks
+    if (!setPropTryTypedObject(&emitted, obj, id, value) || emitted)
+        return emitted;
+
     // Try to emit store from definite slots.
     if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
         return emitted;
 
     // Try to emit a monomorphic/polymorphic store based on baseline caches.
     if (!setPropTryInlineAccess(&emitted, obj, name, id, value, barrier, objTypes) || emitted)
         return emitted;
 
@@ -8602,17 +8725,17 @@ IonBuilder::setPropTryCommonSetter(bool 
     current->add(wrapper);
 
     MPassArg *arg = MPassArg::New(value);
     current->push(arg);
     current->add(arg);
 
     // Call the setter. Note that we have to push the original value, not
     // the setter's return value.
-    CallInfo callInfo(cx, false);
+    CallInfo callInfo(false);
     if (!callInfo.init(current, 1))
         return false;
 
     // Ensure that we know we are calling a setter in case we inline it.
     callInfo.markAsSetter();
 
     // Inline the setter if we can.
     if (makeInliningDecision(commonSetter, callInfo) && commonSetter->isInterpreted()) {
@@ -8659,16 +8782,76 @@ IonBuilder::setPropTryCommonDOMSetter(bo
     if (!resumeAfter(set))
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
+IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
+                                  jsid id, MDefinition *value)
+{
+    TypeRepresentationSet fieldTypeReprs;
+    int32_t fieldOffset;
+    size_t fieldIndex;
+    if (!lookupTypedObjectField(obj, id, &fieldOffset, &fieldTypeReprs,
+                                &fieldIndex))
+        return false;
+    if (fieldTypeReprs.empty())
+        return true;
+
+    switch (fieldTypeReprs.kind()) {
+      case TypeRepresentation::Struct:
+      case TypeRepresentation::Array:
+        // For now, only optimize storing scalars.
+        return true;
+
+      case TypeRepresentation::Scalar:
+        break;
+    }
+
+    // Must always be storing the same scalar type
+    if (fieldTypeReprs.length() != 1)
+        return true;
+    ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
+
+    // OK!
+    *emitted = true;
+
+    MTypedObjectElements *elements = MTypedObjectElements::New(obj);
+    current->add(elements);
+
+    // Typed array offsets are expressed in units of the alignment,
+    // and the binary data API guarantees all offsets are properly
+    // aligned.
+    JS_ASSERT(fieldOffset % fieldTypeRepr->alignment() == 0);
+    int32_t scaledFieldOffset = fieldOffset / fieldTypeRepr->alignment();
+
+    MConstant *offset = MConstant::New(Int32Value(scaledFieldOffset));
+    current->add(offset);
+
+    // Clamp value to [0, 255] for Uint8ClampedArray.
+    MDefinition *toWrite = value;
+    if (fieldTypeRepr->type() == ScalarTypeRepresentation::TYPE_UINT8_CLAMPED) {
+        toWrite = MClampToUint8::New(value);
+        current->add(toWrite->toInstruction());
+    }
+
+    MStoreTypedArrayElement *store =
+        MStoreTypedArrayElement::New(elements, offset, toWrite,
+                                     fieldTypeRepr->type());
+    current->add(store);
+
+    current->push(value);
+
+    return true;
+}
+
+bool
 IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
                                    PropertyName *name, MDefinition *value,
                                    bool barrier, types::TemporaryTypeSet *objTypes)
 {
     JS_ASSERT(*emitted == false);
 
     if (barrier)
         return true;
@@ -8697,17 +8880,17 @@ IonBuilder::setPropTryInlineAccess(bool 
                                    MDefinition *value, bool barrier,
                                    types::TemporaryTypeSet *objTypes)
 {
     JS_ASSERT(*emitted == false);
 
     if (barrier)
         return true;
 
-    Vector<Shape *> shapes(cx);
+    BaselineInspector::ShapeVector shapes;
     if (!inspector->maybeShapesForPropertyOp(pc, shapes))
         return false;
 
     if (shapes.empty())
         return true;
 
     if (!CanInlinePropertyOpShapes(shapes))
         return true;
@@ -8841,19 +9024,16 @@ IonBuilder::jsop_object(JSObject *obj)
     current->push(ins);
 
     return true;
 }
 
 bool
 IonBuilder::jsop_lambda(JSFunction *fun)
 {
-    if (fun->isInterpreted() && !fun->getOrCreateScript(cx))
-        return false;
-
     JS_ASSERT(analysis().usesScopeChain());
     if (fun->isArrow())
         return abort("bound arrow function");
     if (fun->isNative() && IsAsmJSModuleNative(fun->native()))
         return abort("asm.js module function");
 
     MLambda *ins = MLambda::New(current->scopeChain(), fun);
     current->add(ins);
@@ -9333,8 +9513,177 @@ types::TemporaryTypeSet *
 IonBuilder::cloneTypeSet(types::StackTypeSet *types)
 {
     // Clone a type set so that it can be stored into the MIR and accessed
     // during off thread compilation. This is necessary because main thread
     // updates to type sets can race with reads in the compiler backend, and
     // after bug 804676 this code can be removed.
     return types->clone(GetIonContext()->temp->lifoAlloc());
 }
+
+TypeRepresentationSetHash *
+IonBuilder::getOrCreateReprSetHash()
+{
+    if (!reprSetHash_) {
+        TypeRepresentationSetHash* hash =
+            cx->new_<TypeRepresentationSetHash>();
+        if (!hash || !hash->init()) {
+            js_delete(hash);
+            return NULL;
+        }
+
+        reprSetHash_ = hash;
+    }
+    return reprSetHash_.get();
+}
+
+bool
+IonBuilder::lookupTypeRepresentationSet(MDefinition *typedObj,
+                                        TypeRepresentationSet *out)
+{
+    *out = TypeRepresentationSet(); // default to unknown
+
+    // Extract TypeRepresentationSet directly if we can
+    if (typedObj->isNewDerivedTypedObject()) {
+        *out = typedObj->toNewDerivedTypedObject()->set();
+        return true;
+    }
+
+    // Extract TypeRepresentationSet directly if we can
+    types::TemporaryTypeSet *types = typedObj->resultTypeSet();
+    if (!types || types->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
+        return true;
+
+    // And only known objects.
+    if (types->unknownObject())
+        return true;
+
+    TypeRepresentationSetBuilder set;
+    for (uint32_t i = 0; i < types->getObjectCount(); i++) {
+        types::TypeObject *type = types->getTypeObject(0);
+        if (!type || type->unknownProperties())
+            return true;
+
+        if (!type->hasTypedObject())
+            return true;
+
+        TypeRepresentation *typeRepr = type->typedObject()->typeRepr;
+        if (!set.insert(typeRepr))
+            return false;
+    }
+
+    return set.build(*this, out);
+}
+
+MDefinition *
+IonBuilder::loadTypedObjectType(MDefinition *typedObj)
+{
+    // Shortcircuit derived type objects, meaning the intermediate
+    // objects created to represent `a.b` in an expression like
+    // `a.b.c`. In that case, the type object can be simply pulled
+    // from the operands of that instruction.
+    if (typedObj->isNewDerivedTypedObject())
+        return typedObj->toNewDerivedTypedObject()->type();
+
+    MInstruction *load = MLoadFixedSlot::New(typedObj, js::SLOT_DATATYPE);
+    current->add(load);
+    return load;
+}
+
+// Given a typed object `typedObj` and an offset `offset` into that
+// object's data, returns another typed object and adusted offset
+// where the data can be found. Often, these returned values are the
+// same as the inputs, but in cases where intermediate derived type
+// objects have been created, the return values will remove
+// intermediate layers (often rendering those derived type objects
+// into dead code).
+void
+IonBuilder::loadTypedObjectData(MDefinition *typedObj,
+                                int32_t offset,
+                                MDefinition **owner,
+                                MDefinition **ownerOffset)
+{
+    MConstant *offsetDef = MConstant::New(Int32Value(offset));
+    current->add(offsetDef);
+
+    // Shortcircuit derived type objects, meaning the intermediate
+    // objects created to represent `a.b` in an expression like
+    // `a.b.c`. In that case, the owned and a base offset can be
+    // pulled from the operands of the instruction and combined with
+    // `offset`.
+    if (typedObj->isNewDerivedTypedObject()) {
+        // If we see that the
+        MNewDerivedTypedObject *ins = typedObj->toNewDerivedTypedObject();
+
+        MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offsetDef,
+                                         MIRType_Int32);
+        current->add(offsetAdd);
+
+        *owner = ins->owner();
+        *ownerOffset = offsetAdd;
+        return;
+    }
+
+    *owner = typedObj;
+    *ownerOffset = offsetDef;
+}
+
+// Looks up the offset/type-repr-set of the field `id`, given the type
+// set `objTypes` of the field owner. Note that even when true is
+// returned, `*fieldTypeReprs` might be empty if no useful type/offset
+// pair could be determined.
+bool
+IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
+                                   jsid id,
+                                   int32_t *fieldOffset,
+                                   TypeRepresentationSet *fieldTypeReprs,
+                                   size_t *fieldIndex)
+{
+    TypeRepresentationSet objTypeReprs;
+    if (!lookupTypeRepresentationSet(typedObj, &objTypeReprs))
+        return false;
+
+    // Must be accessing a struct.
+    if (!objTypeReprs.allOfKind(TypeRepresentation::Struct))
+        return true;
+
+    // Determine the type/offset of the field `id`, if any.
+    size_t offset;
+    if (!objTypeReprs.fieldNamed(*this, id, &offset,
+                                 fieldTypeReprs, fieldIndex))
+        return false;
+    if (fieldTypeReprs->empty())
+        return false;
+
+    // Field offset must be representable as signed integer.
+    if (offset >= size_t(INT_MAX)) {
+        *fieldTypeReprs = TypeRepresentationSet();
+        return true;
+    }
+
+    *fieldOffset = int32_t(offset);
+    JS_ASSERT(*fieldOffset >= 0);
+
+    return true;
+}
+
+MDefinition *
+IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
+                                             size_t fieldIndex)
+{
+    // Load list of field type objects.
+
+    MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, SLOT_STRUCT_FIELD_TYPES);
+    current->add(fieldTypes);
+
+    // Index into list with index of field.
+
+    MInstruction *fieldTypesElements = MElements::New(fieldTypes);
+    current->add(fieldTypesElements);
+
+    MConstant *fieldIndexDef = MConstant::New(Int32Value(fieldIndex));
+    current->add(fieldIndexDef);
+
+    MInstruction *fieldType = MLoadElement::New(fieldTypesElements, fieldIndexDef, false, false);
+    current->add(fieldType);
+
+    return fieldType;
+}
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -10,16 +10,17 @@
 #ifdef JS_ION
 
 // This file declares the data structures for building a MIRGraph from a
 // JSScript.
 
 #include "jit/BytecodeAnalysis.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
+#include "jit/TypeRepresentationSet.h"
 
 namespace js {
 namespace jit {
 
 class CodeGenerator;
 class CallInfo;
 class BaselineInspector;
 
@@ -222,17 +223,17 @@ class IonBuilder : public MIRGenerator
     void spew(const char *message);
 
     static bool inliningEnabled() {
         return js_IonOptions.inlining;
     }
 
     JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
     bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
-                            AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda);
+                            ObjectVector &targets, uint32_t maxTargets, bool *gotLambda);
     bool canInlineTarget(JSFunction *target, bool constructing);
 
     void popCfgStack();
     DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge);
     bool processDeferredContinues(CFGState &state);
     ControlStatus processControlEnd();
     ControlStatus processCfgStack();
     ControlStatus processCfgEntry(CFGState &state);
@@ -358,16 +359,27 @@ class IonBuilder : public MIRGenerator
     bool getPropTryArgumentsLength(bool *emitted);
     bool getPropTryConstant(bool *emitted, jsid id, types::TemporaryTypeSet *types);
     bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
                                 bool barrier, types::TemporaryTypeSet *types);
     bool getPropTryCommonGetter(bool *emitted, jsid id,
                                 bool barrier, types::TemporaryTypeSet *types);
     bool getPropTryInlineAccess(bool *emitted, PropertyName *name, jsid id,
                                 bool barrier, types::TemporaryTypeSet *types);
+    bool getPropTryTypedObject(bool *emitted, jsid id,
+                               types::TemporaryTypeSet *resultTypes);
+    bool getPropTryScalarPropOfTypedObject(bool *emitted,
+                                           int32_t fieldOffset,
+                                           TypeRepresentationSet fieldTypeReprs,
+                                           types::TemporaryTypeSet *resultTypes);
+    bool getPropTryComplexPropOfTypedObject(bool *emitted,
+                                            int32_t fieldOffset,
+                                            TypeRepresentationSet fieldTypeReprs,
+                                            size_t fieldIndex,
+                                            types::TemporaryTypeSet *resultTypes);
     bool getPropTryCache(bool *emitted, PropertyName *name, jsid id,
                          bool barrier, types::TemporaryTypeSet *types);
     bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
 
     // jsop_setprop() helpers.
     bool setPropTryCommonSetter(bool *emitted, MDefinition *obj,
                                 PropertyName *name, jsid id,
                                 MDefinition *value);
@@ -376,20 +388,38 @@ class IonBuilder : public MIRGenerator
                                    bool isDOM);
     bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
                                 PropertyName *name, MDefinition *value,
                                 bool barrier, types::TemporaryTypeSet *objTypes);
     bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
                                 PropertyName *name, jsid id,
                                 MDefinition *value, bool barrier,
                                 types::TemporaryTypeSet *objTypes);
+    bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
+                               jsid id, MDefinition *value);
     bool setPropTryCache(bool *emitted, MDefinition *obj,
                          PropertyName *name, MDefinition *value,
                          bool barrier, types::TemporaryTypeSet *objTypes);
 
+    // binary data lookup helpers.
+    bool lookupTypeRepresentationSet(MDefinition *typedObj,
+                                     TypeRepresentationSet *out);
+    bool lookupTypedObjectField(MDefinition *typedObj,
+                                jsid id,
+                                int32_t *fieldOffset,
+                                TypeRepresentationSet *fieldTypeReprs,
+                                size_t *fieldIndex);
+    MDefinition *loadTypedObjectType(MDefinition *value);
+    void loadTypedObjectData(MDefinition *inOwner,
+                             int32_t inOffset,
+                             MDefinition **outOwner,
+                             MDefinition **outOffset);
+    MDefinition *typeObjectForFieldFromStructType(MDefinition *type,
+                                                  size_t fieldIndex);
+
     // jsop_setelem() helpers.
     bool setElemTryTyped(bool *emitted, MDefinition *object,
                          MDefinition *index, MDefinition *value);
     bool setElemTryTypedStatic(bool *emitted, MDefinition *object,
                                MDefinition *index, MDefinition *value);
     bool setElemTryDense(bool *emitted, MDefinition *object,
                          MDefinition *index, MDefinition *value);
     bool setElemTryArguments(bool *emitted, MDefinition *object,
@@ -490,17 +520,18 @@ class IonBuilder : public MIRGenerator
         InliningStatus_Error,
         InliningStatus_NotInlined,
         InliningStatus_Inlined
     };
 
     // Oracles.
     bool canEnterInlinedFunction(JSFunction *target);
     bool makeInliningDecision(JSFunction *target, CallInfo &callInfo);
-    uint32_t selectInliningTargets(AutoObjectVector &targets, CallInfo &callInfo, Vector<bool> &choiceSet);
+    uint32_t selectInliningTargets(ObjectVector &targets, CallInfo &callInfo,
+                                   BoolVector &choiceSet);
 
     // Native inlining helpers.
     types::StackTypeSet *getOriginalInlineReturnTypeSet();
     types::TemporaryTypeSet *getInlineReturnTypeSet();
     MIRType getInlineReturnType();
 
     // Array natives.
     InliningStatus inlineArray(CallInfo &callInfo);
@@ -565,20 +596,20 @@ class IonBuilder : public MIRGenerator
     InliningStatus inlineAssertFloat32(CallInfo &callInfo);
 
     // Main inlining functions
     InliningStatus inlineNativeCall(CallInfo &callInfo, JSNative native);
     bool inlineScriptedCall(CallInfo &callInfo, JSFunction *target);
     InliningStatus inlineSingleCall(CallInfo &callInfo, JSFunction *target);
 
     // Call functions
-    InliningStatus inlineCallsite(AutoObjectVector &targets, AutoObjectVector &originals,
+    InliningStatus inlineCallsite(ObjectVector &targets, ObjectVector &originals,
                                   bool lambda, CallInfo &callInfo);
-    bool inlineCalls(CallInfo &callInfo, AutoObjectVector &targets, AutoObjectVector &originals,
-                     Vector<bool> &choiceSet, MGetPropertyCache *maybeCache);
+    bool inlineCalls(CallInfo &callInfo, ObjectVector &targets, ObjectVector &originals,
+                     BoolVector &choiceSet, MGetPropertyCache *maybeCache);
 
     // Inlining helpers.
     bool inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock,
                                bool clonedAtCallsite);
     bool inlineTypeObjectFallback(CallInfo &callInfo, MBasicBlock *dispatchBlock,
                                   MTypeObjectDispatch *dispatch, MGetPropertyCache *cache,
                                   MBasicBlock **fallbackTarget);
 
@@ -635,22 +666,25 @@ class IonBuilder : public MIRGenerator
 
     JSScript *script() const { return script_.get(); }
 
     CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
     void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
 
     AbortReason abortReason() { return abortReason_; }
 
+    TypeRepresentationSetHash *getOrCreateReprSetHash(); // fallible
+
   private:
     bool init();
 
     JSContext *cx;
     BaselineFrame *baselineFrame_;
     AbortReason abortReason_;
+    ScopedJSDeletePtr<TypeRepresentationSetHash> reprSetHash_;
 
     // Basic analysis information about the script.
     BytecodeAnalysis analysis_;
     BytecodeAnalysis &analysis() {
         return analysis_;
     }
 
     GSNCache gsn;
@@ -708,26 +742,25 @@ class IonBuilder : public MIRGenerator
     // If this is an inline builder, the call info for the builder.
     const CallInfo *inlineCallInfo_;
 };
 
 class CallInfo
 {
     MDefinition *fun_;
     MDefinition *thisArg_;
-    Vector<MDefinition *> args_;
+    MDefinitionVector args_;
 
     bool constructing_;
     bool setter_;
 
   public:
-    CallInfo(JSContext *cx, bool constructing)
+    CallInfo(bool constructing)
       : fun_(NULL),
         thisArg_(NULL),
-        args_(cx),
         constructing_(constructing),
         setter_(false)
     { }
 
     bool init(CallInfo &callInfo) {
         JS_ASSERT(constructing_ == callInfo.constructing());
 
         fun_ = callInfo.fun();
@@ -770,26 +803,26 @@ class CallInfo
 
     uint32_t argc() const {
         return args_.length();
     }
     uint32_t numFormals() const {
         return argc() + 2;
     }
 
-    void setArgs(Vector<MDefinition *> *args) {
+    void setArgs(MDefinitionVector *args) {
         JS_ASSERT(args_.length() == 0);
         args_.append(args->begin(), args->end());
     }
 
-    Vector<MDefinition *> &argv() {
+    MDefinitionVector &argv() {
         return args_;
     }
 
-    const Vector<MDefinition *> &argv() const {
+    const MDefinitionVector &argv() const {
         return args_;
     }
 
     MDefinition *getArg(uint32_t i) const {
         JS_ASSERT(i < argc());
         return args_[i];
     }
 
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -2146,17 +2146,17 @@ SetPropertyIC::attachGenericProxy(JSCont
     Label failures;
     {
         Label proxyFailures;
         Label proxySuccess;
 
         RegisterSet regSet(RegisterSet::All());
         regSet.take(AnyRegister(object()));
         if (!value().constant())
-            regSet.maybeTake(value().reg());
+            regSet.takeUnchecked(value().reg());
 
         Register scratch = regSet.takeGeneral();
         masm.push(scratch);
 
         GenerateProxyClassGuards(masm, object(), scratch, &proxyFailures, &proxySuccess);
 
         // Remove the DOM proxies. They'll take care of themselves so this stub doesn't
         // catch too much.
@@ -2236,17 +2236,17 @@ GenerateCallSetter(JSContext *cx, IonScr
                    void *returnAddr)
 {
     // Generate prototype guards if needed.
     // Take a scratch register for use, save on stack.
     {
         RegisterSet regSet(RegisterSet::All());
         regSet.take(AnyRegister(object));
         if (!value.constant())
-            regSet.maybeTake(value.reg());
+            regSet.takeUnchecked(value.reg());
         Register scratchReg = regSet.takeGeneral();
         masm.push(scratchReg);
 
         Label protoFailure;
         Label protoSuccess;
 
         // Generate prototype/shape guards.
         if (obj != holder)
@@ -2975,17 +2975,17 @@ GenerateGetTypedArrayElement(JSContext *
         } else {
             JS_ASSERT(!index.reg().typedReg().isFloat());
             str = index.reg().typedReg().gpr();
         }
 
         // Part 2: Call to translate the str into index
         RegisterSet regs = RegisterSet::Volatile();
         masm.PushRegsInMask(regs);
-        regs.maybeTake(str);
+        regs.takeUnchecked(str);
 
         Register temp = regs.takeGeneral();
 
         masm.setupUnalignedABICall(1, temp);
         masm.passABIArg(str);
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, GetIndexFromString));
         masm.mov(ReturnReg, indexReg);
 
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1345,17 +1345,17 @@ void printf1_(const char *output, uintpt
 }
 
 void
 MacroAssembler::printf(const char *output, Register value)
 {
     RegisterSet regs = RegisterSet::Volatile();
     PushRegsInMask(regs);
 
-    regs.maybeTake(value);
+    regs.takeUnchecked(value);
 
     Register temp = regs.takeGeneral();
 
     setupUnalignedABICall(2, temp);
     movePtr(ImmPtr(output), temp);
     passABIArg(temp);
     passABIArg(value);
     callWithABI(JS_FUNC_TO_DATA_PTR(void *, printf1_));
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -496,16 +496,42 @@ public:
         return getTemp(0)->output();
     }
 
     const LAllocation *getTemp1() {
         return getTemp(1)->output();
     }
 };
 
+class LNewDerivedTypedObject : public LCallInstructionHelper<1, 3, 0>
+{
+  public:
+    LIR_HEADER(NewDerivedTypedObject);
+
+    LNewDerivedTypedObject(const LAllocation &type,
+                           const LAllocation &owner,
+                           const LAllocation &offset) {
+        setOperand(0, type);
+        setOperand(1, owner);
+        setOperand(2, offset);
+    }
+
+    const LAllocation *type() {
+        return getOperand(0);
+    }
+
+    const LAllocation *owner() {
+        return getOperand(1);
+    }
+
+    const LAllocation *offset() {
+        return getOperand(2);
+    }
+};
+
 class LNewStringObject : public LInstructionHelper<1, 1, 1>
 {
   public:
     LIR_HEADER(NewStringObject)
 
     LNewStringObject(const LAllocation &input, const LDefinition &temp) {
         setOperand(0, input);
         setTemp(0, temp);
@@ -3037,16 +3063,30 @@ class LTypedArrayElements : public LInst
     LTypedArrayElements(const LAllocation &object) {
         setOperand(0, object);
     }
     const LAllocation *object() {
         return getOperand(0);
     }
 };
 
+// Load a typed array's elements vector.
+class LTypedObjectElements : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(TypedObjectElements)
+
+    LTypedObjectElements(const LAllocation &object) {
+        setOperand(0, object);
+    }
+    const LAllocation *object() {
+        return getOperand(0);
+    }
+};
+
 // Bailout if index >= length.
 class LBoundsCheck : public LInstructionHelper<0, 2, 0>
 {
   public:
     LIR_HEADER(BoundsCheck)
 
     LBoundsCheck(const LAllocation &index, const LAllocation &length) {
         setOperand(0, index);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -27,16 +27,17 @@
     _(NewObject)                    \
     _(NewSlots)                     \
     _(NewDeclEnvObject)             \
     _(NewCallObject)                \
     _(NewStringObject)              \
     _(NewPar)                       \
     _(NewDenseArrayPar)             \
     _(NewCallObjectPar)             \
+    _(NewDerivedTypedObject)        \
     _(AbortPar)                     \
     _(InitElem)                     \
     _(InitElemGetterSetter)         \
     _(InitProp)                     \
     _(InitPropGetterSetter)         \
     _(CheckOverRecursed)            \
     _(CheckOverRecursedPar)         \
     _(DefVar)                       \
@@ -216,16 +217,17 @@
     _(CallIteratorStart)            \
     _(IteratorStart)                \
     _(IteratorNext)                 \
     _(IteratorMore)                 \
     _(IteratorEnd)                  \
     _(ArrayLength)                  \
     _(TypedArrayLength)             \
     _(TypedArrayElements)           \
+    _(TypedObjectElements)          \
     _(StringLength)                 \
     _(ArgumentsLength)              \
     _(GetArgument)                  \
     _(RunOncePrologue)              \
     _(Rest)                         \
     _(RestPar)                      \
     _(TypeOfV)                      \
     _(ToIdV)                        \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -18,16 +18,17 @@
 
 #include "jsinferinlines.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace jit;
 
+using mozilla::DebugOnly;
 using JS::GenericNaN;
 
 bool
 LIRGenerator::visitParameter(MParameter *param)
 {
     ptrdiff_t offset;
     if (param->index() == MParameter::THIS_SLOT)
         offset = THIS_FRAME_SLOT;
@@ -202,16 +203,26 @@ LIRGenerator::visitNewCallObject(MNewCal
 
     if (!assignSafepoint(lir, ins))
         return false;
 
     return true;
 }
 
 bool
+LIRGenerator::visitNewDerivedTypedObject(MNewDerivedTypedObject *ins)
+{
+    LNewDerivedTypedObject *lir =
+        new LNewDerivedTypedObject(useRegisterAtStart(ins->type()),
+                                   useRegisterAtStart(ins->owner()),
+                                   useRegisterAtStart(ins->offset()));
+    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
 {
     const LAllocation &parThreadContext = useRegister(ins->forkJoinSlice());
     const LDefinition &temp1 = temp();
     const LDefinition &temp2 = temp();
 
     LNewCallObjectPar *lir;
     if (ins->slots()->type() == MIRType_Slots) {
@@ -1761,35 +1772,35 @@ LIRGenerator::visitRegExpTest(MRegExpTes
     LRegExpTest *lir = new LRegExpTest(useRegisterAtStart(ins->regexp()),
                                        useRegisterAtStart(ins->string()));
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitLambda(MLambda *ins)
 {
-    if (ins->fun()->hasSingletonType() || types::UseNewTypeForClone(ins->fun())) {
+    if (ins->info().singletonType || ins->info().useNewTypeForClone) {
         // If the function has a singleton type, this instruction will only be
         // executed once so we don't bother inlining it.
         //
         // If UseNewTypeForClone is true, we will assign a singleton type to
         // the clone and we have to clone the script, we can't do that inline.
         LLambdaForSingleton *lir = new LLambdaForSingleton(useRegisterAtStart(ins->scopeChain()));
         return defineReturn(lir, ins) && assignSafepoint(lir, ins);
     }
 
     LLambda *lir = new LLambda(useRegister(ins->scopeChain()));
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitLambdaPar(MLambdaPar *ins)
 {
-    JS_ASSERT(!ins->fun()->hasSingletonType());
-    JS_ASSERT(!types::UseNewTypeForClone(ins->fun()));
+    JS_ASSERT(!ins->info().singletonType);
+    JS_ASSERT(!ins->info().useNewTypeForClone);
     LLambdaPar *lir = new LLambdaPar(useRegister(ins->forkJoinSlice()),
                                      useRegister(ins->scopeChain()),
                                      temp(), temp());
     return define(lir, ins);
 }
 
 bool
 LIRGenerator::visitImplicitThis(MImplicitThis *ins)
@@ -2063,16 +2074,23 @@ LIRGenerator::visitTypedArrayLength(MTyp
 bool
 LIRGenerator::visitTypedArrayElements(MTypedArrayElements *ins)
 {
     JS_ASSERT(ins->type() == MIRType_Elements);
     return define(new LTypedArrayElements(useRegisterAtStart(ins->object())), ins);
 }
 
 bool
+LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
+{
+    JS_ASSERT(ins->type() == MIRType_Elements);
+    return define(new LTypedObjectElements(useRegisterAtStart(ins->object())), ins);
+}
+
+bool
 LIRGenerator::visitInitializedLength(MInitializedLength *ins)
 {
     JS_ASSERT(ins->elements()->type() == MIRType_Elements);
     return define(new LInitializedLength(useRegisterAtStart(ins->elements())), ins);
 }
 
 bool
 LIRGenerator::visitSetInitializedLength(MSetInitializedLength *ins)
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -84,16 +84,17 @@ class LIRGenerator : public LIRGenerator
     bool visitTableSwitch(MTableSwitch *tableswitch);
     bool visitNewSlots(MNewSlots *ins);
     bool visitNewParallelArray(MNewParallelArray *ins);
     bool visitNewArray(MNewArray *ins);
     bool visitNewObject(MNewObject *ins);
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
+    bool visitNewDerivedTypedObject(MNewDerivedTypedObject *ins);
     bool visitNewPar(MNewPar *ins);
     bool visitNewCallObjectPar(MNewCallObjectPar *ins);
     bool visitNewDenseArrayPar(MNewDenseArrayPar *ins);
     bool visitAbortPar(MAbortPar *ins);
     bool visitInitElem(MInitElem *ins);
     bool visitInitElemGetterSetter(MInitElemGetterSetter *ins);
     bool visitInitProp(MInitProp *ins);
     bool visitInitPropGetterSetter(MInitPropGetterSetter *ins);
@@ -177,16 +178,17 @@ class LIRGenerator : public LIRGenerator
     bool visitCheckInterruptPar(MCheckInterruptPar *ins);
     bool visitStoreSlot(MStoreSlot *ins);
     bool visitTypeBarrier(MTypeBarrier *ins);
     bool visitMonitorTypes(MMonitorTypes *ins);
     bool visitPostWriteBarrier(MPostWriteBarrier *ins);
     bool visitArrayLength(MArrayLength *ins);
     bool visitTypedArrayLength(MTypedArrayLength *ins);
     bool visitTypedArrayElements(MTypedArrayElements *ins);
+    bool visitTypedObjectElements(MTypedObjectElements *ins);
     bool visitInitializedLength(MInitializedLength *ins);
     bool visitSetInitializedLength(MSetInitializedLength *ins);
     bool visitNot(MNot *ins);
     bool visitBoundsCheck(MBoundsCheck *ins);
     bool visitBoundsCheckLower(MBoundsCheckLower *ins);
     bool visitLoadElement(MLoadElement *ins);
     bool visitLoadElementHole(MLoadElementHole *ins);
     bool visitStoreElement(MStoreElement *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1266,23 +1266,16 @@ IonBuilder::inlineParallelArrayTail(Call
     uint32_t targetArgs = argc;
     if (target && !target->isNative())
         targetArgs = Max<uint32_t>(target->nargs, argc);
 
     MCall *call = MCall::New(target, targetArgs + 1, argc, false);
     if (!call)
         return InliningStatus_Error;
 
-    // Save the script for inspection by visitCallKnown().
-    if (target && target->isInterpreted()) {
-        if (!target->getOrCreateScript(cx))
-            return InliningStatus_Error;
-        call->rootTargetScript(target);
-    }
-
     callInfo.unwrapArgs();
 
     // Explicitly pad any missing arguments with |undefined|.
     // This permits skipping the argumentsRectifier.
     for (uint32_t i = targetArgs; i > argc; i--) {
         JS_ASSERT_IF(target, !target->isNative());
         MConstant *undef = MConstant::New(UndefinedValue());
         current->add(undef);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -534,16 +534,23 @@ MCompare::printOpcode(FILE *fp) const
 
 void
 MConstantElements::printOpcode(FILE *fp) const
 {
     PrintOpcodeName(fp, op());
     fprintf(fp, " %p", value());
 }
 
+void
+MLoadTypedArrayElement::printOpcode(FILE *fp) const
+{
+    MDefinition::printOpcode(fp);
+    fprintf(fp, " %s", ScalarTypeRepresentation::typeName(arrayType()));
+}
+
 MParameter *
 MParameter::New(int32_t index, types::TemporaryTypeSet *types)
 {
     return new MParameter(index, types);
 }
 
 void
 MParameter::printOpcode(FILE *fp) const
@@ -2463,17 +2470,17 @@ bool
 MLoadSlot::mightAlias(MDefinition *store)
 {
     if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot())
         return false;
     return true;
 }
 
 void
-InlinePropertyTable::trimTo(AutoObjectVector &targets, Vector<bool> &choiceSet)
+InlinePropertyTable::trimTo(ObjectVector &targets, BoolVector &choiceSet)
 {
     for (size_t i = 0; i < targets.length(); i++) {
         // If the target was inlined, don't erase the entry.
         if (choiceSet[i])
             continue;
 
         JSFunction *target = &targets[i]->as<JSFunction>();
 
@@ -2484,17 +2491,17 @@ InlinePropertyTable::trimTo(AutoObjectVe
                 entries_.erase(&entries_[j]);
             else
                 j++;
         }
     }
 }
 
 void
-InlinePropertyTable::trimToTargets(AutoObjectVector &targets)
+InlinePropertyTable::trimToTargets(ObjectVector &targets)
 {
     IonSpew(IonSpew_Inlining, "Got inlineable property cache with %d cases",
             (int)numEntries());
 
     size_t i = 0;
     while (i < numEntries()) {
         bool foundFunc = false;
         for (size_t j = 0; j < targets.length(); j++) {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -19,16 +19,17 @@
 #include "jit/Bailouts.h"
 #include "jit/CompilerRoot.h"
 #include "jit/FixedList.h"
 #include "jit/InlineList.h"
 #include "jit/IonAllocPolicy.h"
 #include "jit/IonMacroAssembler.h"
 #include "jit/MOpcodes.h"
 #include "jit/TypePolicy.h"
+#include "jit/TypeRepresentationSet.h"
 #include "vm/ScopeObject.h"
 
 namespace js {
 
 class StringObject;
 
 namespace jit {
 
@@ -456,16 +457,22 @@ class MDefinition : public MNode
     }
 
     // Float32 specialization operations (see big comment in IonAnalysis before the Float32
     // specialization algorithm).
     virtual bool isFloat32Commutative() const { return false; }
     virtual bool canProduceFloat32() const { return false; }
     virtual bool canConsumeFloat32() const { return false; }
     virtual void trySpecializeFloat32() {}
+#ifdef DEBUG
+    // Used during the pass that checks that Float32 flow into valid MDefinitions
+    virtual bool isConsistentFloat32Use() const {
+        return type() == MIRType_Float32 || canConsumeFloat32();
+    }
+#endif
 
     // Returns the beginning of this definition's use chain.
     MUseIterator usesBegin() const {
         return uses_.begin();
     }
 
     // Returns the end of this definition's use chain.
     MUseIterator usesEnd() const {
@@ -1476,16 +1483,76 @@ class MNewPar : public MUnaryInstruction
         return getOperand(0);
     }
 
     JSObject *templateObject() const {
         return templateObject_;
     }
 };
 
+// Creates a new derived type object. At runtime, this is just a call
+// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
+// compile to particularly optimized code. However, using a distinct
+// MIR for creating derived type objects allows the compiler to
+// optimize ephemeral typed objects as would be created for a
+// reference like `a.b.c` -- here, the `a.b` will create an ephemeral
+// derived type object that aliases the memory of `a` itself. The
+// specific nature of `a.b` is revealed by using
+// `MNewDerivedTypedObject` rather than `MGetProperty` or what have
+// you. Moreover, the compiler knows that there are no side-effects,
+// so `MNewDerivedTypedObject` instructions can be reordered or pruned
+// as dead code.
+class MNewDerivedTypedObject
+  : public MTernaryInstruction,
+    public Mix3Policy<ObjectPolicy<0>,
+                      ObjectPolicy<1>,
+                      IntPolicy<2> >
+{
+  private:
+    TypeRepresentationSet set_;
+
+  public:
+    INSTRUCTION_HEADER(NewDerivedTypedObject);
+
+    MNewDerivedTypedObject(TypeRepresentationSet set,
+                           MDefinition *type,
+                           MDefinition *owner,
+                           MDefinition *offset)
+      : MTernaryInstruction(type, owner, offset),
+        set_(set)
+    {
+        setMovable();
+        setResultType(MIRType_Object);
+    }
+
+    TypeRepresentationSet set() const {
+        return set_;
+    }
+
+    MDefinition *type() const {
+        return getOperand(0);
+    }
+
+    MDefinition *owner() const {
+        return getOperand(1);
+    }
+
+    MDefinition *offset() const {
+        return getOperand(2);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+
+    virtual AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 // Abort parallel execution.
 class MAbortPar : public MAryControlInstruction<0, 0>
 {
   public:
     INSTRUCTION_HEADER(AbortPar);
 
     MAbortPar()
       : MAryControlInstruction<0, 0>()
@@ -1691,27 +1758,24 @@ class MCall
     static const size_t FunctionOperandIndex   = 1;
     static const size_t NumNonArgumentOperands = 2;
 
   protected:
     // True if the call is for JSOP_NEW.
     bool construct_;
     // Monomorphic cache of single target from TI, or NULL.
     CompilerRootFunction target_;
-    // Holds a target's Script alive.
-    CompilerRootScript targetScript_;
     // Original value of argc from the bytecode.
     uint32_t numActualArgs_;
 
     bool needsArgCheck_;
 
     MCall(JSFunction *target, uint32_t numActualArgs, bool construct)
       : construct_(construct),
         target_(target),
-        targetScript_(NULL),
         numActualArgs_(numActualArgs),
         needsArgCheck_(true)
     {
         setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(Call)
@@ -1749,23 +1813,16 @@ class MCall
     MDefinition *getArg(uint32_t index) const {
         return getOperand(NumNonArgumentOperands + index);
     }
 
     void replaceArg(uint32_t index, MDefinition *def) {
         replaceOperand(NumNonArgumentOperands + index, def);
     }
 
-    void rootTargetScript(JSFunction *target) {
-        targetScript_.setRoot(target->nonLazyScript());
-    }
-    bool hasRootedScript() {
-        return targetScript_ != NULL;
-    }
-
     // For TI-informed monomorphic callsites.
     JSFunction *getSingleTarget() const {
         return target_;
     }
 
     bool isConstructing() const {
         return construct_;
     }
@@ -2693,16 +2750,20 @@ class MToDouble
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     void computeRange();
     bool truncate();
     bool isOperandTruncated(size_t index) const;
+
+#ifdef DEBUG
+    bool isConsistentFloat32Use() const { return true; }
+#endif
 };
 
 // Converts a primitive (either typed or untyped) to a float32. If the input is
 // not primitive at runtime, a bailout occurs.
 class MToFloat32
   : public MUnaryInstruction,
     public ToDoublePolicy
 {
@@ -4418,85 +4479,106 @@ class MRegExpTest
         return this;
     }
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
+struct LambdaFunctionInfo
+{
+    // The functions used in lambdas are the canonical original function in
+    // the script, and are immutable except for delazification. Record this
+    // information while still on the main thread to avoid races.
+    CompilerRootFunction fun;
+    uint16_t flags;
+    gc::Cell *scriptOrLazyScript;
+    bool singletonType;
+    bool useNewTypeForClone;
+
+    LambdaFunctionInfo(JSFunction *fun)
+      : fun(fun), flags(fun->flags),
+        scriptOrLazyScript(fun->hasScript()
+                           ? (gc::Cell *) fun->nonLazyScript()
+                           : (gc::Cell *) fun->lazyScript()),
+        singletonType(fun->hasSingletonType()),
+        useNewTypeForClone(types::UseNewTypeForClone(fun))
+    {}
+};
+
 class MLambda
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
-    CompilerRootFunction fun_;
+    LambdaFunctionInfo info_;
 
     MLambda(MDefinition *scopeChain, JSFunction *fun)
-      : MUnaryInstruction(scopeChain), fun_(fun)
+      : MUnaryInstruction(scopeChain), info_(fun)
     {
         setResultType(MIRType_Object);
         if (!fun->hasSingletonType() && !types::UseNewTypeForClone(fun))
             setResultTypeSet(MakeSingletonTypeSet(fun));
     }
 
   public:
     INSTRUCTION_HEADER(Lambda)
 
     static MLambda *New(MDefinition *scopeChain, JSFunction *fun) {
         return new MLambda(scopeChain, fun);
     }
     MDefinition *scopeChain() const {
         return getOperand(0);
     }
-    JSFunction *fun() const {
-        return fun_;
+    const LambdaFunctionInfo &info() const {
+        return info_;
     }
     TypePolicy *typePolicy() {
         return this;
     }
 };
 
 class MLambdaPar
   : public MBinaryInstruction,
     public SingleObjectPolicy
 {
-    CompilerRootFunction fun_;
+    LambdaFunctionInfo info_;
 
     MLambdaPar(MDefinition *slice, MDefinition *scopeChain, JSFunction *fun,
                types::TemporaryTypeSet *resultTypes)
-      : MBinaryInstruction(slice, scopeChain), fun_(fun)
+      : MBinaryInstruction(slice, scopeChain), info_(fun)
     {
         JS_ASSERT(!fun->hasSingletonType());
         JS_ASSERT(!types::UseNewTypeForClone(fun));
         setResultType(MIRType_Object);
         setResultTypeSet(resultTypes);
     }
 
   public:
     INSTRUCTION_HEADER(LambdaPar);
 
     static MLambdaPar *New(MDefinition *slice, MDefinition *scopeChain, JSFunction *fun) {
         return new MLambdaPar(slice, scopeChain, fun, MakeSingletonTypeSet(fun));
     }
 
     static MLambdaPar *New(MDefinition *slice, MLambda *lambda) {
-        return new MLambdaPar(slice, lambda->scopeChain(), lambda->fun(),
+        return new MLambdaPar(slice, lambda->scopeChain(), lambda->info().fun,
                               lambda->resultTypeSet());
     }
 
     MDefinition *forkJoinSlice() const {
         return getOperand(0);
     }
 
     MDefinition *scopeChain() const {
         return getOperand(1);
     }
 
-    JSFunction *fun() const {
-        return fun_;
+    const LambdaFunctionInfo &info() const {
+        return info_;
     }
 };
 
 // Determines the implicit |this| value for function calls.
 class MImplicitThis
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
@@ -4856,16 +4938,52 @@ class MTypedArrayElements
     bool congruentTo(MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
+// Load a binary data object's "elements", which is just its opaque
+// binary data space. Eventually this should probably be
+// unified with `MTypedArrayElements`.
+class MTypedObjectElements
+  : public MUnaryInstruction,
+    public SingleObjectPolicy
+{
+  private:
+    MTypedObjectElements(MDefinition *object)
+      : MUnaryInstruction(object)
+    {
+        setResultType(MIRType_Elements);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypedObjectElements)
+
+    static MTypedObjectElements *New(MDefinition *object) {
+        return new MTypedObjectElements(object);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    MDefinition *object() const {
+        return getOperand(0);
+    }
+    bool congruentTo(MDefinition *ins) const {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
 // Perform !-operation
 class MNot
   : public MUnaryInstruction,
     public TestPolicy
 {
     bool operandMightEmulateUndefined_;
 
   public:
@@ -5397,16 +5515,18 @@ class MLoadTypedArrayElement
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::TypedArrayElement);
     }
 
+    void printOpcode(FILE *fp) const;
+
     void computeRange();
 
     bool canProduceFloat32() const { return arrayType_ == ScalarTypeRepresentation::TYPE_FLOAT32; }
 };
 
 // Load a value from a typed array. Out-of-bounds accesses are handled using
 // a VM call.
 class MLoadTypedArrayElementHole
@@ -5840,16 +5960,19 @@ class MStoreFixedSlot
     bool needsBarrier() const {
         return needsBarrier_;
     }
     void setNeedsBarrier() {
         needsBarrier_ = true;
     }
 };
 
+typedef Vector<JSObject *, 4, IonAllocPolicy> ObjectVector;
+typedef Vector<bool, 4, IonAllocPolicy> BoolVector;
+
 class InlinePropertyTable : public TempObject
 {
     struct Entry : public TempObject {
         CompilerRoot<types::TypeObject *> typeObj;
         CompilerRootFunction func;
 
         Entry(types::TypeObject *typeObj, JSFunction *func)
           : typeObj(typeObj), func(func)
@@ -5895,20 +6018,20 @@ class InlinePropertyTable : public TempO
         JS_ASSERT(i < numEntries());
         return entries_[i]->func;
     }
 
     bool hasFunction(JSFunction *func) const;
     types::TemporaryTypeSet *buildTypeSetForFunction(JSFunction *func) const;
 
     // Remove targets that vetoed inlining from the InlinePropertyTable.
-    void trimTo(AutoObjectVector &targets, Vector<bool> &choiceSet);
+    void trimTo(ObjectVector &targets, BoolVector &choiceSet);
 
     // Ensure that the InlinePropertyTable's domain is a subset of |targets|.
-    void trimToTargets(AutoObjectVector &targets);
+    void trimToTargets(ObjectVector &targets);
 };
 
 class CacheLocationList : public InlineConcatList<CacheLocationList>
 {
   public:
     CacheLocationList()
       : pc(NULL),
         script(NULL)
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -118,16 +118,17 @@ namespace jit {
     _(SetElementCache)                                                      \
     _(BindNameCache)                                                        \
     _(GuardShape)                                                           \
     _(GuardObjectType)                                                      \
     _(GuardClass)                                                           \
     _(ArrayLength)                                                          \
     _(TypedArrayLength)                                                     \
     _(TypedArrayElements)                                                   \
+    _(TypedObjectElements)                                                  \
     _(InitializedLength)                                                    \
     _(SetInitializedLength)                                                 \
     _(Not)                                                                  \
     _(BoundsCheck)                                                          \
     _(BoundsCheckLower)                                                     \
     _(InArray)                                                              \
     _(LoadElement)                                                          \
     _(LoadElementHole)                                                      \
@@ -192,16 +193,17 @@ namespace jit {
     _(AsmJSVoidReturn)                                                      \
     _(AsmJSPassStackArg)                                                    \
     _(AsmJSCall)                                                            \
     _(AsmJSCheckOverRecursed)                                               \
     _(CheckOverRecursedPar)                                                 \
     _(NewCallObjectPar)                                                     \
     _(NewPar)                                                               \
     _(NewDenseArrayPar)                                                     \
+    _(NewDerivedTypedObject)                                                \
     _(AbortPar)                                                             \
     _(LambdaPar)                                                            \
     _(RestPar)                                                              \
     _(ForkJoinSlice)                                                        \
     _(GuardThreadLocalObject)                                               \
     _(CheckInterruptPar)
 
 // Forward declarations of MIR types.
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -170,16 +170,17 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(TruncateToInt32)
     SAFE_OP(MaybeToDoubleElement)
     CUSTOM_OP(ToString)
     SAFE_OP(NewSlots)
     CUSTOM_OP(NewArray)
     CUSTOM_OP(NewObject)
     CUSTOM_OP(NewCallObject)
     CUSTOM_OP(NewParallelArray)
+    UNSAFE_OP(NewDerivedTypedObject)
     UNSAFE_OP(InitElem)
     UNSAFE_OP(InitElemGetterSetter)
     UNSAFE_OP(InitProp)
     UNSAFE_OP(InitPropGetterSetter)
     SAFE_OP(Start)
     UNSAFE_OP(OsrEntry)
     SAFE_OP(Nop)
     UNSAFE_OP(RegExp)
@@ -202,16 +203,17 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(BindNameCache)
     SAFE_OP(GuardShape)
     SAFE_OP(GuardObjectType)
     SAFE_OP(GuardClass)
     SAFE_OP(AssertRange)
     SAFE_OP(ArrayLength)
     SAFE_OP(TypedArrayLength)
     SAFE_OP(TypedArrayElements)
+    SAFE_OP(TypedObjectElements)
     SAFE_OP(InitializedLength)
     WRITE_GUARDED_OP(SetInitializedLength, elements)
     SAFE_OP(Not)
     SAFE_OP(BoundsCheck)
     SAFE_OP(BoundsCheckLower)
     SAFE_OP(LoadElement)
     SAFE_OP(LoadElementHole)
     MAYBE_WRITE_GUARDED_OP(StoreElement, elements)
@@ -508,19 +510,17 @@ ParallelSafetyVisitor::visitNewCallObjec
 {
     replace(ins, MNewCallObjectPar::New(forkJoinSlice(), ins));
     return true;
 }
 
 bool
 ParallelSafetyVisitor::visitLambda(MLambda *ins)
 {
-    if (ins->fun()->hasSingletonType() ||
-        types::UseNewTypeForClone(ins->fun()))
-    {
+    if (ins->info().singletonType || ins->info().useNewTypeForClone) {
         // slow path: bail on parallel execution.
         return markUnsafe();
     }
 
     // fast path: replace with LambdaPar op
     replace(ins, MLambdaPar::New(forkJoinSlice(), ins));
     return true;
 }
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -596,43 +596,36 @@ class RegisterSet {
     }
     MOZ_CONSTEXPR FloatRegisterSet fpus() const {
         return fpu_;
     }
     bool operator ==(const RegisterSet &other) const {
         return other.gpr_ == gpr_ && other.fpu_ == fpu_;
     }
 
-    void maybeTake(Register reg) {
+    void takeUnchecked(Register reg) {
         gpr_.takeUnchecked(reg);
     }
-    void maybeTake(FloatRegister reg) {
+    void takeUnchecked(FloatRegister reg) {
         fpu_.takeUnchecked(reg);
     }
-    void maybeTake(AnyRegister reg) {
+    void takeUnchecked(AnyRegister reg) {
         if (reg.isFloat())
             fpu_.takeUnchecked(reg.fpu());
         else
             gpr_.takeUnchecked(reg.gpr());
     }
-    void maybeTake(ValueOperand value) {
-#if defined(JS_NUNBOX32)
-        gpr_.takeUnchecked(value.typeReg());
-        gpr_.takeUnchecked(value.payloadReg());
-#elif defined(JS_PUNBOX64)
-        gpr_.takeUnchecked(value.valueReg());
-#else
-#error "Bad architecture"
-#endif
+    void takeUnchecked(ValueOperand value) {
+        gpr_.takeUnchecked(value);
     }
-    void maybeTake(TypedOrValueRegister reg) {
+    void takeUnchecked(TypedOrValueRegister reg) {
         if (reg.hasValue())
-            maybeTake(reg.valueReg());
+            takeUnchecked(reg.valueReg());
         else if (reg.hasTyped())
-            maybeTake(reg.typedReg());
+            takeUnchecked(reg.typedReg());
     }
 };
 
 // iterates in whatever order happens to be convenient.
 // Use TypedRegisterBackwardIterator or TypedRegisterForwardIterator if a
 // specific order is required.
 template <typename T>
 class TypedRegisterIterator
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -411,16 +411,17 @@ IntPolicy<Op>::staticAdjustInputs(MInstr
     MUnbox *replace = MUnbox::New(in, MIRType_Int32, MUnbox::Fallible);
     def->block()->insertBefore(def, replace);
     def->replaceOperand(Op, replace);
     return true;
 }
 
 template bool IntPolicy<0>::staticAdjustInputs(MInstruction *def);
 template bool IntPolicy<1>::staticAdjustInputs(MInstruction *def);
+template bool IntPolicy<2>::staticAdjustInputs(MInstruction *def);
 
 template <unsigned Op>
 bool
 DoublePolicy<Op>::staticAdjustInputs(MInstruction *def)
 {
     MDefinition *in = def->getOperand(Op);
     if (in->type() == MIRType_Double)
         return true;
new file mode 100644
--- /dev/null
+++ b/js/src/jit/TypeRepresentationSet.cpp
@@ -0,0 +1,278 @@
+/* -*- 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/. */
+
+#include "jit/TypeRepresentationSet.h"
+
+#include "mozilla/HashFunctions.h"
+
+#include "jit/IonBuilder.h"
+
+#include "jsinferinlines.h"
+
+using namespace js;
+using namespace jit;
+
+///////////////////////////////////////////////////////////////////////////
+// TypeRepresentationSet hasher
+
+HashNumber
+TypeRepresentationSetHasher::hash(TypeRepresentationSet key)
+{
+    HashNumber hn = mozilla::HashGeneric(key.length());
+    for (size_t i = 0; i < key.length(); i++)
+        hn = mozilla::AddToHash(hn, uintptr_t(key.get(i)));
+    return hn;
+}
+
+bool
+TypeRepresentationSetHasher::match(TypeRepresentationSet key1,
+                                   TypeRepresentationSet key2)
+{
+    if (key1.length() != key2.length())
+        return false;
+
+    // Note: entries are always sorted
+    for (size_t i = 0; i < key1.length(); i++) {
+        if (key1.get(i) != key2.get(i))
+            return false;
+    }
+
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeRepresentationSetBuilder
+
+TypeRepresentationSetBuilder::TypeRepresentationSetBuilder()
+  : invalid_(false)
+{}
+
+bool
+TypeRepresentationSetBuilder::insert(TypeRepresentation *typeRepr)
+{
+    if (invalid_)
+        return true;
+
+    if (entries_.length() == 0)
+        return entries_.append(typeRepr);
+
+    // Check that this new type repr is of the same basic kind as the
+    // ones we have seen thus far. If not, for example if we have an
+    // `int` and a `struct`, then convert this set to the invalid set.
+    TypeRepresentation *entry0 = entries_[0];
+    if (typeRepr->kind() != entry0->kind()) {
+        invalid_ = true;
+        entries_.clear();
+        return true;
+    }
+
+    // Otherwise, use binary search to find the right place to insert
+    // the type descriptor. We keep list sorted by the *address* of
+    // the type representations within.
+    uintptr_t typeReprAddr = (uintptr_t) typeRepr;
+    size_t min = 0;
+    size_t max = entries_.length();
+    while (min != max) {
+        size_t i = min + ((max - min) >> 1); // average w/o fear of overflow
+
+        uintptr_t entryiaddr = (uintptr_t) entries_[i];
+        if (entryiaddr == typeReprAddr)
+            return true; // typeRepr already present in the set
+
+        if (entryiaddr < typeReprAddr) {
+            // typeRepr lies to the right of entry i
+            min = i;
+        } else {
+            // typeRepr lies to the left of entry i
+            max = i;
+        }
+    }
+
+    // As a sanity check, give up if the TypeRepresentationSet grows too large.
+    if (entries_.length() >= 512) {
+        invalid_ = true;
+        entries_.clear();
+        return true;
+    }
+
+    // Not present. Insert at position `min`.
+    if (min == entries_.length())
+        return entries_.append(typeRepr);
+    TypeRepresentation **insertLoc = &entries_[min];
+    return entries_.insert(insertLoc, typeRepr) != NULL;
+}
+
+bool
+TypeRepresentationSetBuilder::build(IonBuilder &builder,
+                                    TypeRepresentationSet *out)
+{
+    if (invalid_) {
+        *out = TypeRepresentationSet();
+        return true;
+    }
+
+    TypeRepresentationSetHash *table = builder.getOrCreateReprSetHash();
+    if (!table)
+        return false;
+
+    // Check if there is already a copy in the hashtable.
+    size_t length = entries_.length();
+    TypeRepresentationSet tempSet(length, entries_.begin());
+    TypeRepresentationSetHash::AddPtr p = table->lookupForAdd(tempSet);
+    if (p) {
+        *out = *p;
+        return true;
+    }
+
+    // If not, allocate a permanent copy in Ion temp memory and add it.
+    size_t space = sizeof(TypeRepresentation*) * length;
+    TypeRepresentation **array = (TypeRepresentation**)
+        GetIonContext()->temp->allocate(space);
+    if (!array)
+        return false;
+    memcpy(array, entries_.begin(), space);
+    TypeRepresentationSet permSet(length, array);
+    if (!table->add(p, permSet))
+        return false;
+
+    *out = permSet;
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeRepresentationSet
+
+TypeRepresentationSet::TypeRepresentationSet(const TypeRepresentationSet &c)
+  : length_(c.length_),
+    entries_(c.entries_)
+{}
+
+TypeRepresentationSet::TypeRepresentationSet(size_t length,
+                                             TypeRepresentation **entries)
+  : length_(length),
+    entries_(entries)
+{}
+
+TypeRepresentationSet::TypeRepresentationSet()
+  : length_(0),
+    entries_(NULL)
+{}
+
+bool
+TypeRepresentationSet::empty()
+{
+    return length() == 0;
+}
+
+size_t
+TypeRepresentationSet::length()
+{
+    return length_;
+}
+
+TypeRepresentation *
+TypeRepresentationSet::get(size_t i)
+{
+    JS_ASSERT(i < length());
+    return entries_[i];
+}
+
+bool
+TypeRepresentationSet::allOfKind(TypeRepresentation::Kind aKind)
+{
+    if (empty())
+        return false;
+
+    return kind() == aKind;
+}
+
+TypeRepresentation::Kind
+TypeRepresentationSet::kind()
+{
+    JS_ASSERT(!empty());
+    return get(0)->kind();
+}
+
+size_t
+TypeRepresentationSet::arrayLength()
+{
+    JS_ASSERT(kind() == TypeRepresentation::Array);
+    const size_t result = get(0)->asArray()->length();
+    for (size_t i = 1; i < length(); i++) {
+        if (get(i)->asArray()->length() != result)
+            return SIZE_MAX;
+    }
+    return result;
+}
+
+bool
+TypeRepresentationSet::arrayElementType(IonBuilder &builder,
+                                        TypeRepresentationSet *out)
+{
+    JS_ASSERT(kind() == TypeRepresentation::Array);
+
+    TypeRepresentationSetBuilder elementTypes;
+    for (size_t i = 0; i < length(); i++) {
+        if (!elementTypes.insert(get(i)->asArray()->element()))
+            return false;
+    }
+    return elementTypes.build(builder, out);
+}
+
+bool
+TypeRepresentationSet::fieldNamed(IonBuilder &builder,
+                                  jsid id,
+                                  size_t *offset,
+                                  TypeRepresentationSet *out,
+                                  size_t *index)
+{
+    JS_ASSERT(kind() == TypeRepresentation::Struct);
+
+    // Initialize `*offset` and `*out` for the case where incompatible
+    // or absent fields are found.
+    *offset = SIZE_MAX;
+    *index = SIZE_MAX;
+    *out = TypeRepresentationSet();
+
+    // Remember offset of the first field.
+    size_t offset0;
+    size_t index0;
+    TypeRepresentationSetBuilder fieldTypes;
+    {
+        const StructField *field = get(0)->asStruct()->fieldNamed(id);
+        if (!field)
+            return true;
+
+        offset0 = field->offset;
+        index0 = field->index;
+        if (!fieldTypes.insert(field->typeRepr))
+            return false;
+    }
+
+    // Check that all subsequent fields are at the same offset
+    // and compute the union of their types.
+    for (size_t i = 1; i < length(); i++) {
+        const StructField *field = get(i)->asStruct()->fieldNamed(id);
+        if (!field)
+            return true;
+
+        if (field->offset != offset0)
+            return true;
+
+        if (field->index != index0)
+            index0 = SIZE_MAX;
+
+        if (!fieldTypes.insert(field->typeRepr))
+            return false;
+    }
+
+    // All struct types had a field named `id` at the same offset
+    // (though it's still possible that the types are incompatible and
+    // that the indices disagree).
+    *offset = offset0;
+    *index = index0;
+    return fieldTypes.build(builder, out);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit/TypeRepresentationSet.h
@@ -0,0 +1,146 @@
+/* -*- 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 jit_TypeRepresentationSet_h
+#define jit_TypeRepresentationSet_h
+
+#include "builtin/TypeRepresentation.h"
+#include "jit/IonAllocPolicy.h"
+#include "js/HashTable.h"
+
+// TypeRepresentationSet stores a set of TypeRepresentation* objects,
+// representing the possible types of the binary data associated with
+// a typed object value.  Often TypeRepresentationSets will be
+// singleton sets, but it is also possible to have cases where many
+// type representations flow into a single point. In such cases, the
+// various type representations may differ in their details but often
+// have a common prefix. We try to optimize this case as well.
+//
+// So, for example, consider some code like:
+//
+//     var Point2Type = new StructType({x: uint8, y: uint8});
+//     var Point3Type = new StructType({x: uint8, y: uint8, z: uint8});
+//
+//     function distance2d(pnt) {
+//         return Math.sqrt(pnt.x * pnt.x + pnt.y * pnt.y);
+//     }
+//
+// Even if the function `distance2d()` were used with instances of
+// both Point2Type and Point3Type, we can still generate optimal code,
+// because both of those types contain fields named `x` and `y` with
+// the same types at the same offset.
+
+namespace js {
+namespace jit {
+
+class IonBuilder;
+class TypeRepresentationSet;
+
+class TypeRepresentationSetBuilder {
+  private:
+    Vector<TypeRepresentation *, 4, SystemAllocPolicy> entries_;
+    bool invalid_;
+
+    bool overlaps(TypeRepresentation *a, TypeRepresentation *b);
+
+  public:
+    TypeRepresentationSetBuilder();
+
+    bool insert(TypeRepresentation *typeRepr);
+    bool build(IonBuilder &builder, TypeRepresentationSet *out);
+};
+
+class TypeRepresentationSet {
+  private:
+    friend class TypeRepresentationSetBuilder;
+
+    size_t length_;
+    TypeRepresentation **entries_; // Allocated using temp policy
+
+    TypeRepresentationSet(size_t length, TypeRepresentation **entries);
+
+  public:
+    //////////////////////////////////////////////////////////////////////
+    // Constructors
+    //
+    // For more flexible constructors, see
+    // TypeRepresentationSetBuilder above.
+
+    TypeRepresentationSet(const TypeRepresentationSet &c);
+    TypeRepresentationSet(); // empty set
+
+    //////////////////////////////////////////////////////////////////////
+    // Query the set
+
+    bool empty();
+    size_t length();
+    TypeRepresentation *get(size_t i);
+    bool allOfKind(TypeRepresentation::Kind kind);
+
+    //////////////////////////////////////////////////////////////////////
+    // The following operations are only valid on a non-empty set:
+
+    TypeRepresentation::Kind kind();
+
+    //////////////////////////////////////////////////////////////////////
+    // Array operations
+    //
+    // Only valid when `kind() == TypeRepresentation::Array`
+
+    // Returns the length of the arrays in this set, or SIZE_MAX
+    // if they are not all the same.
+    size_t arrayLength();
+
+    // Returns a `TypeRepresentationSet` representing the element
+    // types of the various array types in this set. The returned set
+    // may be the empty set.
+    bool arrayElementType(IonBuilder &builder, TypeRepresentationSet *out);
+
+    //////////////////////////////////////////////////////////////////////
+    // Struct operations
+    //
+    // Only valid when `kind() == TypeRepresentation::Struct`
+
+    // Searches the type in the set for a field named `id`. All
+    // possible types must agree on the offset of the field within the
+    // structure and the possible types of the field must be
+    // compatible. If any pair of types disagree on the offset or have
+    // incompatible types for the field, then `*out` will be set to
+    // the empty set.
+    //
+    // Upon success, `out` will be set to the set of possible types of
+    // the field and `offset` will be set to the field's offset within
+    // the struct (measured in bytes).
+    //
+    // The parameter `*index` is special. If all types agree on the
+    // index of the field, then `*index` is set to the field index.
+    // Otherwise, it is set to SIZE_MAX. Note that two types may agree
+    // on the type and offset of a field but disagree about its index,
+    // e.g. the field `c` in `new StructType({a: uint8, b: uint8, c:
+    // uint16})` and `new StructType({a: uint16, c: uint16})`.
+    bool fieldNamed(IonBuilder &builder,
+                    jsid id,
+                    size_t *offset,
+                    TypeRepresentationSet *out,
+                    size_t *index);
+};
+
+struct TypeRepresentationSetHasher
+{
+    typedef TypeRepresentationSet Lookup;
+    static HashNumber hash(TypeRepresentationSet key);
+    static bool match(TypeRepresentationSet key1,
+                      TypeRepresentationSet key2);
+};
+
+typedef js::HashSet<TypeRepresentationSet,
+                    TypeRepresentationSetHasher,
+                    IonAllocPolicy> TypeRepresentationSetHash;
+
+} // namespace jit
+} // namespace js
+
+#endif
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -2,16 +2,17 @@
  * 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/. */
 
 #include "jit/VMFunctions.h"
 
 #include "builtin/ParallelArray.h"
+#include "builtin/TypedObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "jit/BaselineIC.h"
 #include "jit/Ion.h"
 #include "jit/IonCompartment.h"
 #include "jit/IonFrames.h"
 #include "vm/ArrayObject.h"
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
@@ -867,10 +868,17 @@ LeaveBlock(JSContext *cx, BaselineFrame 
 }
 
 bool
 InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame, uint32_t numStackValues)
 {
     return frame->initForOsr(interpFrame, numStackValues);
 }
 
+JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
+                                HandleObject owner, int32_t offset)
+{
+    return BinaryBlock::createDerived(cx, type, owner, offset);
+}
+
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -660,12 +660,15 @@ bool HandleDebugTrap(JSContext *cx, Base
 bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn);
 
 bool EnterBlock(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block);
 bool LeaveBlock(JSContext *cx, BaselineFrame *frame);
 
 bool InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame,
                              uint32_t numStackValues);
 
+JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
+                                HandleObject owner, int32_t offset);
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -10,16 +10,115 @@
 #include <cstddef>
 
 #include "assembler/assembler/X86Assembler.h"
 #include "jit/shared/Assembler-shared.h"
 
 namespace js {
 namespace jit {
 
+class Operand
+{
+  public:
+    enum Kind {
+        REG,
+        MEM_REG_DISP,
+        FPREG,
+        MEM_SCALE,
+        MEM_ADDRESS32
+    };
+
+  private:
+    Kind kind_ : 4;
+    int32_t base_ : 5;
+    Scale scale_ : 3;
+    int32_t index_ : 5;
+    int32_t disp_;
+
+  public:
+    explicit Operand(Register reg)
+      : kind_(REG),
+        base_(reg.code())
+    { }
+    explicit Operand(FloatRegister reg)
+      : kind_(FPREG),
+        base_(reg.code())
+    { }
+    explicit Operand(const Address &address)
+      : kind_(MEM_REG_DISP),
+        base_(address.base.code()),
+        disp_(address.offset)
+    { }
+    explicit Operand(const BaseIndex &address)
+      : kind_(MEM_SCALE),
+        base_(address.base.code()),
+        scale_(address.scale),
+        index_(address.index.code()),
+        disp_(address.offset)
+    { }
+    Operand(Register base, Register index, Scale scale, int32_t disp = 0)
+      : kind_(MEM_SCALE),
+        base_(base.code()),
+        scale_(scale),
+        index_(index.code()),
+        disp_(disp)
+    { }
+    Operand(Register reg, int32_t disp)
+      : kind_(MEM_REG_DISP),
+        base_(reg.code()),
+        disp_(disp)
+    { }
+    explicit Operand(const AbsoluteAddress &address)
+      : kind_(MEM_ADDRESS32),
+        disp_(JSC::X86Assembler::addressImmediate(address.addr))
+    { }
+
+    Address toAddress() {
+        JS_ASSERT(kind() == MEM_REG_DISP);
+        return Address(Register::FromCode(base()), disp());
+    }
+
+    BaseIndex toBaseIndex() {
+        JS_ASSERT(kind() == MEM_SCALE);
+        return BaseIndex(Register::FromCode(base()), Register::FromCode(index()), scale(), disp());
+    }
+
+    Kind kind() const {
+        return kind_;
+    }
+    Registers::Code reg() const {
+        JS_ASSERT(kind() == REG);
+        return (Registers::Code)base_;
+    }
+    Registers::Code base() const {
+        JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE);
+        return (Registers::Code)base_;
+    }
+    Registers::Code index() const {
+        JS_ASSERT(kind() == MEM_SCALE);
+        return (Registers::Code)index_;
+    }
+    Scale scale() const {
+        JS_ASSERT(kind() == MEM_SCALE);
+        return scale_;
+    }
+    FloatRegisters::Code fpu() const {
+        JS_ASSERT(kind() == FPREG);
+        return (FloatRegisters::Code)base_;
+    }
+    int32_t disp() const {
+        JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE);
+        return disp_;
+    }
+    void *address() const {
+        JS_ASSERT(kind() == MEM_ADDRESS32);
+        return reinterpret_cast<void *>(disp_);
+    }
+};
+
 class AssemblerX86Shared
 {
   protected:
     struct RelativePatch {
         int32_t offset;
         void *target;
         Relocation::Kind kind;
 
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -300,32 +300,32 @@ class CodeGeneratorShared : public LInst
     // (The only registers that don't need to be saved/restored are 1) the
     // temporary register used to store the return value of the function call,
     // if there is one [otherwise that stored value would be overwritten]; and
     // 2) temporary registers whose values aren't needed in the rest of the LIR
     // instruction [this is purely an optimization].  All other volatiles must
     // be saved and restored in case future LIR instructions need those values.)
     void saveVolatile(Register output) {
         RegisterSet regs = RegisterSet::Volatile();
-        regs.maybeTake(output);
+        regs.takeUnchecked(output);
         masm.PushRegsInMask(regs);
     }
     void restoreVolatile(Register output) {
         RegisterSet regs = RegisterSet::Volatile();
-        regs.maybeTake(output);
+        regs.takeUnchecked(output);
         masm.PopRegsInMask(regs);
     }
     void saveVolatile(FloatRegister output) {
         RegisterSet regs = RegisterSet::Volatile();
-        regs.maybeTake(output);
+        regs.takeUnchecked(output);
         masm.PushRegsInMask(regs);
     }
     void restoreVolatile(FloatRegister output) {
         RegisterSet regs = RegisterSet::Volatile();
-        regs.maybeTake(output);
+        regs.takeUnchecked(output);
         masm.PopRegsInMask(regs);
     }
     void saveVolatile(RegisterSet temps) {
         masm.PushRegsInMask(RegisterSet::VolatileNot(temps));
     }
     void restoreVolatile(RegisterSet temps) {
         masm.PopRegsInMask(RegisterSet::VolatileNot(temps));
     }
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -477,16 +477,27 @@ class MacroAssemblerX86Shared : public A
         // "2. Optimizing subroutines in assembly language" by Agner Fog, and as
         // previously implemented here. However, with x86 and x64 both using
         // constant pool loads for double constants, this is probably only
         // worthwhile in cases where a load is likely to be delayed.
 
         return false;
     }
 
+    bool maybeInlineFloat(float f, const FloatRegister &dest) {
+        uint32_t u = mozilla::BitwiseCast<uint32_t>(f);
+
+        // See comment above
+        if (u == 0) {
+            xorps(dest, dest);
+            return true;
+        }
+        return false;
+    }
+
     void convertBoolToInt32(Register source, Register dest) {
         // Note that C++ bool is only 1 byte, so zero extend it to clear the
         // higher-order bits.
         movzxbl(source, dest);
     }
 
     void emitSet(Assembler::Condition cond, const Register &dest,
                  Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond) {
--- a/js/src/jit/x64/Assembler-x64.cpp
+++ b/js/src/jit/x64/Assembler-x64.cpp
@@ -141,17 +141,17 @@ Assembler::PatchJumpEntry(uint8_t *entry
 
 void
 Assembler::finish()
 {
     if (!jumps_.length() || oom())
         return;
 
     // Emit the jump table.
-    masm.align(16);
+    masm.align(SizeOfJumpTableEntry);
     extendedJumpTable_ = masm.size();
 
     // Now that we know the offset to the jump table, squirrel it into the
     // jump relocation buffer if any IonCode references exist and must be
     // tracked for GC.
     JS_ASSERT_IF(jumpRelocations_.length(), jumpRelocations_.length() >= sizeof(uint32_t));
     if (jumpRelocations_.length())
         *(uint32_t *)jumpRelocations_.buffer() = extendedJumpTable_;
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -163,116 +163,16 @@ static const uint32_t StackAlignment = 1
 static const bool StackKeptAligned = false;
 static const uint32_t CodeAlignment = 8;
 static const uint32_t NativeFrameSize = sizeof(void*);
 static const uint32_t AlignmentAtPrologue = sizeof(void*);
 static const uint32_t AlignmentMidPrologue = AlignmentAtPrologue;
 
 static const Scale ScalePointer = TimesEight;
 
-class Operand
-{
-  public:
-    enum Kind {
-        REG,
-        MEM_REG_DISP,
-        FPREG,
-        MEM_SCALE,
-        MEM_ADDRESS32
-    };
-
-  private:
-    Kind kind_ : 4;
-    int32_t base_ : 5;
-    Scale scale_ : 3;
-    int32_t index_ : 5;
-    int32_t disp_;
-
-  public:
-    explicit Operand(Register reg)
-      : kind_(REG),
-        base_(reg.code())
-    { }
-    explicit Operand(FloatRegister reg)
-      : kind_(FPREG),
-        base_(reg.code())
-    { }
-    explicit Operand(const Address &address)
-      : kind_(MEM_REG_DISP),
-        base_(address.base.code()),
-        disp_(address.offset)
-    { }
-    explicit Operand(const BaseIndex &address)
-      : kind_(MEM_SCALE),
-        base_(address.base.code()),
-        scale_(address.scale),
-        index_(address.index.code()),
-        disp_(address.offset)
-    { }
-    Operand(Register base, Register index, Scale scale, int32_t disp = 0)
-      : kind_(MEM_SCALE),
-        base_(base.code()),
-        scale_(scale),
-        index_(index.code()),
-        disp_(disp)
-    { }
-    Operand(Register reg, int32_t disp)
-      : kind_(MEM_REG_DISP),
-        base_(reg.code()),
-        disp_(disp)
-    { }
-    explicit Operand(const AbsoluteAddress &address)
-      : kind_(MEM_ADDRESS32)
-    {
-        disp_ = JSC::X86Assembler::addressImmediate(address.addr);
-    }
-
-    Address toAddress() const {
-        JS_ASSERT(kind() == MEM_REG_DISP);
-        return Address(Register::FromCode(base()), disp());
-    }
-
-    BaseIndex toBaseIndex() const {
-        JS_ASSERT(kind() == MEM_SCALE);
-        return BaseIndex(Register::FromCode(base()), Register::FromCode(index()), scale(), disp());
-    }
-
-    Kind kind() const {
-        return kind_;
-    }
-    Register::Code reg() const {
-        JS_ASSERT(kind() == REG);
-        return (Registers::Code)base_;
-    }
-    Registers::Code base() const {
-        JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE);
-        return (Registers::Code)base_;
-    }
-    Registers::Code index() const {
-        JS_ASSERT(kind() == MEM_SCALE);
-        return (Registers::Code)index_;
-    }
-    Scale scale() const {
-        JS_ASSERT(kind() == MEM_SCALE);
-        return scale_;
-    }
-    FloatRegisters::Code fpu() const {
-        JS_ASSERT(kind() == FPREG);
-        return (FloatRegisters::Code)base_;
-    }
-    int32_t disp() const {
-        JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE);
-        return disp_;
-    }
-    void *address() const {
-        JS_ASSERT(kind() == MEM_ADDRESS32);
-        return reinterpret_cast<void *>(intptr_t(disp_));
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #include "jit/shared/Assembler-x86-shared.h"
 
 namespace js {
 namespace jit {
 
--- a/js/src/jit/x64/BaselineRegisters-x64.h
+++ b/js/src/jit/x64/BaselineRegisters-x64.h
@@ -16,18 +16,16 @@ namespace jit {
 
 static MOZ_CONSTEXPR_VAR Register BaselineFrameReg    = rbp;
 static MOZ_CONSTEXPR_VAR Register BaselineStackReg    = rsp;
 
 static MOZ_CONSTEXPR_VAR ValueOperand R0(rcx);
 static MOZ_CONSTEXPR_VAR ValueOperand R1(rbx);
 static MOZ_CONSTEXPR_VAR ValueOperand R2(rax);
 
-// BaselineTailCallReg and BaselineStubReg reuse
-// registers from R2.
 static MOZ_CONSTEXPR_VAR Register BaselineTailCallReg = rsi;
 static MOZ_CONSTEXPR_VAR Register BaselineStubReg     = rdi;
 
 static MOZ_CONSTEXPR_VAR Register ExtractTemp0        = r14;
 static MOZ_CONSTEXPR_VAR Register ExtractTemp1        = r15;
 
 // FloatReg0 must be equal to ReturnFloatReg.
 static MOZ_CONSTEXPR_VAR FloatRegister FloatReg0      = xmm0;
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -46,22 +46,18 @@ MacroAssemblerX64::loadConstantDouble(do
     JmpSrc j = masm.movsd_ripr(dest.code());
     JmpSrc prev = JmpSrc(dbl.uses.use(j.offset()));
     masm.setNextJump(j, prev);
 }
 
 void
 MacroAssemblerX64::loadConstantFloat32(float f, const FloatRegister &dest)
 {
-    // In particular, use hardware instructions if loading 0
-    uint32_t u = mozilla::BitwiseCast<uint32_t>(f);
-    if (u == 0) {
-        xorps(dest, dest);
+    if (maybeInlineFloat(f, dest))
         return;
-    }
 
     if (!floatMap_.initialized()) {
         enoughMemory_ &= floatMap_.init();
         if (!enoughMemory_)
             return;
     }
     size_t floatIndex;
     if (FloatMap::AddPtr p = floatMap_.lookupForAdd(f)) {
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -103,115 +103,16 @@ struct ImmType : public ImmTag
 {
     ImmType(JSValueType type)
       : ImmTag(JSVAL_TYPE_TO_TAG(type))
     { }
 };
 
 static const Scale ScalePointer = TimesFour;
 
-class Operand
-{
-  public:
-    enum Kind {
-        REG,
-        MEM_REG_DISP,
-        FPREG,
-        MEM_SCALE,
-        MEM_ADDRESS32
-    };
-
-  private:
-    Kind kind_ : 4;
-    int32_t base_ : 5;
-    Scale scale_ : 3;
-    int32_t index_ : 5;
-    int32_t disp_;
-
-  public:
-    explicit Operand(Register reg)
-      : kind_(REG),
-        base_(reg.code())
-    { }
-    explicit Operand(FloatRegister reg)
-      : kind_(FPREG),
-        base_(reg.code())
-    { }
-    explicit Operand(const Address &address)
-      : kind_(MEM_REG_DISP),
-        base_(address.base.code()),
-        disp_(address.offset)
-    { }
-    explicit Operand(const BaseIndex &address)
-      : kind_(MEM_SCALE),
-        base_(address.base.code()),
-        scale_(address.scale),
-        index_(address.index.code()),
-        disp_(address.offset)
-    { }
-    Operand(Register base, Register index, Scale scale, int32_t disp = 0)
-      : kind_(MEM_SCALE),
-        base_(base.code()),
-        scale_(scale),
-        index_(index.code()),
-        disp_(disp)
-    { }
-    Operand(Register reg, int32_t disp)
-      : kind_(MEM_REG_DISP),
-        base_(reg.code()),
-        disp_(disp)
-    { }
-    explicit Operand(const AbsoluteAddress &address)
-      : kind_(MEM_ADDRESS32),
-        disp_(reinterpret_cast<int32_t>(address.addr))
-    { }
-
-    Address toAddress() {
-        JS_ASSERT(kind() == MEM_REG_DISP);
-        return Address(Register::FromCode(base()), disp());
-    }
-
-    BaseIndex toBaseIndex() {
-        JS_ASSERT(kind() == MEM_SCALE);
-        return BaseIndex(Register::FromCode(base()), Register::FromCode(index()), scale(), disp());
-    }
-
-    Kind kind() const {
-        return kind_;<