Merge m-c to s-c.
authorRichard Newman <rnewman@mozilla.com>
Mon, 05 Dec 2011 09:37:18 -0800
changeset 84613 bc612072dddaf5b528bd7259ff922491ef643537
parent 84612 86386bb687adf2579efb4b18594dc2c2d5b4d4d1 (current diff)
parent 83030 1bd7482ad4d195aaa4511f241b3de74eac9e8f2c (diff)
child 84614 fefb15b96b0fc5f1ff538e890e47b9cacba657bc
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone11.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 s-c.
xpinstall/Makefile.in
xpinstall/public/Makefile.in
xpinstall/public/nsIDOMInstallTriggerGlobal.h
xpinstall/public/nsIXPIDialogService.idl
xpinstall/public/nsIXPIInstallInfo.idl
xpinstall/public/nsIXPIProgressDialog.idl
xpinstall/public/nsIXPInstallManager.idl
xpinstall/public/nsPICertNotification.idl
xpinstall/public/nsSoftwareUpdateIIDs.h
xpinstall/public/xpinstall.js
xpinstall/src/CertReader.cpp
xpinstall/src/CertReader.h
xpinstall/src/Makefile.in
xpinstall/src/nsInstall.h
xpinstall/src/nsInstallTrigger.cpp
xpinstall/src/nsInstallTrigger.h
xpinstall/src/nsJSInstallTriggerGlobal.cpp
xpinstall/src/nsSoftwareUpdate.cpp
xpinstall/src/nsXPIInstallInfo.cpp
xpinstall/src/nsXPIInstallInfo.h
xpinstall/src/nsXPITriggerInfo.cpp
xpinstall/src/nsXPITriggerInfo.h
xpinstall/src/nsXPInstallManager.cpp
xpinstall/src/nsXPInstallManager.h
xpinstall/test/pre_checkin.xpi
xpinstall/test/pre_checkin_trigger.html
xpinstall/test/testXPIDialogService.js
xpinstall/tests/Makefile.in
xpinstall/tests/authRedirect.sjs
xpinstall/tests/browser_auth.js
xpinstall/tests/browser_auth2.js
xpinstall/tests/browser_auth3.js
xpinstall/tests/browser_badhash.js
xpinstall/tests/browser_badhashtype.js
xpinstall/tests/browser_bug540558.js
xpinstall/tests/browser_cancel.js
xpinstall/tests/browser_chrome.js
xpinstall/tests/browser_cookies.js
xpinstall/tests/browser_cookies2.js
xpinstall/tests/browser_cookies3.js
xpinstall/tests/browser_cookies4.js
xpinstall/tests/browser_corrupt.js
xpinstall/tests/browser_empty.js
xpinstall/tests/browser_enabled.js
xpinstall/tests/browser_enabled2.js
xpinstall/tests/browser_enabled3.js
xpinstall/tests/browser_hash.js
xpinstall/tests/browser_installchrome.js
xpinstall/tests/browser_localfile.js
xpinstall/tests/browser_localfile2.js
xpinstall/tests/browser_navigateaway.js
xpinstall/tests/browser_navigateaway2.js
xpinstall/tests/browser_offline.js
xpinstall/tests/browser_opendialog.js
xpinstall/tests/browser_signed_multiple.js
xpinstall/tests/browser_signed_naming.js
xpinstall/tests/browser_signed_tampered.js
xpinstall/tests/browser_signed_trigger.js
xpinstall/tests/browser_signed_untrusted.js
xpinstall/tests/browser_signed_url.js
xpinstall/tests/browser_softwareupdate.js
xpinstall/tests/browser_unsigned_trigger.js
xpinstall/tests/browser_unsigned_url.js
xpinstall/tests/browser_whitelist.js
xpinstall/tests/browser_whitelist2.js
xpinstall/tests/browser_whitelist3.js
xpinstall/tests/browser_whitelist4.js
xpinstall/tests/browser_whitelist5.js
xpinstall/tests/browser_whitelist6.js
xpinstall/tests/bug540558.html
xpinstall/tests/cookieRedirect.sjs
xpinstall/tests/corrupt.xpi
xpinstall/tests/empty.xpi
xpinstall/tests/enabled.html
xpinstall/tests/harness.js
xpinstall/tests/installchrome.html
xpinstall/tests/installtrigger.html
xpinstall/tests/signed-no-cn.xpi
xpinstall/tests/signed-no-o.xpi
xpinstall/tests/signed-tampered.xpi
xpinstall/tests/signed-untrusted.xpi
xpinstall/tests/signed.xpi
xpinstall/tests/signed2.xpi
xpinstall/tests/startsoftwareupdate.html
xpinstall/tests/unsigned.xpi
--- a/accessible/src/atk/nsMaiInterfaceDocument.cpp
+++ b/accessible/src/atk/nsMaiInterfaceDocument.cpp
@@ -76,34 +76,16 @@ getDocumentLocaleCB(AtkDocument *aDocume
     nsAutoString locale;
     docAccessNode->GetLanguage(locale);
     if (locale.IsEmpty()) {
       return nsnull;
     }
     return nsAccessibleWrap::ReturnString(locale);
 }
 
-const gchar *
-getDocumentTypeCB(AtkDocument *aDocument)
-{
-    nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
-    if (!accWrap)
-        return nsnull;
-
-    nsCOMPtr<nsIAccessibleDocument> accDocument;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleDocument),
-                            getter_AddRefs(accDocument));
-    NS_ENSURE_TRUE(accDocument, nsnull);
-
-    nsAutoString mimeType;
-    nsresult rv = accDocument->GetMimeType(mimeType);
-    NS_ENSURE_SUCCESS(rv, nsnull);
-    return nsAccessibleWrap::ReturnString(mimeType);
-}
-
 static inline GSList *
 prependToList(GSList *aList, const char *const aName, const nsAutoString &aValue)
 {
     // libspi will free these
     AtkAttribute *atkAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
     atkAttr->name = g_strdup(aName);
     atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get());
     return g_slist_prepend(aList, atkAttr);
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -655,32 +655,16 @@ nsCoreUtils::GetFirstSensibleColumn(nsIT
   nsCOMPtr<nsITreeColumn> column;
   cols->GetFirstColumn(getter_AddRefs(column));
   if (column && IsColumnHidden(column))
     return GetNextSensibleColumn(column);
 
   return column.forget();
 }
 
-already_AddRefed<nsITreeColumn>
-nsCoreUtils::GetLastSensibleColumn(nsITreeBoxObject *aTree)
-{
-  nsCOMPtr<nsITreeColumns> cols;
-  aTree->GetColumns(getter_AddRefs(cols));
-  if (!cols)
-    return nsnull;
-
-  nsCOMPtr<nsITreeColumn> column;
-  cols->GetLastColumn(getter_AddRefs(column));
-  if (column && IsColumnHidden(column))
-    return GetPreviousSensibleColumn(column);
-
-  return column.forget();
-}
-
 PRUint32
 nsCoreUtils::GetSensibleColumnCount(nsITreeBoxObject *aTree)
 {
   PRUint32 count = 0;
 
   nsCOMPtr<nsITreeColumns> cols;
   aTree->GetColumns(getter_AddRefs(cols));
   if (!cols)
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -323,22 +323,16 @@ public:
 
   /**
    * Return first sensible column for the given tree box object.
    */
   static already_AddRefed<nsITreeColumn>
     GetFirstSensibleColumn(nsITreeBoxObject *aTree);
 
   /**
-   * Return last sensible column for the given tree box object.
-   */
-  static already_AddRefed<nsITreeColumn>
-    GetLastSensibleColumn(nsITreeBoxObject *aTree);
-
-  /**
    * Return sensible columns count for the given tree box object.
    */
   static PRUint32 GetSensibleColumnCount(nsITreeBoxObject *aTree);
 
   /**
    * Return sensible column at the given index for the given tree box object.
    */
   static already_AddRefed<nsITreeColumn>
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -81,16 +81,17 @@ if [ ! "$LIBXUL_SDK" ]; then
   if [ "$MOZ_MEMORY" ]; then
     add_makefiles "
       memory/jemalloc/Makefile
     "
   fi
   if [ "$MOZ_WIDGET_TOOLKIT" = "android" ]; then
     add_makefiles "
       other-licenses/android/Makefile
+      other-licenses/skia-npapi/Makefile
     "
   fi
 fi
 
 if [ "$OS_ARCH" = "WINNT" ]; then
   add_makefiles "
     build/win32/Makefile
     build/win32/crashinjectdll/Makefile
@@ -110,16 +111,19 @@ fi
 
 if [ "$COMPILER_DEPEND" = "" -a "$MOZ_NATIVE_MAKEDEPEND" = "" ]; then
   add_makefiles "
     config/mkdepend/Makefile
   "
 fi
 
 if [ "$ENABLE_TESTS" ]; then
+  add_makefiles "
+    build/autoconf/test/Makefile
+  "
   if [ "$_MSC_VER" -a "$OS_TEST" != "x86_64" ]; then
     add_makefiles "
       build/win32/vmwarerecordinghelper/Makefile
     "
   fi
   if [ "$OS_ARCH" != "WINNT" -a "$OS_ARCH" != "OS2" ]; then 
     add_makefiles "
       build/unix/test/Makefile
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3473,20 +3473,39 @@ const BrowserSearch = {
 
     // getSubmission can return null if the engine doesn't have a URL
     // with a text/html response type.  This is unlikely (since
     // SearchService._addEngineToStore() should fail for such an engine),
     // but let's be on the safe side.
     if (!submission)
       return;
 
+    let newTab;
+    function newTabHandler(event) {
+      newTab = event.target;
+    }
+    gBrowser.tabContainer.addEventListener("TabOpen", newTabHandler);
+
     openLinkIn(submission.uri.spec,
                useNewTab ? "tab" : "current",
                { postData: submission.postData,
                  relatedToCurrent: true });
+
+    gBrowser.tabContainer.removeEventListener("TabOpen", newTabHandler);
+    if (newTab && !newTab.selected) {
+      let tabSelected = false;
+      function tabSelectHandler() {
+        tabSelected = true;
+      }
+      newTab.addEventListener("TabSelect", tabSelectHandler);
+      setTimeout(function () {
+        newTab.removeEventListener("TabSelect", tabSelectHandler);
+        Services.telemetry.getHistogramById("FX_CONTEXT_SEARCH_AND_TAB_SELECT").add(tabSelected);
+      }, 5000);
+    }
   },
 
   /**
    * Returns the search bar element if it is present in the toolbar, null otherwise.
    */
   get searchBar() {
     return document.getElementById("searchbar");
   },
@@ -7654,17 +7673,18 @@ var FeedHandler = {
 
     browserForLink.feeds.push({ href: link.href, title: link.title });
 
     // If this addition was for the current browser, update the UI. For
     // background browsers, we'll update on tab switch.
     if (browserForLink == gBrowser.selectedBrowser) {
       // Batch updates to avoid updating the UI for multiple onLinkAdded events
       // fired within 100ms of each other.
-      clearTimeout(this._updateFeedTimeout);
+      if (this._updateFeedTimeout)
+        clearTimeout(this._updateFeedTimeout);
       this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100);
     }
   }
 };
 
 /**
  * Re-open a closed tab.
  * @param aIndex
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -987,17 +987,17 @@ function makePreview(row)
     newImage.controls = true;
     isAudio = true;
 
     document.getElementById("theimagecontainer").collapsed = false;
     document.getElementById("brokenimagecontainer").collapsed = true;
   }
 #endif
   else {
-    // fallback image for protocols not allowed (e.g., data: or javascript:)
+    // fallback image for protocols not allowed (e.g., javascript:)
     // or elements not [yet] handled (e.g., object, embed).
     document.getElementById("brokenimagecontainer").collapsed = false;
     document.getElementById("theimagecontainer").collapsed = true;
   }
 
   var imageSize = "";
   if (url && !isAudio) {
     if (width != physWidth || height != physHeight) {
@@ -1223,13 +1223,11 @@ function selectImage()
       return;
     }
   }
 }
 
 function checkProtocol(img)
 {
   var url = img[COL_IMAGE_ADDRESS];
-  if (/^data:/.test(url) && /^image\//.test(img[COL_IMAGE_NODE].type))
-    return true;
-  const regex = /^(https?|ftp|file|about|chrome|resource):/;
-  return regex.test(url);
+  return /^data:image\//i.test(url) ||
+    /^(https?|ftp|file|about|chrome|resource):/.test(url);
 }
--- a/browser/makefiles.sh
+++ b/browser/makefiles.sh
@@ -64,18 +64,20 @@ browser/components/sessionstore/Makefile
 browser/components/sessionstore/src/Makefile
 browser/components/sidebar/src/Makefile
 browser/components/shell/Makefile
 browser/components/shell/public/Makefile
 browser/components/shell/src/Makefile
 browser/components/tabview/Makefile
 browser/devtools/Makefile
 browser/devtools/highlighter/Makefile
+browser/devtools/scratchpad/Makefile
 browser/devtools/shared/Makefile
 browser/devtools/sourceeditor/Makefile
+browser/devtools/styleeditor/Makefile
 browser/devtools/styleinspector/Makefile
 browser/devtools/webconsole/Makefile
 browser/fuel/Makefile
 browser/fuel/public/Makefile
 browser/fuel/src/Makefile
 browser/installer/Makefile
 browser/locales/Makefile
 browser/themes/Makefile
@@ -135,16 +137,17 @@ if [ "$ENABLE_TESTS" ]; then
     browser/components/privatebrowsing/test/Makefile
     browser/components/privatebrowsing/test/browser/Makefile
     browser/components/tabview/test/Makefile
     browser/components/test/browser/Makefile
     browser/devtools/highlighter/test/Makefile
     browser/devtools/scratchpad/test/Makefile
     browser/devtools/shared/test/Makefile
     browser/devtools/sourceeditor/test/Makefile
+    browser/devtools/styleeditor/test/Makefile
     browser/devtools/styleinspector/test/browser/Makefile
     browser/devtools/webconsole/test/browser/Makefile
     browser/fuel/test/Makefile
   "
   if [ "$MOZ_SAFE_BROWSING" ]; then
     add_makefiles "
       browser/components/safebrowsing/content/test/Makefile
     "
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -183,8 +183,12 @@ https://www.bank1.com:443           priv
 https://www.bank2.com:443           privileged,cert=escapeattack2
 
 #
 # CONNECT for redirproxy results in a 302 redirect to
 # test1.example.com
 #
 https://redirproxy.example.com:443          privileged,redir=test1.example.com
 
+# Host used for IndexedDB Quota testing
+http://bug704464-1.example.com:80        privileged
+http://bug704464-2.example.com:80        privileged
+http://bug704464-3.example.com:80        privileged
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1733,17 +1733,17 @@ nsScriptSecurityManager::CheckFunctionAc
         GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
 
     // If subject is null, get a principal from the function object's scope.
     if (NS_SUCCEEDED(rv) && !subject)
     {
 #ifdef DEBUG
         {
             JS_ASSERT(JS_ObjectIsFunction(aCx, (JSObject *)aFunObj));
-            JSFunction *fun = (JSFunction *)JS_GetPrivate(aCx, (JSObject *)aFunObj);
+            JSFunction *fun = JS_GetObjectFunction((JSObject *)aFunObj);
             JSScript *script = JS_GetFunctionScript(aCx, fun);
 
             NS_ASSERTION(!script, "Null principal for non-native function!");
         }
 #endif
 
         subject = doGetObjectPrincipal((JSObject*)aFunObj);
     }
@@ -2214,17 +2214,17 @@ nsScriptSecurityManager::GetFunctionObje
     {
         // Protect against pseudo-functions (like SJOWs).
         nsIPrincipal *result = doGetObjectPrincipal(obj);
         if (!result)
             *rv = NS_ERROR_FAILURE;
         return result;
     }
 
-    JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
+    JSFunction *fun = JS_GetObjectFunction(obj);
     JSScript *script = JS_GetFunctionScript(cx, fun);
 
     if (!script)
     {
         // A native function: skip it in order to find its scripted caller.
         return nsnull;
     }
 
@@ -2238,17 +2238,17 @@ nsScriptSecurityManager::GetFunctionObje
         // principal we want is in the frame's script, not in the
         // function's script. The function's script is where the
         // eval-calling code came from, not where the eval or new
         // Script object came from, and we want the principal of
         // the eval function object or new Script object.
 
         script = frameScript;
     }
-    else if (JS_GetFunctionObject(fun) != obj)
+    else if (!js::IsOriginalScriptFunction(fun))
     {
         // Here, obj is a cloned function object.  In this case, the
         // clone's prototype may have been precompiled from brutally
         // shared chrome, or else it is a lambda or nested function.
         // The general case here is a function compiled against a
         // different scope than the one it is parented by at runtime,
         // hence the creation of a clone to carry the correct scope
         // chain linkage.
@@ -2280,17 +2280,17 @@ nsScriptSecurityManager::GetFramePrincip
         return GetScriptPrincipal(cx, script, rv);
     }
 
     nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
 
 #ifdef DEBUG
     if (NS_SUCCEEDED(*rv) && !result)
     {
-        JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
+        JSFunction *fun = JS_GetObjectFunction(obj);
         JSScript *script = JS_GetFunctionScript(cx, fun);
 
         NS_ASSERTION(!script, "Null principal for non-native function!");
     }
 #endif
 
     return result;
 }
@@ -2427,17 +2427,17 @@ nsScriptSecurityManager::doGetObjectPrin
         aObj = js::GetObjectParent(aObj);
 
         if (!aObj)
             return nsnull;
 
         jsClass = js::GetObjectClass(aObj);
 
         if (jsClass == &js::CallClass) {
-            aObj = js::GetObjectParent(aObj);
+            aObj = js::GetObjectParentMaybeScope(aObj);
 
             if (!aObj)
                 return nsnull;
 
             jsClass = js::GetObjectClass(aObj);
         }
     }
 
@@ -2479,17 +2479,17 @@ nsScriptSecurityManager::doGetObjectPrin
                 result = objPrin->GetPrincipal();
 
                 if (result) {
                     break;
                 }
             }
         }
 
-        aObj = js::GetObjectParent(aObj);
+        aObj = js::GetObjectParentMaybeScope(aObj);
 
         if (!aObj)
             break;
 
         jsClass = js::GetObjectClass(aObj);
     } while (1);
 
 #ifdef DEBUG
--- a/content/base/src/nsAttrAndChildArray.cpp
+++ b/content/base/src/nsAttrAndChildArray.cpp
@@ -362,41 +362,16 @@ nsAttrAndChildArray::AttrAt(PRUint32 aPo
   if (aPos < mapped) {
     return mImpl->mMappedAttrs->AttrAt(aPos);
   }
 
   return &ATTRS(mImpl)[aPos - mapped].mValue;
 }
 
 nsresult
-nsAttrAndChildArray::SetAttr(nsIAtom* aLocalName, const nsAString& aValue)
-{
-  PRUint32 i, slotCount = AttrSlotCount();
-  for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
-    if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
-      ATTRS(mImpl)[i].mValue.SetTo(aValue);
-
-      return NS_OK;
-    }
-  }
-
-  NS_ENSURE_TRUE(slotCount < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
-                 NS_ERROR_FAILURE);
-
-  if (i == slotCount && !AddAttrSlot()) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  new (&ATTRS(mImpl)[i].mName) nsAttrName(aLocalName);
-  new (&ATTRS(mImpl)[i].mValue) nsAttrValue(aValue);
-
-  return NS_OK;
-}
-
-nsresult
 nsAttrAndChildArray::SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
 {
   PRUint32 i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
       ATTRS(mImpl)[i].mValue.Reset();
       ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
 
--- a/content/base/src/nsAttrAndChildArray.h
+++ b/content/base/src/nsAttrAndChildArray.h
@@ -98,17 +98,16 @@ public:
   // Like RemoveChildAt but hands the reference to the child being
   // removed back to the caller instead of just releasing it.
   already_AddRefed<nsIContent> TakeChildAt(PRUint32 aPos);
   PRInt32 IndexOfChild(nsINode* aPossibleChild) const;
 
   PRUint32 AttrCount() const;
   const nsAttrValue* GetAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID = kNameSpaceID_None) const;
   const nsAttrValue* AttrAt(PRUint32 aPos) const;
-  nsresult SetAttr(nsIAtom* aLocalName, const nsAString& aValue);
   nsresult SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
   nsresult SetAndTakeAttr(nsINodeInfo* aName, nsAttrValue& aValue);
 
   // Remove the attr at position aPos.  The value of the attr is placed in
   // aValue; any value that was already in aValue is destroyed.
   nsresult RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue);
 
   // Returns attribute name at given position, *not* out-of-bounds safe
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -589,16 +589,19 @@ GK_ATOM(mouseup, "mouseup")
 GK_ATOM(mozfullscreenchange, "mozfullscreenchange")
 GK_ATOM(mozfullscreenerror, "mozfullscreenerror")
 GK_ATOM(moz_opaque, "moz-opaque")
 GK_ATOM(moz_action_hint, "mozactionhint")
 GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
 GK_ATOM(msthemecompatible, "msthemecompatible")
 GK_ATOM(multicol, "multicol")
 GK_ATOM(multiple, "multiple")
+#ifdef MOZ_MEDIA
+GK_ATOM(muted, "muted")
+#endif
 GK_ATOM(name, "name")
 GK_ATOM(_namespace, "namespace")
 GK_ATOM(namespaceAlias, "namespace-alias")
 GK_ATOM(namespaceUri, "namespace-uri")
 GK_ATOM(NaN, "NaN")
 GK_ATOM(nav, "nav")
 GK_ATOM(negate, "negate")
 GK_ATOM(never, "never")
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -174,21 +174,21 @@ PRUint32 nsStyleLinkElement::ParseLinkTy
   PRUint32 linkMask = 0;
   nsAString::const_iterator start, done;
   aTypes.BeginReading(start);
   aTypes.EndReading(done);
   if (start == done)
     return linkMask;
 
   nsAString::const_iterator current(start);
-  bool inString = !nsCRT::IsAsciiSpace(*current);
+  bool inString = !nsContentUtils::IsHTMLWhitespace(*current);
   nsAutoString subString;
   
   while (current != done) {
-    if (nsCRT::IsAsciiSpace(*current)) {
+    if (nsContentUtils::IsHTMLWhitespace(*current)) {
       if (inString) {
         ToLowerCase(Substring(start, current), subString);
         linkMask |= ToLinkMask(subString);
         inString = false;
       }
     }
     else {
       if (!inString) {
--- a/content/base/src/nsTreeSanitizer.cpp
+++ b/content/base/src/nsTreeSanitizer.cpp
@@ -248,16 +248,19 @@ nsIAtom** const kAttributesHTML[] = {
   &nsGkAtoms::low,
   &nsGkAtoms::max,
   &nsGkAtoms::maxlength,
   &nsGkAtoms::media,
   &nsGkAtoms::method,
   &nsGkAtoms::min,
   &nsGkAtoms::mozdonotsend,
   &nsGkAtoms::multiple,
+#ifdef MOZ_MEDIA
+  &nsGkAtoms::muted,
+#endif
   &nsGkAtoms::name,
   &nsGkAtoms::nohref,
   &nsGkAtoms::noshade,
   &nsGkAtoms::novalidate,
   &nsGkAtoms::nowrap,
   &nsGkAtoms::open,
   &nsGkAtoms::optimum,
   &nsGkAtoms::pattern,
--- a/content/base/src/nsXHTMLContentSerializer.cpp
+++ b/content/base/src/nsXHTMLContentSerializer.cpp
@@ -738,17 +738,17 @@ nsXHTMLContentSerializer::IsShorthandAtt
   if ((aAttrName == nsGkAtoms::selected) &&
       (aElementName == nsGkAtoms::option)) {
     return true;
   }
 
 #ifdef MOZ_MEDIA
   // autoplay and controls
   if ((aElementName == nsGkAtoms::video || aElementName == nsGkAtoms::audio) &&
-    (aAttrName == nsGkAtoms::autoplay ||
+    (aAttrName == nsGkAtoms::autoplay || aAttrName == nsGkAtoms::muted ||
      aAttrName == nsGkAtoms::controls)) {
     return true;
   }
 #endif
 
   return false;
 }
 
--- a/content/base/src/nsXMLContentSerializer.cpp
+++ b/content/base/src/nsXMLContentSerializer.cpp
@@ -1147,31 +1147,16 @@ nsXMLContentSerializer::CheckElementEnd(
                                         bool & aForceFormat,
                                         nsAString& aStr)
 {
   // We don't output a separate end tag for empty element
   aForceFormat = false;
   return aContent->GetChildCount() > 0;
 }
 
-void
-nsXMLContentSerializer::AppendToString(const PRUnichar* aStr,
-                                       PRInt32 aLength,
-                                       nsAString& aOutputStr)
-{
-  if (mBodyOnly && !mInBody) {
-    return;
-  }
-  PRInt32 length = (aLength == -1) ? nsCRT::strlen(aStr) : aLength;
-
-  mColPos += length;
-
-  aOutputStr.Append(aStr, length);
-}
-
 void 
 nsXMLContentSerializer::AppendToString(const PRUnichar aChar,
                                        nsAString& aOutputStr)
 {
   if (mBodyOnly && !mInBody) {
     return;
   }
   mColPos += 1;
--- a/content/base/src/nsXMLContentSerializer.h
+++ b/content/base/src/nsXMLContentSerializer.h
@@ -98,23 +98,16 @@ class nsXMLContentSerializer : public ns
   NS_IMETHOD Flush(nsAString& aStr) { return NS_OK; }
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
  protected:
 
   /**
-   * Appends a PRUnichar string and increments the column position
-   */
-  void AppendToString(const PRUnichar* aStr,
-                      PRInt32 aLength,
-                      nsAString& aOutputStr);
-
-  /**
    * Appends a PRUnichar character and increments the column position
    */
   void AppendToString(const PRUnichar aChar,
                       nsAString& aOutputStr);
 
   /**
    * Appends a nsAString string and increments the column position
    */
--- a/content/canvas/src/CanvasUtils.cpp
+++ b/content/canvas/src/CanvasUtils.cpp
@@ -96,44 +96,16 @@ DoDrawImageSecurityCheck(nsHTMLCanvasEle
     if (NS_SUCCEEDED(rv) && subsumes) {
         // This canvas has access to that image anyway
         return;
     }
 
     aCanvasElement->SetWriteOnly();
 }
 
-void
-LogMessage (const nsCString& errorString)
-{
-    nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-    if (!console)
-        return;
-
-    console->LogStringMessage(NS_ConvertUTF8toUTF16(errorString).get());
-    fprintf(stderr, "%s\n", errorString.get());
-}
-
-void
-LogMessagef (const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    char buf[256];
-
-    nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-    if (console) {
-        PR_vsnprintf(buf, 256, fmt, ap);
-        console->LogStringMessage(NS_ConvertUTF8toUTF16(nsDependentCString(buf)).get());
-        fprintf(stderr, "%s\n", buf);
-    }
-
-    va_end(ap);
-}
-
 bool
 CoerceDouble(jsval v, double* d)
 {
     if (JSVAL_IS_DOUBLE(v)) {
         *d = JSVAL_TO_DOUBLE(v);
     } else if (JSVAL_IS_INT(v)) {
         *d = double(JSVAL_TO_INT(v));
     } else if (JSVAL_IS_VOID(v)) {
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -72,19 +72,16 @@ inline bool CheckSaneSubrectSize(PRInt32
 // Flag aCanvasElement as write-only if drawing an image with aPrincipal
 // onto it would make it such.
 
 void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
                               nsIPrincipal *aPrincipal,
                               bool forceWriteOnly,
                               bool CORSUsed);
 
-void LogMessage (const nsCString& errorString);
-void LogMessagef (const char *fmt, ...);
-
 // Make a double out of |v|, treating undefined values as 0.0 (for
 // the sake of sparse arrays).  Return true iff coercion
 // succeeded.
 bool CoerceDouble(jsval v, double* d);
 
 // Return true iff the conversion succeeded, false otherwise.  *rv is
 // the value to return to script if this returns false.
 bool JSValToMatrix(JSContext* cx, const jsval& val,
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1157,19 +1157,31 @@ WebGLContext::Notify(nsITimer* timer)
 }
 
 void
 WebGLContext::MaybeRestoreContext()
 {
     if (mContextLost || mAllowRestore)
         return;
 
-    gl->MakeCurrent();
-    GLContext::ContextResetARB resetStatus = 
-        (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
+    GLContext::ContextResetARB resetStatus = GLContext::CONTEXT_NO_ERROR;
+    if (mHasRobustness) {
+        gl->MakeCurrent();
+        resetStatus = (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
+    // This call is safe as it does not actually interact with GL, so the
+    // context does not have to be current.
+    } else if (gl->GetContextType() == GLContext::ContextTypeEGL) {
+        // Simulate a ARB_robustness guilty context loss for when we
+        // get an EGL_CONTEXT_LOST error. It may not actually be guilty,
+        // but we can't make any distinction, so we must assume the worst
+        // case.
+        if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
+            resetStatus = GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB;
+        }
+    }
     
     if (resetStatus != GLContext::CONTEXT_NO_ERROR) {
         // It's already lost, but clean up after it and signal to JS that it is
         // lost.
         ForceLoseContext();
     }
 
     switch (resetStatus) {
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -52,16 +52,17 @@
 
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsHTMLCanvasElement.h"
 #include "nsWeakReference.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsIMemoryReporter.h"
+#include "nsContentUtils.h"
 
 #include "GLContextProvider.h"
 #include "Layers.h"
 
 #include "CheckedInt.h"
 
 /* 
  * Minimum value constants defined in 6.2 State Tables of OpenGL ES - 2.0.25
@@ -444,17 +445,17 @@ public:
     
     bool MinCapabilityMode() const {
         return mMinCapability;
     }
 
     // Sets up the GL_ARB_robustness timer if it isn't already, so that if the
     // driver gets restarted, the context may get reset with it.
     void SetupRobustnessTimer() {
-        if (mContextLost || !mHasRobustness)
+        if (mContextLost || (!mHasRobustness && gl->GetContextType() != gl::GLContext::ContextTypeEGL))
             return;
 
         // If the timer was already running, don't restart it here. Instead,
         // wait until the previous call is done, then fire it one more time.
         // This is an optimization to prevent unnecessary cross-communication
         // between threads.
         if (mRobustnessTimerRunning) {
             mDrawSinceRobustnessTimerSet = true;
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3988,29 +3988,32 @@ WebGLContext::ConvertImage(size_t width,
             return;
     }
 }
 
 nsresult
 WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
                                        gfxImageSurface **imageOut, int *format)
 {
-    gfxImageSurface *surf = nsnull;
+    nsCOMPtr<nsIContent> content = do_QueryInterface(imageOrCanvas);
+    if (!content) {
+        return NS_ERROR_FAILURE;
+    }        
 
     PRUint32 flags =
         nsLayoutUtils::SFE_WANT_NEW_SURFACE |
         nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
 
     if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
         flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
     if (!mPixelStorePremultiplyAlpha)
         flags |= nsLayoutUtils::SFE_NO_PREMULTIPLY_ALPHA;
 
     nsLayoutUtils::SurfaceFromElementResult res =
-        nsLayoutUtils::SurfaceFromElement(imageOrCanvas, flags);
+        nsLayoutUtils::SurfaceFromElement(content->AsElement(), flags);
     if (!res.mSurface)
         return NS_ERROR_FAILURE;
     if (res.mSurface->GetType() != gfxASurface::SurfaceTypeImage) {
         // SurfaceFromElement lied!
         return NS_ERROR_FAILURE;
     }
 
     // We disallow loading cross-domain images that have not been validated
@@ -4029,35 +4032,34 @@ WebGLContext::DOMElementToImageSurface(n
         nsresult rv = HTMLCanvasElement()->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
         if (NS_FAILED(rv) || !subsumes) {
             LogMessageIfVerbose("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
                                 "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
             return NS_ERROR_DOM_SECURITY_ERR;
         }
     }
 
-    // part 2: if the DOM element is a canvas, check that it's not write-only. That would indicate a tainted canvas,
-    // i.e. a canvas that could contain cross-domain image data.
-    nsCOMPtr<nsIContent> maybeDOMCanvas = do_QueryInterface(imageOrCanvas);
-    if (maybeDOMCanvas && maybeDOMCanvas->IsHTML(nsGkAtoms::canvas)) {
-        nsHTMLCanvasElement *canvas = static_cast<nsHTMLCanvasElement*>(maybeDOMCanvas.get());
+    // part 2: if the DOM element is a canvas, check that it's not write-only.
+    // That would indicate a tainted canvas, i.e. a canvas that could contain
+    // cross-domain image data.
+    if (nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content)) {
         if (canvas->IsWriteOnly()) {
             LogMessageIfVerbose("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden "
                                 "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example "
                                 "when a cross-domain image is drawn on it. "
                                 "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
             return NS_ERROR_DOM_SECURITY_ERR;
         }
     }
 
     // End of security checks, now we should be safe regarding cross-domain images
     // Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
     // texture sources in the first place.
 
-    surf = static_cast<gfxImageSurface*>(res.mSurface.get());
+    gfxImageSurface* surf = static_cast<gfxImageSurface*>(res.mSurface.get());
 
     res.mSurface.forget();
     *imageOut = surf;
 
     switch (surf->Format()) {
         case gfxASurface::ImageFormatARGB32:
             *format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
             break;
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -1808,50 +1808,50 @@ nsCanvasRenderingContext2D::CreateRadial
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image,
                                           const nsAString& repeat,
                                           nsIDOMCanvasPattern **_retval)
 {
-    if (!image) {
+    nsCOMPtr<nsIContent> content = do_QueryInterface(image);
+    if (!content) {
         return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
     }
+
     gfxPattern::GraphicsExtend extend;
-
     if (repeat.IsEmpty() || repeat.EqualsLiteral("repeat")) {
         extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("repeat-x")) {
         // XX
         extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("repeat-y")) {
         // XX
         extend = gfxPattern::EXTEND_REPEAT;
     } else if (repeat.EqualsLiteral("no-repeat")) {
         extend = gfxPattern::EXTEND_NONE;
     } else {
         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         return NS_ERROR_DOM_SYNTAX_ERR;
     }
 
-    nsCOMPtr<nsIContent> content = do_QueryInterface(image);
     nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content);
     if (canvas) {
         nsIntSize size = canvas->GetSize();
         if (size.width == 0 || size.height == 0) {
             return NS_ERROR_DOM_INVALID_STATE_ERR;
         }
     }
 
     // The canvas spec says that createPattern should use the first frame
     // of animated images
     nsLayoutUtils::SurfaceFromElementResult res =
-        nsLayoutUtils::SurfaceFromElement(image, nsLayoutUtils::SFE_WANT_FIRST_FRAME |
-                                                 nsLayoutUtils::SFE_WANT_NEW_SURFACE);
+        nsLayoutUtils::SurfaceFromElement(content->AsElement(),
+            nsLayoutUtils::SFE_WANT_FIRST_FRAME | nsLayoutUtils::SFE_WANT_NEW_SURFACE);
     if (!res.mSurface)
         return NS_ERROR_NOT_AVAILABLE;
 
     nsRefPtr<gfxPattern> thebespat = new gfxPattern(res.mSurface);
 
     thebespat->SetExtend(extend);
 
     nsRefPtr<nsCanvasPattern> pat = new nsCanvasPattern(thebespat, res.mPrincipal,
@@ -3394,21 +3394,21 @@ NS_IMETHODIMP
 nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
                                       float a2, float a3, float a4, float a5,
                                       float a6, float a7, float a8,
                                       PRUint8 optional_argc)
 {
     if (!EnsureSurface())
         return NS_ERROR_FAILURE;
 
-    if (!imgElt) {
+    nsCOMPtr<nsIContent> content = do_QueryInterface(imgElt);
+    if (!content) {
         return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
     }
 
-    nsCOMPtr<nsIContent> content = do_QueryInterface(imgElt);
     nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content);
     if (canvas) {
         nsIntSize size = canvas->GetSize();
         if (size.width == 0 || size.height == 0) {
             return NS_ERROR_DOM_INVALID_STATE_ERR;
         }
     }
 
@@ -3418,27 +3418,28 @@ nsCanvasRenderingContext2D::DrawImage(ns
     nsRefPtr<gfxASurface> imgsurf =
       CanvasImageCache::Lookup(imgElt, HTMLCanvasElement(), &imgSize);
 
     if (!imgsurf) {
         // The canvas spec says that drawImage should draw the first frame
         // of animated images
         PRUint32 sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME;
         nsLayoutUtils::SurfaceFromElementResult res =
-            nsLayoutUtils::SurfaceFromElement(imgElt, sfeFlags);
+            nsLayoutUtils::SurfaceFromElement(content->AsElement(), sfeFlags);
         if (!res.mSurface) {
             // Spec says to silently do nothing if the element is still loading.
             return res.mIsStillLoading ? NS_OK : NS_ERROR_NOT_AVAILABLE;
         }
 
         // Force a copy if we're using drawImage with our destination
         // as a source to work around some Cairo self-copy semantics issues.
         if (res.mSurface == mSurface) {
             sfeFlags |= nsLayoutUtils::SFE_WANT_NEW_SURFACE;
-            res = nsLayoutUtils::SurfaceFromElement(imgElt, sfeFlags);
+            res = nsLayoutUtils::SurfaceFromElement(content->AsElement(),
+                                                    sfeFlags);
             if (!res.mSurface)
                 return NS_ERROR_NOT_AVAILABLE;
         }
 
         imgsurf = res.mSurface.forget();
         imgSize = res.mSize;
 
         if (mCanvasElement) {
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -1884,17 +1884,18 @@ nsCanvasRenderingContext2DAzure::CreateR
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2DAzure::CreatePattern(nsIDOMHTMLElement *image,
                                                const nsAString& repeat,
                                                nsIDOMCanvasPattern **_retval)
 {
-  if (!image) {
+  nsCOMPtr<nsIContent> content = do_QueryInterface(image);
+  if (!content) {
     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
   }
 
   nsCanvasPatternAzure::RepeatMode repeatMode =
     nsCanvasPatternAzure::NOREPEAT;
 
   if (repeat.IsEmpty() || repeat.EqualsLiteral("repeat")) {
     repeatMode = nsCanvasPatternAzure::REPEAT;
@@ -1903,19 +1904,17 @@ nsCanvasRenderingContext2DAzure::CreateP
   } else if (repeat.EqualsLiteral("repeat-y")) {
     repeatMode = nsCanvasPatternAzure::REPEATY;
   } else if (repeat.EqualsLiteral("no-repeat")) {
     repeatMode = nsCanvasPatternAzure::NOREPEAT;
   } else {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
-  nsCOMPtr<nsIContent> content = do_QueryInterface(image);
   nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content);
-
   if (canvas) {
     nsIntSize size = canvas->GetSize();
     if (size.width == 0 || size.height == 0) {
       return NS_ERROR_DOM_INVALID_STATE_ERR;
     }
   }
 
   // Special case for Canvas, which could be an Azure canvas!
@@ -1934,18 +1933,18 @@ nsCanvasRenderingContext2DAzure::CreateP
         return NS_OK;
       }
     }
   }
 
   // The canvas spec says that createPattern should use the first frame
   // of animated images
   nsLayoutUtils::SurfaceFromElementResult res =
-    nsLayoutUtils::SurfaceFromElement(image, nsLayoutUtils::SFE_WANT_FIRST_FRAME |
-                                              nsLayoutUtils::SFE_WANT_NEW_SURFACE);
+    nsLayoutUtils::SurfaceFromElement(content->AsElement(),
+      nsLayoutUtils::SFE_WANT_FIRST_FRAME | nsLayoutUtils::SFE_WANT_NEW_SURFACE);
 
   if (!res.mSurface) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Ignore nsnull cairo surfaces! See bug 666312.
   if (!res.mSurface->CairoSurface()) {
     return NS_OK;
@@ -3565,17 +3564,18 @@ nsCanvasRenderingContext2DAzure::IsPoint
 //   -- render the region defined by (sx,sy,sw,wh) in image-local space into the region (dx,dy,dw,dh) on the canvas
 
 NS_IMETHODIMP
 nsCanvasRenderingContext2DAzure::DrawImage(nsIDOMElement *imgElt, float a1,
                                            float a2, float a3, float a4, float a5,
                                            float a6, float a7, float a8,
                                            PRUint8 optional_argc)
 {
-  if (!imgElt) {
+  nsCOMPtr<nsIContent> content = do_QueryInterface(imgElt);
+  if (!content) {
     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
   }
 
   if (optional_argc == 0) {
     if (!FloatValidate(a1, a2)) {
       return NS_OK;
     }
   } else if (optional_argc == 2) {
@@ -3586,17 +3586,16 @@ nsCanvasRenderingContext2DAzure::DrawIma
     if (!FloatValidate(a1, a2, a3, a4, a5, a6) || !FloatValidate(a7, a8)) {
       return NS_OK;
     }
   }
 
   double sx,sy,sw,sh;
   double dx,dy,dw,dh;
 
-  nsCOMPtr<nsIContent> content = do_QueryInterface(imgElt);
   nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content);
   if (canvas) {
     nsIntSize size = canvas->GetSize();
     if (size.width == 0 || size.height == 0) {
       return NS_ERROR_DOM_INVALID_STATE_ERR;
     }
   }
     
@@ -3638,17 +3637,17 @@ nsCanvasRenderingContext2DAzure::DrawIma
     }
   }
 
   if (!srcSurf) {
     // The canvas spec says that drawImage should draw the first frame
     // of animated images
     PRUint32 sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME;
     nsLayoutUtils::SurfaceFromElementResult res =
-      nsLayoutUtils::SurfaceFromElement(imgElt, sfeFlags);
+      nsLayoutUtils::SurfaceFromElement(content->AsElement(), sfeFlags);
 
     if (!res.mSurface) {
       // Spec says to silently do nothing if the element is still loading.
       return res.mIsStillLoading ? NS_OK : NS_ERROR_NOT_AVAILABLE;
     }
 
     // Ignore cairo surfaces that are bad! See bug 666312.
     if (res.mSurface->CairoStatus()) {
--- a/content/html/content/public/nsHTMLVideoElement.h
+++ b/content/html/content/public/nsHTMLVideoElement.h
@@ -43,16 +43,24 @@
 
 class nsHTMLVideoElement : public nsHTMLMediaElement,
                            public nsIDOMHTMLVideoElement
 {
 public:
   nsHTMLVideoElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~nsHTMLVideoElement();
 
+  static nsHTMLVideoElement* FromContent(nsIContent* aPossibleVideo)
+  {
+    if (!aPossibleVideo || !aPossibleVideo->IsHTML(nsGkAtoms::video)) {
+      return NULL;
+    }
+    return static_cast<nsHTMLVideoElement*>(aPossibleVideo);
+  }
+
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE(nsHTMLMediaElement::)
 
   // nsIDOMElement
   NS_FORWARD_NSIDOMELEMENT(nsHTMLMediaElement::)
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -1511,16 +1511,19 @@ nsresult nsHTMLMediaElement::SetAttr(PRI
   nsresult rv =
     nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                   aNotify);
   if (NS_FAILED(rv))
     return rv;
   if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
     Load();
   }
+  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::muted) {
+    mMuted = true;
+  }
   if (aNotify && aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::autoplay) {
       StopSuspendingAfterFirstFrame();
       if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
         NotifyAutoplayDataReady();
       }
       // This attribute can affect AddRemoveSelfReference
       AddRemoveSelfReference();
@@ -2682,28 +2685,27 @@ nsHTMLMediaElement::CopyInnerTo(nsGeneri
   NS_ENSURE_SUCCESS(rv, rv);
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     nsHTMLMediaElement* dest = static_cast<nsHTMLMediaElement*>(aDest);
     if (mPrintSurface) {
       dest->mPrintSurface = mPrintSurface;
       dest->mMediaSize = mMediaSize;
     } else {
       nsIFrame* frame = GetPrimaryFrame();
-      nsCOMPtr<nsIDOMElement> elem;
+      Element* element;
       if (frame && frame->GetType() == nsGkAtoms::HTMLVideoFrame &&
           static_cast<nsVideoFrame*>(frame)->ShouldDisplayPoster()) {
-        elem = do_QueryInterface(static_cast<nsVideoFrame*>(frame)->
-                                 GetPosterImage());
+        nsIContent* content = static_cast<nsVideoFrame*>(frame)->GetPosterImage();
+        element = content ? content->AsElement() : NULL;
       } else {
-        elem = do_QueryInterface(
-          static_cast<nsGenericElement*>(const_cast<nsHTMLMediaElement*>(this)));
+        element = const_cast<nsHTMLMediaElement*>(this);
       }
 
       nsLayoutUtils::SurfaceFromElementResult res =
-        nsLayoutUtils::SurfaceFromElement(elem,
+        nsLayoutUtils::SurfaceFromElement(element,
                                           nsLayoutUtils::SFE_WANT_NEW_SURFACE);
       dest->mPrintSurface = res.mSurface;
       dest->mMediaSize = nsIntSize(res.mSize.width, res.mSize.height);
     }
   }
   return rv;
 }
 
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1740,17 +1740,18 @@ nsHTMLDocument::Open(const nsAString& aC
 
     // Now make sure we're not flagged as the initial document anymore, now
     // that we've had stuff done to us.  From now on, if anyone tries to
     // document.open() us, they get a new inner window.
     SetIsInitialDocument(false);
 
     nsCOMPtr<nsIScriptGlobalObject> newScope(do_QueryReferent(mScopeObject));
     if (oldScope && newScope != oldScope) {
-      nsContentUtils::ReparentContentWrappersInScope(cx, oldScope, newScope);
+      rv = nsContentUtils::ReparentContentWrappersInScope(cx, oldScope, newScope);
+      NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   // Call Reset(), this will now do the full reset
   Reset(channel, group);
   if (baseURI) {
     mDocumentBaseURI = baseURI;
   }
@@ -1949,16 +1950,18 @@ nsHTMLDocument::WriteCommon(JSContext *c
               1, getter_AddRefs(ignored));
 
     // If Open() fails, or if it didn't create a parser (as it won't
     // if the user chose to not discard the current document through
     // onbeforeunload), don't write anything.
     if (NS_FAILED(rv) || !mParser) {
       return rv;
     }
+    NS_ABORT_IF_FALSE(!JS_IsExceptionPending(cx),
+                      "Open() succeeded but JS exception is pending");
   }
 
   static NS_NAMED_LITERAL_STRING(new_line, "\n");
 
   // Save the data in cache
   if (mWyciwygChannel) {
     if (!aText.IsEmpty()) {
       mWyciwygChannel->WriteToCacheEntry(aText);
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -2359,33 +2359,16 @@ nsXULDocument::ContextStack::SetTopIndex
     if (mDepth == 0)
         return NS_ERROR_UNEXPECTED;
 
     mTop->mIndex = aIndex;
     return NS_OK;
 }
 
 
-bool
-nsXULDocument::ContextStack::IsInsideXULTemplate()
-{
-    if (mDepth) {
-        for (nsIContent* element = mTop->mElement; element;
-             element = element->GetParent()) {
-
-            if (element->NodeInfo()->Equals(nsGkAtoms::_template,
-                                            kNameSpaceID_XUL)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-
 //----------------------------------------------------------------------
 //
 // Content model walking routines
 //
 
 nsresult
 nsXULDocument::PrepareToWalk()
 {
--- a/content/xul/document/src/nsXULDocument.h
+++ b/content/xul/document/src/nsXULDocument.h
@@ -352,18 +352,16 @@ protected:
 
         PRInt32 Depth() { return mDepth; }
 
         nsresult Push(nsXULPrototypeElement* aPrototype, nsIContent* aElement);
         nsresult Pop();
         nsresult Peek(nsXULPrototypeElement** aPrototype, nsIContent** aElement, PRInt32* aIndex);
 
         nsresult SetTopIndex(PRInt32 aIndex);
-
-        bool IsInsideXULTemplate();
     };
 
     friend class ContextStack;
     ContextStack mContextStack;
 
     enum State { eState_Master, eState_Overlay };
     State mState;
 
--- a/content/xul/templates/src/nsRuleNetwork.cpp
+++ b/content/xul/templates/src/nsRuleNetwork.cpp
@@ -449,23 +449,16 @@ TestNode::Constrain(InstantiationSet& aI
 
     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
            ("TestNode[%p]: Constrain() end", this));
 
     return rv;
 }
 
 
-bool
-TestNode::HasAncestor(const ReteNode* aNode) const
-{
-    return aNode == this || (mParent && mParent->HasAncestor(aNode));
-}
-
-
 //----------------------------------------------------------------------
 
 ReteNodeSet::ReteNodeSet()
     : mNodes(nsnull), mCount(0), mCapacity(0)
 {
 }
 
 ReteNodeSet::~ReteNodeSet()
--- a/content/xul/templates/src/nsRuleNetwork.h
+++ b/content/xul/templates/src/nsRuleNetwork.h
@@ -874,24 +874,16 @@ public:
      *        isn't important to the caller.
      * @return NS_OK if no errors occurred.
      */
     virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations,
                                           bool* aCantHandleYet) const = 0;
     //XXX probably better named "ApplyConstraints" or "Discrminiate" or something
 
     /**
-     * Determine if this node has another node as its direct ancestor.
-     * @param aNode the node to look for.
-     * @return true if aNode is a direct ancestor of this node, false
-     *   otherwise.
-     */
-    bool HasAncestor(const ReteNode* aNode) const;
-
-    /**
      * Add another node as a child of this node.
      * @param aNode the node to add.
      * @return NS_OK if no errors occur.
      */
     nsresult AddChild(ReteNode* aNode) { return mKids.Add(aNode); }
 
     /**
      * Remove all the children of this node
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -864,20 +864,28 @@ nsDOMWindowUtils::NodesFromRect(float aX
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mWindow->GetExtantDocument()));
   NS_ENSURE_STATE(doc);
 
   return doc->NodesFromRectHelper(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize, 
                                   aIgnoreRootScrollFrame, aFlushLayout, aReturn);
 }
 
 static already_AddRefed<gfxImageSurface>
-CanvasToImageSurface(nsIDOMHTMLCanvasElement *canvas)
+CanvasToImageSurface(nsIDOMHTMLCanvasElement* aCanvas)
 {
+  nsCOMPtr<nsINode> node = do_QueryInterface(aCanvas);
+  if (!node) {
+    return nsnull;
+  }
+
+  NS_ABORT_IF_FALSE(node->IsElement(),
+                    "An nsINode that implements nsIDOMHTMLCanvasElement should "
+                    "be an element.");
   nsLayoutUtils::SurfaceFromElementResult result =
-    nsLayoutUtils::SurfaceFromElement(canvas,
+    nsLayoutUtils::SurfaceFromElement(node->AsElement(),
                                       nsLayoutUtils::SFE_WANT_IMAGE_SURFACE);
   return static_cast<gfxImageSurface*>(result.mSurface.forget().get());
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::CompareCanvases(nsIDOMHTMLCanvasElement *aCanvas1,
                                   nsIDOMHTMLCanvasElement *aCanvas2,
                                   PRUint32* aMaxDifference,
@@ -1437,54 +1445,30 @@ nsDOMWindowUtils::SendContentCommandEven
     event.mTransferable = aTransferable;
   }
 
   nsEventStatus status;
   return widget->DispatchEvent(&event, status);
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::GetClassName(char **aName)
+nsDOMWindowUtils::GetClassName(const JS::Value& aObject, JSContext* aCx, char** aName)
 {
   if (!nsContentUtils::IsCallerTrustedForRead()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  // get the xpconnect native call context
-  nsAXPCNativeCallContext *cc = nsnull;
-  nsContentUtils::XPConnect()->GetCurrentNativeCallContext(&cc);
-  if(!cc)
-    return NS_ERROR_FAILURE;
-
-  // Get JSContext of current call
-  JSContext* cx;
-  nsresult rv = cc->GetJSContext(&cx);
-  if(NS_FAILED(rv) || !cx)
-    return NS_ERROR_FAILURE;
+  // Our argument must be a non-null object.
+  if (JSVAL_IS_PRIMITIVE(aObject)) {
+    return NS_ERROR_XPC_BAD_CONVERT_JS;
+  }
 
-  // get argc and argv and verify arg count
-  PRUint32 argc;
-  rv = cc->GetArgc(&argc);
-  if(NS_FAILED(rv))
-    return NS_ERROR_FAILURE;
-
-  if(argc < 1)
-    return NS_ERROR_XPC_NOT_ENOUGH_ARGS;
-
-  jsval* argv;
-  rv = cc->GetArgvPtr(&argv);
-  if(NS_FAILED(rv) || !argv)
-    return NS_ERROR_FAILURE;
-
-  // Our argument must be a non-null object.
-  if(JSVAL_IS_PRIMITIVE(argv[0]))
-    return NS_ERROR_XPC_BAD_CONVERT_JS;
-
-  *aName = NS_strdup(JS_GET_CLASS(cx, JSVAL_TO_OBJECT(argv[0]))->name);
-  return *aName ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+  *aName = NS_strdup(JS_GET_CLASS(aCx, JSVAL_TO_OBJECT(aObject))->name);
+  NS_ABORT_IF_FALSE(*aName, "NS_strdup should be infallible.");
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetVisitedDependentComputedStyle(
                     nsIDOMElement *aElement, const nsAString& aPseudoElement,
                     const nsAString& aPropertyName, nsAString& aResult)
 {
   aResult.Truncate();
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -274,30 +274,30 @@ AsyncConnectionHelper::Run()
     if (NS_SUCCEEDED(rv)) {
       setProgressHandler = true;
     }
   }
 
   if (NS_SUCCEEDED(rv)) {
     bool hasSavepoint = false;
     if (mDatabase) {
-      IndexedDatabaseManager::SetCurrentDatabase(mDatabase);
+      IndexedDatabaseManager::SetCurrentWindow(mDatabase->Owner());
 
       // Make the first savepoint.
       if (mTransaction) {
         if (!(hasSavepoint = mTransaction->StartSavepoint())) {
           NS_WARNING("Failed to make savepoint!");
         }
       }
     }
 
     mResultCode = DoDatabaseWork(connection);
 
     if (mDatabase) {
-      IndexedDatabaseManager::SetCurrentDatabase(nsnull);
+      IndexedDatabaseManager::SetCurrentWindow(nsnull);
 
       // Release or roll back the savepoint depending on the error code.
       if (hasSavepoint) {
         NS_ASSERTION(mTransaction, "Huh?!");
         if (NS_SUCCEEDED(mResultCode)) {
           mTransaction->ReleaseSavepoint();
         }
         else {
--- a/dom/indexedDB/CheckQuotaHelper.cpp
+++ b/dom/indexedDB/CheckQuotaHelper.cpp
@@ -93,21 +93,19 @@ GetQuotaPermissions(const nsACString& aA
                                          &permission);
   NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
 
   return permission;
 }
 
 } // anonymous namespace
 
-CheckQuotaHelper::CheckQuotaHelper(IDBDatabase* aDatabase,
+CheckQuotaHelper::CheckQuotaHelper(nsPIDOMWindow* aWindow,
                                    mozilla::Mutex& aMutex)
-: mWindow(aDatabase->Owner()),
-  mWindowSerial(mWindow->GetSerial()),
-  mOrigin(aDatabase->Origin()),
+: mWindow(aWindow),
   mMutex(aMutex),
   mCondVar(mMutex, "CheckQuotaHelper::mCondVar"),
   mPromptResult(0),
   mWaiting(true),
   mHasPrompted(false)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   mMutex.AssertCurrentThreadOwns();
@@ -170,61 +168,69 @@ NS_IMPL_THREADSAFE_ISUPPORTS3(CheckQuota
                                                 nsIInterfaceRequestor,
                                                 nsIObserver)
 
 NS_IMETHODIMP
 CheckQuotaHelper::Run()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (!mHasPrompted) {
-    mPromptResult = GetQuotaPermissions(mOrigin, mWindow);
+  nsresult rv = NS_OK;
+
+  if (mASCIIOrigin.IsEmpty()) {
+    rv = IndexedDatabaseManager::GetASCIIOriginFromWindow(mWindow,
+                                                          mASCIIOrigin);
   }
 
-  nsresult rv;
-  if (mHasPrompted) {
-    // Add permissions to the database, but only if we are in the parent
-    // process (if we are in the child process, we have already
-    // set the permission when the prompt was shown in the parent, as
-    // we cannot set the permission from the child).
-    if (mPromptResult != nsIPermissionManager::UNKNOWN_ACTION &&
-        XRE_GetProcessType() == GeckoProcessType_Default) {
-      nsCOMPtr<nsIURI> uri;
-      rv = NS_NewURI(getter_AddRefs(uri), mOrigin);
-      NS_ENSURE_SUCCESS(rv, rv);
-  
-      nsCOMPtr<nsIPermissionManager> permissionManager =
-        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
-      NS_ENSURE_STATE(permissionManager);
-  
-      rv = permissionManager->Add(uri, PERMISSION_INDEXEDDB_UNLIMITED,
-                                  mPromptResult,
-                                  nsIPermissionManager::EXPIRE_NEVER, 0);
-      NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_SUCCEEDED(rv)) {
+    if (!mHasPrompted) {
+      mPromptResult = GetQuotaPermissions(mASCIIOrigin, mWindow);
     }
-  }
-  else if (mPromptResult == nsIPermissionManager::UNKNOWN_ACTION) {
-    PRUint32 quota = IndexedDatabaseManager::GetIndexedDBQuotaMB();
-
-    nsString quotaString;
-    quotaString.AppendInt(quota);
-
-    nsCOMPtr<nsIObserverService> obs = GetObserverService();
-    NS_ENSURE_STATE(obs);
 
-    // We have to watch to make sure that the window doesn't go away without
-    // responding to us. Otherwise our database threads will hang.
-    rv = obs->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, false);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (mHasPrompted) {
+      // Add permissions to the database, but only if we are in the parent
+      // process (if we are in the child process, we have already
+      // set the permission when the prompt was shown in the parent, as
+      // we cannot set the permission from the child).
+      if (mPromptResult != nsIPermissionManager::UNKNOWN_ACTION &&
+          XRE_GetProcessType() == GeckoProcessType_Default) {
+        nsCOMPtr<nsIURI> uri;
+        rv = NS_NewURI(getter_AddRefs(uri), mASCIIOrigin);
+        NS_ENSURE_SUCCESS(rv, rv);
+    
+        nsCOMPtr<nsIPermissionManager> permissionManager =
+          do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+        NS_ENSURE_STATE(permissionManager);
+    
+        rv = permissionManager->Add(uri, PERMISSION_INDEXEDDB_UNLIMITED,
+                                    mPromptResult,
+                                    nsIPermissionManager::EXPIRE_NEVER, 0);
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+    }
+    else if (mPromptResult == nsIPermissionManager::UNKNOWN_ACTION) {
+      PRUint32 quota = IndexedDatabaseManager::GetIndexedDBQuotaMB();
 
-    rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
-                              TOPIC_QUOTA_PROMPT, quotaString.get());
-    NS_ENSURE_SUCCESS(rv, rv);
+      nsString quotaString;
+      quotaString.AppendInt(quota);
+
+      nsCOMPtr<nsIObserverService> obs = GetObserverService();
+      NS_ENSURE_STATE(obs);
 
-    return NS_OK;
+      // We have to watch to make sure that the window doesn't go away without
+      // responding to us. Otherwise our database threads will hang.
+      rv = obs->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, false);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
+                                TOPIC_QUOTA_PROMPT, quotaString.get());
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      return NS_OK;
+    }
   }
 
   MutexAutoLock lock(mMutex);
 
   NS_ASSERTION(mWaiting, "Huh?!");
 
     // This should never be used again.
   mWindow = nsnull;
--- a/dom/indexedDB/CheckQuotaHelper.h
+++ b/dom/indexedDB/CheckQuotaHelper.h
@@ -60,33 +60,27 @@ class CheckQuotaHelper : public nsIRunna
                          public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIOBSERVER
 
-  CheckQuotaHelper(IDBDatabase* aDatabase,
+  CheckQuotaHelper(nsPIDOMWindow* aWindow,
                    mozilla::Mutex& aMutex);
 
   bool PromptAndReturnQuotaIsDisabled();
 
   void Cancel();
 
-  PRUint32 WindowSerial()
-  {
-    return mWindowSerial;
-  }
-
 private:
   nsPIDOMWindow* mWindow;
-  PRUint32 mWindowSerial;
-  nsCString mOrigin;
 
+  nsCString mASCIIOrigin;
   mozilla::Mutex& mMutex;
   mozilla::CondVar mCondVar;
   PRUint32 mPromptResult;
   bool mWaiting;
   bool mHasPrompted;
 };
 
 END_INDEXEDDB_NAMESPACE
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -59,22 +59,16 @@
 #include "IndexedDatabaseManager.h"
 #include "LazyIdleThread.h"
 #include "TransactionThreadPool.h"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
-PRUint32 gDatabaseInstanceCount = 0;
-mozilla::Mutex* gPromptHelpersMutex = nsnull;
-
-// Protected by gPromptHelpersMutex.
-nsTArray<nsRefPtr<CheckQuotaHelper> >* gPromptHelpers = nsnull;
-
 class CreateObjectStoreHelper : public AsyncConnectionHelper
 {
 public:
   CreateObjectStoreHelper(IDBTransaction* aTransaction,
                           IDBObjectStore* aObjectStore)
   : AsyncConnectionHelper(aTransaction, nsnull), mObjectStore(aObjectStore)
   { }
 
@@ -190,21 +184,16 @@ IDBDatabase::Create(nsIScriptContext* aS
 IDBDatabase::IDBDatabase()
 : mDatabaseId(0),
   mInvalidated(0),
   mRegistered(false),
   mClosed(false),
   mRunningVersionChange(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  if (!gDatabaseInstanceCount++) {
-    NS_ASSERTION(!gPromptHelpersMutex, "Should be null!");
-    gPromptHelpersMutex = new mozilla::Mutex("IDBDatabase gPromptHelpersMutex");
-  }
 }
 
 IDBDatabase::~IDBDatabase()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (mRegistered) {
     CloseInternal(true);
@@ -213,96 +202,30 @@ IDBDatabase::~IDBDatabase()
     if (mgr) {
       mgr->UnregisterDatabase(this);
     }
   }
 
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
-
-  if (!--gDatabaseInstanceCount) {
-    NS_ASSERTION(gPromptHelpersMutex, "Should not be null!");
-
-    delete gPromptHelpers;
-    gPromptHelpers = nsnull;
-
-    delete gPromptHelpersMutex;
-    gPromptHelpersMutex = nsnull;
-  }
-}
-
-bool
-IDBDatabase::IsQuotaDisabled()
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(gPromptHelpersMutex, "This should never be null!");
-
-  MutexAutoLock lock(*gPromptHelpersMutex);
-
-  if (!gPromptHelpers) {
-    gPromptHelpers = new nsAutoTArray<nsRefPtr<CheckQuotaHelper>, 10>();
-  }
-
-  CheckQuotaHelper* foundHelper = nsnull;
-
-  PRUint32 count = gPromptHelpers->Length();
-  for (PRUint32 index = 0; index < count; index++) {
-    nsRefPtr<CheckQuotaHelper>& helper = gPromptHelpers->ElementAt(index);
-    if (helper->WindowSerial() == Owner()->GetSerial()) {
-      foundHelper = helper;
-      break;
-    }
-  }
-
-  if (!foundHelper) {
-    nsRefPtr<CheckQuotaHelper>* newHelper = gPromptHelpers->AppendElement();
-    if (!newHelper) {
-      NS_WARNING("Out of memory!");
-      return false;
-    }
-    *newHelper = new CheckQuotaHelper(this, *gPromptHelpersMutex);
-    foundHelper = *newHelper;
-
-    {
-      // Unlock before calling out to XPCOM.
-      MutexAutoUnlock unlock(*gPromptHelpersMutex);
-
-      nsresult rv = NS_DispatchToMainThread(foundHelper, NS_DISPATCH_NORMAL);
-      NS_ENSURE_SUCCESS(rv, false);
-    }
-  }
-
-  return foundHelper->PromptAndReturnQuotaIsDisabled();
 }
 
 void
 IDBDatabase::Invalidate()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(gPromptHelpersMutex, "This should never be null!");
 
   // Make sure we're closed too.
   Close();
 
-  // Cancel any quota prompts that are currently being displayed.
-  {
-    MutexAutoLock lock(*gPromptHelpersMutex);
-
-    if (gPromptHelpers) {
-      PRUint32 count = gPromptHelpers->Length();
-      for (PRUint32 index = 0; index < count; index++) {
-        nsRefPtr<CheckQuotaHelper>& helper = gPromptHelpers->ElementAt(index);
-        if (helper->WindowSerial() == Owner()->GetSerial()) {
-          helper->Cancel();
-          break;
-        }
-      }
-    }
-  }
+  // When the IndexedDatabaseManager needs to invalidate databases, all it has
+  // is an origin, so we call back into the manager to cancel any prompts for
+  // our owner.
+  IndexedDatabaseManager::CancelPromptsForWindow(Owner());
 
   mInvalidated = true;
 }
 
 bool
 IDBDatabase::IsInvalidated()
 {
   return !!mInvalidated;
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -117,18 +117,16 @@ public:
 
   already_AddRefed<nsIDocument> GetOwnerDocument()
   {
     NS_ASSERTION(mOwner, "This should never be null!");
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mOwner->GetExtantDocument());
     return doc.forget();
   }
 
-  bool IsQuotaDisabled();
-
   nsCString& Origin()
   {
     return mASCIIOrigin;
   }
 
   void Invalidate();
 
   // Whether or not the database has been invalidated. If it has then no further
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -398,34 +398,20 @@ IDBFactory::OpenCommon(const nsAString& 
   NS_ENSURE_TRUE(window, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
   NS_ENSURE_TRUE(sgo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsIScriptContext* context = sgo->GetContext();
   NS_ENSURE_TRUE(context, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  nsCOMPtr<nsIPrincipal> principal;
-  nsresult rv = nsContentUtils::GetSecurityManager()->
-    GetSubjectPrincipal(getter_AddRefs(principal));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
   nsCString origin;
-  if (nsContentUtils::IsSystemPrincipal(principal)) {
-    origin.AssignLiteral("chrome");
-  }
-  else {
-    rv = nsContentUtils::GetASCIIOrigin(principal, origin);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    if (origin.EqualsLiteral("null")) {
-      NS_WARNING("IndexedDB databases not allowed for this principal!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-  }
+  nsresult rv =
+    IndexedDatabaseManager::GetASCIIOriginFromWindow(window, origin);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<IDBOpenDBRequest> request =
     IDBOpenDBRequest::Create(context, window);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenDatabaseHelper> openHelper =
     new OpenDatabaseHelper(request, aName, origin, aVersion, aDeleting);
 
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -882,17 +882,17 @@ CommitHelper::Run()
   }
 
   IDBDatabase* database = mTransaction->Database();
   if (database->IsInvalidated()) {
     mAborted = true;
   }
 
   if (mConnection) {
-    IndexedDatabaseManager::SetCurrentDatabase(database);
+    IndexedDatabaseManager::SetCurrentWindow(database->Owner());
 
     if (!mAborted) {
       NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION");
       if (NS_FAILED(mConnection->ExecuteSimpleSQL(release))) {
         mAborted = true;
       }
     }
 
@@ -918,13 +918,13 @@ CommitHelper::Run()
   }
 
   mDoomedObjects.Clear();
 
   if (mConnection) {
     mConnection->Close();
     mConnection = nsnull;
 
-    IndexedDatabaseManager::SetCurrentDatabase(nsnull);
+    IndexedDatabaseManager::SetCurrentWindow(nsnull);
   }
 
   return NS_OK;
 }
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -36,29 +36,32 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IndexedDatabaseManager.h"
 
 #include "nsIFile.h"
 #include "nsIObserverService.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsIScriptSecurityManager.h"
 #include "nsISHEntry.h"
 #include "nsISimpleEnumerator.h"
 #include "nsITimer.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/storage.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 
 #include "AsyncConnectionHelper.h"
+#include "CheckQuotaHelper.h"
 #include "IDBDatabase.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "LazyIdleThread.h"
 #include "TransactionThreadPool.h"
 
 // The amount of time, in milliseconds, that our IO thread will stay alive
 // after the last event it processes.
@@ -70,52 +73,44 @@
 
 // Amount of space that IndexedDB databases may use by default in megabytes.
 #define DEFAULT_QUOTA_MB 50
 
 // Preference that users can set to override DEFAULT_QUOTA_MB
 #define PREF_INDEXEDDB_QUOTA "dom.indexedDB.warningQuota"
 
 // A bad TLS index number.
-#define BAD_TLS_INDEX (PRUintn)-1
+#define BAD_TLS_INDEX (PRUintn)-1 
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::services;
 using mozilla::Preferences;
 
 namespace {
 
 PRInt32 gShutdown = 0;
 
 // Does not hold a reference.
 IndexedDatabaseManager* gInstance = nsnull;
 
-PRUintn gCurrentDatabaseIndex = BAD_TLS_INDEX;
-
 PRInt32 gIndexedDBQuotaMB = DEFAULT_QUOTA_MB;
 
 class QuotaCallback : public mozIStorageQuotaCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD
   QuotaExceeded(const nsACString& aFilename,
                 PRInt64 aCurrentSizeLimit,
                 PRInt64 aCurrentTotalSize,
                 nsISupports* aUserData,
                 PRInt64* _retval)
   {
-    NS_ASSERTION(gCurrentDatabaseIndex != BAD_TLS_INDEX,
-                 "This should be impossible!");
-
-    IDBDatabase* database =
-      static_cast<IDBDatabase*>(PR_GetThreadPrivate(gCurrentDatabaseIndex));
-
-    if (database && database->IsQuotaDisabled()) {
+    if (IndexedDatabaseManager::QuotaIsLifted()) {
       *_retval = 0;
       return NS_OK;
     }
 
     return NS_ERROR_FAILURE;
   }
 };
 
@@ -141,16 +136,18 @@ EnumerateToTArray(const nsACString& aKey
   }
 
   return PL_DHASH_NEXT;
 }
 
 } // anonymous namespace
 
 IndexedDatabaseManager::IndexedDatabaseManager()
+: mCurrentWindowIndex(BAD_TLS_INDEX),
+  mQuotaHelperMutex("IndexedDatabaseManager.mQuotaHelperMutex")
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!gInstance, "More than one instance!");
 }
 
 IndexedDatabaseManager::~IndexedDatabaseManager()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -167,40 +164,41 @@ IndexedDatabaseManager::GetOrCreate()
   if (IsShuttingDown()) {
     NS_ERROR("Calling GetOrCreateInstance() after shutdown!");
     return nsnull;
   }
 
   nsRefPtr<IndexedDatabaseManager> instance(gInstance);
 
   if (!instance) {
-    // We need a thread-local to hold our current database.
-    if (gCurrentDatabaseIndex == BAD_TLS_INDEX) {
-      if (PR_NewThreadPrivateIndex(&gCurrentDatabaseIndex, nsnull) !=
-          PR_SUCCESS) {
-        NS_ERROR("PR_NewThreadPrivateIndex failed!");
-        gCurrentDatabaseIndex = BAD_TLS_INDEX;
-        return nsnull;
-      }
-
-      if (NS_FAILED(Preferences::AddIntVarCache(&gIndexedDBQuotaMB,
-                                                PREF_INDEXEDDB_QUOTA,
-                                                DEFAULT_QUOTA_MB))) {
-        NS_WARNING("Unable to respond to quota pref changes!");
-        gIndexedDBQuotaMB = DEFAULT_QUOTA_MB;
-      }
+    if (NS_FAILED(Preferences::AddIntVarCache(&gIndexedDBQuotaMB,
+                                              PREF_INDEXEDDB_QUOTA,
+                                              DEFAULT_QUOTA_MB))) {
+      NS_WARNING("Unable to respond to quota pref changes!");
+      gIndexedDBQuotaMB = DEFAULT_QUOTA_MB;
     }
 
     instance = new IndexedDatabaseManager();
 
-    if (!instance->mLiveDatabases.Init()) {
+    if (!instance->mLiveDatabases.Init() ||
+        !instance->mQuotaHelperHash.Init()) {
       NS_WARNING("Out of memory!");
       return nsnull;
     }
 
+    // We need a thread-local to hold the current window.
+    NS_ASSERTION(instance->mCurrentWindowIndex == BAD_TLS_INDEX, "Huh?");
+
+    if (PR_NewThreadPrivateIndex(&instance->mCurrentWindowIndex, nsnull) !=
+        PR_SUCCESS) {
+      NS_ERROR("PR_NewThreadPrivateIndex failed, IndexedDB disabled");
+      instance->mCurrentWindowIndex = BAD_TLS_INDEX;
+      return nsnull;
+    }
+
     // Make a timer here to avoid potential failures later. We don't actually
     // initialize the timer until shutdown.
     instance->mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     NS_ENSURE_TRUE(instance->mShutdownTimer, nsnull);
 
     nsCOMPtr<nsIObserverService> obs = GetObserverService();
     NS_ENSURE_TRUE(obs, nsnull);
 
@@ -543,40 +541,33 @@ IndexedDatabaseManager::OnDatabaseClosed
           }
         }
         break;
       }
     }
   }
 }
 
-// static
-bool
-IndexedDatabaseManager::SetCurrentDatabase(IDBDatabase* aDatabase)
+void
+IndexedDatabaseManager::SetCurrentWindowInternal(nsPIDOMWindow* aWindow)
 {
-  NS_ASSERTION(gCurrentDatabaseIndex != BAD_TLS_INDEX,
-               "This should have been set already!");
-
+  if (aWindow) {
 #ifdef DEBUG
-  if (aDatabase) {
-    NS_ASSERTION(!PR_GetThreadPrivate(gCurrentDatabaseIndex),
-                 "Someone forgot to unset gCurrentDatabaseIndex!");
+    NS_ASSERTION(!PR_GetThreadPrivate(mCurrentWindowIndex),
+                 "Somebody forgot to clear the current window!");
+#endif
+    PR_SetThreadPrivate(mCurrentWindowIndex, aWindow);
   }
   else {
-    NS_ASSERTION(PR_GetThreadPrivate(gCurrentDatabaseIndex),
-                 "Someone forgot to set gCurrentDatabaseIndex!");
-  }
+#ifdef DEBUG
+    NS_ASSERTION(PR_GetThreadPrivate(mCurrentWindowIndex),
+               "Somebody forgot to clear the current window!");
 #endif
-
-  if (PR_SetThreadPrivate(gCurrentDatabaseIndex, aDatabase) != PR_SUCCESS) {
-    NS_WARNING("Failed to set gCurrentDatabaseIndex!");
-    return false;
+    PR_SetThreadPrivate(mCurrentWindowIndex, nsnull);
   }
-
-  return true;
 }
 
 // static
 PRUint32
 IndexedDatabaseManager::GetIndexedDBQuotaMB()
 {
   return PRUint32(NS_MAX(gIndexedDBQuotaMB, 0));
 }
@@ -657,16 +648,112 @@ IndexedDatabaseManager::EnsureQuotaManag
   }
 
   NS_ASSERTION(!mTrackedQuotaPaths.Contains(path), "What?!");
 
   mTrackedQuotaPaths.AppendElement(path);
   return rv;
 }
 
+bool
+IndexedDatabaseManager::QuotaIsLiftedInternal()
+{
+  nsPIDOMWindow* window = nsnull;
+  nsRefPtr<CheckQuotaHelper> helper = nsnull;
+  bool createdHelper = false;
+
+  window =
+    static_cast<nsPIDOMWindow*>(PR_GetThreadPrivate(mCurrentWindowIndex));
+
+  // Once IDB is supported outside of Windows this should become an early
+  // return true.
+  NS_ASSERTION(window, "Why don't we have a Window here?");
+
+  // Hold the lock from here on.
+  MutexAutoLock autoLock(mQuotaHelperMutex);
+
+  mQuotaHelperHash.Get(window, getter_AddRefs(helper));
+
+  if (!helper) {
+    helper = new CheckQuotaHelper(window, mQuotaHelperMutex);
+    createdHelper = true;
+
+    bool result = mQuotaHelperHash.Put(window, helper);
+    NS_ENSURE_TRUE(result, result);
+
+    // Unlock while calling out to XPCOM
+    {
+      MutexAutoUnlock autoUnlock(mQuotaHelperMutex);
+
+      nsresult rv = NS_DispatchToMainThread(helper);
+      NS_ENSURE_SUCCESS(rv, false);
+    }
+
+    // Relocked.  If any other threads hit the quota limit on the same Window,
+    // they are using the helper we created here and are now blocking in
+    // PromptAndReturnQuotaDisabled.
+  }
+
+  bool result = helper->PromptAndReturnQuotaIsDisabled();
+
+  // If this thread created the helper and added it to the hash, this thread
+  // must remove it.
+  if (createdHelper) {
+    mQuotaHelperHash.Remove(window);
+  }
+
+  return result;
+}
+
+void
+IndexedDatabaseManager::CancelPromptsForWindowInternal(nsPIDOMWindow* aWindow)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  nsRefPtr<CheckQuotaHelper> helper;
+
+  MutexAutoLock autoLock(mQuotaHelperMutex);
+
+  mQuotaHelperHash.Get(aWindow, getter_AddRefs(helper));
+
+  if (helper) {
+    helper->Cancel();
+  }
+}
+
+// static
+nsresult
+IndexedDatabaseManager::GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow,
+                                                 nsCString& aASCIIOrigin)
+{
+  NS_ASSERTION(NS_IsMainThread(),
+               "We're about to touch a window off the main thread!");
+
+  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
+  NS_ENSURE_TRUE(sop, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
+  NS_ENSURE_TRUE(principal, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (nsContentUtils::IsSystemPrincipal(principal)) {
+    aASCIIOrigin.AssignLiteral("chrome");
+  }
+  else {
+    nsresult rv = nsContentUtils::GetASCIIOrigin(principal, aASCIIOrigin);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (aASCIIOrigin.EqualsLiteral("null")) {
+      NS_WARNING("IndexedDB databases not allowed for this principal!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+  }
+
+  return NS_OK;
+}
+
 // static
 nsresult
 IndexedDatabaseManager::DispatchHelper(AsyncConnectionHelper* aHelper)
 {
   nsresult rv = NS_OK;
 
   // If the helper has a transaction, dispatch it to the transaction
   // threadpool.
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -39,34 +39,39 @@
 
 #ifndef mozilla_dom_indexeddb_indexeddatabasemanager_h__
 #define mozilla_dom_indexeddb_indexeddatabasemanager_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 #include "mozilla/dom/indexedDB/IDBDatabase.h"
 #include "mozilla/dom/indexedDB/IDBRequest.h"
 
+#include "mozilla/Mutex.h"
+
 #include "nsIIndexedDatabaseManager.h"
 #include "nsIObserver.h"
 #include "nsIRunnable.h"
 #include "nsIThread.h"
 #include "nsIURI.h"
 
 #include "nsClassHashtable.h"
+#include "nsRefPtrHashtable.h"
 #include "nsHashKeys.h"
 
 #define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1"
 
 class mozIStorageQuotaCallback;
 class nsITimer;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 
+class CheckQuotaHelper;
+
 class IndexedDatabaseManager : public nsIIndexedDatabaseManager,
                                public nsIObserver
 {
   friend class IDBDatabase;
 
 public:
   static already_AddRefed<IndexedDatabaseManager> GetOrCreate();
 
@@ -124,34 +129,69 @@ public:
   // Called when a window is being purged from the bfcache or the user leaves
   // a page which isn't going into the bfcache. Forces any live database
   // objects to close themselves and aborts any running transactions.
   void AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow);
 
   // Used to check if there are running transactions in a given window.
   bool HasOpenTransactions(nsPIDOMWindow* aWindow);
 
-  static bool
-  SetCurrentDatabase(IDBDatabase* aDatabase);
+  // Set the Window that the current thread is doing operations for.
+  // The caller is responsible for ensuring that aWindow is held alive.
+  static inline void
+  SetCurrentWindow(nsPIDOMWindow* aWindow)
+  {
+    IndexedDatabaseManager* mgr = Get();
+    NS_ASSERTION(mgr, "Must have a manager here!");
+
+    return mgr->SetCurrentWindowInternal(aWindow);
+  }
 
   static PRUint32
   GetIndexedDBQuotaMB();
 
   nsresult EnsureQuotaManagementForDirectory(nsIFile* aDirectory);
 
+  // Determine if the quota is lifted for the Window the current thread is
+  // using.
+  static inline bool
+  QuotaIsLifted()
+  {
+    IndexedDatabaseManager* mgr = Get();
+    NS_ASSERTION(mgr, "Must have a manager here!");
+
+    return mgr->QuotaIsLiftedInternal();
+  }
+
+  static inline void
+  CancelPromptsForWindow(nsPIDOMWindow* aWindow)
+  {
+    IndexedDatabaseManager* mgr = Get();
+    NS_ASSERTION(mgr, "Must have a manager here!");
+
+    mgr->CancelPromptsForWindowInternal(aWindow);
+  }
+
+  static nsresult
+  GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow, nsCString& aASCIIOrigin);
+
 private:
   IndexedDatabaseManager();
   ~IndexedDatabaseManager();
 
   nsresult AcquireExclusiveAccess(const nsACString& aOrigin, 
                                   IDBDatabase* aDatabase,
                                   AsyncConnectionHelper* aHelper,
                                   WaitingOnDatabasesCallback aCallback,
                                   void* aClosure);
 
+  void SetCurrentWindowInternal(nsPIDOMWindow* aWindow);
+  bool QuotaIsLiftedInternal();
+  void CancelPromptsForWindowInternal(nsPIDOMWindow* aWindow);
+
   // Called when a database is created.
   bool RegisterDatabase(IDBDatabase* aDatabase);
 
   // Called when a database is being unlinked or destroyed.
   void UnregisterDatabase(IDBDatabase* aDatabase);
 
   // Called when a database has been closed.
   void OnDatabaseClosed(IDBDatabase* aDatabase);
@@ -262,16 +302,25 @@ private:
     SynchronizedOp* mOp;
   };
 
   static nsresult DispatchHelper(AsyncConnectionHelper* aHelper);
 
   // Maintains a list of live databases per origin.
   nsClassHashtable<nsCStringHashKey, nsTArray<IDBDatabase*> > mLiveDatabases;
 
+  // TLS storage index for the current thread's window
+  PRUintn mCurrentWindowIndex;
+
+  // Lock protecting mQuotaHelperHash
+  mozilla::Mutex mQuotaHelperMutex;
+
+  // A map of Windows to the corresponding quota helper.
+  nsRefPtrHashtable<nsPtrHashKey<nsPIDOMWindow>, CheckQuotaHelper> mQuotaHelperHash;
+
   // Maintains a list of origins that we're currently enumerating to gather
   // usage statistics.
   nsAutoTArray<nsRefPtr<AsyncUsageRunnable>, 1> mUsageRunnables;
 
   // Maintains a list of synchronized operatons that are in progress or queued.
   nsAutoTArray<nsAutoPtr<SynchronizedOp>, 5> mSynchronizedOps;
 
   // Thread on which IO is performed.
@@ -285,11 +334,26 @@ private:
   nsCOMPtr<mozIStorageQuotaCallback> mQuotaCallbackSingleton;
 
   // A list of all paths that are under SQLite's quota tracking system. This
   // list isn't protected by any mutex but it is only ever touched on the IO
   // thread.
   nsTArray<nsCString> mTrackedQuotaPaths;
 };
 
+class AutoEnterWindow
+{
+public:
+  AutoEnterWindow(nsPIDOMWindow* aWindow)
+  {
+    NS_ASSERTION(aWindow, "This should never be null!");
+    IndexedDatabaseManager::SetCurrentWindow(aWindow);
+  }
+
+  ~AutoEnterWindow()
+  {
+    IndexedDatabaseManager::SetCurrentWindow(nsnull);
+  }
+};
+
 END_INDEXEDDB_NAMESPACE
 
 #endif /* mozilla_dom_indexeddb_indexeddatabasemanager_h__ */
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -1085,16 +1085,24 @@ OpenDatabaseHelper::DoDatabaseWork()
 #endif
 
   mState = eFiringEvents; // In case we fail somewhere along the line.
 
   if (IndexedDatabaseManager::IsShuttingDown()) {
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
+  NS_ASSERTION(mOpenDBRequest, "This should never be null!");
+
+  // Once we support IDB outside of Windows this assertion will no longer hold.
+  nsPIDOMWindow* window = mOpenDBRequest->Owner();
+  NS_ASSERTION(window, "This should never be null");
+
+  AutoEnterWindow autoWindow(window);
+
   nsCOMPtr<nsIFile> dbFile;
   nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbFile->GetPath(mDatabaseFilePath);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIFile> dbDirectory;
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -124,16 +124,18 @@ BROWSER_TEST_FILES = \
   browserHelpers.js \
   browser_permissionsPrompt.html \
   browser_permissionsPromptAllow.js \
   browser_permissionsPromptDeny.js \
   browser_privateBrowsing.js \
   browser_quotaPrompt.html \
   browser_quotaPromptAllow.js \
   browser_quotaPromptDeny.js \
+  browser_quotaPromptDatabases.html \
+  browser_quotaPromptDatabases.js \
   head.js \
   $(NULL)
 
 libs:: $(BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 endif
 
 libs:: $(TEST_FILES)
--- a/dom/indexedDB/test/browser_quotaPromptAllow.js
+++ b/dom/indexedDB/test/browser_quotaPromptAllow.js
@@ -1,15 +1,15 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Make sure this is a unique origin or the tests will randomly fail!
-const testPageURL = "http://test1.example.org/browser/" +
+const testPageURL = "http://bug704464-1.example.com/browser/" +
   "dom/indexedDB/test/browser_quotaPrompt.html";
 const notificationID = "indexedDB-quota-prompt";
 
 function test()
 {
   waitForExplicitFinish();
   requestLongerTimeout(10);
   setPermission(testPageURL, "indexedDB");
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/browser_quotaPromptDatabases.html
@@ -0,0 +1,55 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+  <head>
+    <title>Indexed Database Test</title>
+
+    <script type="text/javascript;version=1.7">
+      const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
+
+      let db;
+      let i = 0;
+
+      function onAddMore() {
+        const name = window.location.pathname + i++;
+
+        let request = mozIndexedDB.open(name, 1);
+        request.onerror = errorHandler;
+        request.onsuccess = grabEventAndContinueHandler;
+
+        request.onsuccess = function(event) {
+          setTimeout(testFinishedCallback, 0, "complete");
+        }
+        request.onerror = function(event) {
+          setTimeout(testFinishedCallback, 0, "abort");
+        }
+      }
+
+      function onDone() {
+        window.removeEventListener("indexedDB-addMore", onAddMore, true);
+        window.removeEventListener("indexedDB-done", onDone, true);
+
+        testResult = "finished";
+        testException = undefined;
+        finishTest();
+      }
+
+      function testSteps()
+      {
+        window.addEventListener("indexedDB-addMore", onAddMore, true);
+        window.addEventListener("indexedDB-done", onDone, true);
+
+        setTimeout(testFinishedCallback, 0, "ready");
+        yield;
+      }
+    </script>
+
+    <script type="text/javascript;version=1.7" src="browserHelpers.js"></script>
+
+  </head>
+
+  <body onload="runTest();" onunload="finishTestNow();"></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/browser_quotaPromptDatabases.js
@@ -0,0 +1,76 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Make sure this is a unique origin or the tests will randomly fail!
+const testPageURL = "http://bug704464-3.example.com/browser/" +
+  "dom/indexedDB/test/browser_quotaPromptDatabases.html";
+const notificationID = "indexedDB-quota-prompt";
+
+function test()
+{
+  waitForExplicitFinish();
+  requestLongerTimeout(10);
+  setPermission(testPageURL, "indexedDB");
+  removePermission(testPageURL, "indexedDB-unlimited");
+  Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
+  executeSoon(test1);
+}
+
+let addMoreTest1Count = 0;
+
+function test1()
+{
+  gBrowser.selectedTab = gBrowser.addTab();
+
+  gBrowser.selectedBrowser.addEventListener("load", function () {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+    let seenPopupCount;
+
+    setFinishedCallback(function(result) {
+      is(result, "ready", "Got 'ready' result");
+
+      setFinishedCallback(function(result) {
+        is(result, "complete", "Got 'complete' result");
+
+        if (addMoreTest1Count >= seenPopupCount + 5) {
+          setFinishedCallback(function(result) {
+            is(result, "finished", "Got 'finished' result");
+            is(getPermission(testPageURL, "indexedDB-unlimited"),
+               Components.interfaces.nsIPermissionManager.ALLOW_ACTION,
+               "Correct permission set");
+            gBrowser.removeCurrentTab();
+            unregisterAllPopupEventHandlers();
+            addMoreTest1Count = seenPopupCount;
+            executeSoon(finish);
+          });
+          executeSoon(function() { dispatchEvent("indexedDB-done"); });
+        }
+        else {
+          ++addMoreTest1Count;
+          executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
+        }
+      });
+      ++addMoreTest1Count;
+      executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
+    });
+
+    registerPopupEventHandler("popupshowing", function () {
+      ok(true, "prompt showing");
+      seenPopupCount = addMoreTest1Count - 1;
+    });
+    registerPopupEventHandler("popupshown", function () {
+      ok(true, "prompt shown");
+      triggerMainCommand(this);
+    });
+    registerPopupEventHandler("popuphidden", function () {
+      ok(true, "prompt hidden");
+    });
+
+  }, true);
+
+  info("loading test page: " + testPageURL);
+  content.location = testPageURL;
+}
--- a/dom/indexedDB/test/browser_quotaPromptDeny.js
+++ b/dom/indexedDB/test/browser_quotaPromptDeny.js
@@ -1,15 +1,15 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Make sure this is a unique origin or the tests will randomly fail!
-const testPageURL = "http://test2.example.org/browser/" +
+const testPageURL = "http://bug704464-2.example.com/browser/" +
   "dom/indexedDB/test/browser_quotaPrompt.html";
 const notificationID = "indexedDB-quota-prompt";
 
 function test()
 {
   waitForExplicitFinish();
   requestLongerTimeout(10);
   setPermission(testPageURL, "indexedDB");
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -63,17 +63,17 @@ interface nsIDOMElement;
 interface nsIDOMHTMLCanvasElement;
 interface nsIDOMEvent;
 interface nsITransferable;
 interface nsIQueryContentEventResult;
 interface nsIDOMWindow;
 interface nsIDOMFile;
 interface nsIFile;
 
-[scriptable, uuid(c5cf91b3-0b89-4417-b13c-5540ba6ebde8)]
+[scriptable, uuid(bf868921-0288-4799-a806-2fa642590197)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -552,17 +552,17 @@ interface nsIDOMWindowUtils : nsISupport
   boolean dispatchDOMEventViaPresShell(in nsIDOMNode aTarget,
                                        in nsIDOMEvent aEvent,
                                        in boolean aTrusted);
 
   /**
    * Returns the real classname (possibly of the mostly-transparent security
    * wrapper) of aObj.
    */
-  string getClassName(/*in JSObjectPtr aObj*/);
+  [implicit_jscontext] string getClassName(in jsval aObject);
 
   /**
    * Generate a content command event.
    *
    * Cannot be accessed from unprivileged context (not content-accessible)
    * Will throw a DOM security error if called without UniversalXPConnect
    * privileges.
    *
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "base/basictypes.h"
 
 // FIXME(bug 332648): Give me a real API please!
 #include "jscntxt.h"
+#include "jsfriendapi.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsJSNPRuntime.h"
 #include "nsNPAPIPlugin.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsDOMJSUtils.h"
@@ -1478,17 +1479,17 @@ CallNPMethodInternal(JSContext *cx, JSOb
 
       msg = "Attempt to construct object from class with no constructor.";
     }
   } else if (funobj != obj) {
     // A obj.function() style call is made, get the method name from
     // the function object.
 
     if (npobj->_class->invoke) {
-      JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj);
+      JSFunction *fun = ::JS_GetObjectFunction(funobj);
       JSString *name = ::JS_InternJSString(cx, ::JS_GetFunctionId(fun));
       NPIdentifier id = StringToNPIdentifier(cx, name);
 
       ok = npobj->_class->invoke(npobj, id, npargs, argc, &v);
     } else {
       ok = JS_FALSE;
 
       msg = "Attempt to call a method on object with no invoke method.";
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -86,32 +86,31 @@ public:
   {
     return &sClass;
   }
 
   static JSObject*
   InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
             bool aMainRuntime)
   {
-    JSObject* proto = JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct,
-                                   0, sProperties, sFunctions, NULL, NULL);
+    JSObject* proto = js::InitClassWithReserved(aCx, aObj, aParentProto, &sClass, Construct,
+                                                0, sProperties, sFunctions, NULL, NULL);
     if (!proto) {
       return NULL;
     }
 
     if (!aMainRuntime) {
       WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
       parent->AssertIsOnWorkerThread();
 
       JSObject* constructor = JS_GetConstructor(aCx, proto);
-      if (!constructor ||
-          !JS_SetReservedSlot(aCx, constructor, CONSTRUCTOR_SLOT_PARENT,
-                              PRIVATE_TO_JSVAL(parent))) {
+      if (!constructor)
         return NULL;
-      }
+      js::SetFunctionNativeReserved(constructor, CONSTRUCTOR_SLOT_PARENT,
+                                    PRIVATE_TO_JSVAL(parent));
     }
 
     return proto;
   }
 
   static void
   ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
   {
@@ -148,21 +147,18 @@ protected:
       return false;
     }
 
     JSString* scriptURL = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
     if (!scriptURL) {
       return false;
     }
 
-    jsval priv;
-    if (!JS_GetReservedSlot(aCx, JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp)),
-                            CONSTRUCTOR_SLOT_PARENT, &priv)) {
-      return false;
-    }
+    jsval priv = js::GetFunctionNativeReserved(JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp)),
+                                               CONSTRUCTOR_SLOT_PARENT);
 
     RuntimeService* runtimeService;
     WorkerPrivate* parent;
 
     if (JSVAL_IS_VOID(priv)) {
       runtimeService = RuntimeService::GetOrCreateService();
       if (!runtimeService) {
         JS_ReportError(aCx, "Failed to create runtime service!");
@@ -340,32 +336,31 @@ public:
   {
     return &sClass;
   }
 
   static JSObject*
   InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
             bool aMainRuntime)
   {
-    JSObject* proto = JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct,
-                                   0, NULL, NULL, NULL, NULL);
+    JSObject* proto = js::InitClassWithReserved(aCx, aObj, aParentProto, &sClass, Construct,
+                                                0, NULL, NULL, NULL, NULL);
     if (!proto) {
       return NULL;
     }
 
     if (!aMainRuntime) {
       WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
       parent->AssertIsOnWorkerThread();
 
       JSObject* constructor = JS_GetConstructor(aCx, proto);
-      if (!constructor ||
-          !JS_SetReservedSlot(aCx, constructor, CONSTRUCTOR_SLOT_PARENT,
-                              PRIVATE_TO_JSVAL(parent))) {
+      if (!constructor)
         return NULL;
-      }
+      js::SetFunctionNativeReserved(constructor, CONSTRUCTOR_SLOT_PARENT,
+                                    PRIVATE_TO_JSVAL(parent));
     }
 
     return proto;
   }
 
   static void
   ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
   {
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -266,21 +266,18 @@ private:
   {
     JS_ASSERT(JSVAL_IS_OBJECT(JS_CALLEE(aCx, aVp)));
     JS_ASSERT(aArgc == 1);
     JS_ASSERT(JSVAL_IS_OBJECT(JS_ARGV(aCx, aVp)[0]));
 
     JSObject* wrapper = JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp));
     JS_ASSERT(JS_ObjectIsFunction(aCx, wrapper));
 
-    jsval scope, listener;
-    if (!JS_GetReservedSlot(aCx, wrapper, SLOT_wrappedScope, &scope) ||
-        !JS_GetReservedSlot(aCx, wrapper, SLOT_wrappedFunction, &listener)) {
-      return false;
-    }
+    jsval scope = js::GetFunctionNativeReserved(wrapper, SLOT_wrappedScope);
+    jsval listener = js::GetFunctionNativeReserved(wrapper, SLOT_wrappedFunction);
 
     JS_ASSERT(JSVAL_IS_OBJECT(scope));
 
     JSObject* event = JSVAL_TO_OBJECT(JS_ARGV(aCx, aVp)[0]);
 
     jsval argv[3] = { JSVAL_VOID, JSVAL_VOID, JSVAL_VOID };
     if (!JS_GetProperty(aCx, event, "message", &argv[0]) ||
         !JS_GetProperty(aCx, event, "filename", &argv[1]) ||
@@ -314,52 +311,47 @@ private:
 
     jsval adaptor;
     if (!scope->GetEventListenerOnEventTarget(aCx, name + 2, &adaptor)) {
       return false;
     }
 
     JS_ASSERT(JSVAL_IS_OBJECT(adaptor));
 
-    jsval listener;
-    if (!JS_GetReservedSlot(aCx, JSVAL_TO_OBJECT(adaptor), SLOT_wrappedFunction,
-                            &listener)) {
-      return false;
-    }
+    jsval listener = js::GetFunctionNativeReserved(JSVAL_TO_OBJECT(adaptor),
+                                                   SLOT_wrappedFunction);
 
     *aVp = listener;
     return true;
   }
 
   static JSBool
   SetOnErrorListener(JSContext* aCx, JSObject* aObj, jsid aIdval,
                      JSBool aStrict, jsval* aVp)
   {
     const char* name = sEventStrings[STRING_onerror];
     WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
     if (!scope) {
       return false;
     }
 
-    JSFunction* adaptor = JS_NewFunction(aCx, UnwrapErrorEvent, 1, 0,
-                                         JS_GetGlobalObject(aCx), "unwrap");
+    JSFunction* adaptor = js::NewFunctionWithReserved(aCx, UnwrapErrorEvent, 1, 0,
+                                                      JS_GetGlobalObject(aCx), "unwrap");
     if (!adaptor) {
       return false;
     }
 
     JSObject* listener = JS_GetFunctionObject(adaptor);
     if (!listener) {
       return false;
     }
 
-    if (!JS_SetReservedSlot(aCx, listener, SLOT_wrappedScope,
-                            OBJECT_TO_JSVAL(aObj)) ||
-        !JS_SetReservedSlot(aCx, listener, SLOT_wrappedFunction, *aVp)) {
-      return false;
-    }
+    js::SetFunctionNativeReserved(listener, SLOT_wrappedScope,
+                                  OBJECT_TO_JSVAL(aObj));
+    js::SetFunctionNativeReserved(listener, SLOT_wrappedFunction, *aVp);
 
     jsval val = OBJECT_TO_JSVAL(listener);
     return scope->SetEventListenerOnEventTarget(aCx, name + 2, &val);
   }
 
   static JSBool
   GetNavigator(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
   {
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -1017,17 +1017,17 @@ nsEditor::SetShouldTxnSetSelection(bool 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditor::GetDocumentIsEmpty(bool *aDocumentIsEmpty)
 {
   *aDocumentIsEmpty = true;
 
-  nsIDOMElement *rootElement = GetRoot(); 
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER); 
 
   bool hasChildNodes;
   nsresult res = rootElement->HasChildNodes(&hasChildNodes);
 
   *aDocumentIsEmpty = !hasChildNodes;
 
   return res;
@@ -1058,17 +1058,17 @@ NS_IMETHODIMP nsEditor::BeginningOfDocum
 
   // get the selection
   nsCOMPtr<nsISelection> selection;
   nsresult result = GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(result, result);
   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
     
   // get the root element 
-  nsIDOMElement *rootElement = GetRoot(); 
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER); 
   
   // find first editable thingy
   nsCOMPtr<nsIDOMNode> firstNode;
   result = GetFirstEditableNode(rootElement, address_of(firstNode));
   if (firstNode)
   {
     // if firstNode is text, set selection to beginning of the text node
@@ -1104,22 +1104,19 @@ nsEditor::EndOfDocument()
 
   // get selection 
   nsCOMPtr<nsISelection> selection; 
   res = GetSelection(getter_AddRefs(selection)); 
   NS_ENSURE_SUCCESS(res, res); 
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); 
   
   // get the root element 
-  nsIDOMElement *rootElement = GetRoot(); 
-  NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER); 
-
-  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(rootElement);
+  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(GetRoot());
+  NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); 
   nsCOMPtr<nsIDOMNode> child;
-  NS_ASSERTION(node, "Invalid root element");
 
   do {
     node->GetLastChild(getter_AddRefs(child));
 
     if (child) {
       if (IsContainer(child)) {
         node = child;
       } else {
@@ -1973,28 +1970,24 @@ nsEditor::GetPhonetic(nsAString& aPhonet
   else
     aPhonetic.Truncate(0);
 
   return NS_OK;
 }
 
 
 static nsresult
-GetEditorContentWindow(nsIDOMElement *aRoot, nsIWidget **aResult)
+GetEditorContentWindow(dom::Element *aRoot, nsIWidget **aResult)
 {
   NS_ENSURE_TRUE(aRoot && aResult, NS_ERROR_NULL_POINTER);
 
   *aResult = 0;
 
-  nsCOMPtr<nsIContent> content = do_QueryInterface(aRoot);
-
-  NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
-
   // Not ref counted
-  nsIFrame *frame = content->GetPrimaryFrame();
+  nsIFrame *frame = aRoot->GetPrimaryFrame();
 
   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
   *aResult = frame->GetNearestWidget();
   NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE);
 
   NS_ADDREF(*aResult);
   return NS_OK;
@@ -2098,18 +2091,18 @@ nsEditor::GetComposing(bool* aResult)
 
 /* Non-interface, public methods */
 
 NS_IMETHODIMP
 nsEditor::GetRootElement(nsIDOMElement **aRootElement)
 {
   NS_ENSURE_ARG_POINTER(aRootElement);
   NS_ENSURE_TRUE(mRootElement, NS_ERROR_NOT_AVAILABLE);
-  *aRootElement = mRootElement;
-  NS_ADDREF(*aRootElement);
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(mRootElement);
+  rootElement.forget(aRootElement);
   return NS_OK;
 }
 
 
 /** All editor operations which alter the doc should be prefaced
  *  with a call to StartOperation, naming the action and direction */
 NS_IMETHODIMP
 nsEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
@@ -2170,22 +2163,20 @@ nsEditor::CloneAttributes(nsIDOMNode *aD
   nsCOMPtr<nsIDOMNamedNodeMap> destAttributes;
   destElement->GetAttributes(getter_AddRefs(destAttributes));
   NS_ENSURE_TRUE(sourceAttributes && destAttributes, NS_ERROR_FAILURE);
 
   nsAutoEditBatch beginBatching(this);
 
   // Use transaction system for undo only if destination
   //   is already in the document
-  nsIDOMElement *rootElement = GetRoot();
-  NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
-
+  nsCOMPtr<nsIDOMNode> p = aDestNode;
+  nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(GetRoot());
+  NS_ENSURE_TRUE(rootNode, NS_ERROR_NULL_POINTER);
   bool destInBody = true;
-  nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootElement);
-  nsCOMPtr<nsIDOMNode> p = aDestNode;
   while (p && p != rootNode)
   {
     nsCOMPtr<nsIDOMNode> tmp;
     if (NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp)
     {
       destInBody = false;
       break;
     }
@@ -2287,34 +2278,35 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(c
   // class to turn off txn selection updating.  Caller also turned on rules sniffing
   // if desired.
   
   nsresult res;
   NS_ENSURE_TRUE(aInOutNode && *aInOutNode && aInOutOffset && aDoc, NS_ERROR_NULL_POINTER);
   if (!mInIMEMode && aStringToInsert.IsEmpty()) return NS_OK;
   nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(*aInOutNode);
   if (!nodeAsText && IsPlaintextEditor()) {
+    nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(GetRoot());
     // In some cases, aInOutNode is the anonymous DIV, and aInOutOffset is 0.
     // To avoid injecting unneeded text nodes, we first look to see if we have
     // one available.  In that case, we'll just adjust aInOutNode and aInOutOffset
     // accordingly.
-    if (*aInOutNode == GetRoot() && *aInOutOffset == 0) {
+    if (*aInOutNode == rootNode && *aInOutOffset == 0) {
       nsCOMPtr<nsIDOMNode> possibleTextNode;
       res = (*aInOutNode)->GetFirstChild(getter_AddRefs(possibleTextNode));
       if (NS_SUCCEEDED(res)) {
         nodeAsText = do_QueryInterface(possibleTextNode);
         if (nodeAsText) {
           *aInOutNode = possibleTextNode;
         }
       }
     }
     // In some other cases, aInOutNode is the anonymous DIV, and aInOutOffset points
     // to the terminating mozBR.  In that case, we'll adjust aInOutNode and aInOutOffset
     // to the preceding text node, if any.
-    if (!nodeAsText && *aInOutNode == GetRoot() && *aInOutOffset > 0) {
+    if (!nodeAsText && *aInOutNode == rootNode && *aInOutOffset > 0) {
       nsCOMPtr<nsIDOMNodeList> children;
       res = (*aInOutNode)->GetChildNodes(getter_AddRefs(children));
       if (NS_SUCCEEDED(res)) {
         nsCOMPtr<nsIDOMNode> possibleMozBRNode;
         children->Item(*aInOutOffset, getter_AddRefs(possibleMozBRNode));
         if (possibleMozBRNode && nsTextEditUtils::IsMozBR(possibleMozBRNode)) {
           nsCOMPtr<nsIDOMNode> possibleTextNode;
           res = children->Item(*aInOutOffset - 1, getter_AddRefs(possibleTextNode));
@@ -2358,17 +2350,17 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(c
         res = nodeAsText->GetLength(&length);
         if (NS_SUCCEEDED(res)) {
           *aInOutOffset = PRInt32(length);
           *aInOutNode = previous;
         }
       } else {
         nsCOMPtr<nsIDOMNode> parent;
         (*aInOutNode)->GetParentNode(getter_AddRefs(parent));
-        if (parent == GetRoot()) {
+        if (parent == rootNode) {
           *aInOutNode = parent;
         }
       }
     }
   }
   PRInt32 offset = *aInOutOffset;
   if (mInIMEMode)
   {
@@ -2525,17 +2517,17 @@ nsresult nsEditor::InsertTextIntoTextNod
   return result;
 }
 
 
 NS_IMETHODIMP nsEditor::SelectEntireDocument(nsISelection *aSelection)
 {
   if (!aSelection) { return NS_ERROR_NULL_POINTER; }
 
-  nsIDOMElement *rootElement = GetRoot();
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
   if (!rootElement) { return NS_ERROR_NOT_INITIALIZED; }
 
   return aSelection->SelectAllChildren(rootElement);
 }
 
 
 nsresult nsEditor::GetFirstEditableNode(nsIDOMNode *aRoot, nsCOMPtr<nsIDOMNode> *outFirstNode)
 {
@@ -3541,43 +3533,43 @@ nsEditor::TagCanContainTag(const nsAStri
   return true;
 }
 
 bool
 nsEditor::IsRootNode(nsIDOMNode *inNode)
 {
   NS_ENSURE_TRUE(inNode, false);
 
-  return inNode == GetRoot();
+  nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(GetRoot());
+
+  return inNode == rootNode;
 }
 
 bool 
 nsEditor::IsRootNode(nsINode *inNode) 
 {
   NS_ENSURE_TRUE(inNode, false);
 
-  nsIDOMElement *rootElement = GetRoot();
-
-  nsCOMPtr<nsIDOMNode> node = do_QueryInterface(inNode);
-
-  return node == rootElement;
+  nsCOMPtr<nsINode> rootNode = GetRoot();
+
+  return inNode == rootNode;
 }
 
 bool 
 nsEditor::IsDescendantOfBody(nsIDOMNode *inNode) 
 {
   nsCOMPtr<nsINode> node = do_QueryInterface(inNode);
   return IsDescendantOfBody(node);
 }
 
 bool
 nsEditor::IsDescendantOfBody(nsINode *inNode)
 {
   NS_ENSURE_TRUE(inNode, false);
-  nsCOMPtr<nsIContent> root = do_QueryInterface(GetRoot());
+  nsCOMPtr<nsIContent> root = GetRoot();
   NS_ENSURE_TRUE(root, false);
 
   return nsContentUtils::ContentIsDescendantOf(inNode, root);
 }
 
 bool 
 nsEditor::IsContainer(nsIDOMNode *aNode)
 {
@@ -5144,17 +5136,17 @@ nsEditor::HandleInlineSpellCheck(PRInt32
                                                        aStartOffset,
                                                        aEndNode,
                                                        aEndOffset) : NS_OK;
 }
 
 already_AddRefed<nsIContent>
 nsEditor::FindSelectionRoot(nsINode *aNode)
 {
-  nsCOMPtr<nsIContent> rootContent = do_QueryInterface(GetRoot());
+  nsCOMPtr<nsIContent> rootContent = GetRoot();
   return rootContent.forget();
 }
 
 nsresult
 nsEditor::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
 {
   nsCOMPtr<nsINode> targetNode = do_QueryInterface(aFocusEventTarget);
   NS_ENSURE_TRUE(targetNode, NS_ERROR_INVALID_ARG);
@@ -5213,17 +5205,17 @@ nsEditor::InitializeSelection(nsIDOMEven
     if (rangeCount == 0) {
       BeginningOfDocument();
     }
   }
 
   return NS_OK;
 }
 
-nsIDOMElement *
+dom::Element *
 nsEditor::GetRoot()
 {
   if (!mRootElement)
   {
     nsCOMPtr<nsIDOMElement> root;
 
     // Let GetRootElement() do the work
     GetRootElement(getter_AddRefs(root));
@@ -5231,28 +5223,24 @@ nsEditor::GetRoot()
 
   return mRootElement;
 }
 
 nsresult
 nsEditor::DetermineCurrentDirection()
 {
   // Get the current root direction from its frame
-  nsIDOMElement *rootElement = GetRoot();
-
-  nsresult rv;
+  dom::Element *rootElement = GetRoot();
 
   // If we don't have an explicit direction, determine our direction
   // from the content's direction
   if (!(mFlags & (nsIPlaintextEditor::eEditorLeftToRight |
                   nsIPlaintextEditor::eEditorRightToLeft))) {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(rootElement, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsIFrame* frame = content->GetPrimaryFrame();
+
+    nsIFrame* frame = rootElement->GetPrimaryFrame();
     NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
     // Set the flag here, to enable us to use the same code path below.
     // It will be flipped before returning from the function.
     if (frame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
       mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
     } else {
       mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
@@ -5261,63 +5249,61 @@ nsEditor::DetermineCurrentDirection()
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditor::SwitchTextDirection()
 {
   // Get the current root direction from its frame
-  nsIDOMElement *rootElement = GetRoot();
-
+  dom::Element *rootElement = GetRoot();
   nsresult rv = DetermineCurrentDirection();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Apply the opposite direction
   if (mFlags & nsIPlaintextEditor::eEditorRightToLeft) {
     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
                  "Unexpected mutually exclusive flag");
     mFlags &= ~nsIPlaintextEditor::eEditorRightToLeft;
     mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
-    rv = rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("ltr"));
+    rv = rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), true);
   } else if (mFlags & nsIPlaintextEditor::eEditorLeftToRight) {
     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorRightToLeft),
                  "Unexpected mutually exclusive flag");
     mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
     mFlags &= ~nsIPlaintextEditor::eEditorLeftToRight;
-    rv = rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("rtl"));
+    rv = rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("rtl"), true);
   }
 
   return rv;
 }
 
 void
 nsEditor::SwitchTextDirectionTo(PRUint32 aDirection)
 {
   // Get the current root direction from its frame
-  nsIDOMElement *rootElement = GetRoot();
-
+  dom::Element *rootElement = GetRoot();
   nsresult rv = DetermineCurrentDirection();
   NS_ENSURE_SUCCESS(rv, );
 
   // Apply the requested direction
   if (aDirection == nsIPlaintextEditor::eEditorLeftToRight &&
       (mFlags & nsIPlaintextEditor::eEditorRightToLeft)) {
     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorLeftToRight),
                  "Unexpected mutually exclusive flag");
     mFlags &= ~nsIPlaintextEditor::eEditorRightToLeft;
     mFlags |= nsIPlaintextEditor::eEditorLeftToRight;
-    rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("ltr"));
+    rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("ltr"), true);
   } else if (aDirection == nsIPlaintextEditor::eEditorRightToLeft &&
              (mFlags & nsIPlaintextEditor::eEditorLeftToRight)) {
     NS_ASSERTION(!(mFlags & nsIPlaintextEditor::eEditorRightToLeft),
                  "Unexpected mutually exclusive flag");
     mFlags |= nsIPlaintextEditor::eEditorRightToLeft;
     mFlags &= ~nsIPlaintextEditor::eEditorLeftToRight;
-    rootElement->SetAttribute(NS_LITERAL_STRING("dir"), NS_LITERAL_STRING("rtl"));
+    rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, NS_LITERAL_STRING("rtl"), true);
   }
 }
 
 #if DEBUG_JOE
 void
 nsEditor::DumpNode(nsIDOMNode *aNode, PRInt32 indent)
 {
   PRInt32 i;
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -646,17 +646,17 @@ public:
                                     nsIDOMNode *aStartNode,
                                     PRInt32 aStartOffset,
                                     nsIDOMNode *aEndNode,
                                     PRInt32 aEndOffset);
 
   virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget() = 0;
 
   // Fast non-refcounting editor root element accessor
-  nsIDOMElement *GetRoot();
+  mozilla::dom::Element *GetRoot();
 
   // Accessor methods to flags
   bool IsPlaintextEditor() const
   {
     return (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0;
   }
 
   bool IsSingleLineEditor() const
@@ -758,18 +758,18 @@ public:
 
   // This method has to be called by nsEditorEventListener::Focus.
   // All actions that have to be done when the editor is focused needs to be
   // added here.
   void OnFocus(nsIDOMEventTarget* aFocusEventTarget);
 
 protected:
 
-  PRUint32        mModCount;		// number of modifications (for undo/redo stack)
-  PRUint32        mFlags;		// behavior flags. See nsIPlaintextEditor.idl for the flags we use.
+  PRUint32        mModCount;     // number of modifications (for undo/redo stack)
+  PRUint32        mFlags;        // behavior flags. See nsIPlaintextEditor.idl for the flags we use.
 
   nsWeakPtr       mSelConWeak;   // weak reference to the nsISelectionController
   PRInt32         mUpdateCount;
   nsIViewManager::UpdateViewBatch mBatch;
 
   // Spellchecking
   enum Tristate {
     eTriUnset,
@@ -780,17 +780,17 @@ protected:
 
   nsCOMPtr<nsITransactionManager> mTxnMgr;
   nsWeakPtr         mPlaceHolderTxn;     // weak reference to placeholder for begin/end batch purposes
   nsIAtom          *mPlaceHolderName;    // name of placeholder transaction
   PRInt32           mPlaceHolderBatch;   // nesting count for batching
   nsSelectionState *mSelState;           // saved selection state for placeholder txn batching
   nsSelectionState  mSavedSel;           // cached selection for nsAutoSelectionReset
   nsRangeUpdater    mRangeUpdater;       // utility class object for maintaining preserved ranges
-  nsCOMPtr<nsIDOMElement> mRootElement;    // cached root node
+  nsCOMPtr<mozilla::dom::Element> mRootElement;   // cached root node
   PRInt32           mAction;             // the current editor action
   EDirection        mDirection;          // the current direction of editor action
   
   // data necessary to build IME transactions
   nsCOMPtr<nsIPrivateTextRangeList> mIMETextRangeList; // IME special selection ranges
   nsCOMPtr<nsIDOMCharacterData>     mIMETextNode;      // current IME text node
   PRUint32                          mIMETextOffset;    // offset in text node where IME comp string begins
   PRUint32                          mIMEBufferLength;  // current length of IME comp string
--- a/editor/libeditor/html/nsHTMLCSSUtils.cpp
+++ b/editor/libeditor/html/nsHTMLCSSUtils.cpp
@@ -1396,22 +1396,8 @@ nsresult
 nsHTMLCSSUtils::SetCSSPropertyPixels(nsIDOMElement * aElement,
                                      const nsAString & aProperty,
                                      PRInt32 aIntValue)
 {
   nsAutoString s;
   s.AppendInt(aIntValue);
   return SetCSSProperty(aElement, aProperty, s + NS_LITERAL_STRING("px"));
 }
-
-nsresult
-nsHTMLCSSUtils::RemoveCSSProperty(nsIDOMElement * aElement,
-                                  const nsAString & aProperty)
-{
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
-  PRUint32 length;
-  nsresult res = GetInlineStyles(aElement, getter_AddRefs(cssDecl), &length);
-  if (NS_FAILED(res) || !cssDecl) return res;
-
-  nsAutoString returnString;
-  return cssDecl->RemoveProperty(aProperty, returnString);
-}
-
--- a/editor/libeditor/html/nsHTMLCSSUtils.h
+++ b/editor/libeditor/html/nsHTMLCSSUtils.h
@@ -134,18 +134,16 @@ public:
     * @param aValue         [IN] a string containing the new value of the CSS property
     */
   nsresult    SetCSSProperty(nsIDOMElement * aElement,
                              const nsAString & aProperty,
                              const nsAString & aValue);
   nsresult    SetCSSPropertyPixels(nsIDOMElement * aElement,
                                    const nsAString & aProperty,
                                    PRInt32 aIntValue);
-  nsresult    RemoveCSSProperty(nsIDOMElement * aElement,
-                                const nsAString & aProperty);
 
   /** gets the specified/computed style value of a CSS property for a given node (or its element
     * ancestor if it is not an element)
     *
     * @param aNode          [IN] a DOM node
     * @param aProperty      [IN] an atom containing the CSS property to get
     * @param aPropertyValue [OUT] the retrieved value of the property
     */
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -76,16 +76,17 @@
 #include "nsUnicharUtils.h"
 
 #include "nsFrameSelection.h"
 #include "nsContentUtils.h"
 #include "nsTArray.h"
 #include "nsIHTMLDocument.h"
 
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 
 //const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
 //const static char* kMOZEditorBogusNodeValue="TRUE";
 
 enum
 {
@@ -251,17 +252,17 @@ nsHTMLEditRules::Init(nsPlaintextEditor 
   // XXX Why was this pref designed as a string and not bool?
   mReturnInEmptyLIKillsList = !returnInEmptyLIKillsList.EqualsLiteral("false");
 
   // make a utility range for use by the listenter
   mUtilRange = do_CreateInstance("@mozilla.org/content/range;1");
   NS_ENSURE_TRUE(mUtilRange, NS_ERROR_NULL_POINTER);
    
   // set up mDocChangeRange to be whole doc
-  nsIDOMElement *rootElem = mHTMLEditor->GetRoot();
+  nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot());
   if (rootElem)
   {
     // temporarily turn off rules sniffing
     nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this);
     if (!mDocChangeRange)
     {
       mDocChangeRange = do_CreateInstance("@mozilla.org/content/range;1");
       NS_ENSURE_TRUE(mDocChangeRange, NS_ERROR_NULL_POINTER);
@@ -800,17 +801,17 @@ nsHTMLEditRules::GetAlignment(bool *aMix
 
   // get selection
   nsCOMPtr<nsISelection>selection;
   nsresult res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(res, res);
 
   // get selection location
   nsCOMPtr<nsIDOMNode> parent;
-  nsIDOMElement *rootElem = mHTMLEditor->GetRoot();
+  nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot());
   NS_ENSURE_TRUE(rootElem, NS_ERROR_FAILURE);
 
   PRInt32 offset, rootOffset;
   res = nsEditor::GetNodeLocation(rootElem, address_of(parent), &rootOffset);
   NS_ENSURE_SUCCESS(res, res);
   res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(parent), &offset);
   NS_ENSURE_SUCCESS(res, res);
 
@@ -1007,23 +1008,20 @@ nsHTMLEditRules::GetIndentState(bool *aC
   
   if (!*aCanOutdent)
   {
     // if we haven't found something to outdent yet, also check the parents
     // of selection endpoints.  We might have a blockquote or list item 
     // in the parent hierarchy.
     
     // gather up info we need for test
-    nsCOMPtr<nsIDOMNode> parent, tmp, root;
-    nsIDOMElement *rootElem = mHTMLEditor->GetRoot();
-    NS_ENSURE_TRUE(rootElem, NS_ERROR_NULL_POINTER);
+    nsCOMPtr<nsIDOMNode> parent, tmp, root = do_QueryInterface(mHTMLEditor->GetRoot());
+    NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER);
     nsCOMPtr<nsISelection> selection;
     PRInt32 selOffset;
-    root = do_QueryInterface(rootElem);
-    NS_ENSURE_TRUE(root, NS_ERROR_NO_INTERFACE);
     res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
     NS_ENSURE_SUCCESS(res, res);
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     
     // test start parent hierarchy
     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(parent), &selOffset);
     NS_ENSURE_SUCCESS(res, res);
     while (parent && (parent!=root))
@@ -1103,17 +1101,17 @@ nsHTMLEditRules::GetParagraphState(bool 
     res = mHTMLEditor->GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
     NS_ENSURE_SUCCESS(res, res);
     NS_ENSURE_TRUE(selNode, NS_ERROR_NULL_POINTER);
     arrayOfNodes.AppendObject(selNode);
     listCount = 1;
   }
 
   // remember root node
-  nsIDOMElement *rootElem = mHTMLEditor->GetRoot();
+  nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot());
   NS_ENSURE_TRUE(rootElem, NS_ERROR_NULL_POINTER);
 
   // loop through the nodes in selection and examine their paragraph format
   for (i=listCount-1; i>=0; i--)
   {
     nsCOMPtr<nsIDOMNode> curNode = arrayOfNodes[i];
     nsAutoString format;
     // if it is a known format node we have it easy
@@ -7773,19 +7771,18 @@ nsHTMLEditRules::AdjustSelection(nsISele
   else theblock = mHTMLEditor->GetBlockNodeParent(selNode);
   if (theblock && mHTMLEditor->IsEditable(theblock)) {
     bool bIsEmptyNode;
     res = mHTMLEditor->IsEmptyNode(theblock, &bIsEmptyNode, false, false);
     NS_ENSURE_SUCCESS(res, res);
     // check if br can go into the destination node
     if (bIsEmptyNode && mHTMLEditor->CanContainTag(selNode, NS_LITERAL_STRING("br")))
     {
-      nsIDOMElement *rootElement = mHTMLEditor->GetRoot();
-      NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
-      nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
+      nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(mHTMLEditor->GetRoot());
+      NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
       if (selNode == rootNode)
       {
         // Our root node is completely empty. Don't add a <br> here.
         // AfterEditInner() will add one for us when it calls
         // CreateBogusNodeIfNeeded()!
         return NS_OK;
       }
 
@@ -8354,17 +8351,17 @@ nsHTMLEditRules::RemoveListStructure(nsI
 
 
 nsresult 
 nsHTMLEditRules::ConfirmSelectionInBody()
 {
   nsresult res = NS_OK;
 
   // get the body  
-  nsIDOMElement *rootElement = mHTMLEditor->GetRoot();
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(mHTMLEditor->GetRoot());
   NS_ENSURE_TRUE(rootElement, NS_ERROR_UNEXPECTED);
 
   // get the selection
   nsCOMPtr<nsISelection>selection;
   res = mHTMLEditor->GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(res, res);
   
   // get the selection start location
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -376,38 +376,39 @@ nsHTMLEditor::GetRootElement(nsIDOMEleme
     return nsEditor::GetRootElement(aRootElement);
   }
 
   *aRootElement = nsnull;
 
   // Use the HTML documents body element as the editor root if we didn't
   // get a root element during initialization.
 
+  nsCOMPtr<nsIDOMElement> rootElement; 
   nsCOMPtr<nsIDOMHTMLElement> bodyElement; 
   nsresult rv = GetBodyElement(getter_AddRefs(bodyElement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (bodyElement) {
-    mRootElement = bodyElement;
+    rootElement = bodyElement;
   } else {
     // If there is no HTML body element,
     // we should use the document root element instead.
     nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
     NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
 
-    rv = doc->GetDocumentElement(getter_AddRefs(mRootElement));
+    rv = doc->GetDocumentElement(getter_AddRefs(rootElement));
     NS_ENSURE_SUCCESS(rv, rv);
     // Document can have no elements
-    if (!mRootElement) {
+    if (!rootElement) {
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
-  *aRootElement = mRootElement;
-  NS_ADDREF(*aRootElement);
+  mRootElement = do_QueryInterface(rootElement);
+  rootElement.forget(aRootElement);
 
   return NS_OK;
 }
 
 already_AddRefed<nsIContent>
 nsHTMLEditor::FindSelectionRoot(nsINode *aNode)
 {
   NS_PRECONDITION(aNode->IsNodeOfType(nsINode::eDOCUMENT) ||
@@ -539,17 +540,17 @@ nsHTMLEditor::BeginningOfDocument()
 
   // get the selection
   nsCOMPtr<nsISelection> selection;
   nsresult res = GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(res, res);
   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
 
   // Get the root element.
-  nsIDOMElement *rootElement = GetRoot();
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
   if (!rootElement) {
     NS_WARNING("GetRoot() returned a null pointer (mRootElement is null)");
     return NS_OK;
   }
 
   // find first editable thingy
   bool done = false;
   nsCOMPtr<nsIDOMNode> curNode(rootElement), selNode;
@@ -964,165 +965,16 @@ nsHTMLEditor::GetBlockNodeParent(nsIDOMN
       break;
 
     p = tmp;
   }
   return p.forget();
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// GetBlockSection: return leftmost/rightmost nodes in aChild's block
-//               
-nsresult
-nsHTMLEditor::GetBlockSection(nsIDOMNode *aChild,
-                              nsIDOMNode **aLeftNode, 
-                              nsIDOMNode **aRightNode) 
-{
-  nsresult result = NS_OK;
-  if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;}
-  *aLeftNode = aChild;
-  *aRightNode = aChild;
-
-  nsCOMPtr<nsIDOMNode>sibling;
-  result = aChild->GetPreviousSibling(getter_AddRefs(sibling));
-  while ((NS_SUCCEEDED(result)) && sibling)
-  {
-    bool isBlock;
-    NodeIsBlockStatic(sibling, &isBlock);
-    if (isBlock)
-    {
-      nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
-      if (!nodeAsText) {
-        break;
-      }
-      // XXX: needs some logic to work for other leaf nodes besides text!
-    }
-    *aLeftNode = sibling;
-    result = (*aLeftNode)->GetPreviousSibling(getter_AddRefs(sibling)); 
-  }
-  NS_ADDREF((*aLeftNode));
-  // now do the right side
-  result = aChild->GetNextSibling(getter_AddRefs(sibling));
-  while ((NS_SUCCEEDED(result)) && sibling)
-  {
-    bool isBlock;
-    NodeIsBlockStatic(sibling, &isBlock);
-    if (isBlock) 
-    {
-      nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(sibling);
-      if (!nodeAsText) {
-        break;
-      }
-    }
-    *aRightNode = sibling;
-    result = (*aRightNode)->GetNextSibling(getter_AddRefs(sibling)); 
-  }
-  NS_ADDREF((*aRightNode));
-
-  return result;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// GetBlockSectionsForRange: return list of block sections that intersect 
-//                           this range
-nsresult
-nsHTMLEditor::GetBlockSectionsForRange(nsIDOMRange *aRange,
-                                       nsCOMArray<nsIDOMRange>& aSections) 
-{
-  if (!aRange) {return NS_ERROR_NULL_POINTER;}
-
-  nsresult result;
-  nsCOMPtr<nsIContentIterator>iter =
-    do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &result);
-  if (NS_FAILED(result) || !iter) {
-    return result;
-  }
-  nsCOMPtr<nsIDOMRange> lastRange;
-  iter->Init(aRange);
-  while (iter->IsDone())
-  {
-    nsCOMPtr<nsIContent> currentContent =
-      do_QueryInterface(iter->GetCurrentNode());
-
-    nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(currentContent);
-    if (currentNode)
-    {
-      // <BR> divides block content ranges.  We can achieve this by nulling out lastRange
-      if (currentContent->Tag() == nsEditProperty::br)
-      {
-        lastRange = nsnull;
-      }
-      else
-      {
-        bool isNotInlineOrText;
-        result = NodeIsBlockStatic(currentNode, &isNotInlineOrText);
-        if (isNotInlineOrText)
-        {
-          PRUint16 nodeType;
-          currentNode->GetNodeType(&nodeType);
-          if (nsIDOMNode::TEXT_NODE == nodeType) {
-            isNotInlineOrText = true;
-          }
-        }
-        if (!isNotInlineOrText) {
-          nsCOMPtr<nsIDOMNode> leftNode;
-          nsCOMPtr<nsIDOMNode> rightNode;
-          result = GetBlockSection(currentNode,
-                                   getter_AddRefs(leftNode),
-                                   getter_AddRefs(rightNode));
-          if ((NS_SUCCEEDED(result)) && leftNode && rightNode) {
-            // Add range to the list if it doesn't overlap with the previous
-            // range.
-            bool addRange = true;
-            if (lastRange)
-            {
-              nsCOMPtr<nsIDOMNode> lastStartNode;
-              lastRange->GetStartContainer(getter_AddRefs(lastStartNode));
-              nsCOMPtr<nsIDOMNode> blockParentNodeOfLastStartNode =
-                GetBlockNodeParent(lastStartNode);
-              nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode =
-                do_QueryInterface(blockParentNodeOfLastStartNode);
-              if (blockParentOfLastStartNode)
-              {
-                nsCOMPtr<nsIDOMNode> blockParentNodeOfLeftNode =
-                  GetBlockNodeParent(leftNode);
-                nsCOMPtr<nsIDOMElement> blockParentOfLeftNode =
-                  do_QueryInterface(blockParentNodeOfLeftNode);
-                if (blockParentOfLeftNode &&
-                    blockParentOfLastStartNode == blockParentOfLeftNode) {
-                  addRange = false;
-                }
-              }
-            }
-            if (addRange) {
-              nsCOMPtr<nsIDOMRange> range =
-                   do_CreateInstance("@mozilla.org/content/range;1", &result);
-              if ((NS_SUCCEEDED(result)) && range) {
-                // Initialize the range.
-                range->SetStart(leftNode, 0);
-                range->SetEnd(rightNode, 0);
-                aSections.AppendObject(range);
-                lastRange = do_QueryInterface(range);
-              }
-            }        
-          }
-        }
-      }
-    }
-    /* do not check result here, and especially do not return the result code.
-     * we rely on iter->IsDone to tell us when the iteration is complete
-     */
-    iter->Next();
-  }
-  return result;
-}
-
-
-///////////////////////////////////////////////////////////////////////////
 // NextNodeInBlock: gets the next/prev node in the block, if any.  Next node
 //                  must be an element or text node, others are ignored
 already_AddRefed<nsIDOMNode>
 nsHTMLEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir)
 {
   NS_ENSURE_TRUE(aNode, nsnull);
 
   nsresult rv;
@@ -1804,18 +1656,17 @@ NS_IMETHODIMP
 nsHTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString)
 {
   ForceCompositionEnd();
 
   nsCOMPtr<nsISelection>selection;
   nsresult res = GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(res, res);
 
-  nsIDOMElement *bodyElement = GetRoot();
-  NS_ENSURE_SUCCESS(res, res);
+  nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
   NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
 
   // Find where the <body> tag starts.
   nsReadingIterator<PRUnichar> beginbody;
   nsReadingIterator<PRUnichar> endbody;
   aSourceString.BeginReading(beginbody);
   aSourceString.EndReading(endbody);
   bool foundbody = CaseInsensitiveFindInReadable(NS_LITERAL_STRING("<body"),
@@ -2447,20 +2298,20 @@ nsHTMLEditor::GetHTMLBackgroundColorStat
     // from nested cells/tables, so search up parent chain
     nsCOMPtr<nsIDOMNode> parentNode;
     res = element->GetParentNode(getter_AddRefs(parentNode));
     NS_ENSURE_SUCCESS(res, res);
     element = do_QueryInterface(parentNode);
   }
 
   // If no table or cell found, get page body
-  element = GetRoot();
-  NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
-
-  return element->GetAttribute(styleName, aOutColor);
+  mozilla::dom::Element *bodyElement = GetRoot();
+  NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
+
+  return bodyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::bgcolor, aOutColor);
 }
 
 NS_IMETHODIMP 
 nsHTMLEditor::GetListState(bool *aMixed, bool *aOL, bool *aUL, bool *aDL)
 {
   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
   NS_ENSURE_TRUE(aMixed && aOL && aUL && aDL, NS_ERROR_NULL_POINTER);
   nsHTMLEditRules* htmlRules = static_cast<nsHTMLEditRules*>(mRules.get());
@@ -3387,17 +3238,17 @@ nsHTMLEditor::SetHTMLBackgroundColor(con
           GetNextSelectedCell(nsnull, getter_AddRefs(cell));
         };
         return res;
       }
     }
     // If we failed to find a cell, fall through to use originally-found element
   } else {
     // No table element -- set the background color on the body tag
-    element = GetRoot();
+    element = do_QueryInterface(GetRoot());
     NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
   }
   // Use the editor method that goes through the transaction system
   if (setColor)
     res = SetAttribute(element, bgcolor, aColor);
   else
     res = RemoveAttribute(element, bgcolor);
 
@@ -3406,18 +3257,17 @@ nsHTMLEditor::SetHTMLBackgroundColor(con
 
 NS_IMETHODIMP nsHTMLEditor::SetBodyAttribute(const nsAString& aAttribute, const nsAString& aValue)
 {
   // TODO: Check selection for Cell, Row, Column or table and do color on appropriate level
 
   NS_ASSERTION(mDocWeak, "Missing Editor DOM Document");
   
   // Set the background color attribute on the body tag
-  nsIDOMElement *bodyElement = GetRoot();
-
+  nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
   NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
 
   // Use the editor method that goes through the transaction system
   return SetAttribute(bodyElement, aAttribute, aValue);
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::GetLinkedObjects(nsISupportsArray** aNodeList)
@@ -3875,17 +3725,17 @@ nsHTMLEditor::ContentRemoved(nsIDocument
 
 
 /* This routine examines aNode and it's ancestors looking for any node which has the
    -moz-user-select: all style lit.  Return the highest such ancestor.  */
 already_AddRefed<nsIDOMNode>
 nsHTMLEditor::FindUserSelectAllNode(nsIDOMNode* aNode)
 {
   nsCOMPtr<nsIDOMNode> node = aNode;
-  nsIDOMElement *root = GetRoot();
+  nsCOMPtr<nsIDOMElement> root = do_QueryInterface(GetRoot());
   if (!nsEditorUtils::IsDescendantOf(aNode, root))
     return nsnull;
 
   nsCOMPtr<nsIDOMNode> resultNode;  // starts out empty
   nsAutoString mozUserSelectValue;
   while (node)
   {
     // retrieve the computed style of -moz-user-select for node
@@ -4140,17 +3990,17 @@ NS_IMETHODIMP
 nsHTMLEditor::SelectEntireDocument(nsISelection *aSelection)
 {
   if (!aSelection || !mRules) { return NS_ERROR_NULL_POINTER; }
   
   // Protect the edit rules object from dying
   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
 
   // get editor root node
-  nsIDOMElement *rootElement = GetRoot();
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
   
   // is doc empty?
   bool bDocIsEmpty;
   nsresult res = mRules->DocumentIsEmpty(&bDocIsEmpty);
   NS_ENSURE_SUCCESS(res, res);
     
   if (bDocIsEmpty)
   {
@@ -4185,17 +4035,19 @@ nsHTMLEditor::SelectAll()
   
   // If the anchor content has independent selection, we never need to explicitly
   // select its children.
   if (anchorContent->HasIndependentSelection()) {
     nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
     NS_ENSURE_TRUE(selPriv, NS_ERROR_UNEXPECTED);
     rv = selPriv->SetAncestorLimiter(nsnull);
     NS_ENSURE_SUCCESS(rv, rv);
-    return selection->SelectAllChildren(mRootElement);
+    nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(mRootElement, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    return selection->SelectAllChildren(rootElement);
   }
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   nsIContent *rootContent = anchorContent->GetSelectionRootContent(ps);
   NS_ENSURE_TRUE(rootContent, NS_ERROR_UNEXPECTED);
 
   nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(rootContent, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -4476,17 +4328,17 @@ nsHTMLEditor::CollapseAdjacentTextNodes(
   }
 
   return result;
 }
 
 NS_IMETHODIMP 
 nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
 {
-  nsIDOMElement *rootElement = GetRoot();  
+  nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
 
   return aSelection->Collapse(rootElement,0);
 }
 
 
 ///////////////////////////////////////////////////////////////////////////
 // RemoveBlockContainer: remove inNode, reparenting it's children into their
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -272,48 +272,16 @@ public:
   /* miscellaneous */
   // This sets background on the appropriate container element (table, cell,)
   //   or calls into nsTextEditor to set the page background
   NS_IMETHOD SetCSSBackgroundColor(const nsAString& aColor);
   NS_IMETHOD SetHTMLBackgroundColor(const nsAString& aColor);
 
   /* ------------ Block methods moved from nsEditor -------------- */
   static already_AddRefed<nsIDOMNode> GetBlockNodeParent(nsIDOMNode *aNode);
-  /** Determines the bounding nodes for the block section containing aNode.
-    * The calculation is based on some nodes intrinsically being block elements
-    * acording to HTML.  Style sheets are not considered in this calculation.
-    * <BR> tags separate block content sections.  So the HTML markup:
-    * <PRE>
-    *      <P>text1<BR>text2<B>text3</B></P>
-    * </PRE>
-    * contains two block content sections.  The first has the text node "text1"
-    * for both endpoints.  The second has "text2" as the left endpoint and
-    * "text3" as the right endpoint.
-    * Notice that offsets aren't required, only leaf nodes.  Offsets are implicit.
-    *
-    * @param aNode      the block content returned includes aNode
-    * @param aLeftNode  [OUT] the left endpoint of the block content containing aNode
-    * @param aRightNode [OUT] the right endpoint of the block content containing aNode
-    *
-    */
-  static nsresult GetBlockSection(nsIDOMNode  *aNode,
-                                  nsIDOMNode **aLeftNode, 
-                                  nsIDOMNode **aRightNode);
-
-  /** Compute the set of block sections in a given range.
-    * A block section is the set of (leftNode, rightNode) pairs given
-    * by GetBlockSection.  The set is computed by computing the 
-    * block section for every leaf node in the range and throwing 
-    * out duplicates.
-    *
-    * @param aRange     The range to compute block sections for.
-    * @param aSections  Allocated storage for the resulting set, stored as nsIDOMRanges.
-    */
-  static nsresult GetBlockSectionsForRange(nsIDOMRange      *aRange, 
-                                           nsCOMArray<nsIDOMRange>& aSections);
 
   static already_AddRefed<nsIDOMNode> NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir);
   nsresult IsNextCharWhitespace(nsIDOMNode *aParentNode, 
                                 PRInt32 aOffset, 
                                 bool *outIsSpace, 
                                 bool *outIsNBSP,
                                 nsCOMPtr<nsIDOMNode> *outNode = 0,
                                 PRInt32 *outOffset = 0);
--- a/editor/libeditor/html/nsHTMLInlineTableEditor.cpp
+++ b/editor/libeditor/html/nsHTMLInlineTableEditor.cpp
@@ -38,16 +38,17 @@
 #include "nsHTMLEditor.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIPresShell.h"
 #include "nsIDocumentObserver.h"
 #include "nsIContent.h"
 #include "nsHTMLEditUtils.h"
 #include "nsReadableUtils.h"
+#include "mozilla/dom/Element.h"
 
 // Uncomment the following line if you want to disable
 // table deletion when the only column/row is removed
 // #define DISABLE_TABLE_DELETION 1
 
 NS_IMETHODIMP
 nsHTMLEditor::SetInlineTableEditingEnabled(bool aIsEnabled)
 {
@@ -72,17 +73,17 @@ nsHTMLEditor::ShowInlineTableEditingUI(n
     return NS_OK;
 
   if (mInlineEditedCell) {
     NS_ERROR("call HideInlineTableEditingUI first");
     return NS_ERROR_UNEXPECTED;
   }
 
   // the resizers and the shadow will be anonymous children of the body
-  nsIDOMElement *bodyElement = GetRoot();
+  nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
   NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
 
   CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
                          NS_LITERAL_STRING("mozTableAddColumnBefore"),
                          false, getter_AddRefs(mAddColumnBeforeButton));
   CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
                          NS_LITERAL_STRING("mozTableRemoveColumn"),
                          false, getter_AddRefs(mRemoveColumnButton));
@@ -125,20 +126,17 @@ nsHTMLEditor::HideInlineTableEditingUI()
 
   // get the presshell's document observer interface.
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   // We allow the pres shell to be null; when it is, we presume there
   // are no document observers to notify, but we still want to
   // UnbindFromTree.
 
   // get the root content node.
-
-  nsIDOMElement *bodyElement = GetRoot();
-
-  nsCOMPtr<nsIContent> bodyContent( do_QueryInterface(bodyElement) );
+  nsCOMPtr<nsIContent> bodyContent = GetRoot();
   NS_ENSURE_TRUE(bodyContent, NS_ERROR_FAILURE);
 
   DeleteRefToAnonymousNode(mAddColumnBeforeButton, bodyContent, ps);
   mAddColumnBeforeButton = nsnull;
   DeleteRefToAnonymousNode(mRemoveColumnButton, bodyContent, ps);
   mRemoveColumnButton = nsnull;
   DeleteRefToAnonymousNode(mAddColumnAfterButton, bodyContent, ps);
   mAddColumnAfterButton = nsnull;
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -70,16 +70,17 @@
 #include "nsEditorUtils.h"  // nsAutoEditBatch, nsAutoRules
 #include "nsUnicharUtils.h"
 #include "nsContentCID.h"
 #include "nsInternetCiter.h"
 #include "nsEventDispatcher.h"
 #include "nsGkAtoms.h"
 #include "nsDebug.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/Element.h"
 
 // Drag & Drop, Clipboard
 #include "nsIClipboard.h"
 #include "nsITransferable.h"
 #include "nsCopySupport.h"
 
 #include "mozilla/FunctionTimer.h"
 
@@ -566,32 +567,32 @@ nsPlaintextEditor::GetTextSelectionOffse
   nsresult rv;
   nsCOMPtr<nsIDOMNode> startNode, endNode;
   PRInt32 startNodeOffset, endNodeOffset;
   aSelection->GetAnchorNode(getter_AddRefs(startNode));
   aSelection->GetAnchorOffset(&startNodeOffset);
   aSelection->GetFocusNode(getter_AddRefs(endNode));
   aSelection->GetFocusOffset(&endNodeOffset);
 
-  nsIDOMElement* rootNode = GetRoot();
+  dom::Element *rootElement = GetRoot();
+  nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootElement);
   NS_ENSURE_TRUE(rootNode, NS_ERROR_NULL_POINTER);
 
   PRInt32 startOffset = -1;
   PRInt32 endOffset = -1;
 
   nsCOMPtr<nsIContentIterator> iter =
     do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
     
 #ifdef NS_DEBUG
   PRInt32 nodeCount = 0; // only needed for the assertions below
 #endif
   PRUint32 totalLength = 0;
-  nsCOMPtr<nsIContent> rootContent = do_QueryInterface(rootNode);
-  iter->Init(rootContent);
+  iter->Init(rootElement);
   for (; !iter->IsDone() && (startOffset == -1 || endOffset == -1); iter->Next()) {
     nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(iter->GetCurrentNode());
     nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(currentNode);
     if (textNode) {
       // Note that sometimes we have an empty #text-node as start/endNode,
       // which we regard as not editable because the frame width == 0,
       // see nsEditor::IsEditable().
       bool editable = IsEditable(currentNode);
@@ -1015,26 +1016,25 @@ nsPlaintextEditor::GetTextLength(PRInt32
   
   // special-case for empty document, to account for the bogus node
   bool docEmpty;
   nsresult rv = GetDocumentIsEmpty(&docEmpty);
   NS_ENSURE_SUCCESS(rv, rv);
   if (docEmpty)
     return NS_OK;
 
-  nsIDOMElement* rootNode = GetRoot();
-  NS_ENSURE_TRUE(rootNode, NS_ERROR_NULL_POINTER);
+  dom::Element *rootElement = GetRoot();
+  NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIContentIterator> iter =
     do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRUint32 totalLength = 0;
-  nsCOMPtr<nsIContent> rootContent = do_QueryInterface(rootNode);
-  iter->Init(rootContent);
+  iter->Init(rootElement);
   for (; !iter->IsDone(); iter->Next()) {
     nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(iter->GetCurrentNode());
     nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(currentNode);
     if (textNode && IsEditable(currentNode)) {
       PRUint32 length;
       textNode->GetLength(&length);
       totalLength += length;
     }
@@ -1099,23 +1099,22 @@ nsPlaintextEditor::SetWrapWidth(PRInt32 
 
   // Make sure we're a plaintext editor, otherwise we shouldn't
   // do the rest of this.
   if (!IsPlaintextEditor())
     return NS_OK;
 
   // Ought to set a style sheet here ...
   // Probably should keep around an mPlaintextStyleSheet for this purpose.
-  nsIDOMElement *rootElement = GetRoot();
+  dom::Element *rootElement = GetRoot();
   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
 
   // Get the current style for this root element:
-  NS_NAMED_LITERAL_STRING(styleName, "style");
   nsAutoString styleValue;
-  nsresult res = rootElement->GetAttribute(styleName, styleValue);
+  nsresult res = rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::style, styleValue);
   NS_ENSURE_SUCCESS(res, res);
 
   // We'll replace styles for these values:
   CutStyle("white-space", styleValue);
   CutStyle("width", styleValue);
   CutStyle("font-family", styleValue);
 
   // If we have other style left, trim off any existing semicolons
@@ -1149,17 +1148,17 @@ nsPlaintextEditor::SetWrapWidth(PRInt32 
     styleValue.AppendInt(aWrapColumn);
     styleValue.AppendLiteral("ch;");
   }
   else if (mWrapToWindow || aWrapColumn == 0)
     styleValue.AppendLiteral("white-space: pre-wrap;");
   else
     styleValue.AppendLiteral("white-space: pre;");
 
-  return rootElement->SetAttribute(styleName, styleValue);
+  return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::style, styleValue, true);
 }
 
 NS_IMETHODIMP 
 nsPlaintextEditor::SetWrapColumn(PRInt32 aWrapColumn)
 {
   mWrapColumn = aWrapColumn;
   return NS_OK;
 }
@@ -1349,17 +1348,17 @@ nsPlaintextEditor::GetAndInitDocEncoder(
     if (NS_SUCCEEDED(rv) && selection)
       rv = docEncoder->SetSelection(selection);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   // ... or if the root element is not a body,
   // in which case we set the selection to encompass the root.
   else
   {
-    nsIDOMElement *rootElement = GetRoot();
+    nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
     NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
     if (!nsTextEditUtils::IsBody(rootElement))
     {
       rv = docEncoder->SetContainerNode(rootElement);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
@@ -1679,17 +1678,17 @@ nsPlaintextEditor::SelectEntireDocument(
   // Protect the edit rules object from dying
   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
 
   // is doc empty?
   bool bDocIsEmpty;
   if (NS_SUCCEEDED(mRules->DocumentIsEmpty(&bDocIsEmpty)) && bDocIsEmpty)
   {
     // get root node
-    nsIDOMElement *rootElement = GetRoot();
+    nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
     NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
 
     // if it's empty don't select entire doc - that would select the bogus node
     return aSelection->Collapse(rootElement, 0);
   }
 
   nsresult rv = nsEditor::SelectEntireDocument(aSelection);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -63,16 +63,17 @@
 #include "nsNodeIterator.h"
 #include "nsIDOMNodeFilter.h"
 
 // for IBMBIDI
 #include "nsFrameSelection.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
+#include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 
 #define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
   if (IsReadonly() || IsDisabled()) \
   {                     \
     *aCancel = true; \
     return NS_OK;       \
@@ -455,18 +456,17 @@ nsTextEditRules::CollapseSelectionToTrai
     return NS_OK;
 
   nsCOMPtr<nsIDOMNode> parentNode;
   PRInt32 parentOffset;
   res = nsEditor::GetNodeLocation(selNode, address_of(parentNode),
                                   &parentOffset);
   NS_ENSURE_SUCCESS(res, res);
 
-  nsIDOMElement *rootElem = mEditor->GetRoot();
-  nsCOMPtr<nsIDOMNode> root = do_QueryInterface(rootElem);
+  nsCOMPtr<nsIDOMNode> root = do_QueryInterface(mEditor->GetRoot());
   NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER);
   if (parentNode != root) return NS_OK;
 
   nsCOMPtr<nsIDOMNode> nextNode = mEditor->GetChildAt(parentNode,
                                                       parentOffset + 1);
   if (nextNode && nsTextEditUtils::IsMozBR(nextNode))
   {
     res = aSelection->Collapse(parentNode, parentOffset + 1);
@@ -944,17 +944,17 @@ nsTextEditRules::DidUndo(nsISelection *a
   if (!aSelection) { return NS_ERROR_NULL_POINTER; }
   if (NS_SUCCEEDED(res)) 
   {
     if (mBogusNode) {
       mBogusNode = nsnull;
     }
     else
     {
-      nsIDOMElement *theRoot = mEditor->GetRoot();
+      nsCOMPtr<nsIDOMElement> theRoot = do_QueryInterface(mEditor->GetRoot());
       NS_ENSURE_TRUE(theRoot, NS_ERROR_FAILURE);
       nsCOMPtr<nsIDOMNode> node = mEditor->GetLeftmostChild(theRoot);
       if (node && mEditor->IsMozEditorBogusNode(node))
         mBogusNode = node;
     }
   }
   return res;
 }
@@ -977,17 +977,17 @@ nsTextEditRules::DidRedo(nsISelection *a
   if (!aSelection) { return NS_ERROR_NULL_POINTER; }
   if (NS_SUCCEEDED(res)) 
   {
     if (mBogusNode) {
       mBogusNode = nsnull;
     }
     else
     {
-      nsIDOMElement *theRoot = mEditor->GetRoot();
+      nsCOMPtr<nsIDOMElement> theRoot = do_QueryInterface(mEditor->GetRoot());
       NS_ENSURE_TRUE(theRoot, NS_ERROR_FAILURE);
       
       nsCOMPtr<nsIDOMNodeList> nodeList;
       res = theRoot->GetElementsByTagName(NS_LITERAL_STRING("br"),
                                           getter_AddRefs(nodeList));
       NS_ENSURE_SUCCESS(res, res);
       if (nodeList)
       {
@@ -1051,17 +1051,17 @@ nsTextEditRules::RemoveRedundantTrailing
   // If the bogus node exists, we have no work to do
   if (mBogusNode)
     return NS_OK;
 
   // Likewise, nothing to be done if we could never have inserted a trailing br
   if (IsSingleLineEditor())
     return NS_OK;
 
-  nsIDOMNode* body = mEditor->GetRoot();
+  nsCOMPtr<nsIDOMNode> body = do_QueryInterface(mEditor->GetRoot());
   if (!body)
     return NS_ERROR_NULL_POINTER;
 
   bool hasChildren;
   nsresult res = body->HasChildNodes(&hasChildren);
   NS_ENSURE_SUCCESS(res, res);
 
   if (hasChildren) {
@@ -1106,17 +1106,17 @@ nsTextEditRules::RemoveRedundantTrailing
 }
 
 nsresult
 nsTextEditRules::CreateTrailingBRIfNeeded()
 {
   // but only if we aren't a single line edit field
   if (IsSingleLineEditor())
     return NS_OK;
-  nsIDOMNode *body = mEditor->GetRoot();
+  nsCOMPtr<nsIDOMNode> body = do_QueryInterface(mEditor->GetRoot());
   NS_ENSURE_TRUE(body, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIDOMNode> lastChild;
   nsresult res = body->GetLastChild(getter_AddRefs(lastChild));
   // assuming CreateBogusNodeIfNeeded() has been called first
   NS_ENSURE_SUCCESS(res, res);  
   NS_ENSURE_TRUE(lastChild, NS_ERROR_NULL_POINTER);
 
   if (!nsTextEditUtils::IsBreak(lastChild))
@@ -1136,17 +1136,17 @@ nsTextEditRules::CreateBogusNodeIfNeeded
 {
   if (!aSelection) { return NS_ERROR_NULL_POINTER; }
   if (!mEditor) { return NS_ERROR_NULL_POINTER; }
   if (mBogusNode) return NS_OK;  // let's not create more than one, ok?
 
   // tell rules system to not do any post-processing
   nsAutoRules beginRulesSniffing(mEditor, nsEditor::kOpIgnore, nsIEditor::eNone);
 
-  nsIDOMNode* body = mEditor->GetRoot();
+  nsCOMPtr<nsIDOMNode> body = do_QueryInterface(mEditor->GetRoot());
   if (!body)
   {
     // we don't even have a body yet, don't insert any bogus nodes at
     // this point.
 
     return NS_OK;
   }
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -73,17 +73,17 @@
 typedef char realGLboolean;
 
 #include "GLContextSymbols.h"
 
 namespace mozilla {
   namespace layers {
     class LayerManagerOGL;
     class ColorTextureLayerProgram;
-  };
+  }
 
 namespace gl {
 class GLContext;
 
 class LibrarySymbolLoader
 {
 public:
     bool OpenLibrary(const char *library);
@@ -537,16 +537,17 @@ public:
         mIsOffscreen(aIsOffscreen),
 #ifdef USE_GLES2
         mIsGLES2(true),
 #else
         mIsGLES2(false),
 #endif
         mIsGlobalSharedContext(false),
         mHasRobustness(false),
+        mContextLost(false),
         mVendor(-1),
         mDebugMode(0),
         mCreationFormat(aFormat),
         mSharedContext(aSharedContext),
         mOffscreenTexture(0),
         mFlipped(false),
         mBlitProgram(0),
         mBlitFramebuffer(0),
@@ -590,16 +591,18 @@ public:
 
     bool MakeCurrent(bool aForce = false) {
 #ifdef DEBUG
         sCurrentGLContext = this;
 #endif
         return MakeCurrentImpl(aForce);
     }
 
+    bool IsContextLost() { return mContextLost; }
+
     virtual bool SetupLookupFunction() = 0;
 
     virtual void WindowDestroyed() {}
 
     virtual void ReleaseSurface() {}
 
     void *GetUserData(void *aKey) {
         void *result = nsnull;
@@ -1321,16 +1324,17 @@ public:
     }
 
 protected:
     bool mInitialized;
     bool mIsOffscreen;
     bool mIsGLES2;
     bool mIsGlobalSharedContext;
     bool mHasRobustness;
+    bool mContextLost;
 
     PRInt32 mVendor;
 
     enum {
         DebugEnabled = 1 << 0,
         DebugTrace = 1 << 1,
         DebugAbortOnError = 1 << 2
     };
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -829,16 +829,20 @@ public:
             mSurface = CreateSurfaceForWindow(NULL, config);
             aForce = true;
         }
 #endif
         if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
             succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
                                                  mSurface, mSurface,
                                                  mContext);
+            if (!succeeded && sEGLLibrary.fGetError() == LOCAL_EGL_CONTEXT_LOST) {
+                mContextLost = true;
+                NS_WARNING("EGL context has been lost.");
+            }
             NS_ASSERTION(succeeded, "Failed to make GL context current!");
         }
 
         return succeeded;
     }
 
 #ifdef MOZ_WIDGET_QT
     virtual bool
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -117,16 +117,23 @@ CreateDummyWindow(HDC *aWindowDC = nsnul
 
     if (aWindowDC) {
         *aWindowDC = dc;
     }
 
     return win;
 }
 
+static inline bool
+HasExtension(const char* aExtensions, const char* aRequiredExtension)
+{
+    return GLContext::ListHasExtension(
+        reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
+}
+
 bool
 WGLLibrary::EnsureInitialized()
 {
     if (mInitialized)
         return true;
 
     mozilla::ScopedGfxFeatureReporter reporter("WGL");
 
@@ -200,19 +207,57 @@ WGLLibrary::EnsureInitialized()
 
     if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &pixFmtSymbols[0],
          (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress))
     {
         // this isn't an error, just means that we don't have the pixel format extension
         fChoosePixelFormat = nsnull;
     }
 
+    LibrarySymbolLoader::SymLoadStruct extensionsSymbols[] = {
+        { (PRFuncPtr *) &fGetExtensionsString, { "wglGetExtensionsStringARB", NULL} },
+        { NULL, { NULL } }
+    };
+
+    LibrarySymbolLoader::SymLoadStruct robustnessSymbols[] = {
+        { (PRFuncPtr *) &fCreateContextAttribs, { "wglCreateContextAttribsARB", NULL} },
+        { NULL, { NULL } }
+    };
+
+    if (LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &extensionsSymbols[0],
+        (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress)) {
+        const char *wglExts = fGetExtensionsString(gSharedWindowDC);
+        if (wglExts && HasExtension(wglExts, "WGL_ARB_create_context")) {
+            LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &robustnessSymbols[0],
+            (LibrarySymbolLoader::PlatformLookupFunction)fGetProcAddress);
+            if (HasExtension(wglExts, "WGL_ARB_create_context_robustness")) {
+                mHasRobustness = true;
+            }
+        }
+    }
+
     // reset back to the previous context, just in case
     fMakeCurrent(curDC, curCtx);
 
+    if (mHasRobustness) {
+        fDeleteContext(gSharedWindowGLContext);
+
+        int attribs[] = {
+            LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
+            LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
+            NULL
+        };
+
+        gSharedWindowGLContext = fCreateContextAttribs(gSharedWindowDC, NULL, attribs);
+        if (!gSharedWindowGLContext) {
+            mHasRobustness = false;
+            gSharedWindowGLContext = fCreateContext(gSharedWindowDC);
+        }
+    }
+
     mInitialized = true;
 
     // Call this to create the global GLContext instance,
     // and to check for errors.  Note that this must happen /after/
     // setting mInitialized to TRUE, or an infinite loop results.
     if (GLContextProviderWGL::GetGlobalContext() == nsnull) {
         mInitialized = false;
         return false;
@@ -304,17 +349,17 @@ public:
     }
 
     virtual bool IsDoubleBuffered() {
         return mIsDoubleBuffered;
     }
 
     bool SupportsRobustness()
     {
-        return false;
+        return sWGLLibrary.HasRobustness();
     }
 
     virtual bool SwapBuffers() {
         if (!mIsDoubleBuffered)
             return false;
         return ::SwapBuffers(mDC);
     }
 
@@ -497,26 +542,45 @@ GLContextProviderWGL::CreateForWindow(ns
        * We need to make sure we call SetPixelFormat -after- calling 
        * EnsureInitialized, otherwise it can load/unload the dll and 
        * wglCreateContext will fail.
        */
 
     HDC dc = (HDC)aWidget->GetNativeData(NS_NATIVE_GRAPHIC);
 
     SetPixelFormat(dc, gSharedWindowPixelFormat, NULL);
-    HGLRC context = sWGLLibrary.fCreateContext(dc);
-    if (!context) {
-        return nsnull;
+    HGLRC context;
+
+    GLContextWGL *shareContext = GetGlobalContextWGL();
+
+    if (sWGLLibrary.HasRobustness()) {
+        int attribs[] = {
+            LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
+            LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
+            NULL
+        };
+
+        context = sWGLLibrary.fCreateContextAttribs(dc,
+                                                    shareContext ? shareContext->Context() : nsnull,
+                                                    attribs);
+        if (!context && shareContext) {
+            context = sWGLLibrary.fCreateContextAttribs(dc, nsnull, attribs);
+            if (context) {
+                shareContext = nsnull;
+            }
+        } else {
+            context = sWGLLibrary.fCreateContext(dc);
+            if (context && shareContext && !sWGLLibrary.fShareLists(shareContext->Context(), context)) {
+                shareContext = nsnull;
+            }
+        }
     }
 
-    GLContextWGL *shareContext = GetGlobalContextWGL();
-    if (shareContext &&
-        !sWGLLibrary.fShareLists(shareContext->Context(), context))
-    {
-        shareContext = nsnull;
+    if (!context) {
+        return nsnull;
     }
 
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24),
                                                         shareContext, dc, context);
     if (!glContext->Init()) {
         return nsnull;
     }
 
@@ -592,17 +656,29 @@ CreatePBufferOffscreenContext(const gfxI
                                                 pbattrs.Elements());
     if (!pbuffer) {
         return nsnull;
     }
 
     HDC pbdc = sWGLLibrary.fGetPbufferDC(pbuffer);
     NS_ASSERTION(pbdc, "expected a dc");
 
-    HGLRC context = sWGLLibrary.fCreateContext(pbdc);
+    HGLRC context;
+    if (sWGLLibrary.HasRobustness()) {
+        int attribs[] = {
+            LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
+            LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
+            NULL
+        };
+
+        context = sWGLLibrary.fCreateContextAttribs(pbdc, nsnull, attribs);
+    } else {
+        context = sWGLLibrary.fCreateContext(pbdc);
+    }
+
     if (!context) {
         sWGLLibrary.fDestroyPbuffer(pbuffer);
         return false;
     }
 
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat,
                                                         nsnull,
                                                         pbuffer,
@@ -624,25 +700,38 @@ CreateWindowOffscreenContext(const Conte
     
     HDC dc;
     HWND win = CreateDummyWindow(&dc);
     if (!win) {
         return nsnull;
     }
     
     HGLRC context = sWGLLibrary.fCreateContext(dc);
-    if (!context) {
-        return nsnull;
+    if (sWGLLibrary.HasRobustness()) {
+        int attribs[] = {
+            LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
+            LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
+            NULL
+        };
+
+        context = sWGLLibrary.fCreateContextAttribs(dc, shareContext->Context(), attribs);
+    } else {
+        context = sWGLLibrary.fCreateContext(dc);
+        if (context && shareContext &&
+            !sWGLLibrary.fShareLists(shareContext->Context(), context))
+        {
+            NS_WARNING("wglShareLists failed!");
+
+            sWGLLibrary.fDeleteContext(context);
+            DestroyWindow(win);
+            return nsnull;
+        }
     }
 
-    if (!sWGLLibrary.fShareLists(shareContext->Context(), context)) {
-        NS_WARNING("wglShareLists failed!");
-
-        sWGLLibrary.fDeleteContext(context);
-        DestroyWindow(win);
+    if (!context) {
         return nsnull;
     }
 
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat, shareContext,
                                                         dc, context, win, true);
 
     return glContext.forget();
 }
--- a/gfx/gl/GLDefs.h
+++ b/gfx/gl/GLDefs.h
@@ -3241,9 +3241,10 @@ typedef ptrdiff_t GLintptr;
 #define LOCAL_EGL_LOCK_USAGE_HINT_KHR         0x30C5
 #define LOCAL_EGL_MAP_PRESERVE_PIXELS_KHR     0x30C4
 #define LOCAL_EGL_READ_SURFACE_BIT_KHR        0x0001
 #define LOCAL_EGL_WRITE_SURFACE_BIT_KHR       0x0002
 #define LOCAL_EGL_LOCK_SURFACE_BIT_KHR        0x0080
 #define LOCAL_EGL_CORE_NATIVE_ENGINE          0x305B
 #define LOCAL_EGL_READ                        0x305A
 #define LOCAL_EGL_DRAW                        0x3059
+#define LOCAL_EGL_CONTEXT_LOST                0x300E
 #endif
--- a/gfx/gl/Makefile.in
+++ b/gfx/gl/Makefile.in
@@ -1,8 +1,42 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
 
 DEPTH		= ../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
--- a/gfx/gl/WGLLibrary.h
+++ b/gfx/gl/WGLLibrary.h
@@ -37,17 +37,18 @@
 #include "GLContext.h"
 
 namespace mozilla {
 namespace gl {
 
 class WGLLibrary
 {
 public:
-    WGLLibrary() : mInitialized(false), mOGLLibrary(nsnull) {}
+    WGLLibrary() : mInitialized(false), mOGLLibrary(nsnull),
+    mHasRobustness(false) {}
 
     typedef HGLRC (GLAPIENTRY * PFNWGLCREATECONTEXTPROC) (HDC);
     PFNWGLCREATECONTEXTPROC fCreateContext;
     typedef BOOL (GLAPIENTRY * PFNWGLDELETECONTEXTPROC) (HGLRC);
     PFNWGLDELETECONTEXTPROC fDeleteContext;
     typedef BOOL (GLAPIENTRY * PFNWGLMAKECURRENTPROC) (HDC, HGLRC);
     PFNWGLMAKECURRENTPROC fMakeCurrent;
     typedef PROC (GLAPIENTRY * PFNWGLGETPROCADDRESSPROC) (LPCSTR);
@@ -71,21 +72,30 @@ public:
     typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEPROC) (HANDLE hPbuffer, int iBuffer);
     PFNWGLRELEASETEXIMAGEPROC fReleaseTexImage;
 
     typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
     PFNWGLCHOOSEPIXELFORMATPROC fChoosePixelFormat;
     typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues);
     PFNWGLGETPIXELFORMATATTRIBIVPROC fGetPixelFormatAttribiv;
 
+    typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGPROC) (HDC hdc);
+    PFNWGLGETEXTENSIONSSTRINGPROC fGetExtensionsString;
+
+    typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSPROC) (HDC hdc, HGLRC hShareContext, const int *attribList);
+    PFNWGLCREATECONTEXTATTRIBSPROC fCreateContextAttribs;
+
     bool EnsureInitialized();
 
+    bool HasRobustness() const { return mHasRobustness; }
+
 private:
     bool mInitialized;
     PRLibrary *mOGLLibrary;
+    bool mHasRobustness;
 };
 
 // a global WGLLibrary instance
 extern WGLLibrary sWGLLibrary;
 
 } /* namespace gl */
 } /* namespace mozilla */
 
--- a/gfx/qcms/Makefile.in
+++ b/gfx/qcms/Makefile.in
@@ -1,8 +1,43 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
 DEPTH		= ../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE       = qcms
--- a/gfx/src/nsScriptableRegion.cpp
+++ b/gfx/src/nsScriptableRegion.cpp
@@ -157,16 +157,20 @@ NS_IMETHODIMP nsScriptableRegion::GetRec
   PRUint32 numRects = mRegion.GetNumRects();
 
   if (!numRects) {
     *aRects = JSVAL_NULL;
     return NS_OK;
   }
 
   JSObject* destArray = JS_NewArrayObject(aCx, numRects * 4, NULL);
+  if (!destArray) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
   *aRects = OBJECT_TO_JSVAL(destArray);
 
   uint32 n = 0;
   nsIntRegionRectIterator iter(mRegion);
   const nsIntRect *rect;
 
   while ((rect = iter.Next())) {
     // This will contain bogus data if values don't fit in 31 bit
--- a/gfx/thebes/Makefile.in
+++ b/gfx/thebes/Makefile.in
@@ -1,8 +1,42 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
 
 DEPTH		= ../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
--- a/hal/fallback/FallbackHal.cpp
+++ b/hal/fallback/FallbackHal.cpp
@@ -61,13 +61,13 @@ void
 DisableBatteryNotifications()
 {}
 
 void
 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
   aBatteryInfo->level() = dom::battery::kDefaultLevel;
   aBatteryInfo->charging() = dom::battery::kDefaultCharging;
-  aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+  aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
 }
 
 } // hal_impl
 } // namespace mozilla
--- a/hal/linux/LinuxHal.cpp
+++ b/hal/linux/LinuxHal.cpp
@@ -61,15 +61,15 @@ void
 DisableBatteryNotifications()
 {}
 
 void
 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
   aBatteryInfo->level() = dom::battery::kDefaultLevel;
   aBatteryInfo->charging() = dom::battery::kDefaultCharging;
-  aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
+  aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
 }
 #endif // !MOZ_ENABLE_DBUS
 
 } // hal_impl
 } // mozilla
 
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -742,17 +742,17 @@ jsd_GetValueParent(JSDContext* jsdc, JSD
             return NULL;
         JS_BeginRequest(jsdc->dumbContext);
         call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
         if(!call) {
             JS_EndRequest(jsdc->dumbContext);
 
             return NULL;
         }
-        parent = JS_GetParent(jsdc->dumbContext,obj);
+        parent = JS_GetParentOrScopeChain(jsdc->dumbContext,obj);
         JS_LeaveCrossCompartmentCall(call);
         JS_EndRequest(jsdc->dumbContext);
         if(!parent)
             return NULL;
         jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
     }
     if(jsdval->parent)
         jsdval->parent->nref++;
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -352,16 +352,17 @@ class HashTable : private AllocPolicy
         for (Entry *e = oldTable, *end = e + capacity; e != end; ++e)
             e->~Entry();
         alloc.free_(oldTable);
     }
 
   public:
     HashTable(AllocPolicy ap)
       : AllocPolicy(ap),
+        hashShift(sHashBits),
         entryCount(0),
         gen(0),
         removedCount(0),
         table(NULL)
 #ifdef DEBUG
         , entered(false),
         mutationCount(0)
 #endif
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -559,16 +559,21 @@ public:
         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
     }
 
     ptrdiff_t differenceBetween(DataLabel32 from, Label to)
     {
         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
     }
 
+    ptrdiff_t differenceBetween(DataLabelPtr from, Label to)
+    {
+        return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
+    }
+
     ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
     {
         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
     }
 
     ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
     {
         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
--- a/js/src/assembler/assembler/MacroAssembler.h
+++ b/js/src/assembler/assembler/MacroAssembler.h
@@ -329,17 +329,17 @@ public:
         return branch32(cond, left, right);
     }
 
     Jump branchPtr(Condition cond, Address left, ImmPtr right)
     {
         return branch32(cond, left, Imm32(right));
     }
 
-    Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right)
+    Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right, RegisterID scratch)
     {
         return branch32(cond, left, Imm32(right));
     }
 
     Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask)
     {
         return branchTest32(cond, reg, mask);
     }
--- a/js/src/assembler/assembler/MacroAssemblerX86_64.h
+++ b/js/src/assembler/assembler/MacroAssemblerX86_64.h
@@ -426,16 +426,22 @@ public:
     }
 
     Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right)
     {
         move(ImmPtr(left.m_ptr), scratchRegister);
         return branchPtr(cond, Address(scratchRegister), right);
     }
 
+    Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right, RegisterID scratch)
+    {
+        move(ImmPtr(left.m_ptr), scratch);
+        return branchPtr(cond, Address(scratch), right);
+    }
+
     Jump branchPtr(Condition cond, Address left, RegisterID right)
     {
         m_assembler.cmpq_rm(right, left.offset, left.base);
         return Jump(m_assembler.jCC(x86Condition(cond)));
     }
 
     Jump branchPtr(Condition cond, Address left, ImmPtr right)
     {
--- a/js/src/assembler/assembler/RepatchBuffer.h
+++ b/js/src/assembler/assembler/RepatchBuffer.h
@@ -105,19 +105,19 @@ public:
         MacroAssembler::repatchNearCall(nearCall, destination);
     }
 
     void repatch(CodeLocationDataLabel32 dataLabel32, int32_t value)
     {
         MacroAssembler::repatchInt32(dataLabel32, value);
     }
 
-    void repatch(CodeLocationDataLabelPtr dataLabelPtr, void* value)
+    void repatch(CodeLocationDataLabelPtr dataLabelPtr, const void* value)
     {
-        MacroAssembler::repatchPointer(dataLabelPtr, value);
+        MacroAssembler::repatchPointer(dataLabelPtr, (void*) value);
     }
 
     void repatchLoadPtrToLEA(CodeLocationInstruction instruction)
     {
         MacroAssembler::repatchLoadPtrToLEA(instruction);
     }
 
     void repatchLEAToLoadPtr(CodeLocationInstruction instruction)
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -636,17 +636,17 @@ InitTypeConstructor(JSContext* cx,
                     JSFunctionSpec spec,
                     JSFunctionSpec* fns,
                     JSPropertySpec* props,
                     JSFunctionSpec* instanceFns,
                     JSPropertySpec* instanceProps,
                     JSObject*& typeProto,
                     JSObject*& dataProto)
 {
-  JSFunction* fun = JS_DefineFunction(cx, parent, spec.name, spec.call, 
+  JSFunction* fun = js::DefineFunctionWithReserved(cx, parent, spec.name, spec.call, 
                       spec.nargs, spec.flags);
   if (!fun)
     return false;
 
   JSObject* obj = JS_GetFunctionObject(fun);
   if (!obj)
     return false;
 
@@ -667,18 +667,17 @@ InitTypeConstructor(JSContext* cx,
     return false;
 
   if (!JS_DefineProperty(cx, typeProto, "constructor", OBJECT_TO_JSVAL(obj),
          NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
   // the type constructor, for faster lookup.
-  if (!JS_SetReservedSlot(cx, obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto)))
-    return false;
+  js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto));
 
   // Create an object to serve as the common ancestor for all CData objects
   // created from the given type constructor. This has ctypes.CData.prototype
   // as its prototype, such that it inherits the properties and functions
   // common to all CDatas.
   dataProto = JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent);
   if (!dataProto)
     return false;
@@ -720,24 +719,28 @@ InitInt64Class(JSContext* cx,
     return NULL;
 
   JSObject* ctor = JS_GetConstructor(cx, prototype);
   if (!ctor)
     return NULL;
   if (!JS_FreezeObject(cx, ctor))
     return NULL;
 
-  // Stash ctypes.{Int64,UInt64}.prototype on a reserved slot of the 'join'
-  // function.
-  jsval join;
-  ASSERT_OK(JS_GetProperty(cx, ctor, "join", &join));
-  if (!JS_SetReservedSlot(cx, JSVAL_TO_OBJECT(join), SLOT_FN_INT64PROTO,
-         OBJECT_TO_JSVAL(prototype)))
+  // Redefine the 'join' function as an extended native and stash
+  // ctypes.{Int64,UInt64}.prototype in a reserved slot of the new function.
+  JS_ASSERT(clasp == &sInt64ProtoClass || clasp == &sUInt64ProtoClass);
+  JSNative native = (clasp == &sInt64ProtoClass) ? Int64::Join : UInt64::Join;
+  JSFunction* fun = js::DefineFunctionWithReserved(cx, ctor, "join", native,
+                      2, CTYPESFN_FLAGS);
+  if (!fun)
     return NULL;
 
+  js::SetFunctionNativeReserved(fun, SLOT_FN_INT64PROTO,
+    OBJECT_TO_JSVAL(prototype));
+
   if (!JS_FreezeObject(cx, prototype))
     return NULL;
 
   return prototype;
 }
 
 static JSBool
 AttachProtos(JSContext* cx, JSObject* proto, JSObject** protos)
@@ -3040,18 +3043,17 @@ CType::GetName(JSContext* cx, JSObject* 
   return JSVAL_TO_STRING(string);
 }
 
 JSObject*
 CType::GetProtoFromCtor(JSContext* cx, JSObject* obj, CTypeProtoSlot slot)
 {
   // Get ctypes.{Pointer,Array,Struct}Type.prototype from a reserved slot
   // on the type constructor.
-  jsval protoslot;
-  ASSERT_OK(JS_GetReservedSlot(cx, obj, SLOT_FN_CTORPROTO, &protoslot));
+  jsval protoslot = js::GetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO);
   JSObject* proto = JSVAL_TO_OBJECT(protoslot);
   JS_ASSERT(proto);
   JS_ASSERT(CType::IsCTypeProto(cx, proto));
 
   // Get the desired prototype.
   jsval result;
   ASSERT_OK(JS_GetReservedSlot(cx, proto, slot, &result));
   return JSVAL_TO_OBJECT(result);
@@ -6286,18 +6288,17 @@ Int64::Join(JSContext* cx, uintN argc, j
   if (!jsvalToInteger(cx, argv[1], &lo))
     return TypeError(cx, "uint32", argv[1]);
 
   JSInt64 i = (JSInt64(hi) << 32) + JSInt64(lo);
 
   // Get Int64.prototype from the function's reserved slot.
   JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
 
-  jsval slot;
-  ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot));
+  jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
   JSObject* proto = JSVAL_TO_OBJECT(slot);
   JS_ASSERT(JS_GET_CLASS(cx, proto) == &sInt64ProtoClass);
 
   JSObject* result = Int64Base::Construct(cx, proto, i, false);
   if (!result)
     return JS_FALSE;
 
   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
@@ -6454,18 +6455,17 @@ UInt64::Join(JSContext* cx, uintN argc, 
   if (!jsvalToInteger(cx, argv[1], &lo))
     return TypeError(cx, "uint32_t", argv[1]);
 
   JSUint64 u = (JSUint64(hi) << 32) + JSUint64(lo);
 
   // Get UInt64.prototype from the function's reserved slot.
   JSObject* callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
 
-  jsval slot;
-  ASSERT_OK(JS_GetReservedSlot(cx, callee, SLOT_FN_INT64PROTO, &slot));
+  jsval slot = js::GetFunctionNativeReserved(callee, SLOT_FN_INT64PROTO);
   JSObject* proto = JSVAL_TO_OBJECT(slot);
   JS_ASSERT(JS_GET_CLASS(cx, proto) == &sUInt64ProtoClass);
 
   JSObject* result = Int64Base::Construct(cx, proto, u, true);
   if (!result)
     return JS_FALSE;
 
   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -88,17 +88,17 @@ DefineGlobals(JSContext *cx, GlobalScope
          * the global directly during compilation and avoid having to emit type
          * checks every time it is accessed in the script.
          */
         const Shape *shape =
             DefineNativeProperty(cx, globalObj, id, rval, JS_PropertyStub, JS_StrictPropertyStub,
                                  JSPROP_ENUMERATE | JSPROP_PERMANENT, 0, 0, DNP_SKIP_TYPE);
         if (!shape)
             return false;
-        def.knownSlot = shape->slot;
+        def.knownSlot = shape->slot();
     }
 
     Vector<JSScript *, 16> worklist(cx);
     if (!worklist.append(script))
         return false;
 
     /*
      * Recursively walk through all scripts we just compiled. For each script,
@@ -118,20 +118,20 @@ DefineGlobals(JSContext *cx, GlobalScope
              * stored in the first object slot as an inner function.
              */
             size_t start = outer->savedCallerFun ? 1 : 0;
 
             for (size_t i = start; i < arr->length; i++) {
                 JSObject *obj = arr->vector[i];
                 if (!obj->isFunction())
                     continue;
-                JSFunction *fun = obj->getFunctionPrivate();
+                JSFunction *fun = obj->toFunction();
                 JS_ASSERT(fun->isInterpreted());
                 JSScript *inner = fun->script();
-                if (outer->isHeavyweightFunction) {
+                if (outer->function() && outer->function()->isHeavyweight()) {
                     outer->isOuterFunction = true;
                     inner->isInnerFunction = true;
                 }
                 if (!JSScript::isValidOffset(inner->globalsOffset) &&
                     !JSScript::isValidOffset(inner->objectsOffset)) {
                     continue;
                 }
                 if (!worklist.append(inner))
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1378,17 +1378,17 @@ frontend::PushStatement(TreeContext *tc,
 }
 
 void
 frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, ObjectBox *blockBox, ptrdiff_t top)
 {
     PushStatement(tc, stmt, STMT_BLOCK, top);
     stmt->flags |= SIF_SCOPE;
     blockBox->parent = tc->blockChainBox;
-    blockBox->object->setParent(tc->blockChain());
+    blockBox->object->setStaticBlockScopeChain(tc->blockChain());
     stmt->downScope = tc->topScopeStmt;
     tc->topScopeStmt = stmt;
     tc->blockChainBox = blockBox;
     stmt->blockBox = blockBox;
 }
 
 /*
  * Emit a backpatch op with offset pointing to the previous jump of this type,
@@ -1716,17 +1716,17 @@ frontend::LexicalLookup(TreeContext *tc,
         JS_ASSERT(obj->isStaticBlock());
 
         const Shape *shape = obj->nativeLookup(tc->parser->context, ATOM_TO_JSID(atom));
         if (shape) {
             JS_ASSERT(shape->hasShortID());
 
             if (slotp) {
                 JS_ASSERT(obj->getSlot(JSSLOT_BLOCK_DEPTH).isInt32());
-                *slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid;
+                *slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid();
             }
             return stmt;
         }
     }
 
     if (slotp)
         *slotp = -1;
     return stmt;
@@ -1776,18 +1776,18 @@ LookupCompileTimeConstant(JSContext *cx,
                 if (shape) {
                     /*
                      * We're compiling code that will be executed immediately,
                      * not re-executed against a different scope chain and/or
                      * variable object.  Therefore we can get constant values
                      * from our variable object here.
                      */
                     if (!shape->writable() && !shape->configurable() &&
-                        shape->hasDefaultGetter() && obj->containsSlot(shape->slot)) {
-                        *constp = obj->getSlot(shape->slot);
+                        shape->hasDefaultGetter() && obj->containsSlot(shape->slot())) {
+                        *constp = obj->getSlot(shape->slot());
                     }
                 }
 
                 if (shape)
                     break;
             }
         }
     } while (bce->parent && (bce = bce->parent->asBytecodeEmitter()));
@@ -2015,18 +2015,23 @@ EmitEnterBlock(JSContext *cx, ParseNode 
     }
 
     /*
      * If clones of this block will have any extensible parents, then the
      * clones must get unique shapes; see the comments for
      * js::Bindings::extensibleParents.
      */
     if ((bce->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
-        bce->bindings.extensibleParents())
-        blockObj->setBlockOwnShape(cx);
+        bce->bindings.extensibleParents()) {
+        HeapPtrShape shape;
+        shape.init(blockObj->lastProperty());
+        if (!Shape::setExtensibleParents(cx, &shape))
+            return false;
+        blockObj->setLastPropertyInfallible(shape);
+    }
 
     return true;
 }
 
 static JSBool
 EmitLeaveBlock(JSContext *cx, BytecodeEmitter *bce, JSOp op, ObjectBox *box)
 {
     JSOp bigSuffix;
@@ -2327,17 +2332,16 @@ BindNameToSlot(JSContext *cx, BytecodeEm
     uint16 level = cookie.level();
     JS_ASSERT(bce->staticLevel >= level);
 
     const uintN skip = bce->staticLevel - level;
     if (skip != 0) {
         JS_ASSERT(bce->inFunction());
         JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, bce->roLexdeps->lookup(atom));
         JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
-        JS_ASSERT(bce->fun()->u.i.skipmin <= skip);
 
         /*
          * If op is a mutating opcode, this upvar's lookup skips too many levels,
          * or the function is heavyweight, we fall back on JSOP_*NAME*.
          */
         if (op != JSOP_NAME)
             return JS_TRUE;
         if (skip >= UpvarCookie::UPVAR_LEVEL_LIMIT)
@@ -3839,23 +3843,16 @@ frontend::EmitFunctionScript(JSContext *
      */
     if (bce->needsEagerArguments()) {
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0 || Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         bce->switchToMain();
     }
 
-    if (bce->flags & TCF_FUN_UNBRAND_THIS) {
-        bce->switchToProlog();
-        if (Emit1(cx, bce, JSOP_UNBRANDTHIS) < 0)
-            return false;
-        bce->switchToMain();
-    }
-
     return EmitTree(cx, bce, body) &&
            Emit1(cx, bce, JSOP_STOP) >= 0 &&
            JSScript::NewScriptFromEmitter(cx, bce);
 }
 
 static bool
 MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
                  jsatomid *result)
@@ -4751,17 +4748,17 @@ ParseNode::getConstantValue(JSContext *c
 
         types::FixArrayType(cx, obj);
         vp->setObject(*obj);
         return true;
       }
       case PNK_RC: {
         JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
 
-        gc::AllocKind kind = GuessObjectGCKind(pn_count, false);
+        gc::AllocKind kind = GuessObjectGCKind(pn_count);
         JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
         if (!obj)
             return false;
 
         for (ParseNode *pn = pn_head; pn; pn = pn->pn_next) {
             Value value;
             if (!pn->pn_right->getConstantValue(cx, strictChecks, &value))
                 return false;
@@ -5443,16 +5440,50 @@ EmitWith(JSContext *cx, BytecodeEmitter 
     if (!EmitTree(cx, bce, pn->pn_right))
         return false;
     if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
         return false;
     return PopStatementBCE(cx, bce);
 }
 
 static bool
+SetMethodFunction(JSContext *cx, FunctionBox *funbox, JSAtom *atom)
+{
+    /*
+     * Replace a boxed function with a new one with a method atom. Methods
+     * require a function with the extended size finalize kind, which normal
+     * functions don't have. We don't eagerly allocate functions with the
+     * expanded size for boxed functions, as most functions are not methods.
+     */
+    JSFunction *fun = js_NewFunction(cx, NULL, NULL,
+                                     funbox->function()->nargs,
+                                     funbox->function()->flags,
+                                     funbox->function()->getParent(),
+                                     funbox->function()->atom,
+                                     JSFunction::ExtendedFinalizeKind);
+    if (!fun)
+        return false;
+
+    JSScript *script = funbox->function()->script();
+    if (script) {
+        fun->setScript(script);
+        if (!script->typeSetFunction(cx, fun))
+            return false;
+    }
+
+    JS_ASSERT(funbox->function()->joinable());
+    fun->setJoinable();
+
+    fun->setMethodAtom(atom);
+
+    funbox->object = fun;
+    return true;
+}
+
+static bool
 EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     StmtInfo stmtInfo;
     PushStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
 
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
@@ -6324,16 +6355,18 @@ frontend::EmitTree(JSContext *cx, Byteco
                      * script evaluator, to ensure that the joined function
                      * can't escape directly.
                      */
                     if (!wantval &&
                         pn2->isKind(PNK_ASSIGN) &&
                         pn2->pn_left->isOp(JSOP_SETPROP) &&
                         pn2->pn_right->isOp(JSOP_LAMBDA) &&
                         pn2->pn_right->pn_funbox->joinable()) {
+                        if (!SetMethodFunction(cx, pn2->pn_right->pn_funbox, pn2->pn_left->pn_atom))
+                            return JS_FALSE;
                         pn2->pn_left->setOp(JSOP_SETMETHOD);
                     }
                     if (!EmitTree(cx, bce, pn2))
                         return JS_FALSE;
                     if (Emit1(cx, bce, op) < 0)
                         return JS_FALSE;
                 }
             }
@@ -7091,17 +7124,17 @@ frontend::EmitTree(JSContext *cx, Byteco
             return JS_FALSE;
 
         /*
          * Try to construct the shape of the object as we go, so we can emit a
          * JSOP_NEWOBJECT with the final shape instead.
          */
         JSObject *obj = NULL;
         if (!bce->hasSharps() && bce->compileAndGo()) {
-            gc::AllocKind kind = GuessObjectGCKind(pn->pn_count, false);
+            gc::AllocKind kind = GuessObjectGCKind(pn->pn_count);
             obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
             if (!obj)
                 return JS_FALSE;
         }
 
         uintN methodInits = 0, slowMethodInits = 0;
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
@@ -7139,16 +7172,18 @@ frontend::EmitTree(JSContext *cx, Byteco
                 ParseNode *init = pn2->pn_right;
                 bool lambda = init->isOp(JSOP_LAMBDA);
                 if (lambda)
                     ++methodInits;
                 if (op == JSOP_INITPROP && lambda && init->pn_funbox->joinable()) {
                     obj = NULL;
                     op = JSOP_INITMETHOD;
                     pn2->setOp(op);
+                    if (!SetMethodFunction(cx, init->pn_funbox, pn3->pn_atom))
+                        return JS_FALSE;
                 } else {
                     /*
                      * Disable NEWOBJECT on initializers that set __proto__, which has
                      * a non-standard setter on objects.
                      */
                     if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
                         obj = NULL;
                     op = JSOP_INITPROP;
@@ -7166,21 +7201,16 @@ frontend::EmitTree(JSContext *cx, Byteco
                     if (obj->inDictionaryMode())
                         obj = NULL;
                 }
 
                 EMIT_INDEX_OP(op, index);
             }
         }
 
-        if (bce->funbox && bce->funbox->shouldUnbrand(methodInits, slowMethodInits)) {
-            obj = NULL;
-            if (Emit1(cx, bce, JSOP_UNBRAND) < 0)
-                return JS_FALSE;
-        }
         if (!EmitEndInit(cx, bce, pn->pn_count))
             return JS_FALSE;
 
         if (obj) {
             /*
              * The object survived and has a predictable shape.  Update the original bytecode,
              * as long as we can do so without using a big index prefix/suffix.
              */
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -199,25 +199,16 @@ struct StmtInfo {
  * certain strict warnings as errors, and forbid the use of 'with'. See also
  * TSF_STRICT_MODE_CODE, JSScript::strictModeCode, and JSREPORT_STRICT_ERROR.
  */
 #define TCF_STRICT_MODE_CODE    0x20000
 
 /* bits 0x40000 and 0x80000 are unused */
 
 /*
- * Flag signifying that the current function seems to be a constructor that
- * sets this.foo to define "methods", at least one of which can't be a null
- * closure, so we should avoid over-specializing property cache entries and
- * trace inlining guards to method function object identity, which will vary
- * per instance.
- */
-#define TCF_FUN_UNBRAND_THIS   0x100000
-
-/*
  * "Module pattern", i.e., a lambda that is immediately applied and the whole
  * of an expression statement.
  */
 #define TCF_FUN_MODULE_PATTERN 0x200000
 
 /*
  * Flag to prevent a non-escaping function from being optimized into a null
  * closure (i.e., a closure that needs only its global object for free variable
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -128,30 +128,16 @@ FunctionBox::inAnyDynamicScope() const
 }
 
 bool
 FunctionBox::scopeIsExtensible() const
 {
     return tcflags & TCF_FUN_EXTENSIBLE_SCOPE;
 }
 
-bool
-FunctionBox::shouldUnbrand(uintN methods, uintN slowMethods) const
-{
-    if (slowMethods != 0) {
-        for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) {
-            if (!(funbox->tcflags & TCF_FUN_MODULE_PATTERN))
-                return true;
-            if (funbox->inLoop)
-                return true;
-        }
-    }
-    return false;
-}
-
 /* Add |node| to |parser|'s free node list. */
 void
 ParseNodeAllocator::freeNode(ParseNode *pn)
 {
     /* Catch back-to-back dup recycles. */
     JS_ASSERT(pn != freelist);
 
     /* 
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1266,28 +1266,16 @@ struct FunctionBox : public ObjectBox
      */
     bool inAnyDynamicScope() const;
 
     /* 
      * Must this function's descendants be marked as having an extensible
      * ancestor?
      */
     bool scopeIsExtensible() const;
-
-    /*
-     * Unbrand an object being initialized or constructed if any method cannot
-     * be joined to one compiler-created null closure shared among N different
-     * closure environments.
-     *
-     * We despecialize from caching function objects, caching slots or shapes
-     * instead, because an unbranded object may still have joined methods (for
-     * which shape->isMethod), since PropertyCache::fill gives precedence to
-     * joined methods over branded methods.
-     */
-    bool shouldUnbrand(uintN methods, uintN slowMethods) const;
 };
 
 struct FunctionBoxQueue {
     FunctionBox         **vector;
     size_t              head, tail;
     size_t              lengthMask;
 
     size_t count()  { return head - tail; }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -528,17 +528,17 @@ js::CheckStrictParameters(JSContext *cx,
 
     /* name => whether we've warned about the name already */
     HashMap<JSAtom *, bool> parameters(cx);
     if (!parameters.init(tc->bindings.countArgs()))
         return false;
 
     /* Start with lastVariable(), not lastArgument(), for destructuring. */
     for (Shape::Range r = tc->bindings.lastVariable(); !r.empty(); r.popFront()) {
-        jsid id = r.front().propid;
+        jsid id = r.front().propid();
         if (!JSID_IS_ATOM(id))
             continue;
 
         JSAtom *name = JSID_TO_ATOM(id);
 
         if (name == argumentsAtom || name == evalAtom) {
             if (!ReportBadParameter(cx, tc, name, JSMSG_BAD_BINDING))
                 return false;
@@ -927,18 +927,21 @@ Parser::newFunction(TreeContext *tc, JSA
         tc = tc->parent;
     JSObject *parent = tc->inFunction() ? NULL : tc->scopeChain();
 
     JSFunction *fun =
         js_NewFunction(context, NULL, NULL, 0,
                        JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0),
                        parent, atom);
     if (fun && !tc->compileAndGo()) {
-        fun->clearParent();
-        fun->clearType();
+        if (!fun->clearParent(context))
+            return NULL;
+        if (!fun->clearType(context))
+            return NULL;
+        fun->setEnvironment(NULL);
     }
     return fun;
 }
 
 static JSBool
 MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts)
 {
     TokenKind tt = ts->peekTokenSameLine(TSF_OPERAND);
@@ -1164,17 +1167,17 @@ LeaveFunction(ParseNode *fn, TreeContext
 
     /*
      * Check whether any parameters have been assigned within this function.
      * In strict mode parameters do not alias arguments[i], and to make the
      * arguments object reflect initial parameter values prior to any mutation
      * we create it eagerly whenever parameters are (or might, in the case of
      * calls to eval) be assigned.
      */
-    if (funtc->inStrictMode() && funbox->object->getFunctionPrivate()->nargs > 0) {
+    if (funtc->inStrictMode() && funbox->object->toFunction()->nargs > 0) {
         AtomDeclsIter iter(&funtc->decls);
         Definition *dn;
 
         while ((dn = iter()) != NULL) {
             if (dn->kind() == Definition::ARG && dn->isAssigned()) {
                 funbox->tcflags |= TCF_FUN_MUTATES_PARAMETER;
                 break;
             }
@@ -1946,46 +1949,39 @@ BindLet(JSContext *cx, BindData *data, J
 
     /*
      * Store pn temporarily in what would be shape-mapped slots in a cloned
      * block object (once the prototype's final population is known, after all
      * 'let' bindings for this block have been parsed). We free these slots in
      * BytecodeEmitter.cpp:EmitEnterBlock so they don't tie up unused space
      * in the so-called "static" prototype Block.
      */
-    blockObj->setSlot(shape->slot, PrivateValue(pn));
+    blockObj->setSlot(shape->slot(), PrivateValue(pn));
     return true;
 }
 
 static void
 PopStatement(TreeContext *tc)
 {
     StmtInfo *stmt = tc->topStmt;
 
     if (stmt->flags & SIF_SCOPE) {
         JSObject *obj = stmt->blockBox->object;
         JS_ASSERT(!obj->isClonedBlock());
 
         for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
-            JSAtom *atom = JSID_TO_ATOM(r.front().propid);
+            JSAtom *atom = JSID_TO_ATOM(r.front().propid());
 
             /* Beware the empty destructuring dummy. */
             if (atom == tc->parser->context->runtime->atomState.emptyAtom)
                 continue;
             tc->decls.remove(atom);
         }
 
-        /*
-         * js_CloneBlockObject requires obj's shape to be frozen. Compare
-         * Bindings::makeImmutable.
-         *
-         * (This is a second pass over the shapes, if obj has a dictionary, but
-         * that is rare.)
-         */
-        obj->lastProp->freezeIfDictionary();
+        JS_ASSERT(!obj->inDictionaryMode());
     }
     PopStatementTC(tc);
 }
 
 static inline bool
 OuterLet(TreeContext *tc, StmtInfo *stmt, JSAtom *atom)
 {
     while (stmt->downScope) {
@@ -2046,17 +2042,17 @@ DefineGlobal(ParseNode *pn, BytecodeEmit
                 globalObj != holder ||
                 shape->configurable() ||
                 !shape->hasSlot() ||
                 !shape->hasDefaultGetterOrIsMethod() ||
                 !shape->hasDefaultSetter()) {
                 return true;
             }
 
-            def = GlobalScope::GlobalDef(shape->slot);
+            def = GlobalScope::GlobalDef(shape->slot());
         } else {
             def = GlobalScope::GlobalDef(name, funbox);
         }
 
         if (!globalScope->defs.append(def))
             return false;
 
         jsatomid index = globalScope->names.count();
@@ -3682,17 +3678,17 @@ Parser::letStatement()
              * list stack, if it isn't already there.  If it is there, but it
              * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
              * block.
              */
             stmt->flags |= SIF_SCOPE;
             stmt->downScope = tc->topScopeStmt;
             tc->topScopeStmt = stmt;
 
-            obj->setParent(tc->blockChain());
+            obj->setStaticBlockScopeChain(tc->blockChain());
             blockbox->parent = tc->blockChainBox;
             tc->blockChainBox = blockbox;
             stmt->blockBox = blockbox;
 
 #ifdef DEBUG
             ParseNode *tmp = tc->blockNode;
             JS_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
 #endif
@@ -7151,18 +7147,20 @@ Parser::primaryExpr(TokenKind tt, JSBool
             reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
         else
             reobj = RegExpObject::createNoStatics(context, chars, length, flags, &tokenStream);
 
         if (!reobj)
             return NULL;
 
         if (!tc->compileAndGo()) {
-            reobj->clearParent();
-            reobj->clearType();
+            if (!reobj->clearParent(context))
+                return NULL;
+            if (!reobj->clearType(context))
+                return NULL;
         }
 
         pn->pn_objbox = tc->parser->newObjectBox(reobj);
         if (!pn->pn_objbox)
             return NULL;
 
         pn->setOp(JSOP_REGEXP);
         break;
--- a/js/src/frontend/SemanticAnalysis.cpp
+++ b/js/src/frontend/SemanticAnalysis.cpp
@@ -159,17 +159,16 @@ CleanFunctionList(ParseNodeAllocator *al
 static uintN
 FindFunArgs(FunctionBox *funbox, int level, FunctionBoxQueue *queue)
 {
     uintN allskipmin = UpvarCookie::FREE_LEVEL;
 
     do {
         ParseNode *fn = funbox->node;
         JS_ASSERT(fn->isArity(PN_FUNC));
-        JSFunction *fun = funbox->function();
         int fnlevel = level;
 
         /*
          * An eval can leak funbox, functions along its ancestor line, and its
          * immediate kids. Since FindFunArgs uses DFS and the parser propagates
          * TCF_FUN_HEAVYWEIGHT bottom up, funbox's ancestor function nodes have
          * already been marked as funargs by this point. Therefore we have to
          * flag only funbox->node and funbox->kids' nodes here.
@@ -240,22 +239,20 @@ FindFunArgs(FunctionBox *funbox, int lev
                 --kidskipmin;
                 if (kidskipmin != 0 && kidskipmin < skipmin)
                     skipmin = kidskipmin;
             }
         }
 
         /*
          * Finally, after we've traversed all of the current function's kids,
-         * minimize fun's skipmin against our accumulated skipmin. Do likewise
-         * with allskipmin, but minimize across funbox and all of its siblings,
-         * to compute our return value.
+         * minimize allskipmin against our accumulated skipmin. Minimize across
+         * funbox and all of its siblings, to compute our return value.
          */
         if (skipmin != UpvarCookie::FREE_LEVEL) {
-            fun->u.i.skipmin = skipmin;
             if (skipmin < allskipmin)
                 allskipmin = skipmin;
         }
     } while ((funbox = funbox->siblings) != NULL);
 
     return allskipmin;
 }
 
@@ -508,66 +505,24 @@ FlagHeavyweights(Definition *dn, Functio
         funbox->tcflags |= TCF_FUN_ENTRAINS_SCOPES;
     }
 
     if (!funbox && (*tcflags & TCF_IN_FUNCTION))
         *tcflags |= TCF_FUN_HEAVYWEIGHT;
 }
 
 static void
-ConsiderUnbranding(FunctionBox *funbox)
-{
-    /*
-     * We've already recursively set our kids' kinds, which also classifies
-     * enclosing functions holding upvars referenced in those descendants'
-     * bodies. So now we can check our "methods".
-     *
-     * Despecialize from branded method-identity-based shape to shape- or
-     * slot-based shape if this function smells like a constructor and too many
-     * of its methods are *not* joinable null closures (i.e., they have one or
-     * more upvars fetched via the display).
-     */
-    bool returnsExpr = !!(funbox->tcflags & TCF_RETURN_EXPR);
-#if JS_HAS_EXPR_CLOSURES
-    {
-        ParseNode *pn2 = funbox->node->pn_body;
-        if (pn2->isKind(PNK_UPVARS))
-            pn2 = pn2->pn_tree;
-        if (pn2->isKind(PNK_ARGSBODY))
-            pn2 = pn2->last();
-        if (!pn2->isKind(PNK_STATEMENTLIST))
-            returnsExpr = true;
-    }
-#endif
-    if (!returnsExpr) {
-        uintN methodSets = 0, slowMethodSets = 0;
-
-        for (ParseNode *method = funbox->methods; method; method = method->pn_link) {
-            JS_ASSERT(method->isOp(JSOP_LAMBDA) || method->isOp(JSOP_LAMBDA_FC));
-            ++methodSets;
-            if (!method->pn_funbox->joinable())
-                ++slowMethodSets;
-        }
-
-        if (funbox->shouldUnbrand(methodSets, slowMethodSets))
-            funbox->tcflags |= TCF_FUN_UNBRAND_THIS;
-    }
-}
-
-static void
 SetFunctionKinds(FunctionBox *funbox, uint32 *tcflags, bool isDirectEval)
 {
     for (; funbox; funbox = funbox->siblings) {
         ParseNode *fn = funbox->node;
         ParseNode *pn = fn->pn_body;
 
-        if (funbox->kids) {
+        if (funbox->kids)
             SetFunctionKinds(funbox->kids, tcflags, isDirectEval);
-            ConsiderUnbranding(funbox);
-        }
 
         JSFunction *fun = funbox->function();
 
         JS_ASSERT(fun->kind() == JSFUN_INTERPRETED);
 
         if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) {
             /* nothing to do */
         } else if (isDirectEval || funbox->inAnyDynamicScope()) {
@@ -669,42 +624,49 @@ SetFunctionKinds(FunctionBox *funbox, ui
  * and functions that contain function statements (definitions not appearing
  * within the top statement list, which don't take effect unless they are
  * evaluated). Such call objects may acquire bindings that shadow variables
  * defined in enclosing scopes, so any enclosed functions must have their
  * bindings' extensibleParents flags set, and enclosed compiler-created blocks
  * must have their OWN_SHAPE flags set; the comments for
  * js::Bindings::extensibleParents explain why.
  */
-static void
-MarkExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensibleParent) 
+static bool
+MarkExtensibleScopeDescendants(JSContext *context, FunctionBox *funbox, bool hasExtensibleParent) 
 {
     for (; funbox; funbox = funbox->siblings) {
         /*
          * It would be nice to use fun->kind() here to recognize functions
          * that will never consult their parent chains, and thus don't need
          * their 'extensible parents' flag set. Filed as bug 619750.
          */
 
         JS_ASSERT(!funbox->bindings.extensibleParents());
-        if (hasExtensibleParent)
-            funbox->bindings.setExtensibleParents();
+        if (hasExtensibleParent) {
+            if (!funbox->bindings.setExtensibleParents(context))
+                return false;
+        }
 
         if (funbox->kids) {
-            MarkExtensibleScopeDescendants(funbox->kids,
-                                           hasExtensibleParent || funbox->scopeIsExtensible());
+            if (!MarkExtensibleScopeDescendants(context, funbox->kids,
+                                                hasExtensibleParent || funbox->scopeIsExtensible())) {
+                return false;
+            }
         }
     }
+
+    return true;
 }
 
 bool
 frontend::AnalyzeFunctions(TreeContext *tc)
 {
     CleanFunctionList(&tc->parser->allocator, &tc->functionList);
     if (!tc->functionList)
         return true;
     if (!MarkFunArgs(tc->parser->context, tc->functionList, tc->parser->functionCount))
         return false;
-    MarkExtensibleScopeDescendants(tc->functionList, false);
+    if (!MarkExtensibleScopeDescendants(tc->parser->context, tc->functionList, false))
+        return false;
     bool isDirectEval = !!tc->parser->callerFrame;
     SetFunctionKinds(tc->functionList, &tc->flags, isDirectEval);
     return true;
 }
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -266,17 +266,18 @@ BarrieredSetPair(JSCompartment *comp,
     v2.post();
 }
 
 typedef HeapPtr<JSObject> HeapPtrObject;
 typedef HeapPtr<JSFunction> HeapPtrFunction;
 typedef HeapPtr<JSString> HeapPtrString;
 typedef HeapPtr<JSScript> HeapPtrScript;
 typedef HeapPtr<Shape> HeapPtrShape;
-typedef HeapPtr<const Shape> HeapPtrConstShape;
+typedef HeapPtr<BaseShape> HeapPtrBaseShape;
+typedef HeapPtr<types::TypeObject> HeapPtrTypeObject;
 typedef HeapPtr<JSXML> HeapPtrXML;
 
 /* Useful for hashtables with a HeapPtr as key. */
 template<class T>
 struct HeapPtrHasher
 {
     typedef HeapPtr<T> Key;
     typedef T *Lookup;
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -187,17 +187,16 @@ Statistics::beginGC(JSCompartment *comp,
     PodArrayZero(phaseTimes);
 
     triggerReason = reason;
 
     beginPhase(PHASE_GC);
     Probes::GCStart(compartment);
 
     GCCrashData crashData;
-    crashData.isRegen = runtime->shapeGen & SHAPE_OVERFLOW_BIT;
     crashData.isCompartment = !!compartment;
     crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
 }
 
 double
 Statistics::t(Phase phase)
 {
     return double(phaseTimes[phase]) / PRMJ_USEC_PER_MSEC;
@@ -272,18 +271,17 @@ Statistics::endGC()
     crash::SnapshotGCStack();
 
     for (int i = 0; i < PHASE_LIMIT; i++)
         totals[i] += phaseTimes[i];
 
     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
         (*cb)(JS_TELEMETRY_GC_REASON, triggerReason);
         (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0);
-        (*cb)(JS_TELEMETRY_GC_IS_SHAPE_REGEN,
-              runtime->shapeGen & SHAPE_OVERFLOW_BIT ? 1 : 0);
+        (*cb)(JS_TELEMETRY_GC_IS_SHAPE_REGEN, 0);
         (*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC));
         (*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK));
         (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP));
     }
 
     if (JSGCFinishedCallback cb = runtime->gcFinishedCallback) {
         char buffer[1024];
         statsToString(buffer, sizeof(buffer));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug690732.js
@@ -0,0 +1,4 @@
+
+var o4 = Object.freeze({ 
+  set: function(summary) {}       
+});
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug699166.js
@@ -0,0 +1,7 @@
+a = "".__proto__
+b = uneval().__proto__
+for (var i = 0; i < 2; i++) {
+    a.__defineSetter__("valueOf", function() {})
+    a + ""
+    delete b.valueOf
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug700300.js
@@ -0,0 +1,4 @@
+for (let j = 0; j < (20); ++(__lookupSetter__)) {
+  function g() { j; }
+  j++;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug700501.js
@@ -0,0 +1,13 @@
+Function.prototype.__proto__["p"] = 3
+c = [].__proto__
+c[5] = 3
+Namespace.prototype.__proto__[4] = function() {}
+gc()
+Function("\
+    {\
+    function f(d) {}\
+    for each(let z in[0]) {\
+        f(z)\
+    }\
+    }\
+")()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug700799.js
@@ -0,0 +1,1 @@
+for (let x in [<y/>.(let(x) function() {})]) {}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug703818.js
@@ -0,0 +1,3 @@
+Object.defineProperty(Namespace.prototype, "toString", {
+    enumerable: true
+})
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug704134.js
@@ -0,0 +1,12 @@
+function f(s) {
+    eval(s);
+    return function() {
+        with({}) {};
+        return b;
+    };
+}
+var b = 1;
+var g1 = f("");
+var g2 = f("var b = 2;");
+g1('');
+assertEq(g2(''), 2);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug705895-1.js
@@ -0,0 +1,11 @@
+c = (0).__proto__
+function f(o) {
+    o.__proto__ = null
+    for (x in o) {}
+}
+for (i = 0; i < 9; i++) {
+    f(c)
+    Function.prototype.__proto__.__proto__ = c
+    for (x in Function.prototype.__proto__) {}
+    f(Math.__proto__)
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug705895-2.js
@@ -0,0 +1,13 @@
+// |jit-test| error: TypeError
+function f(o) {
+    for (j = 0; j < 9; j++) {
+        if (j) {
+            o.__proto__ = null
+        }
+        for (v in o) {}
+    }
+}
+for (i = 0; i < 9; i++) {
+    (new Boolean).__proto__.__defineGetter__("toString", function() {})
+    f(Boolean.prototype)
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-01.js
@@ -0,0 +1,9 @@
+// Check that an onExceptionUnwind hook can force a frame to return a value early.
+
+var g = newGlobal('new-compartment');
+var dbg = Debugger(g);
+dbg.onExceptionUnwind = function (frame, exc) {
+    return { return:"sproon" };
+};
+g.eval("function f() { throw 'ksnife'; }");
+assertEq(g.f(), "sproon");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-02.js
@@ -0,0 +1,10 @@
+// Check that if an onExceptionUnwind hook forces a constructor frame to
+// return a primitive value, it still gets wrapped up in an object.
+
+var g = newGlobal('new-compartment');
+var dbg = Debugger(g);
+dbg.onExceptionUnwind = function (frame, exc) {
+    return { return:"sproon" };
+};
+g.eval("function f() { throw 'ksnife'; }");
+assertEq(typeof new g.f, "object");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-03.js
@@ -0,0 +1,11 @@
+// Check that an onExceptionUnwind hook can force a frame to throw a different exception.
+
+load(libdir + "asserts.js");
+
+var g = newGlobal('new-compartment');
+var dbg = Debugger(g);
+dbg.onExceptionUnwind = function (frame, exc) {
+    return { throw:"sproon" };
+};
+g.eval("function f() { throw 'ksnife'; }");
+assertThrowsValue(g.f, "sproon");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-04.js
@@ -0,0 +1,17 @@
+// Check that an onExceptionUnwind hook can force a frame to terminate.
+
+var g = newGlobal('new-compartment');
+var dbg = Debugger(g);
+g.eval("function f() { throw 'ksnife'; }");
+var log = '';
+dbg.onDebuggerStatement = function (frame) {
+    log += 'd1';
+    assertEq(frame.eval("f();"), null);
+    log += 'd2';
+};
+dbg.onExceptionUnwind = function (frame, exc) {
+    log += 'u';
+    return null;
+};
+g.eval("debugger;");
+assertEq(log, "d1ud2");
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
@@ -1,14 +1,14 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in main. */
-  a = { valueOf: function () { trap(main, 58, "success()"); } };
+  a = { valueOf: function () { trap(main, 57, "success()"); } };
   b = "";
   eval();
   a + b;
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug704138.js
@@ -0,0 +1,17 @@
+function TestCase(n, d, e, a)
+  this.name=n;
+function reportCompare (expected, actual, description) {
+  new TestCase
+}
+reportCompare(true, "isGenerator" in Function, "Function.prototype.isGenerator present");
+var p = Proxy.create({
+    has : function(id) {}
+});
+function test() {
+    Object.prototype.__proto__=null
+    if (new TestCase)
+        Object.prototype.__proto__=p
+}
+test();
+new TestCase;
+test()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug705873.js
@@ -0,0 +1,7 @@
+a = []
+function f(o) {
+    o[5] = {}
+}
+for (var i = 0; i < 20; i++) {
+    with(a) f(a)
+}
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -169,17 +169,17 @@ BytecodeNoFallThrough(JSOp op)
 void
 ScriptAnalysis::analyzeBytecode(JSContext *cx)
 {
     JS_ASSERT(cx->compartment->activeAnalysis);
     JS_ASSERT(!ranBytecode());
     LifoAlloc &tla = cx->typeLifoAlloc();
 
     unsigned length = script->length;
-    unsigned nargs = script->hasFunction ? script->function()->nargs : 0;
+    unsigned nargs = script->function() ? script->function()->nargs : 0;
 
     numSlots = TotalSlots(script);
 
     codeArray = tla.newArray<Bytecode*>(length);
     escapedSlots = tla.newArray<JSPackedBool>(numSlots);
 
     if (!codeArray || !escapedSlots) {
         setOOM(cx);
@@ -221,25 +221,26 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
     /*
      * If the script is in debug mode, JS_SetFrameReturnValue can be called at
      * any safe point.
      */
     if (cx->compartment->debugMode())
         usesReturnValue_ = true;
 
+    bool heavyweight = script->function() && script->function()->isHeavyweight();
+
     isInlineable = true;
-    if (script->nClosedArgs || script->nClosedVars ||
-        (script->hasFunction && script->function()->isHeavyweight()) ||
+    if (script->nClosedArgs || script->nClosedVars || heavyweight ||
         script->usesEval || script->usesArguments || cx->compartment->debugMode()) {
         isInlineable = false;
     }
 
     modifiesArguments_ = false;
-    if (script->nClosedArgs || (script->hasFunction && script->function()->isHeavyweight()))
+    if (script->nClosedArgs || heavyweight)
         modifiesArguments_ = true;
 
     canTrackVars = true;
 
     /*
      * If we are in the middle of one or more jumps, the offset of the highest
      * target jumping over this bytecode.  Includes implicit jumps from
      * try/catch/finally blocks.
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -389,17 +389,17 @@ static inline uint32 CalleeSlot() {
 }
 static inline uint32 ThisSlot() {
     return 1;
 }
 static inline uint32 ArgSlot(uint32 arg) {
     return 2 + arg;
 }
 static inline uint32 LocalSlot(JSScript *script, uint32 local) {
-    return 2 + (script->hasFunction ? script->function()->nargs : 0) + local;
+    return 2 + (script->function() ? script->function()->nargs : 0) + local;
 }
 static inline uint32 TotalSlots(JSScript *script) {
     return LocalSlot(script, 0) + script->nfixed;
 }
 
 static inline uint32 StackSlot(JSScript *script, uint32 index) {
     return TotalSlots(script) + index;
 }
--- a/js/src/jsapi-tests/testArgumentsObject.cpp
+++ b/js/src/jsapi-tests/testArgumentsObject.cpp
@@ -1,18 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
 
 #include "vm/Stack-inl.h"
 
-#include "jsobjinlines.h"
-
 using namespace js;
 
 static const char NORMAL_ZERO[] =
     "function f() { return arguments; }";
 static const char NORMAL_ONE[] =
     "function f(a) { return arguments; }";
 static const char NORMAL_TWO[] =
     "function f(a, b) { return arguments; }";
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -3,18 +3,16 @@
  *
  * Tests JS_TransplantObject
  */
 
 #include "tests.h"
 #include "jsobj.h"
 #include "jswrapper.h"
 
-#include "jsobjinlines.h"
-
 struct OuterWrapper : js::Wrapper
 {
     OuterWrapper() : Wrapper(0) {}
 
     virtual bool isOuterWindow() {
         return true;
     }
 
--- a/js/src/jsapi-tests/testConservativeGC.cpp
+++ b/js/src/jsapi-tests/testConservativeGC.cpp
@@ -45,23 +45,18 @@ BEGIN_TEST(testConservativeGC)
     CHECK(!memcmp(&str2Copy, str2, sizeof(str2Copy)));
 
     return true;
 }
 
 bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
 {
     /* Ignore fields which are unstable across GCs. */
-    CHECK(savedCopy->lastProp == obj->lastProp);
-    CHECK(savedCopy->getClass() == obj->getClass());
-    CHECK(savedCopy->flags == obj->flags);
-    CHECK(savedCopy->newType == obj->newType);
+    CHECK(savedCopy->lastProperty() == obj->lastProperty());
     CHECK(savedCopy->getProto() == obj->getProto());
-    CHECK(savedCopy->parent == obj->parent);
-    CHECK(savedCopy->privateData == obj->privateData);
     return true;
 }
 
 END_TEST(testConservativeGC)
 
 BEGIN_TEST(testDerivedValues)
 {
   JSString *str = JS_NewStringCopyZ(cx, "once upon a midnight dreary");
--- a/js/src/jsapi-tests/testFuncCallback.cpp
+++ b/js/src/jsapi-tests/testFuncCallback.cpp
@@ -15,18 +15,17 @@ static void
 funcTransition(const JSFunction *,
                const JSScript *,
                const JSContext *cx,
                int entering)
 {
     if (entering > 0) {
         ++depth;
         ++enters;
-        if (! JS_ON_TRACE(cx))
-            ++interpreted;
+        ++interpreted;
     } else {
         --depth;
         ++leaves;
     }
 }
 
 static JSBool called2 = false;
 
@@ -88,22 +87,23 @@ BEGIN_TEST(testFuncCallback_bug507012)
     JS_SetFunctionCallback(cx, funcTransition);
     enters = leaves = depth = 0;
     EXEC("f(3)");
     CHECK_EQUAL(enters, 1+3);
     CHECK_EQUAL(leaves, 1+3);
     CHECK_EQUAL(depth, 0);
     interpreted = enters = leaves = depth = 0;
 
-    // Check calls invoked while running on trace
+    // Check calls invoked while running on trace -- or now, perhaps on
+    // IonMonkey's equivalent, if it ever starts to exist?
     EXEC("function g () { ++x; }");
     interpreted = enters = leaves = depth = 0;
-    EXEC("for (i = 0; i < 50; ++i) { g(); }");
-    CHECK_EQUAL(enters, 1+50);
-    CHECK_EQUAL(leaves, 1+50);
+    EXEC("for (i = 0; i < 5000; ++i) { g(); }");
+    CHECK_EQUAL(enters, 1+5000);
+    CHECK_EQUAL(leaves, 1+5000);
     CHECK_EQUAL(depth, 0);
 
     // Test nesting callbacks via JS_GetFunctionCallback()
     JS_SetFunctionCallback(cx, funcTransition);
     innerCallback = JS_GetFunctionCallback(cx);
     JS_SetFunctionCallback(cx, funcTransitionOverlay);
 
     EXEC("x = 0; function f (n) { if (n > 1) { f(n - 1); } }");
--- a/js/src/jsapi-tests/testIndexToString.cpp
+++ b/js/src/jsapi-tests/testIndexToString.cpp
@@ -4,18 +4,16 @@
 
 #include "tests.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsnum.h"
 #include "jsstr.h"
 
-#include "jsobjinlines.h"
-
 #include "vm/String-inl.h"
 
 using namespace mozilla;
 
 template<size_t N> JSFlatString *
 NewString(JSContext *cx, const jschar (&chars)[N])
 {
     return js_NewStringCopyN(cx, chars, N);
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
 #include "jsfun.h"  // for js::IsInternalFunctionObject
 
+#include "jsobjinlines.h"
+
 BEGIN_TEST(testLookup_bug522590)
 {
     // Define a function that makes method-bearing objects.
     jsvalRoot x(cx);
     EXEC("function mkobj() { return {f: function () {return 2;}} }");
 
     // Calling mkobj() multiple times must create multiple functions in ES5.
     EVAL("mkobj().f !== mkobj().f", x.addr());
@@ -21,17 +23,17 @@ BEGIN_TEST(testLookup_bug522590)
 
     // This lookup must not return an internal function object.
     jsvalRoot r(cx);
     CHECK(JS_LookupProperty(cx, xobj, "f", r.addr()));
     CHECK(JSVAL_IS_OBJECT(r));
     JSObject *funobj = JSVAL_TO_OBJECT(r);
     CHECK(funobj->isFunction());
     CHECK(!js::IsInternalFunctionObject(funobj));
-    CHECK(funobj->getFunctionPrivate() != (JSFunction *) funobj);
+    CHECK(funobj->toFunction()->isClonedMethod());
 
     return true;
 }
 END_TEST(testLookup_bug522590)
 
 JSBool
 document_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
 {
--- a/js/src/jsapi-tests/testVersion.cpp
+++ b/js/src/jsapi-tests/testVersion.cpp
@@ -1,13 +1,14 @@
 #include "tests.h"
 #include "jsscript.h"
 #include "jscntxt.h"
 
 #include "jscntxtinlines.h"
+#include "jsobjinlines.h"
 
 using namespace js;
 
 struct VersionFixture;
 
 /*
  * Fast-native callbacks for use from JS.
  * They set their results on the current fixture instance.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -331,21 +331,21 @@ JS_ConvertArgumentsVA(JSContext *cx, uin
             break;
           case 'o':
             if (!js_ValueToObjectOrNull(cx, *sp, &obj))
                 return JS_FALSE;
             *sp = OBJECT_TO_JSVAL(obj);
             *va_arg(ap, JSObject **) = obj;
             break;
           case 'f':
-            obj = js_ValueToFunctionObject(cx, sp, 0);
+            obj = js_ValueToFunction(cx, sp, 0);
             if (!obj)
                 return JS_FALSE;
             *sp = OBJECT_TO_JSVAL(obj);
-            *va_arg(ap, JSFunction **) = obj->getFunctionPrivate();
+            *va_arg(ap, JSFunction **) = obj->toFunction();
             break;
           case 'v':
             *va_arg(ap, jsval *) = *sp;
             break;
           case '*':
             break;
           default:
             format--;
@@ -424,17 +424,17 @@ JS_ConvertValue(JSContext *cx, jsval v, 
         break;
       case JSTYPE_OBJECT:
         ok = js_ValueToObjectOrNull(cx, v, &obj);
         if (ok)
             *vp = OBJECT_TO_JSVAL(obj);
         break;
       case JSTYPE_FUNCTION:
         *vp = v;
-        obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
+        obj = js_ValueToFunction(cx, vp, JSV2F_SEARCH_STACK);
         ok = (obj != NULL);
         break;
       case JSTYPE_STRING:
         str = js_ValueToString(cx, v);
         ok = (str != NULL);
         if (ok)
             *vp = STRING_TO_JSVAL(str);
         break;
@@ -640,17 +640,16 @@ JSRuntime::JSRuntime()
 #ifdef JS_THREADSAFE
     atomsCompartmentIsLocked(false),
 #endif
     state(),
     cxCallback(NULL),
     compartmentCallback(NULL),
     activityCallback(NULL),
     activityCallbackArg(NULL),
-    protoHazardShape(0),
     gcSystemAvailableChunkListHead(NULL),
     gcUserAvailableChunkListHead(NULL),
     gcKeepAtoms(0),
     gcBytes(0),
     gcTriggerBytes(0),
     gcLastBytes(0),
     gcMaxBytes(0),
     gcMaxMallocBytes(0),
@@ -667,17 +666,16 @@ JSRuntime::JSRuntime()
     gcWeakMapList(NULL),
     gcStats(thisFromCtor()),
     gcTriggerCompartment(NULL),
     gcCurrentCompartment(NULL),
     gcCheckCompartment(NULL),
     gcPoke(false),
     gcMarkAndSweep(false),
     gcRunning(false),
-    gcRegenShapes(false),
 #ifdef JS_GC_ZEAL
     gcZeal_(0),
     gcZealFrequency(0),
     gcNextScheduled(0),
     gcDebugCompartmentGC(false),
 #endif
     gcCallback(NULL),
     gcFinishedCallback(NULL),
@@ -721,17 +719,16 @@ JSRuntime::JSRuntime()
     anynameObject(NULL),
     functionNamespaceObject(NULL),
 #ifdef JS_THREADSAFE
     interruptCounter(0),
 #else
     threadData(thisFromCtor()),
 #endif
     trustedPrincipals_(NULL),
-    shapeGen(0),
     wrapObjectCallback(NULL),
     preWrapObjectCallback(NULL),
     inOOMReport(0)
 {
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&contextList);
     JS_INIT_CLIST(&debuggerList);
 
@@ -2378,16 +2375,20 @@ JS_PrintTraceThingInfo(char *buf, size_t
       case JSTRACE_SCRIPT:
         name = "script";
         break;
 
       case JSTRACE_SHAPE:
         name = "shape";
         break;
 
+      case JSTRACE_BASE_SHAPE:
+        name = "base_shape";
+        break;
+
       case JSTRACE_TYPE_OBJECT:
         name = "type_object";
         break;
 
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_XML:
         name = "xml";
         break;
@@ -2406,17 +2407,17 @@ JS_PrintTraceThingInfo(char *buf, size_t
         bufsize--;
 
         switch (kind) {
           case JSTRACE_OBJECT:
           {
             JSObject  *obj = (JSObject *)thing;
             Class *clasp = obj->getClass();
             if (clasp == &FunctionClass) {
-                JSFunction *fun = obj->getFunctionPrivate();
+                JSFunction *fun = obj->toFunction();
                 if (!fun) {
                     JS_snprintf(buf, bufsize, "<newborn>");
                 } else if (fun != obj) {
                     JS_snprintf(buf, bufsize, "%p", fun);
                 } else {
                     if (fun->atom)
                         PutEscapedString(buf, bufsize, fun->atom, 0);
                 }
@@ -2441,16 +2442,17 @@ JS_PrintTraceThingInfo(char *buf, size_t
           case JSTRACE_SCRIPT:
           {
             JSScript *script = static_cast<JSScript *>(thing);
             JS_snprintf(buf, bufsize, "%s:%u", script->filename, unsigned(script->lineno));
             break;
           }
 
           case JSTRACE_SHAPE:
+          case JSTRACE_BASE_SHAPE:
           case JSTRACE_TYPE_OBJECT:
             break;
 
 #if JS_HAS_XML_SUPPORT
           case JSTRACE_XML:
           {
             extern const char *js_xml_class_str[];
             JSXML *xml = (JSXML *)thing;
@@ -3075,69 +3077,61 @@ JS_GetInstancePrivate(JSContext *cx, JSO
     if (!JS_InstanceOf(cx, obj, clasp, argv))
         return NULL;
     return obj->getPrivate();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetPrototype(JSContext *cx, JSObject *obj)
 {
-    JSObject *proto;
-
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    proto = obj->getProto();
-
-    /* Beware ref to dead object (we may be called from obj's finalizer). */
-    return proto && !proto->isNewborn() ? proto : NULL;
+    return obj->getProto();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, proto);
     return SetProto(cx, obj, proto, JS_FALSE);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetParent(JSContext *cx, JSObject *obj)
 {
+    JS_ASSERT(!obj->isInternalScope());
     assertSameCompartment(cx, obj);
-    JSObject *parent = obj->getParent();
-
-    /* Beware ref to dead object (we may be called from obj's finalizer). */
-    return parent && !parent->isNewborn() ? parent : NULL;
+    return obj->getParent();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
 {
     CHECK_REQUEST(cx);
+    JS_ASSERT(!obj->isInternalScope());
     JS_ASSERT(parent || !obj->getParent());
     assertSameCompartment(cx, obj, parent);
-    obj->setParent(parent);
-    return true;
+    return obj->setParent(cx, parent);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetConstructor(JSContext *cx, JSObject *proto)
 {
     Value cval;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto);
     {
         JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
         if (!proto->getProperty(cx, cx->runtime->atomState.constructorAtom, &cval))
             return NULL;
     }
-    JSObject *funobj;
-    if (!IsFunctionObject(cval, &funobj)) {
+    if (!IsFunctionObject(cval)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
                              proto->getClass()->name);
         return NULL;
     }
     return &cval.toObject();
 }
 
 JS_PUBLIC_API(JSBool)
@@ -3201,24 +3195,23 @@ JS_NewObject(JSContext *cx, JSClass *jsc
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
-    if (proto)
-        proto->getNewType(cx, NULL, /* markUnknown = */ true);
-
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
+    if (proto && !proto->setNewTypeUnknown(cx))
+        return NULL;
+
+    JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
     if (obj) {
         if (clasp->ext.equality)
             MarkTypeObjectFlags(cx, obj, OBJECT_FLAG_SPECIAL_EQUALITY);
-        obj->syncSpecialEquality();
         MarkTypeObjectUnknownProperties(cx, obj->type());
     }
 
     JS_ASSERT_IF(obj, obj->getParent());
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
@@ -3230,21 +3223,19 @@ JS_NewObjectWithGivenProto(JSContext *cx
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
-    JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
-    if (obj) {
-        obj->syncSpecialEquality();
+    JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
+    if (obj)
         MarkTypeObjectUnknownProperties(cx, obj->type());
-    }
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, *vp);
@@ -3344,23 +3335,23 @@ LookupResult(JSContext *cx, JSObject *ob
         vp->setUndefined();
         return JS_TRUE;
     }
 
     if (obj2->isNative()) {
         Shape *shape = (Shape *) prop;
 
         if (shape->isMethod()) {
-            vp->setObject(shape->methodObject());
+            vp->setObject(*obj2->nativeGetMethod(shape));
             return !!obj2->methodReadBarrier(cx, *shape, vp);
         }
 
         /* Peek at the native property's slot value, without doing a Get. */
-        if (obj2->containsSlot(shape->slot)) {
-            *vp = obj2->nativeGetSlot(shape->slot);
+        if (shape->hasSlot()) {
+            *vp = obj2->nativeGetSlot(shape->slot());
             return true;
         }
     } else {
         if (obj2->isDenseArray())
             return js_GetDenseArrayElementValue(cx, obj2, id, vp);
         if (obj2->isProxy()) {
             AutoPropertyDescriptorRooter desc(cx);
             if (!Proxy::getPropertyDescriptor(cx, obj2, id, false, &desc))
@@ -3649,22 +3640,20 @@ JS_DefineObject(JSContext *cx, JSObject 
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, proto);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
-    JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
+    JSObject *nobj = NewObjectWithClassProto(cx, clasp, proto, obj);
     if (!nobj)
         return NULL;
 
-    nobj->syncSpecialEquality();
-
     if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
         return NULL;
 
     return nobj;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
@@ -3721,22 +3710,22 @@ GetPropertyDescriptorById(JSContext *cx,
     desc->obj = obj2;
     if (obj2->isNative()) {
         Shape *shape = (Shape *) prop;
         desc->attrs = shape->attributes();
 
         if (shape->isMethod()) {
             desc->getter = JS_PropertyStub;
             desc->setter = JS_StrictPropertyStub;
-            desc->value.setObject(shape->methodObject());
+            desc->value.setObject(*obj2->nativeGetMethod(shape));
         } else {
             desc->getter = shape->getter();
             desc->setter = shape->setter();
-            if (obj2->containsSlot(shape->slot))
-                desc->value = obj2->nativeGetSlot(shape->slot);
+            if (shape->hasSlot())
+                desc->value = obj2->nativeGetSlot(shape->slot());
             else
                 desc->value.setUndefined();
         }
     } else {
         if (obj2->isProxy()) {
             JSAutoResolveFlags rf(cx, flags);
             return own
                    ? Proxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
@@ -4138,17 +4127,17 @@ JS_NewPropertyIterator(JSContext *cx, JS
 {
     JSObject *iterobj;
     void *pdata;
     jsint index;
     JSIdArray *ida;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
+    iterobj = NewObjectWithClassProto(cx, &prop_iter_class, NULL, obj);
     if (!iterobj)
         return NULL;
 
     if (obj->isNative()) {
         /* Native case: start with the last property in obj. */
         pdata = (void *)obj->lastProperty();
         index = -1;
     } else {
@@ -4186,21 +4175,21 @@ JS_NextProperty(JSContext *cx, JSObject 
         /* Native case: private data is a property tree node pointer. */
         JS_ASSERT(iterobj->getParent()->isNative());
         shape = (Shape *) iterobj->getPrivate();
 
         while (shape->previous() && !shape->enumerable())
             shape = shape->previous();
 
         if (!shape->previous()) {
-            JS_ASSERT(JSID_IS_EMPTY(shape->propid));
+            JS_ASSERT(shape->isEmptyShape());
             *idp = JSID_VOID;
         } else {
             iterobj->setPrivate(const_cast<Shape *>(shape->previous()));
-            *idp = shape->propid;
+            *idp = shape->propid();
         }
     } else {
         /* Non-native case: use the ida enumerated when iterobj was created. */
         ida = (JSIdArray *) iterobj->getPrivate();
         JS_ASSERT(i <= ida->length);
         STATIC_ASSUME(i <= ida->length);
         if (i == 0) {
             *idp = JSID_VOID;
@@ -4377,28 +4366,28 @@ JS_CloneFunctionObject(JSContext *cx, JS
          * We cannot clone this object, so fail (we used to return funobj, bad
          * idea, but we changed incompatibly to teach any abusers a lesson!).
          */
         Value v = ObjectValue(*funobj);
         js_ReportIsNotFunction(cx, &v, 0);
         return NULL;
     }
 
-    JSFunction *fun = funobj->getFunctionPrivate();
+    JSFunction *fun = funobj->toFunction();
     if (!fun->isInterpreted())
-        return CloneFunctionObject(cx, fun, parent);
+        return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
 
     if (fun->script()->compileAndGo) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
         return NULL;
     }
 
     if (!fun->isFlatClosure())
-        return CloneFunctionObject(cx, fun, parent);
+        return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
 
     /*
      * A flat closure carries its own environment, so why clone it? In case
      * someone wants to mutate its fixed slots or add ad-hoc properties. API
      * compatibility suggests we not return funobj and let callers mutate the
      * returned object at will.
      *
      * But it's worse than that: API compatibility according to the test for
@@ -4419,23 +4408,23 @@ JS_CloneFunctionObject(JSContext *cx, JS
         JSObject *obj = parent;
         int skip = uva->vector[i].level();
         while (--skip > 0) {
             if (!obj) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
                 return NULL;
             }
-            obj = obj->getParent();
+            obj = obj->scopeChain();
         }
 
         Value v;
-        if (!obj->getGeneric(cx, r.front().propid, &v))
+        if (!obj->getGeneric(cx, r.front().propid(), &v))
             return NULL;
-        clone->setFlatClosureUpvar(i, v);
+        clone->toFunction()->setFlatClosureUpvar(i, v);
     }
 
     return clone;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun)
 {
@@ -4472,24 +4461,25 @@ JS_ObjectIsCallable(JSContext *cx, JSObj
     return obj->isCallable();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsNativeFunction(JSObject *funobj, JSNative call)
 {
     if (!funobj->isFunction())
         return false;
-    JSFunction *fun = funobj->getFunctionPrivate();
+    JSFunction *fun = funobj->toFunction();
     return fun->isNative() && fun->native() == call;
 }
 
 JSBool
 js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
 {
-    JSFunctionSpec *fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
+    JSFunctionSpec *fs = (JSFunctionSpec *)
+        vp->toObject().toFunction()->getExtendedSlot(0).toPrivate();
     JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
 
     if (argc < 1) {
         js_ReportMissingArg(cx, *vp, 0);
         return JS_FALSE;
     }
 
     /*
@@ -4534,27 +4524,26 @@ JS_DefineFunctions(JSContext *cx, JSObje
                 if (!ctor)
                     return JS_FALSE;
             }
 
             flags &= ~JSFUN_GENERIC_NATIVE;
             fun = js_DefineFunction(cx, ctor, ATOM_TO_JSID(atom),
                                     js_generic_native_method_dispatcher,
                                     fs->nargs + 1,
-                                    flags);
+                                    flags,
+                                    JSFunction::ExtendedFinalizeKind);
             if (!fun)
                 return JS_FALSE;
 
             /*
              * As jsapi.h notes, fs must point to storage that lives as long
              * as fun->object lives.
              */
-            Value priv = PrivateValue(fs);
-            if (!js_SetReservedSlot(cx, fun, 0, priv))
-                return JS_FALSE;
+            fun->setExtendedSlot(0, PrivateValue(fs));
         }
 
         fun = js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), fs->call, fs->nargs, flags);
         if (!fun)
             return JS_FALSE;
     }
     return JS_TRUE;
 }
@@ -5309,16 +5298,30 @@ JS_SaveFrameChain(JSContext *cx)
 
 JS_PUBLIC_API(void)
 JS_RestoreFrameChain(JSContext *cx)
 {
     CHECK_REQUEST(cx);
     cx->stack.restoreFrameChain();
 }
 
+#ifdef MOZ_TRACE_JSCALLS
+JS_PUBLIC_API(void)
+JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
+{
+    cx->functionCallback = fcb;
+}
+
+JS_PUBLIC_API(JSFunctionCallback)
+JS_GetFunctionCallback(JSContext *cx)
+{
+    return cx->functionCallback;
+}
+#endif
+
 /************************************************************************/
 JS_PUBLIC_API(JSString *)
 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
 {
     CHECK_REQUEST(cx);
     return js_NewStringCopyN(cx, s, n);
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1113,16 +1113,24 @@ typedef void
 (* JSTraceDataOp)(JSTracer *trc, void *data);
 
 typedef JSBool
 (* JSOperationCallback)(JSContext *cx);
 
 typedef void
 (* JSErrorReporter)(JSContext *cx, const char *message, JSErrorReport *report);
 
+#ifdef MOZ_TRACE_JSCALLS
+typedef void
+(* JSFunctionCallback)(const JSFunction *fun,
+                       const JSScript *scr,
+                       const JSContext *cx,
+                       int entering);
+#endif
+
 /*
  * Possible exception types. These types are part of a JSErrorFormatString
  * structure. They define which error to throw in case of a runtime error.
  * JSEXN_NONE marks an unthrowable error.
  */
 typedef enum JSExnType {
     JSEXN_NONE = -1,
       JSEXN_ERR,
@@ -3141,18 +3149,17 @@ struct JSClass {
     JSClassInternal     reserved1;
     void                *reserved[40];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  /* objects have private slot */
 #define JSCLASS_NEW_ENUMERATE           (1<<1)  /* has JSNewEnumerateOp hook */
 #define JSCLASS_NEW_RESOLVE             (1<<2)  /* has JSNewResolveOp hook */
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  /* private is (nsISupports *) */
-#define JSCLASS_CONCURRENT_FINALIZER    (1<<4)  /* finalize is called on background thread */
-#define JSCLASS_NEW_RESOLVE_GETS_START  (1<<5)  /* JSNewResolveOp gets starting
+#define JSCLASS_NEW_RESOLVE_GETS_START  (1<<4)  /* JSNewResolveOp gets starting
                                                    object in prototype chain
                                                    passed in via *objp in/out
                                                    parameter */
 #define JSCLASS_DOCUMENT_OBSERVER       (1<<6)  /* DOM document observer */
 
 /*
  * To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
  * JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
@@ -4176,16 +4183,33 @@ JS_IsRunning(JSContext *cx);
  * JS_SaveFrameChain deals with cx not having any code running on it.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_SaveFrameChain(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_RestoreFrameChain(JSContext *cx);
 
+#ifdef MOZ_TRACE_JSCALLS
+/*
+ * The callback is expected to be quick and noninvasive. It should not
+ * trigger interrupts, turn on debugging, or produce uncaught JS
+ * exceptions. The state of the stack and registers in the context
+ * cannot be relied upon, since this callback may be invoked directly
+ * from either JIT. The 'entering' field means we are entering a
+ * function if it is positive, leaving a function if it is zero or
+ * negative.
+ */
+extern JS_PUBLIC_API(void)
+JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb);
+
+extern JS_PUBLIC_API(JSFunctionCallback)
+JS_GetFunctionCallback(JSContext *cx);
+#endif /* MOZ_TRACE_JSCALLS */
+
 /************************************************************************/
 
 /*
  * Strings.
  *
  * NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy;
  * but on error (signified by null return), it leaves chars owned by the
  * caller. So the caller must free bytes in the error case, if it has no use
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -276,20 +276,20 @@ BigIndexToId(JSContext *cx, JSObject *ob
 }
 
 bool
 JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint)
 {
     JS_ASSERT(isDenseArray());
     JS_ASSERT(requiredCapacity > MIN_SPARSE_INDEX);
 
-    uintN cap = numSlots();
+    uintN cap = getDenseArrayCapacity();
     JS_ASSERT(requiredCapacity >= cap);
 
-    if (requiredCapacity >= JSObject::NSLOTS_LIMIT)
+    if (requiredCapacity >= JSObject::NELEMENTS_LIMIT)
         return true;
 
     uintN minimalDenseCount = requiredCapacity / 4;
     if (newElementsHint >= minimalDenseCount)
         return false;
     minimalDenseCount -= newElementsHint;
 
     if (minimalDenseCount > cap)
@@ -347,17 +347,17 @@ JSObject::arrayGetOwnDataElement(JSConte
     jsid id;
     if (!IndexToId(cx, this, i, &hole, &id))
         return false;
 
     const Shape *shape = nativeLookup(cx, id);
     if (!shape || !shape->isDataDescriptor())
         vp->setMagic(JS_ARRAY_HOLE);
     else
-        *vp = getSlot(shape->slot);
+        *vp = getSlot(shape->slot());
     return true;
 }
 
 /*
  * If the property at the given index exists, get its value into location
  * pointed by vp and set *hole to false. Otherwise set *hole to true and *vp
  * to JSVAL_VOID. This function assumes that the location pointed by vp is
  * properly rooted and can be used as GC-protected storage for temporaries.
@@ -629,19 +629,17 @@ array_length_setter(JSContext *cx, JSObj
          * us to disregard length when reading from arrays as long we are within
          * the initialized capacity.
          */
         jsuint oldcap = obj->getDenseArrayCapacity();
         jsuint oldinit = obj->getDenseArrayInitializedLength();
         if (oldinit > newlen)
             obj->setDenseArrayInitializedLength(newlen);
         if (oldcap > newlen)
-            obj->shrinkDenseArrayElements(cx, newlen);
-        if (oldinit > newlen && !cx->typeInferenceEnabled())
-            obj->backfillDenseArrayHoles(cx);
+            obj->shrinkElements(cx, newlen);
     } else if (oldlen - newlen < (1 << 24)) {
         do {
             --oldlen;
             if (!JS_CHECK_OPERATION_LIMIT(cx)) {
                 obj->setArrayLength(cx, oldlen + 1);
                 return false;
             }
             int deletion = DeleteArrayElement(cx, obj, oldlen, strict);
@@ -1214,17 +1212,17 @@ array_fix(JSContext *cx, JSObject *obj, 
         return false;
 
     *success = true;
     return true;
 }
 
 Class js::ArrayClass = {
     "Array",
-    Class::NON_NATIVE | JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
+    Class::NON_NATIVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     NULL,
@@ -1272,143 +1270,147 @@ Class js::ArrayClass = {
         array_fix,
         NULL,       /* thisObject     */
         NULL,       /* clear          */
     }
 };
 
 Class js::SlowArrayClass = {
     "Array",
-    JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
     slowarray_addProperty,
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
+bool
+JSObject::allocateSlowArrayElements(JSContext *cx)
+{
+    JS_ASSERT(hasClass(&js::SlowArrayClass));
+    JS_ASSERT(elements == emptyObjectElements);
+
+    ObjectElements *header = cx->new_<ObjectElements>(0, 0);
+    if (!header)
+        return false;
+
+    elements = header->elements();
+    return true;
+}
+
 static bool
 AddLengthProperty(JSContext *cx, JSObject *obj)
 {
+    /*
+     * Add the 'length' property for a newly created or converted slow array,
+     * and update the elements to be an empty array owned by the object.
+     * The shared emptyObjectElements singleton cannot be used for slow arrays,
+     * as accesses to 'length' will use the elements header.
+     */
+
     const jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     JS_ASSERT(!obj->nativeLookup(cx, lengthId));
 
+    if (!obj->allocateSlowArrayElements(cx))
+        return false;
+
     return obj->addProperty(cx, lengthId, array_length_getter, array_length_setter,
                             SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0);
 }
 
 /*
  * Convert an array object from fast-and-dense to slow-and-flexible.
  */
 JSBool
 JSObject::makeDenseArraySlow(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
 
     MarkTypeObjectFlags(cx, this,
                         OBJECT_FLAG_NON_PACKED_ARRAY |
                         OBJECT_FLAG_NON_DENSE_ARRAY);
-    markDenseArrayNotPacked(cx);
+
+    uint32 arrayCapacity = getDenseArrayCapacity();
+    uint32 arrayInitialized = getDenseArrayInitializedLength();
+
+    /*
+     * Get an allocated array of the existing elements, evicting from the fixed
+     * slots if necessary.
+     */
+    if (!hasDynamicElements()) {
+        if (!growElements(cx, arrayCapacity))
+            return false;
+        JS_ASSERT(hasDynamicElements());
+    }
 
     /*
      * Save old map now, before calling InitScopeForObject. We'll have to undo
      * on error. This is gross, but a better way is not obvious. Note: the
      * exact contents of the array are not preserved on error.
      */
-    js::Shape *oldMap = lastProp;
+    js::Shape *oldShape = lastProperty();
 
     /* Create a native scope. */
     gc::AllocKind kind = getAllocKind();
-    js::EmptyShape *empty = InitScopeForObject(cx, this, &SlowArrayClass,
-                                               getProto()->getNewType(cx), kind);
-    if (!empty)
+    Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, getProto(),
+                                               oldShape->getObjectParent(), kind);
+    if (!shape)
         return false;
-    setMap(empty);
-
-    backfillDenseArrayHoles(cx);
-
-    uint32 arrayCapacity = getDenseArrayCapacity();
-    uint32 arrayInitialized = getDenseArrayInitializedLength();
-
-    /*
-     * Adjust the slots to account for the different layout between dense
-     * arrays and other objects. The slots must be dynamic, and the fixed slots
-     * are now available for newly added properties.
-     */
-    if (denseArrayHasInlineSlots()) {
-        if (!allocSlots(cx, numSlots())) {
-            setMap(oldMap);
-            return false;
-        }
-        JS_ASSERT(!denseArrayHasInlineSlots());
-    }
-    capacity = numFixedSlots() + arrayCapacity;
-    clasp = &SlowArrayClass;
-
-    /*
-     * Root all values in the array during conversion, as SlowArrayClass only
-     * protects up to its slot span.
-     */
-    AutoValueArray autoArray(cx, Valueify(slots), arrayInitialized);
-
-    /* The initialized length is used iff this is a dense array. */
-    initializedLength() = 0;
-    JS_ASSERT(newType == NULL);
+    this->shape_ = shape;
+
+    /* Take ownership of the dense elements, reset to an empty dense array. */
+    HeapValue *elems = elements;
+    elements = emptyObjectElements;
+
+    /* Root all values in the array during conversion. */
+    AutoValueArray autoArray(cx, (Value *) elems, arrayInitialized);
 
     /*
      * Begin with the length property to share more of the property tree.
      * The getter/setter here will directly access the object's private value.
      */
     if (!AddLengthProperty(cx, this)) {
-        setMap(oldMap);
-        capacity = arrayCapacity;
-        initializedLength() = arrayInitialized;
-        clasp = &ArrayClass;
+        this->shape_ = oldShape;
+        cx->free_(getElementsHeader());
+        elements = elems;
         return false;
     }
 
     /*
      * Create new properties pointing to existing elements. Pack the array to
      * remove holes, so that shapes use successive slots (as for other objects).
      */
     uint32 next = 0;
-    for (uint32 i = 0; i < arrayCapacity; i++) {
+    for (uint32 i = 0; i < arrayInitialized; i++) {
         /* Dense array indexes can always fit in a jsid. */
         jsid id;
         JS_ALWAYS_TRUE(ValueToId(cx, Int32Value(i), &id));
 
-        if (slots[i].isMagic(JS_ARRAY_HOLE))
+        if (elems[i].isMagic(JS_ARRAY_HOLE))
             continue;
 
-        /*
-         * No barrier is needed here because the set of reachable objects before
-         * and after slowification is the same. During slowification, the
-         * autoArray rooter guarantees that all slots will be marked.
-         *
-         * It's important that we avoid a barrier here because the fixed slots
-         * of a dense array can be garbage; a write barrier after the switch to
-         * a slow array could cause a crash.
-         */
-        initSlotUnchecked(next, slots[i]);
-
         if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
-            setMap(oldMap);
-            capacity = arrayCapacity;
-            initializedLength() = arrayInitialized;
-            clasp = &ArrayClass;
+            this->shape_ = oldShape;
+            cx->free_(getElementsHeader());
+            elements = elems;
             return false;
         }
 
+        initSlot(next, elems[i]);
+
         next++;
     }
 
-    clearSlotRange(next, capacity - next);
+    ObjectElements *oldheader = ObjectElements::fromElements(elems);
+
+    getElementsHeader()->length = oldheader->length;
+    cx->free_(oldheader);
 
     return true;
 }
 
 #if JS_HAS_TOSOURCE
 class ArraySharpDetector
 {
     JSContext *cx;
@@ -1833,23 +1835,20 @@ InitArrayObject(JSContext *cx, JSObject 
     obj->setArrayLength(cx, length);
     if (!vector || !length)
         return true;
 
     if (!InitArrayTypes(cx, obj->getType(cx), vector, length))
         return false;
 
     /* Avoid ensureDenseArrayElements to skip sparse array checks there. */
-    if (!obj->ensureSlots(cx, length))
+    if (!obj->ensureElements(cx, length))
         return false;
 
-    if (cx->typeInferenceEnabled())
-        obj->setDenseArrayInitializedLength(length);
-    else
-        obj->backfillDenseArrayHoles(cx);
+    obj->setDenseArrayInitializedLength(length);
 
     bool hole = false;
     for (jsuint i = 0; i < length; i++) {
         obj->setDenseArrayElement(i, vector[i]);
         hole |= vector[i].isMagic(JS_ARRAY_HOLE);
     }
     if (hole)
         obj->markDenseArrayNotPacked(cx);
@@ -2296,21 +2295,20 @@ NewbornArrayPushImpl(JSContext *cx, JSOb
         jsid id;
         return IndexToId(cx, length, &id) &&
                js_DefineProperty(cx, obj, id, &v, NULL, NULL, JSPROP_ENUMERATE);
     }
 
     JS_ASSERT(obj->isDenseArray());
     JS_ASSERT(length <= obj->getDenseArrayCapacity());
 
-    if (length == obj->getDenseArrayCapacity() && !obj->ensureSlots(cx, length + 1))
+    if (!obj->ensureElements(cx, length + 1))
         return false;
 
-    if (cx->typeInferenceEnabled())
-        obj->setDenseArrayInitializedLength(length + 1);
+    obj->setDenseArrayInitializedLength(length + 1);
     obj->setDenseArrayLength(length + 1);
     obj->initDenseArrayElementWithType(cx, length, v);
     return true;
 }
 
 JSBool
 js_NewbornArrayPush(JSContext *cx, JSObject *obj, const Value &vp)
 {
@@ -2371,17 +2369,17 @@ array_pop_dense(JSContext *cx, JSObject*
 
     JSBool hole;
     Value elt;
     if (!GetElement(cx, obj, index, &hole, &elt))
         return JS_FALSE;
 
     if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
         return JS_FALSE;
-    if (cx->typeInferenceEnabled() && obj->getDenseArrayInitializedLength() > index)
+    if (obj->getDenseArrayInitializedLength() > index)
         obj->setDenseArrayInitializedLength(index);
 
     obj->setArrayLength(cx, index);
 
     args.rval() = elt;
     return JS_TRUE;
 }
 
@@ -2433,20 +2431,17 @@ js::array_shift(JSContext *cx, uintN arg
 
         if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
             length < obj->getDenseArrayCapacity() &&
             0 < obj->getDenseArrayInitializedLength()) {
             args.rval() = obj->getDenseArrayElement(0);
             if (args.rval().isMagic(JS_ARRAY_HOLE))
                 args.rval().setUndefined();
             obj->moveDenseArrayElements(0, 1, length);
-            if (cx->typeInferenceEnabled())
-                obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
-            else
-                obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE));
+            obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
             obj->setArrayLength(cx, length);
             if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)))
                 return JS_FALSE;
             return JS_TRUE;
         }
 
         JSBool hole;
         if (!GetElement(cx, obj, 0u, &hole, &args.rval()))
@@ -2538,17 +2533,17 @@ static inline void
 TryReuseArrayType(JSObject *obj, JSObject *nobj)
 {
     /*
      * Try to change the type of a newly created array nobj to the same type
      * as obj. This can only be performed if the original object is an array
      * and has the same prototype.
      */
     JS_ASSERT(nobj->isDenseArray());
-    JS_ASSERT(nobj->type() == nobj->getProto()->newType);
+    JS_ASSERT(nobj->getProto()->hasNewType(nobj->type()));
 
     if (obj->isArray() && !obj->hasSingletonType() && obj->getProto() == nobj->getProto())
         nobj->setType(obj->type());
 }
 
 /*
  * Returns true if this is a dense array whose |count| properties starting from
  * |startingIndex| may be accessed (get, set, delete) directly through its
@@ -2688,17 +2683,17 @@ array_splice(JSContext *cx, uintN argc, 
             /*
              * Update the initialized length. Do so before shrinking so that we
              * can apply the write barrier to the old slots.
              */
             if (cx->typeInferenceEnabled())
                 obj->setDenseArrayInitializedLength(finalLength);
 
             /* Steps 12(c)-(d). */
-            obj->shrinkDenseArrayElements(cx, finalLength);
+            obj->shrinkElements(cx, finalLength);
 
             /* Fix running enumerators for the deleted items. */
             if (!js_SuppressDeletedElements(cx, obj, finalLength, len))
                 return false;
         } else {
             /*
              * This is all very slow if the length is very large. We don't yet
              * have the ability to iterate in sorted order, so we just do the
@@ -2803,17 +2798,17 @@ mjit::stubs::ArrayConcatTwoArrays(VMFram
     JS_ASSERT(initlen1 == obj1->getArrayLength());
 
     uint32 initlen2 = obj2->getDenseArrayInitializedLength();
     JS_ASSERT(initlen2 == obj2->getArrayLength());
 
     /* No overflow here due to nslots limit. */
     uint32 len = initlen1 + initlen2;
 
-    if (!result->ensureSlots(f.cx, len))
+    if (!result->ensureElements(f.cx, len))
         THROW();
 
     JS_ASSERT(!result->getDenseArrayInitializedLength());
     result->setDenseArrayInitializedLength(len);
 
     result->initDenseArrayElements(0, obj1->getDenseArrayElements(), initlen1);
     result->initDenseArrayElements(initlen1, obj2->getDenseArrayElements(), initlen2);
 
@@ -2841,18 +2836,16 @@ js::array_concat(JSContext *cx, uintN ar
         length = aobj->getArrayLength();
         const Value *vector = aobj->getDenseArrayElements();
         jsuint initlen = aobj->getDenseArrayInitializedLength();
         nobj = NewDenseCopiedArray(cx, initlen, vector);
         if (!nobj)
             return JS_FALSE;
         TryReuseArrayType(aobj, nobj);
         nobj->setArrayLength(cx, length);
-        if (!aobj->isPackedDenseArray())
-            nobj->markDenseArrayNotPacked(cx);
         vp->setObject(*nobj);
         if (argc == 0)
             return JS_TRUE;
         argc--;
         p++;
     } else {
         nobj = NewDenseEmptyArray(cx);
         if (!nobj)
@@ -2947,18 +2940,16 @@ array_slice(JSContext *cx, uintN argc, V
         begin = end;
 
     if (obj->isDenseArray() && end <= obj->getDenseArrayInitializedLength() &&
         !js_PrototypeHasIndexedProperties(cx, obj)) {
         nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
         if (!nobj)
             return JS_FALSE;
         TryReuseArrayType(obj, nobj);
-        if (!obj->isPackedDenseArray())
-            nobj->markDenseArrayNotPacked(cx);
         args.rval().setObject(*nobj);
         return JS_TRUE;
     }
 
     nobj = NewDenseAllocatedArray(cx, end - begin);
     if (!nobj)
         return JS_FALSE;
     TryReuseArrayType(obj, nobj);
@@ -3604,18 +3595,24 @@ js_InitArrayClass(JSContext *cx, JSObjec
         return NULL;
     arrayProto->setArrayLength(cx, 0);
 
     JSFunction *ctor = global->createConstructor(cx, js_Array, &ArrayClass,
                                                  CLASS_ATOM(cx, Array), 1);
     if (!ctor)
         return NULL;
 
-    /* The default 'new' object for Array.prototype has unknown properties. */
-    arrayProto->getNewType(cx, NULL, /* markUnknown = */ true);
+    /*
+     * The default 'new' type of Array.prototype is required by type inference
+     * to have unknown properties, to simplify handling of e.g. heterogenous
+     * arrays in JSON and script literals and allows setDenseArrayElement to
+     * be used without updating the indexed type set for such default arrays.
+     */
+    if (!arrayProto->setNewTypeUnknown(cx))
+        return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, arrayProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, arrayProto, NULL, array_methods) ||
         !DefinePropertiesAndBrand(cx, ctor, NULL, array_static_methods))
     {
         return NULL;
@@ -3627,44 +3624,88 @@ js_InitArrayClass(JSContext *cx, JSObjec
     return arrayProto;
 }
 
 /*
  * Array allocation functions.
  */
 namespace js {
 
+static inline bool
+EnsureNewArrayElements(JSContext *cx, JSObject *obj, jsuint length)
+{
+    /*
+     * If ensureElements creates dynamically allocated slots, then having
+     * fixedSlots is a waste.
+     */
+    DebugOnly<uint32> cap = obj->getDenseArrayCapacity();
+
+    if (!obj->ensureElements(cx, length))
+        return false;
+
+    JS_ASSERT_IF(cap, !obj->hasDynamicElements());
+
+    return true;
+}
+
 template<bool allocateCapacity>
 static JS_ALWAYS_INLINE JSObject *
 NewArray(JSContext *cx, jsuint length, JSObject *proto)
 {
-    JS_ASSERT_IF(proto, proto->isArray());
-
-    gc::AllocKind kind = GuessObjectGCKind(length, true);
-    JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &ArrayClass, proto, NULL, kind);
+    gc::AllocKind kind = GuessArrayGCKind(length);
+
+#ifdef JS_THREADSAFE
+    JS_ASSERT(CanBeFinalizedInBackground(kind, &ArrayClass));
+    kind = GetBackgroundAllocKind(kind);
+#endif
+
+    GlobalObject *parent = GetCurrentGlobal(cx);
+
+    NewObjectCache &cache = cx->compartment->newObjectCache;
+
+    NewObjectCache::EntryIndex entry = -1;
+    if (cache.lookupGlobal(&ArrayClass, parent, kind, &entry)) {
+        JSObject *obj = cache.newObjectFromHit(cx, entry);
+        if (!obj)
+            return NULL;
+        /* Fixup the elements pointer and length, which may be incorrect. */
+        obj->setFixedElements();
+        obj->setArrayLength(cx, length);
+        if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length))
+            return NULL;
+        return obj;
+    }
+
+    if (!proto && !FindProto(cx, &ArrayClass, parent, &proto))
+        return NULL;
+
+    types::TypeObject *type = proto->getNewType(cx);
+    if (!type)
+        return NULL;
+
+    /*
+     * Get a shape with zero fixed slots, regardless of the size class.
+     * See JSObject::createDenseArray.
+     */
+    Shape *shape = EmptyShape::getInitialShape(cx, &ArrayClass, proto,
+                                               proto->getParent(), gc::FINALIZE_OBJECT0);
+    if (!shape)
+        return NULL;
+
+    JSObject* obj = JSObject::createDenseArray(cx, kind, shape, type, length);
     if (!obj)
         return NULL;
 
-    obj->setArrayLength(cx, length);
-
-    if (!cx->typeInferenceEnabled()) {
-        obj->markDenseArrayNotPacked(cx);
-        obj->backfillDenseArrayHoles(cx);
-    }
-
-    if (allocateCapacity) {
-        /* If ensureSlots creates dynamically allocated slots, then having fixedSlots is a waste. */
-        DebugOnly<uint32> oldSlots = obj->numSlots();
-
-        if (!obj->ensureSlots(cx, length))
-            return NULL;
-
-        JS_ASSERT_IF(obj->numFixedSlots(), oldSlots == obj->numSlots());
-    }
-
+    if (entry != -1)
+        cache.fillGlobal(entry, &ArrayClass, parent, kind, obj);
+
+    if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length))
+        return NULL;
+
+    Probes::createObject(cx, obj);
     return obj;
 }
 
 JSObject * JS_FASTCALL
 NewDenseEmptyArray(JSContext *cx, JSObject *proto)
 {
     return NewArray<false>(cx, 0, proto);
 }
@@ -3705,29 +3746,28 @@ JSObject *
 NewDenseCopiedArray(JSContext *cx, uint32 length, const Value *vp, JSObject *proto /* = NULL */)
 {
     JSObject* obj = NewArray<true>(cx, length, proto);
     if (!obj)
         return NULL;
 
     JS_ASSERT(obj->getDenseArrayCapacity() >= length);
 
-    if (cx->typeInferenceEnabled())
-        obj->setDenseArrayInitializedLength(vp ? length : 0);
+    obj->setDenseArrayInitializedLength(vp ? length : 0);
 
     if (vp)
         obj->initDenseArrayElements(0, vp, length);
 
     return obj;
 }
 
 JSObject *
 NewSlowEmptyArray(JSContext *cx)
 {
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &SlowArrayClass, NULL, NULL);
+    JSObject *obj = NewBuiltinClassInstance(cx, &SlowArrayClass);
     if (!obj || !AddLengthProperty(cx, obj))
         return NULL;
 
     obj->setArrayLength(cx, 0);
     return obj;
 }
 
 }
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -46,30 +46,16 @@
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsatom.h"
 #include "jsobj.h"
 
 /* Small arrays are dense, no matter what. */
 const uintN MIN_SPARSE_INDEX = 256;
 
-inline uint32
-JSObject::getDenseArrayInitializedLength()
-{
-    JS_ASSERT(isDenseArray());
-    return initializedLength();
-}
-
-inline bool
-JSObject::isPackedDenseArray()
-{
-    JS_ASSERT(isDenseArray());
-    return flags & PACKED_ARRAY;
-}
-
 namespace js {
 /* 2^32-2, inclusive */
 const uint32 MAX_ARRAY_INDEX = 4294967294u;
 }
 
 inline JSBool
 js_IdIsIndex(jsid id, jsuint *indexp)
 {
--- a/js/src/jsarrayinlines.h
+++ b/js/src/jsarrayinlines.h
@@ -39,72 +39,47 @@
 
 #ifndef jsarrayinlines_h___
 #define jsarrayinlines_h___
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 inline void
-JSObject::setDenseArrayInitializedLength(uint32 length)
-{
-    JS_ASSERT(isDenseArray());
-    JS_ASSERT(length <= getDenseArrayCapacity());
-    uint32 cur = initializedLength();
-    prepareSlotRangeForOverwrite(length, cur);
-    initializedLength() = length;
-}
-
-inline void
 JSObject::markDenseArrayNotPacked(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
-    if (flags & PACKED_ARRAY) {
-        flags ^= PACKED_ARRAY;
-        MarkTypeObjectFlags(cx, this, js::types::OBJECT_FLAG_NON_PACKED_ARRAY);
-    }
-}
-
-inline void
-JSObject::backfillDenseArrayHoles(JSContext *cx)
-{
-    /* Ensure an array's elements are fully initialized. */
-    ensureDenseArrayInitializedLength(cx, getDenseArrayCapacity(), 0);
+    MarkTypeObjectFlags(cx, this, js::types::OBJECT_FLAG_NON_PACKED_ARRAY);
 }
 
 inline void
 JSObject::ensureDenseArrayInitializedLength(JSContext *cx, uint32 index, uint32 extra)
 {
     /*
      * Ensure that the array's contents have been initialized up to index, and
      * mark the elements through 'index + extra' as initialized in preparation
      * for a write.
      */
-    JS_ASSERT(index + extra <= capacity);
-    if (initializedLength() < index)
+    JS_ASSERT(index + extra <= getDenseArrayCapacity());
+    uint32 &initlen = getElementsHeader()->initializedLength;
+    if (initlen < index)
         markDenseArrayNotPacked(cx);
 
-    if (initializedLength() < index + extra) {
-        js::InitValueRange(slots + initializedLength(), index + extra - initializedLength(), true);
-        initializedLength() = index + extra;
+    if (initlen < index + extra) {
+        js::InitValueRange(elements + initlen, index + extra - initlen, true);
+        initlen = index + extra;
     }
 }
 
 inline JSObject::EnsureDenseResult
 JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
 {
     JS_ASSERT(isDenseArray());
 
-    uintN currentCapacity = numSlots();
-
-    /*
-     * Don't take excessive slow paths when inference is disabled, due to
-     * uninitialized slots between initializedLength and capacity.
-     */
-    JS_ASSERT_IF(!cx->typeInferenceEnabled(), currentCapacity == getDenseArrayInitializedLength());
+    uintN currentCapacity = getDenseArrayCapacity();
 
     uintN requiredCapacity;
     if (extra == 1) {
         /* Optimize for the common case. */
         if (index < currentCapacity) {
             ensureDenseArrayInitializedLength(cx, index, 1);
             return ED_OK;
         }
@@ -128,16 +103,16 @@ JSObject::ensureDenseArrayElements(JSCon
     /*
      * We use the extra argument also as a hint about number of non-hole
      * elements to be inserted.
      */
     if (requiredCapacity > MIN_SPARSE_INDEX &&
         willBeSparseDenseArray(requiredCapacity, extra)) {
         return ED_SPARSE;
     }
-    if (!growSlots(cx, requiredCapacity))
+    if (!growElements(cx, requiredCapacity))
         return ED_FAILED;
 
     ensureDenseArrayInitializedLength(cx, index, extra);
     return ED_OK;
 }
 
 #endif /* jsarrayinlines_h___ */
--- a/js/src/jscell.h
+++ b/js/src/jscell.h
@@ -60,33 +60,31 @@ enum AllocKind {
     FINALIZE_OBJECT4_BACKGROUND,
     FINALIZE_OBJECT8,
     FINALIZE_OBJECT8_BACKGROUND,
     FINALIZE_OBJECT12,
     FINALIZE_OBJECT12_BACKGROUND,
     FINALIZE_OBJECT16,
     FINALIZE_OBJECT16_BACKGROUND,
     FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
-    FINALIZE_FUNCTION,
-    FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
     FINALIZE_SCRIPT,
     FINALIZE_SHAPE,
+    FINALIZE_BASE_SHAPE,
     FINALIZE_TYPE_OBJECT,
 #if JS_HAS_XML_SUPPORT
     FINALIZE_XML,
 #endif
     FINALIZE_SHORT_STRING,
     FINALIZE_STRING,
     FINALIZE_EXTERNAL_STRING,
     FINALIZE_LAST = FINALIZE_EXTERNAL_STRING
 };
 
 static const unsigned FINALIZE_LIMIT = FINALIZE_LAST + 1;
 static const unsigned FINALIZE_OBJECT_LIMIT = FINALIZE_OBJECT_LAST + 1;
-static const unsigned FINALIZE_FUNCTION_AND_OBJECT_LIMIT = FINALIZE_FUNCTION_AND_OBJECT_LAST + 1;
 
 /*
  * Live objects are marked black. How many other additional colors are available
  * depends on the size of the GCThing. Objects marked gray are eligible for
  * cycle collection.
  */
 static const uint32 BLACK = 0;
 static const uint32 GRAY = 1;
--- a/js/src/jsclass.h
+++ b/js/src/jsclass.h
@@ -355,16 +355,20 @@ struct Class
                             sizeof(ClassExtension) - sizeof(ObjectOps)];
 
     /* Class is not native and its map is not a scope. */
     static const uint32 NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
 
     bool isNative() const {
         return !(flags & NON_NATIVE);
     }
+
+    bool hasPrivate() const {
+        return !!(flags & JSCLASS_HAS_PRIVATE);
+    }
 };
 
 JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
 JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
 JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty));
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1184,17 +1184,17 @@ js_ReportMissingArg(JSContext *cx, const
 {
     char argbuf[11];
     char *bytes;
     JSAtom *atom;
 
     JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
     bytes = NULL;
     if (IsFunctionObject(v)) {
-        atom = v.toObject().getFunctionPrivate()->atom;
+        atom = v.toObject().toFunction()->atom;
         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
                                         v, atom);
         if (!bytes)
             return;
     }
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_MISSING_FUN_ARG, argbuf,
                          bytes ? bytes : "");
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -389,30 +389,16 @@ struct JSRuntime
     void setActivityCallback(JSActivityCallback cb, void *arg) {
         activityCallback = cb;
         activityCallbackArg = arg;
     }
 
     JSActivityCallback    activityCallback;
     void                 *activityCallbackArg;
 
-    /*
-     * Shape regenerated whenever a prototype implicated by an "add property"
-     * property cache fill and induced trace guard has a readonly property or a
-     * setter defined on it. This number proxies for the shapes of all objects
-     * along the prototype chain of all objects in the runtime on which such an
-     * add-property result has been cached/traced.
-     *
-     * See bug 492355 for more details.
-     *
-     * This comes early in JSRuntime to minimize the immediate format used by
-     * trace-JITted code that reads it.
-     */
-    uint32              protoHazardShape;
-
     /* Garbage collector state, used by jsgc.c. */
 
     /*
      * Set of all GC chunks with at least one allocated thing. The
      * conservative GC uses it to quickly check if a possible GC thing points
      * into an allocated chunk.
      */
     js::GCChunkSet      gcChunkSet;
@@ -480,17 +466,16 @@ struct JSRuntime
      * We can pack these flags as only the GC thread writes to them. Atomic
      * updates to packed bytes are not guaranteed, so stores issued by one
      * thread may be lost due to unsynchronized read-modify-write cycles on
      * other threads.
      */
     bool                gcPoke;
     bool                gcMarkAndSweep;
     bool                gcRunning;
-    bool                gcRegenShapes;
 
     /*
      * These options control the zealousness of the GC. The fundamental values
      * are gcNextScheduled and gcDebugCompartmentGC. At every allocation,
      * gcNextScheduled is decremented. When it reaches zero, we do either a
      * full or a compartmental GC, based on gcDebugCompartmentGC.
      *
      * At this point, if gcZeal_ >= 2 then gcNextScheduled is reset to the
@@ -659,31 +644,16 @@ struct JSRuntime
 #endif
 
   private:
     JSPrincipals        *trustedPrincipals_;
   public:
     void setTrustedPrincipals(JSPrincipals *p) { trustedPrincipals_ = p; }
     JSPrincipals *trustedPrincipals() const { return trustedPrincipals_; }
 
-    /*
-     * Object shape (property cache structural type) identifier generator.
-     *
-     * Type 0 stands for the empty scope, and must not be regenerated due to
-     * uint32 wrap-around. Since js_GenerateShape (in jsinterp.cpp) uses
-     * atomic pre-increment, the initial value for the first typed non-empty
-     * scope will be 1.
-     *
-     * If this counter overflows into SHAPE_OVERFLOW_BIT (in jsinterp.h), the
-     * cache is disabled, to avoid aliasing two different types. It stays
-     * disabled until a triggered GC at some later moment compresses live
-     * types, minimizing rt->shapeGen in the process.
-     */
-    volatile uint32     shapeGen;
-
     /* Literal table maintained by jsatom.c functions. */
     JSAtomState         atomState;
 
     /* Tables of strings that are pre-allocated in the atomsCompartment. */
     js::StaticStrings   staticStrings;
 
     JSWrapObjectCallback wrapObjectCallback;
     JSPreWrapCallback    preWrapObjectCallback;
@@ -2130,39 +2100,16 @@ namespace mjit {
 } /* namespace js */
 
 /* How much expansion of inlined frames to do when inspecting the stack. */
 enum FrameExpandKind {
     FRAME_EXPAND_NONE = 0,
     FRAME_EXPAND_ALL = 1
 };
 
-static JS_INLINE JSBool
-js_IsPropertyCacheDisabled(JSContext *cx)
-{
-    return cx->runtime->shapeGen >= js::SHAPE_OVERFLOW_BIT;
-}
-
-static JS_INLINE uint32
-js_RegenerateShapeForGC(JSRuntime *rt)
-{
-    JS_ASSERT(rt->gcRunning);
-    JS_ASSERT(rt->gcRegenShapes);
-
-    /*
-     * Under the GC, compared with js_GenerateShape, we don't need to use
-     * atomic increments but we still must make sure that after an overflow
-     * the shape stays such.
-     */
-    uint32 shape = rt->shapeGen;
-    shape = (shape + 1) | (shape & js::SHAPE_OVERFLOW_BIT);
-    rt->shapeGen = shape;
-    return shape;
-}
-
 namespace js {
 
 /************************************************************************/
 
 static JS_ALWAYS_INLINE void
 MakeRangeGCSafe(Value *vec, size_t len)
 {
     PodZero(vec, len);
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -329,17 +329,17 @@ CallJSNativeConstructor(JSContext *cx, N
      * CallOrConstructBoundFunction is an exception as well because we
      * might have used bind on a proxy function.
      *
      * (new Object(Object)) returns the callee.
      */
     JS_ASSERT_IF(native != FunctionProxyClass.construct &&
                  native != CallableObjectClass.construct &&
                  native != js::CallOrConstructBoundFunction &&
-                 (!callee.isFunction() || callee.getFunctionPrivate()->u.n.clasp != &ObjectClass),
+                 (!callee.isFunction() || callee.toFunction()->u.n.clasp != &ObjectClass),
                  !args.rval().isPrimitive() && callee != args.rval().toObject());
 
     return true;
 }
 
 JS_ALWAYS_INLINE bool
 CallJSPropertyOp(JSContext *cx, PropertyOp op, JSObject *receiver, jsid id, Value *vp)
 {
@@ -467,22 +467,16 @@ inline bool
 JSContext::ensureGeneratorStackSpace()
 {
     bool ok = genStack.reserve(genStack.length() + 1);
     if (!ok)
         js_ReportOutOfMemory(this);
     return ok;
 }
 
-inline js::RegExpStatics *
-JSContext::regExpStatics()
-{
-    return js::GetGlobalForScopeChain(this)->getRegExpStatics();
-}
-
 inline void
 JSContext::setPendingException(js::Value v) {
     this->throwing = true;
     this->exception = v;
     js::assertSameCompartment(this, v);
 }
 
 inline bool
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -79,24 +79,17 @@ JSCompartment::JSCompartment(JSRuntime *
     typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     data(NULL),
     active(false),
     hasDebugModeCodeToDrop(false),
 #ifdef JS_METHODJIT
     jaegerCompartment_(NULL),
 #endif
     propertyTree(thisForCtor()),
-    emptyArgumentsShape(NULL),
-    emptyBlockShape(NULL),
-    emptyCallShape(NULL),
-    emptyDeclEnvShape(NULL),
-    emptyEnumeratorShape(NULL),
-    emptyWithShape(NULL),
-    initialRegExpShape(NULL),
-    initialStringShape(NULL),
+    emptyTypeObject(NULL),
     debugModeBits(rt->debugMode ? DebugFromC : 0),
     mathCache(NULL),
     breakpointSites(rt),
     watchpointMap(NULL)
 {
     PodArrayZero(evalCache);
 }
 
@@ -116,16 +109,18 @@ JSCompartment::~JSCompartment()
 }
 
 bool
 JSCompartment::init(JSContext *cx)
 {
     activeAnalysis = activeInference = false;
     types.init(cx);
 
+    newObjectCache.reset();
+
     if (!crossCompartmentWrappers.init())
         return false;
 
     if (!scriptFilenameTable.init())
         return false;
 
     return debuggees.init() && breakpointSites.init();
 }
@@ -255,17 +250,18 @@ JSCompartment::wrap(JSContext *cx, Value
     /* If we already have a wrapper for this value, use it. */
     if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) {
         *vp = p->value;
         if (vp->isObject()) {
             JSObject *obj = &vp->toObject();
             JS_ASSERT(obj->isCrossCompartmentWrapper());
             if (global->getClass() != &dummy_class && obj->getParent() != global) {
                 do {
-                    obj->setParent(global);
+                    if (!obj->setParent(cx, global))
+                        return false;
                     obj = obj->getProto();
                 } while (obj && obj->isCrossCompartmentWrapper());
             }
         }
         return true;
     }
 
     if (vp->isString()) {
@@ -309,17 +305,18 @@ JSCompartment::wrap(JSContext *cx, Value
     vp->setObject(*wrapper);
 
     if (wrapper->getProto() != proto && !SetProto(cx, wrapper, proto, false))
         return false;
 
     if (!crossCompartmentWrappers.put(GetProxyPrivate(wrapper), *vp))
         return false;
 
-    wrapper->setParent(global);
+    if (!wrapper->setParent(cx, global))
+        return false;
     return true;
 }
 
 bool
 JSCompartment::wrap(JSContext *cx, JSString **strp)
 {
     AutoValueRooter tvr(cx, StringValue(*strp));
     if (!wrap(cx, tvr.addr()))
@@ -427,21 +424,21 @@ JSCompartment::markTypes(JSTracer *trc)
     JS_ASSERT(activeAnalysis);
 
     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
         JSScript *script = i.get<JSScript>();
         MarkRoot(trc, script, "mark_types_script");
     }
 
     for (size_t thingKind = FINALIZE_OBJECT0;
-         thingKind < FINALIZE_FUNCTION_AND_OBJECT_LIMIT;
+         thingKind < FINALIZE_OBJECT_LIMIT;
          thingKind++) {
         for (CellIterUnderGC i(this, AllocKind(thingKind)); !i.done(); i.next()) {
             JSObject *object = i.get<JSObject>();
-            if (!object->isNewborn() && object->hasSingletonType())
+            if (object->hasSingletonType())
                 MarkRoot(trc, object, "mark_types_singleton");
         }
     }
 
     for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next())
         MarkRoot(trc, i.get<types::TypeObject>(), "mark_types_scan");
 }
 
@@ -454,34 +451,27 @@ JSCompartment::sweep(JSContext *cx, bool
                      !IsAboutToBeFinalized(cx, e.front().value),
                      e.front().key.isString());
         if (IsAboutToBeFinalized(cx, e.front().key) ||
             IsAboutToBeFinalized(cx, e.front().value)) {
             e.removeFront();
         }
     }
 
-    /* Remove dead empty shapes. */
-    if (emptyArgumentsShape && IsAboutToBeFinalized(cx, emptyArgumentsShape))
-        emptyArgumentsShape = NULL;
-    if (emptyBlockShape && IsAboutToBeFinalized(cx, emptyBlockShape))
-        emptyBlockShape = NULL;
-    if (emptyCallShape && IsAboutToBeFinalized(cx, emptyCallShape))
-        emptyCallShape = NULL;
-    if (emptyDeclEnvShape && IsAboutToBeFinalized(cx, emptyDeclEnvShape))
-        emptyDeclEnvShape = NULL;
-    if (emptyEnumeratorShape && IsAboutToBeFinalized(cx, emptyEnumeratorShape))
-        emptyEnumeratorShape = NULL;
-    if (emptyWithShape && IsAboutToBeFinalized(cx, emptyWithShape))
-        emptyWithShape = NULL;
+    /* Remove dead references held weakly by the compartment. */
 
-    if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape))
-        initialRegExpShape = NULL;
-    if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape))
-        initialStringShape = NULL;
+    sweepBaseShapeTable(cx);
+    sweepInitialShapeTable(cx);
+    sweepNewTypeObjectTable(cx, newTypeObjects);
+    sweepNewTypeObjectTable(cx, lazyTypeObjects);
+
+    if (emptyTypeObject && IsAboutToBeFinalized(cx, emptyTypeObject))
+        emptyTypeObject = NULL;
+
+    newObjectCache.reset();
 
     sweepBreakpoints(cx);
 
     {
         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_CODE);
 
         /*
          * Kick all frames on the stack into the interpreter, and release all JIT
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -41,16 +41,17 @@
 #define jscompartment_h___
 
 #include "jsclist.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsgcstats.h"
 #include "jsobj.h"
+#include "jsscope.h"
 #include "vm/GlobalObject.h"
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 #endif
 
 namespace js {
@@ -243,47 +244,38 @@ struct JS_FRIEND_API(JSCompartment) {
 #ifdef DEBUG
     /* Property metering. */
     jsrefcount                   livePropTreeNodes;
     jsrefcount                   totalPropTreeNodes;
     jsrefcount                   propTreeKidsChunks;
     jsrefcount                   liveDictModeNodes;
 #endif
 
-    typedef js::ReadBarriered<js::EmptyShape> BarrieredEmptyShape;
-    typedef js::ReadBarriered<const js::Shape> BarrieredShape;
+    /* Set of all unowned base shapes in the compartment. */
+    js::BaseShapeSet             baseShapes;
+    void sweepBaseShapeTable(JSContext *cx);
 
-    /*
-     * Runtime-shared empty scopes for well-known built-in objects that lack
-     * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW
-     */
-    BarrieredEmptyShape          emptyArgumentsShape;
-    BarrieredEmptyShape          emptyBlockShape;
-    BarrieredEmptyShape          emptyCallShape;
-    BarrieredEmptyShape          emptyDeclEnvShape;
-    BarrieredEmptyShape          emptyEnumeratorShape;
-    BarrieredEmptyShape          emptyWithShape;
+    /* Set of initial shapes in the compartment. */
+    js::InitialShapeSet          initialShapes;
+    void sweepInitialShapeTable(JSContext *cx);
 
-    typedef js::HashSet<js::EmptyShape *,
-                        js::DefaultHasher<js::EmptyShape *>,
-                        js::SystemAllocPolicy> EmptyShapeSet;
+    /* Set of default 'new' or lazy types in the compartment. */
+    js::types::TypeObjectSet     newTypeObjects;
+    js::types::TypeObjectSet     lazyTypeObjects;
+    void sweepNewTypeObjectTable(JSContext *cx, js::types::TypeObjectSet &table);
 
-    EmptyShapeSet                emptyShapes;
+    js::types::TypeObject        *emptyTypeObject;
 
-    /*
-     * Initial shapes given to RegExp and String objects, encoding the initial
-     * sets of built-in instance properties and the fixed slots where they must
-     * be stored (see JSObject::JSSLOT_(REGEXP|STRING)_*). Later property
-     * additions may cause these shapes to not be used by a RegExp or String
-     * (even along the entire shape parent chain, should the object go into
-     * dictionary mode). But because all the initial properties are
-     * non-configurable, they will always map to fixed slots.
-     */
-    BarrieredShape               initialRegExpShape;
-    BarrieredShape               initialStringShape;
+    /* Get the default 'new' type for objects with a NULL prototype. */
+    inline js::types::TypeObject *getEmptyType(JSContext *cx);
+
+    js::types::TypeObject *getLazyType(JSContext *cx, JSObject *proto);
+
+    /* Cache to speed up object creation. */
+    js::NewObjectCache           newObjectCache;
 
   private:
     enum { DebugFromC = 1, DebugFromJS = 2 };
 
     uintN                        debugModeBits;  // see debugMode() below
 
   public:
     js::NativeIterCache          nativeIterCache;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -1223,19 +1223,21 @@ date_now(JSContext *cx, uintN argc, Valu
 /*
  * Set UTC time to a given time and invalidate cached local time.
  */
 static JSBool
 SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL)
 {
     JS_ASSERT(obj->isDate());
 
-    size_t slotCap = JS_MIN(obj->numSlots(), JSObject::DATE_CLASS_RESERVED_SLOTS);
-    for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; ind < slotCap; ind++)
+    for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
+         ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
+         ind++) {
         obj->setSlot(ind, UndefinedValue());
+    }
 
     obj->setDateUTCTime(DoubleValue(t));
     if (vp)
         vp->setDouble(t);
     return true;
 }
 
 static void
@@ -1252,22 +1254,16 @@ SetDateToNaN(JSContext *cx, JSObject *ob
  */
 static bool
 FillLocalTimes(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isDate());
 
     jsdouble utcTime = obj->getDateUTCTime().toNumber();
 
-    /* Make sure there are slots to store the cached information. */
-    if (obj->numSlots() < JSObject::DATE_CLASS_RESERVED_SLOTS) {
-        if (!obj->growSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
-            return false;
-    }
-
     if (!JSDOUBLE_IS_FINITE(utcTime)) {
         for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START;
              ind < JSObject::DATE_CLASS_RESERVED_SLOTS;
              ind++) {
             obj->setSlot(ind, DoubleValue(utcTime));
         }
         return true;
     }
@@ -2691,30 +2687,28 @@ js_InitDateClass(JSContext *cx, JSObject
     jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom);
     jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom);
     if (!js_GetProperty(cx, dateProto, toUTCStringId, &toUTCStringFun) ||
         !js_DefineProperty(cx, dateProto, toGMTStringId, &toUTCStringFun,
                            JS_PropertyStub, JS_StrictPropertyStub, 0))
     {
         return NULL;
     }
-    if (!cx->typeInferenceEnabled())
-        dateProto->brand(cx);
 
     if (!DefineConstructorAndPrototype(cx, global, JSProto_Date, ctor, dateProto))
         return NULL;
 
     return dateProto;
 }
 
 JS_FRIEND_API(JSObject *)
 js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
 {
     JSObject *obj = NewBuiltinClassInstance(cx, &DateClass);
-    if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
+    if (!obj)
         return NULL;
     if (!SetUTCTime(cx, obj, msec_time))
         return NULL;
     return obj;
 }
 
 JS_FRIEND_API(JSObject *)
 js_NewDateObject(JSContext* cx, int year, int mon, int mday,
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -611,20 +611,25 @@ JS_GetFrameFunction(JSContext *cx, JSSta
 JS_PUBLIC_API(JSObject *)
 JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fpArg)
 {
     StackFrame *fp = Valueify(fpArg);
     if (!fp->isFunctionFrame())
         return NULL;
 
     JS_ASSERT(fp->callee().isFunction());
-    JS_ASSERT(fp->callee().getPrivate() == fp->fun());
     return &fp->callee();
 }
 
+JS_PUBLIC_API(JSObject *)
+JS_GetParentOrScopeChain(JSContext *cx, JSObject *obj)
+{
+    return obj->scopeChain();
+}
+
 JS_PUBLIC_API(JSBool)
 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
 {
     return Valueify(fp)->isConstructing();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
@@ -781,38 +786,38 @@ JS_PropertyIterator(JSObject *obj, JSSco
     /* The caller passes null in *iteratorp to get things started. */
     shape = (Shape *) *iteratorp;
     if (!shape)
         shape = obj->lastProperty();
     else
         shape = shape->previous();
 
     if (!shape->previous()) {
-        JS_ASSERT(JSID_IS_EMPTY(shape->propid));
+        JS_ASSERT(shape->isEmptyShape());
         shape = NULL;
     }
 
     return *iteratorp = reinterpret_cast<JSScopeProperty *>(const_cast<Shape *>(shape));
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
                    JSPropertyDesc *pd)
 {
     assertSameCompartment(cx, obj);
     Shape *shape = (Shape *) sprop;
-    pd->id = IdToJsval(shape->propid);
+    pd->id = IdToJsval(shape->propid());
 
     JSBool wasThrowing = cx->isExceptionPending();
     Value lastException = UndefinedValue();
     if (wasThrowing)
         lastException = cx->getPendingException();
     cx->clearPendingException();
 
-    if (!js_GetProperty(cx, obj, shape->propid, &pd->value)) {
+    if (!js_GetProperty(cx, obj, shape->propid(), &pd->value)) {
         if (!cx->isExceptionPending()) {
             pd->flags = JSPD_ERROR;
             pd->value = JSVAL_VOID;
         } else {
             pd->flags = JSPD_EXCEPTION;
             pd->value = cx->getPendingException();
         }
     } else {
@@ -822,31 +827,31 @@ JS_GetPropertyDesc(JSContext *cx, JSObje
     if (wasThrowing)
         cx->setPendingException(lastException);
 
     pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0)
               |  (!shape->writable()  ? JSPD_READONLY  : 0)
               |  (!shape->configurable() ? JSPD_PERMANENT : 0);
     pd->spare = 0;
     if (shape->getter() == GetCallArg) {
-        pd->slot = shape->shortid;
+        pd->slot = shape->shortid();
         pd->flags |= JSPD_ARGUMENT;
     } else if (shape->getter() == GetCallVar) {
-        pd->slot = shape->shortid;
+        pd->slot = shape->shortid();
         pd->flags |= JSPD_VARIABLE;
     } else {
         pd->slot = 0;
     }
     pd->alias = JSVAL_VOID;
 
-    if (obj->containsSlot(shape->slot)) {
+    if (obj->containsSlot(shape->slot())) {
         for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
             const Shape &aprop = r.front();
-            if (&aprop != shape && aprop.slot == shape->slot) {
-                pd->alias = IdToJsval(aprop.propid);
+            if (&aprop != shape && aprop.slot() == shape->slot()) {
+                pd->alias = IdToJsval(aprop.propid());
                 break;
             }
         }
     }
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -1058,18 +1063,17 @@ JS_PUBLIC_API(JSBool)
 JS_IsSystemObject(JSContext *cx, JSObject *obj)
 {
     return obj->isSystem();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_MakeSystemObject(JSContext *cx, JSObject *obj)
 {
-    obj->setSystem();
-    return true;
+    return obj->setSystem(cx);
 }
 
 /************************************************************************/
 
 JS_FRIEND_API(void)
 js_RevertVersion(JSContext *cx)
 {
     cx->clearVersionOverride();
@@ -1602,32 +1606,16 @@ bool
 js_ResumeVtune()
 {
     VTResume();
     return true;
 }
 
 #endif /* MOZ_VTUNE */
 
-#ifdef MOZ_TRACE_JSCALLS
-
-JS_PUBLIC_API(void)
-JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
-{
-    cx->functionCallback = fcb;
-}
-
-JS_PUBLIC_API(JSFunctionCallback)
-JS_GetFunctionCallback(JSContext *cx)
-{
-    return cx->functionCallback;
-}
-
-#endif /* MOZ_TRACE_JSCALLS */
-
 JS_PUBLIC_API(void)
 JS_DumpBytecode(JSContext *cx, JSScript *script)
 {
 #if defined(DEBUG)
     LifoAlloc lifoAlloc(1024);
     Sprinter sprinter;
     INIT_SPRINTER(cx, &sprinter, &lifoAlloc, 0);
 
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -274,16 +274,19 @@ extern JS_PUBLIC_API(JSBool)
 JS_GetFrameThis(JSContext *cx, JSStackFrame *fp, jsval *thisv);
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp);
 
+extern JS_PUBLIC_API(JSObject *)
+JS_GetParentOrScopeChain(JSContext *cx, JSObject *obj);
+
 /* XXXrginda Initially published with typo */
 #define JS_IsContructorFrame JS_IsConstructorFrame
 extern JS_PUBLIC_API(JSBool)
 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp);
 
@@ -453,19 +456,17 @@ JS_GetFunctionTotalSize(JSContext *cx, J
 
 extern JS_PUBLIC_API(size_t)
 JS_GetScriptTotalSize(JSContext *cx, JSScript *script);
 
 /*
  * Return true if obj is a "system" object, that is, one created by
  * JS_NewSystemObject with the system flag set and not JS_NewObject.
  *
- * What "system" means is up to the API client, but it can be used to implement
- * access control policies based on script filenames and their prefixes, using
- * JS_FlagScriptFilenamePrefix and JS_GetTopScriptFilenameFlags.
+ * What "system" means is up to the API client.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_IsSystemObject(JSContext *cx, JSObject *obj);
 
 /*
  * Mark an object as being a system object. This should be called immediately
  * after allocating the object. A system object is an object for which
  * JS_IsSystemObject returns true.
@@ -572,38 +573,16 @@ js_StopVtune();
 extern JS_FRIEND_API(bool)
 js_PauseVtune();
 
 extern JS_FRIEND_API(bool)
 js_ResumeVtune();
 
 #endif /* MOZ_VTUNE */
 
-#ifdef MOZ_TRACE_JSCALLS
-typedef void (*JSFunctionCallback)(const JSFunction *fun,
-                                   const JSScript *scr,
-                                   const JSContext *cx,
-                                   int entering);
-
-/*
- * The callback is expected to be quick and noninvasive. It should not
- * trigger interrupts, turn on debugging, or produce uncaught JS
- * exceptions. The state of the stack and registers in the context
- * cannot be relied upon, since this callback may be invoked directly
- * from either JIT. The 'entering' field means we are entering a
- * function if it is positive, leaving a function if it is zero or
- * negative.
- */
-extern JS_PUBLIC_API(void)
-JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb);
-
-extern JS_PUBLIC_API(JSFunctionCallback)
-JS_GetFunctionCallback(JSContext *cx);
-#endif /* MOZ_TRACE_JSCALLS */
-
 extern JS_PUBLIC_API(void)
 JS_DumpBytecode(JSContext *cx, JSScript *script);
 
 extern JS_PUBLIC_API(void)
 JS_DumpCompartmentBytecode(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_DumpPCCounts(JSContext *cx, JSScript *script);
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -545,17 +545,17 @@ ValueToShortSource(JSContext *cx, const 
     AutoCompartment ac(cx, obj);
     if (!ac.enter())
         return NULL;
 
     if (obj->isFunction()) {
         /*
          * XXX Avoid function decompilation bloat for now.
          */
-        str = JS_GetFunctionId(obj->getFunctionPrivate());
+        str = JS_GetFunctionId(obj->toFunction());
         if (!str && !(str = js_ValueToSource(cx, v))) {
             /*
              * Continue to soldier on if the function couldn't be
              * converted into a string.
              */
             JS_ClearPendingException(cx);
             str = JS_NewStringCopyZ(cx, "[unknown function]");
         }
@@ -695,20 +695,16 @@ StackTraceToString(JSContext *cx, JSExnP
 /* XXXbe Consolidate the ugly truth that we don't treat filename as UTF-8
          with these two functions. */
 static JSString *
 FilenameToString(JSContext *cx, const char *filename)
 {
     return JS_NewStringCopyZ(cx, filename);
 }
 
-enum {
-    JSSLOT_ERROR_EXNTYPE = 0
-};
-
 static JSBool
 Exception(JSContext *cx, uintN argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /*
      * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
      * called as functions, without operator new.  But as we do not give
@@ -721,17 +717,17 @@ Exception(JSContext *cx, uintN argc, Val
         return false;
 
     if (!protov.isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
         return false;
     }
 
     JSObject *errProto = &protov.toObject();
-    JSObject *obj = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent());
+    JSObject *obj = NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL);
     if (!obj)
         return false;
 
     /* Set the 'message' property. */
     JSString *message;
     if (args.length() != 0 && !args[0].isUndefined()) {
         message = js_ValueToString(cx, args[0]);
         if (!message)
@@ -767,17 +763,17 @@ Exception(JSContext *cx, uintN argc, Val
     uint32_t lineno;
     if (args.length() > 2) {
         if (!ValueToECMAUint32(cx, args[2], &lineno))
             return false;
     } else {
         lineno = iter.done() ? 0 : js_FramePCToLineNumber(cx, iter.fp(), iter.pc());
     }
 
-    intN exnType = args.callee().getReservedSlot(JSSLOT_ERROR_EXNTYPE).toInt32();
+    intN exnType = args.callee().toFunction()->getExtendedSlot(0).toInt32();
     if (!InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType))
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 /*
@@ -1030,20 +1026,21 @@ InitErrorClass(JSContext *cx, GlobalObje
                               JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
         !DefineNativeProperty(cx, errorProto, lineNumberId, Int32Value(0),
                               JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
     {
         return NULL;
     }
 
     /* Create the corresponding constructor. */
-    JSFunction *ctor = global->createConstructor(cx, Exception, &ErrorClass, name, 1);
+    JSFunction *ctor = global->createConstructor(cx, Exception, &ErrorClass, name, 1,
+                                                 JSFunction::ExtendedFinalizeKind);
     if (!ctor)
         return NULL;
-    ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(type)));
+    ctor->setExtendedSlot(0, Int32Value(int32(type)));
 
     if (!LinkConstructorAndPrototype(cx, ctor, errorProto))
         return NULL;
 
     if (!DefineConstructorAndPrototype(cx, global, key, ctor, errorProto))
         return NULL;
 
     JS_ASSERT(!errorProto->getPrivate());
@@ -1169,17 +1166,17 @@ js_ErrorToException(JSContext *cx, const
      * exception constructor name in the scope chain of the current context's
      * top stack frame, or in the global object if no frame is active.
      */
     ok = js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto);
     if (!ok)
         goto out;
     tv[0] = OBJECT_TO_JSVAL(errProto);
 
-    errObject = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent());
+    errObject = NewObjectWithGivenProto(cx, &ErrorClass, errProto, NULL);
     if (!errObject) {
         ok = JS_FALSE;
         goto out;
     }
     tv[1] = OBJECT_TO_JSVAL(errObject);
 
     messageStr = JS_NewStringCopyZ(cx, message);
     if (!messageStr) {
@@ -1357,13 +1354,13 @@ js_CopyErrorObject(JSContext *cx, JSObje
     copy->lineno = priv->lineno;
     copy->stackDepth = 0;
     copy->exnType = priv->exnType;
 
     // Create the Error object.
     JSObject *proto;
     if (!js_GetClassPrototype(cx, scope->getGlobal(), GetExceptionProtoKey(copy->exnType), &proto))
         return NULL;
-    JSObject *copyobj = NewNativeClassInstance(cx, &ErrorClass, proto, proto->getParent());
+    JSObject *copyobj = NewObjectWithGivenProto(cx, &ErrorClass, proto, NULL);
     copyobj->setPrivate(copy);
     autoFree.p = NULL;
     return copyobj;
 }
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -80,17 +80,17 @@ JS_FindCompilationScope(JSContext *cx, J
         obj = op(cx, obj);
     return obj;
 }
 
 JS_FRIEND_API(JSFunction *)
 JS_GetObjectFunction(JSObject *obj)
 {
     if (obj->isFunction())
-        return obj->getFunctionPrivate();
+        return obj->toFunction();
     return NULL;
 }
 
 JS_FRIEND_API(JSObject *)
 JS_GetGlobalForFrame(JSStackFrame *fp)
 {
     return Valueify(fp)->scopeChain().getGlobal();
 }
@@ -120,24 +120,16 @@ JS_FRIEND_API(JSObject *)
 JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
 {
     JSObject *obj = JS_NewObject(cx, clasp, proto, parent);
     if (!obj || !obj->setSingletonType(cx))
         return NULL;
     return obj;
 }
 
-JS_FRIEND_API(uint32)
-JS_ObjectCountDynamicSlots(JSObject *obj)
-{
-    if (obj->hasSlotsArray())
-        return obj->numDynamicSlots(obj->numSlots());
-    return 0;
-}
-    
 JS_PUBLIC_API(void)
 JS_ShrinkingGC(JSContext *cx)
 {
     js_GC(cx, NULL, GC_SHRINK, gcstats::PUBLIC_API);
 }
 
 JS_FRIEND_API(JSPrincipals *)
 JS_GetCompartmentPrincipals(JSCompartment *compartment)
@@ -181,30 +173,136 @@ AutoSwitchCompartment::AutoSwitchCompart
 }
 
 AutoSwitchCompartment::~AutoSwitchCompartment()
 {
     /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
     cx->compartment = oldCompartment;
 }
 
-#ifdef DEBUG
-JS_FRIEND_API(void)
-js::CheckReservedSlot(const JSObject *obj, size_t slot)
+JS_FRIEND_API(size_t)
+js::GetObjectDynamicSlotSize(JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
+{
+    return obj->dynamicSlotSize(mallocSizeOf);
+}
+
+JS_FRIEND_API(size_t)
+js::GetCompartmentShapeTableSize(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf)
+{
+    return c->baseShapes.sizeOfExcludingThis(mallocSizeOf)
+         + c->initialShapes.sizeOfExcludingThis(mallocSizeOf)
+         + c->newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
+         + c->lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
+}
+
+JS_FRIEND_API(bool)
+js::IsScopeObject(const JSObject *obj)
+{
+    return obj->isInternalScope();
+}
+
+JS_FRIEND_API(JSObject *)
+js::GetObjectParentMaybeScope(const JSObject *obj)
+{
+    return obj->scopeChain();
+}
+
+JS_FRIEND_API(JSObject *)
+js::GetGlobalForObjectCrossCompartment(JSObject *obj)
+{
+    return obj->getGlobal();
+}
+
+JS_FRIEND_API(uint32)
+js::GetObjectSlotSpan(const JSObject *obj)
+{
+    return obj->slotSpan();
+}
+
+JS_FRIEND_API(bool)
+js::IsOriginalScriptFunction(JSFunction *fun)
+{
+    return fun->script()->function() == fun;
+}
+
+JS_FRIEND_API(JSFunction *)
+js::DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call,
+                               uintN nargs, uintN attrs)
 {
-    CheckSlot(obj, slot);
-    JS_ASSERT(slot < JSSLOT_FREE(obj->getClass()));
+    JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj);
+    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    if (!atom)
+        return NULL;
+    return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), call, nargs, attrs,
+                             JSFunction::ExtendedFinalizeKind);
+}
+
+JS_FRIEND_API(JSFunction *)
+js::NewFunctionWithReserved(JSContext *cx, JSNative native, uintN nargs, uintN flags,
+                            JSObject *parent, const char *name)
+{
+    JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
+    JSAtom *atom;
+
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, parent);
+
+    if (!name) {
+        atom = NULL;
+    } else {
+        atom = js_Atomize(cx, name, strlen(name));
+        if (!atom)
+            return NULL;
+    }
+
+    return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom,
+                          JSFunction::ExtendedFinalizeKind);
+}
+
+JS_FRIEND_API(JSFunction *)
+js::NewFunctionByIdWithReserved(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent,
+                                jsid id)
+{
+    JS_ASSERT(JSID_IS_STRING(id));
+    JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, parent);
+
+    return js_NewFunction(cx, NULL, native, nargs, flags, parent, JSID_TO_ATOM(id),
+                          JSFunction::ExtendedFinalizeKind);
+}
+
+JS_FRIEND_API(JSObject *)
+js::InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto,
+                          JSClass *clasp, JSNative constructor, uintN nargs,
+                          JSPropertySpec *ps, JSFunctionSpec *fs,
+                          JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
+{
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj, parent_proto);
+    return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor,
+                        nargs, ps, fs, static_ps, static_fs, NULL,
+                        JSFunction::ExtendedFinalizeKind);
+}
+
+JS_FRIEND_API(const Value &)
+js::GetFunctionNativeReserved(JSObject *fun, size_t which)
+{
+    JS_ASSERT(fun->toFunction()->isNative());
+    return fun->toFunction()->getExtendedSlot(which);
 }
 
 JS_FRIEND_API(void)
-js::CheckSlot(const JSObject *obj, size_t slot)
+js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
 {
-    JS_ASSERT(slot < obj->numSlots());
+    JS_ASSERT(fun->toFunction()->isNative());
+    fun->toFunction()->setExtendedSlot(which, val);
 }
-#endif
 
 /*
  * The below code is for temporary telemetry use. It can be removed when
  * sufficient data has been harvested.
  */
 
 extern size_t sE4XObjectsCreated;
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -108,17 +108,16 @@ JS_SetGCFinishedCallback(JSRuntime *rt, 
 
 /* Data for tracking analysis/inference memory usage. */
 typedef struct TypeInferenceMemoryStats
 {
     int64 scripts;
     int64 objects;
     int64 tables;
     int64 temporary;
-    int64 emptyShapes;
 } TypeInferenceMemoryStats;
 
 extern JS_FRIEND_API(void)
 JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
                                TypeInferenceMemoryStats *stats,
                                JSMallocSizeOfFun mallocSizeOf);
 
 extern JS_FRIEND_API(void)
@@ -194,16 +193,22 @@ class JS_FRIEND_API(AutoSwitchCompartmen
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 #ifdef OLD_GETTER_SETTER_METHODS
 JS_FRIEND_API(JSBool) obj_defineGetter(JSContext *cx, uintN argc, js::Value *vp);
 JS_FRIEND_API(JSBool) obj_defineSetter(JSContext *cx, uintN argc, js::Value *vp);
 #endif
 
+extern JS_FRIEND_API(size_t)
+GetObjectDynamicSlotSize(JSObject *obj, JSMallocSizeOfFun mallocSizeOf);
+
+extern JS_FRIEND_API(size_t)
+GetCompartmentShapeTableSize(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
+
 /*
  * Check whether it is OK to assign an undeclared property with name
  * propname of the global object in the current script on cx.  Reports
  * an error if one needs to be reported (in particular in all cases
  * when it returns false).
  */
 extern JS_FRIEND_API(bool)
 CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname);
@@ -239,34 +244,44 @@ TraceWeakMaps(WeakMapTracer *trc);
  * the original header file to ensure that offsets are consistent.
  */
 namespace shadow {
 
 struct TypeObject {
     JSObject    *proto;
 };
 
-struct Object {
-    void        *_1;
+struct BaseShape {
     js::Class   *clasp;
-    uint32      flags;
-    uint32      objShape;
-    void        *_2;
     JSObject    *parent;
-    void        *privateData;
-    jsuword     capacity;
-    js::Value   *slots;
-    TypeObject  *type;
+};
+
+struct Shape {
+    BaseShape   *base;
+    jsid        _1;
+    uint32      slotInfo;
 
     static const uint32 FIXED_SLOTS_SHIFT = 27;
+};
+
+struct Object {
+    Shape       *shape;
+    TypeObject  *type;
+    js::Value   *slots;
+    js::Value   *_1;
+
+    size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; }
+    Value *fixedSlots() const {
+        return (Value *)((jsuword) this + sizeof(shadow::Object));
+    }
 
     js::Value &slotRef(size_t slot) const {
-        size_t nfixed = flags >> FIXED_SLOTS_SHIFT;
+        size_t nfixed = numFixedSlots();
         if (slot < nfixed)
-            return ((Value *)((jsuword) this + sizeof(shadow::Object)))[slot];
+            return fixedSlots()[slot];
         return slots[slot - nfixed];
     }
 };
 
 } /* namespace shadow */
 
 extern JS_FRIEND_DATA(js::Class) AnyNameClass;
 extern JS_FRIEND_DATA(js::Class) AttributeNameClass;
@@ -279,94 +294,115 @@ extern JS_FRIEND_DATA(js::Class) OuterWi
 extern JS_FRIEND_DATA(js::Class) ObjectProxyClass;
 extern JS_FRIEND_DATA(js::Class) QNameClass;
 extern JS_FRIEND_DATA(js::Class) ScriptClass;
 extern JS_FRIEND_DATA(js::Class) XMLClass;
 
 inline js::Class *
 GetObjectClass(const JSObject *obj)
 {
-    return reinterpret_cast<const shadow::Object*>(obj)->clasp;
+    return reinterpret_cast<const shadow::Object*>(obj)->shape->base->clasp;
 }
 
 inline JSClass *
 GetObjectJSClass(const JSObject *obj)
 {
     return js::Jsvalify(GetObjectClass(obj));
 }
 
+JS_FRIEND_API(bool)
+IsScopeObject(const JSObject *obj);
+
 inline JSObject *
 GetObjectParent(const JSObject *obj)
 {
-    return reinterpret_cast<const shadow::Object*>(obj)->parent;
+    JS_ASSERT(!IsScopeObject(obj));
+    return reinterpret_cast<const shadow::Object*>(obj)->shape->base->parent;
 }
 
+JS_FRIEND_API(JSObject *)
+GetObjectParentMaybeScope(const JSObject *obj);
+
+JS_FRIEND_API(JSObject *)
+GetGlobalForObjectCrossCompartment(JSObject *obj);
+
+JS_FRIEND_API(bool)
+IsOriginalScriptFunction(JSFunction *fun);
+
+JS_FRIEND_API(JSFunction *)
+DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call,
+                           uintN nargs, uintN attrs);
+
+JS_FRIEND_API(JSFunction *)
+NewFunctionWithReserved(JSContext *cx, JSNative call, uintN nargs, uintN flags,
+                        JSObject *parent, const char *name);
+
+JS_FRIEND_API(JSFunction *)
+NewFunctionByIdWithReserved(JSContext *cx, JSNative native, uintN nargs, uintN flags,
+                            JSObject *parent, jsid id);
+
+JS_FRIEND_API(JSObject *)
+InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto,
+                      JSClass *clasp, JSNative constructor, uintN nargs,
+                      JSPropertySpec *ps, JSFunctionSpec *fs,
+                      JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
+
+JS_FRIEND_API(const Value &)
+GetFunctionNativeReserved(JSObject *fun, size_t which);
+
+JS_FRIEND_API(void)
+SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val);
+
 inline JSObject *
 GetObjectProto(const JSObject *obj)
 {
     return reinterpret_cast<const shadow::Object*>(obj)->type->proto;
 }
 
 inline void *
 GetObjectPrivate(const JSObject *obj)
 {
-    return reinterpret_cast<const shadow::Object*>(obj)->privateData;
+    const shadow::Object *nobj = reinterpret_cast<const shadow::Object*>(obj);
+    void **addr = reinterpret_cast<void**>(&nobj->fixedSlots()[nobj->numFixedSlots()]);
+    return *addr;
 }
 
-inline JSObject *
-GetObjectGlobal(JSObject *obj)
-{
-    while (JSObject *parent = GetObjectParent(obj))
-        obj = parent;
-    return obj;
-}
-
-#ifdef DEBUG
-extern JS_FRIEND_API(void) CheckReservedSlot(const JSObject *obj, size_t slot);
-extern JS_FRIEND_API(void) CheckSlot(const JSObject *obj, size_t slot);
-#else
-inline void CheckReservedSlot(const JSObject *obj, size_t slot) {}
-inline void CheckSlot(const JSObject *obj, size_t slot) {}
-#endif
-
 /*
  * Get a slot that is both reserved for object's clasp *and* is fixed (fits
  * within the maximum capacity for the object's fixed slots).
  */
 inline const Value &
 GetReservedSlot(const JSObject *obj, size_t slot)
 {
-    CheckReservedSlot(obj, slot);
+    JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
     return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot);
 }
 
 inline void
 SetReservedSlot(JSObject *obj, size_t slot, const Value &value)
 {
-    CheckReservedSlot(obj, slot);
+    JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
     reinterpret_cast<shadow::Object *>(obj)->slotRef(slot) = value;
 }
 
-inline uint32
-GetNumSlots(const JSObject *obj)
-{
-    return uint32(reinterpret_cast<const shadow::Object *>(obj)->capacity);
-}
+JS_FRIEND_API(uint32)
+GetObjectSlotSpan(const JSObject *obj);
 
 inline const Value &
-GetSlot(const JSObject *obj, size_t slot)
+GetObjectSlot(const JSObject *obj, size_t slot)
 {
-    CheckSlot(obj, slot);
+    JS_ASSERT(slot < GetObjectSlotSpan(obj));
     return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot);
 }
 
-inline uint32
+inline Shape *
 GetObjectShape(const JSObject *obj)
 {
-    return reinterpret_cast<const shadow::Object*>(obj)->objShape;
+    shadow::Shape *shape = reinterpret_cast<const shadow::Object*>(obj)->shape;
+    return reinterpret_cast<Shape *>(shape);
 }
 
 static inline js::PropertyOp
 CastAsJSPropertyOp(JSObject *object)
 {
     return JS_DATA_TO_FUNC_PTR(js::PropertyOp, object);
 }
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -118,58 +118,59 @@ js_GetArgsValue(JSContext *cx, StackFram
     argsobj = js_GetArgsObject(cx, fp);
     if (!argsobj)
         return JS_FALSE;
     vp->setObject(*argsobj);
     return JS_TRUE;
 }
 
 js::ArgumentsObject *
-ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
+ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee, StackFrame *fp)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
     JSObject *proto = callee.getGlobal()->getOrCreateObjectPrototype(cx);
     if (!proto)
         return NULL;
 
     TypeObject *type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
-    JS_STATIC_ASSERT(NormalArgumentsObject::RESERVED_SLOTS == 2);
-    JS_STATIC_ASSERT(StrictArgumentsObject::RESERVED_SLOTS == 2);
-    JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
-    if (!obj)
-        return NULL;
-
-    EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx);
+    bool strict = callee.toFunction()->inStrictMode();
+    Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
+    Shape *emptyArgumentsShape =
+        EmptyShape::getInitialShape(cx, clasp, proto,
+                                    proto->getParent(), FINALIZE_KIND,
+                                    BaseShape::INDEXED);
     if (!emptyArgumentsShape)
         return NULL;
 
     ArgumentsData *data = (ArgumentsData *)
         cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
 
     data->callee.init(ObjectValue(callee));
     InitValueRange(data->slots, argc, false);
 
-    /* Can't fail from here on, so initialize everything in argsobj. */
-    obj->init(cx, callee.getFunctionPrivate()->inStrictMode()
-              ? &StrictArgumentsObjectClass
-              : &NormalArgumentsObjectClass,
-              type, proto->getParent(), NULL, false);
-    obj->initMap(emptyArgumentsShape);
+    /* We have everything needed to fill in the object, so make the object. */
+    JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
+    if (!obj)
+        return NULL;
 
     ArgumentsObject *argsobj = obj->asArguments();
 
     JS_ASSERT(UINT32_MAX > (uint64(argc) << PACKED_BITS_COUNT));
     argsobj->initInitialLength(argc);
     argsobj->initData(data);
+    argsobj->setStackFrame(strict ? NULL : fp);
+
+    JS_ASSERT(argsobj->numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
+    JS_ASSERT(argsobj->numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
 
     return argsobj;
 }
 
 struct STATIC_SKIP_INFERENCE PutArg
 {
     PutArg(JSCompartment *comp, HeapValue *dst) : dst(dst), compartment(comp) {}
     HeapValue *dst;
@@ -202,17 +203,17 @@ js_GetArgsObject(JSContext *cx, StackFra
         types::MarkArgumentsCreated(cx, fp->script());
 
     /* Create an arguments object for fp only if it lacks one. */
     JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
     if (fp->hasArgsObj())
         return &fp->argsObj();
 
     ArgumentsObject *argsobj =
-        ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
+        ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee(), fp);
     if (!argsobj)
         return argsobj;
 
     /*
      * Strict mode functions have arguments objects that copy the initial
      * actual parameter values.  It is the caller's responsibility to get the
      * arguments object before any parameters are modified!  (The emitter
      * ensures this by synthesizing an arguments access at the start of any
@@ -517,54 +518,49 @@ strictargs_enumerate(JSContext *cx, JSOb
 }
 
 static void
 args_finalize(JSContext *cx, JSObject *obj)
 {
     cx->free_(reinterpret_cast<void *>(obj->asArguments()->data()));
 }
 
-/*
- * If a generator's arguments or call object escapes, and the generator frame
- * is not executing, the generator object needs to be marked because it is not
- * otherwise reachable. An executing generator is rooted by its invocation.  To
- * distinguish the two cases (which imply different access paths to the
- * generator object), we use the JSFRAME_FLOATING_GENERATOR flag, which is only
- * set on the StackFrame kept in the generator object's JSGenerator.
- */
-static inline void
-MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
-{
-#if JS_HAS_GENERATORS
-    StackFrame *fp = (StackFrame *) obj->getPrivate();
-    if (fp && fp->isFloatingGenerator())
-        MarkObject(trc, js_FloatingFrameToGenerator(fp)->obj, "generator object");
-#endif
-}
-
 static void
 args_trace(JSTracer *trc, JSObject *obj)
 {
     ArgumentsObject *argsobj = obj->asArguments();
     ArgumentsData *data = argsobj->data();
     MarkValue(trc, data->callee, js_callee_str);
     MarkValueRange(trc, argsobj->initialLength(), data->slots, js_arguments_str);
 
-    MaybeMarkGenerator(trc, argsobj);
+    /*
+     * If a generator's arguments or call object escapes, and the generator
+     * frame is not executing, the generator object needs to be marked because
+     * it is not otherwise reachable. An executing generator is rooted by its
+     * invocation.  To distinguish the two cases (which imply different access
+     * paths to the generator object), we use the JSFRAME_FLOATING_GENERATOR
+     * flag, which is only set on the StackFrame kept in the generator object's
+     * JSGenerator.
+     */
+#if JS_HAS_GENERATORS
+    StackFrame *fp = argsobj->maybeStackFrame();
+    if (fp && fp->isFloatingGenerator())
+        MarkObject(trc, js_FloatingFrameToGenerator(fp)->obj, "generator object");
+#endif
 }
 
 /*
  * The classes below collaborate to lazily reflect and synchronize actual
  * argument values, argument count, and callee function object stored in a
  * StackFrame with their corresponding property values in the frame's
  * arguments object.
  */
 Class js::NormalArgumentsObjectClass = {
     "Arguments",
-    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
+    JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     JS_PropertyStub,         /* addProperty */
     args_delProperty,
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     args_enumerate,
     reinterpret_cast<JSResolveOp>(args_resolve),
@@ -581,17 +577,17 @@ Class js::NormalArgumentsObjectClass = {
 
 /*
  * Strict mode arguments is significantly less magical than non-strict mode
  * arguments, so it is represented by a different class while sharing some
  * functionality.
  */
 Class js::StrictArgumentsObjectClass = {
     "Arguments",
-    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
+    JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     JS_PropertyStub,         /* addProperty */
     args_delProperty,
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     strictargs_enumerate,
     reinterpret_cast<JSResolveOp>(strictargs_resolve),
@@ -607,38 +603,50 @@ Class js::StrictArgumentsObjectClass = {
 };
 
 /*
  * A Declarative Environment object stores its active StackFrame pointer in
  * its private slot, just as Call and Arguments objects do.
  */
 Class js::DeclEnvClass = {
     js_Object_str,
-    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_RESERVED_SLOTS(CallObject::DECL_ENV_RESERVED_SLOTS) |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
 static inline JSObject *
 NewDeclEnvObject(JSContext *cx, StackFrame *fp)
 {
-    JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
-    if (!envobj)
+    types::TypeObject *type = cx->compartment->getEmptyType(cx);
+    if (!type)
         return NULL;
 
-    EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
+    JSObject *parent = fp->scopeChain().getGlobal();
+    Shape *emptyDeclEnvShape =
+        EmptyShape::getInitialShape(cx, &DeclEnvClass, NULL,
+                                    parent, CallObject::DECL_ENV_FINALIZE_KIND);
     if (!emptyDeclEnvShape)
         return NULL;
-    envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false);
-    envobj->initMap(emptyDeclEnvShape);
+
+    JSObject *envobj = JSObject::create(cx, CallObject::DECL_ENV_FINALIZE_KIND,
+                                        emptyDeclEnvShape, type, NULL);
+    if (!envobj)
+        return NULL;
+    envobj->setPrivate(fp);
+
+    if (!envobj->setInternalScopeChain(cx, &fp->scopeChain()))
+        return NULL;
 
     return envobj;
 }
 
 namespace js {
 
 CallObject *
 CreateFunCallObject(JSContext *cx, StackFrame *fp)
@@ -719,23 +727,21 @@ js_PutCallObject(StackFrame *fp)
     if (callobj.isForEval()) {
         JS_ASSERT(script->strictModeCode);
         JS_ASSERT(bindings.countArgs() == 0);
 
         /* This could be optimized as below, but keep it simple for now. */
         callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
     } else {
         JSFunction *fun = fp->fun();
-        JS_ASSERT(fun == callobj.getCalleeFunction());
+        JS_ASSERT(script == callobj.getCalleeFunction()->script());
         JS_ASSERT(script == fun->script());
 
         uintN n = bindings.countArgsAndVars();
         if (n > 0) {
-            JS_ASSERT(CallObject::RESERVED_SLOTS + n <= callobj.numSlots());
-
             uint32 nvars = bindings.countVars();
             uint32 nargs = bindings.countArgs();
             JS_ASSERT(fun->nargs == nargs);
             JS_ASSERT(nvars + nargs == n);
 
             JSScript *script = fun->script();
             if (script->usesEval
 #ifdef JS_METHODJIT
@@ -780,17 +786,17 @@ js_PutCallObject(StackFrame *fp)
             if (nesting && script->isOuterFunction) {
                 nesting->argArray = callobj.argArray();
                 nesting->varArray = callobj.varArray();
             }
         }
 
         /* Clear private pointers to fp, which is about to go away. */
         if (js_IsNamedLambda(fun)) {
-            JSObject *env = callobj.getParent();
+            JSObject *env = callobj.internalScopeChain();
 
             JS_ASSERT(env->isDeclEnv());
             JS_ASSERT(env->getPrivate() == fp);
             env->setPrivate(NULL);
         }
     }
 
     callobj.setStackFrame(NULL);
@@ -849,43 +855,43 @@ SetCallArg(JSContext *cx, JSObject *obj,
 
     if (StackFrame *fp = callobj.maybeStackFrame())
         fp->formalArg(i) = *vp;
     else
         callobj.setArg(i, *vp);
 
     JSFunction *fun = callobj.getCalleeFunction();
     JSScript *script = fun->script();
-    if (!script->ensureHasTypes(cx, fun))
+    if (!script->ensureHasTypes(cx))
         return false;
 
     TypeScript::SetArgument(cx, script, i, *vp);
 
     return true;
 }
 
 JSBool
 GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    *vp = callobj.getCallee()->getFlatClosureUpvar(i);
+    *vp = callobj.getCallee()->toFunction()->getFlatClosureUpvar(i);
     return true;
 }
 
 JSBool
 SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    callobj.getCallee()->setFlatClosureUpvar(i, *vp);
+    callobj.getCallee()->toFunction()->setFlatClosureUpvar(i, *vp);
     return true;
 }
 
 JSBool
 GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
@@ -908,17 +914,17 @@ SetCallVar(JSContext *cx, JSObject *obj,
 
     if (StackFrame *fp = callobj.maybeStackFrame())
         fp->varSlot(i) = *vp;
     else
         callobj.setVar(i, *vp);
 
     JSFunction *fun = callobj.getCalleeFunction();
     JSScript *script = fun->script();
-    if (!script->ensureHasTypes(cx, fun))
+    if (!script->ensureHasTypes(cx))
         return false;
 
     TypeScript::SetLocal(cx, script, i, *vp);
 
     return true;
 }
 
 } // namespace js
@@ -929,17 +935,17 @@ call_resolve(JSContext *cx, JSObject *ob
     JS_ASSERT(!obj->getProto());
 
     if (!JSID_IS_ATOM(id))
         return true;
 
     JSObject *callee = obj->asCall().getCallee();
 #ifdef DEBUG
     if (callee) {
-        JSScript *script = callee->getFunctionPrivate()->script();
+        JSScript *script = callee->toFunction()->script();
         JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
     }
 #endif
 
     /*
      * Resolve arguments so that we never store a particular Call object's
      * arguments object reference in a Call prototype's |arguments| slot.
      *
@@ -962,17 +968,22 @@ call_resolve(JSContext *cx, JSObject *ob
     return true;
 }
 
 static void
 call_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isCall());
 
-    MaybeMarkGenerator(trc, obj);
+    /* Mark any generator frame, as for arguments objects. */
+#if JS_HAS_GENERATORS
+    StackFrame *fp = (StackFrame *) obj->getPrivate();
+    if (fp && fp->isFloatingGenerator())
+        MarkObject(trc, js_FloatingFrameToGenerator(fp)->obj, "generator object");
+#endif
 }
 
 JS_PUBLIC_DATA(Class) js::CallClass = {
     "Call",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
     JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
     JS_PropertyStub,         /* addProperty */
@@ -995,124 +1006,117 @@ JS_PUBLIC_DATA(Class) js::CallClass = {
 bool
 StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
 {
     if (!isFunctionFrame()) {
         vp->setNull();
         return true;
     }
 
-    JSFunction *fun = this->fun();
-    JSObject &funobj = callee();
-    vp->setObject(funobj);
+    JSFunction *fun = this->callee().toFunction();
+    vp->setObject(*fun);
 
     /*
      * Check for an escape attempt by a joined function object, which must go
      * through the frame's |this| object's method read barrier for the method
      * atom by which it was uniquely associated with a property.
      */
     const Value &thisv = functionThis();
-    if (thisv.isObject()) {
-        JS_ASSERT(funobj.getFunctionPrivate() == fun);
+    if (thisv.isObject() && fun->methodAtom() && !fun->isClonedMethod()) {
+        JSObject *thisp = &thisv.toObject();
+        JSObject *first_barriered_thisp = NULL;
 
-        if (fun->compiledFunObj() == funobj && fun->methodAtom()) {
-            JSObject *thisp = &thisv.toObject();
-            JSObject *first_barriered_thisp = NULL;
+        do {
+            /*
+             * While a non-native object is responsible for handling its
+             * entire prototype chain, notable non-natives including dense
+             * and typed arrays have native prototypes, so keep going.
+             */
+            if (!thisp->isNative())
+                continue;
 
-            do {
+            const Shape *shape = thisp->nativeLookup(cx, ATOM_TO_JSID(fun->methodAtom()));
+            if (shape) {
                 /*
-                 * While a non-native object is responsible for handling its
-                 * entire prototype chain, notable non-natives including dense
-                 * and typed arrays have native prototypes, so keep going.
+                 * Two cases follow: the method barrier was not crossed
+                 * yet, so we cross it here; the method barrier *was*
+                 * crossed but after the call, in which case we fetch
+                 * and validate the cloned (unjoined) funobj from the
+                 * method property's slot.
+                 *
+                 * In either case we must allow for the method property
+                 * to have been replaced, or its value overwritten.
                  */
-                if (!thisp->isNative())
-                    continue;
+                if (shape->isMethod() && thisp->nativeGetMethod(shape) == fun) {
+                    if (!thisp->methodReadBarrier(cx, *shape, vp))
+                        return false;
+                    overwriteCallee(vp->toObject());
+                    return true;
+                }
 
-                if (thisp->hasMethodBarrier()) {
-                    const Shape *shape = thisp->nativeLookup(cx, ATOM_TO_JSID(fun->methodAtom()));
-                    if (shape) {
+                if (shape->hasSlot()) {
+                    Value v = thisp->getSlot(shape->slot());
+                    JSFunction *clone;
+
+                    if (IsFunctionObject(v, &clone) &&
+                        clone->script() == fun->script() &&
+                        clone->methodObj() == thisp) {
                         /*
-                         * Two cases follow: the method barrier was not crossed
-                         * yet, so we cross it here; the method barrier *was*
-                         * crossed but after the call, in which case we fetch
-                         * and validate the cloned (unjoined) funobj from the
-                         * method property's slot.
-                         *
-                         * In either case we must allow for the method property
-                         * to have been replaced, or its value overwritten.
+                         * N.B. If the method barrier was on a function
+                         * with singleton type, then while crossing the
+                         * method barrier CloneFunctionObject will have
+                         * ignored the attempt to clone the function.
                          */
-                        if (shape->isMethod() && shape->methodObject() == funobj) {
-                            if (!thisp->methodReadBarrier(cx, *shape, vp))
-                                return false;
-                            overwriteCallee(vp->toObject());
-                            return true;
-                        }
-
-                        if (shape->hasSlot()) {
-                            Value v = thisp->getSlot(shape->slot);
-                            JSObject *clone;
-
-                            if (IsFunctionObject(v, &clone) &&
-                                clone->getFunctionPrivate() == fun &&
-                                clone->hasMethodObj(*thisp)) {
-                                /*
-                                 * N.B. If the method barrier was on a function
-                                 * with singleton type, then while crossing the
-                                 * method barrier CloneFunctionObject will have
-                                 * ignored the attempt to clone the function.
-                                 */
-                                JS_ASSERT_IF(!clone->hasSingletonType(), clone != &funobj);
-                                *vp = v;
-                                overwriteCallee(*clone);
-                                return true;
-                            }
-                        }
+                        JS_ASSERT_IF(!clone->hasSingletonType(), clone != fun);
+                        *vp = v;
+                        overwriteCallee(*clone);
+                        return true;
                     }
-
-                    if (!first_barriered_thisp)
-                        first_barriered_thisp = thisp;
                 }
-            } while ((thisp = thisp->getProto()) != NULL);
+            }
 
             if (!first_barriered_thisp)
-                return true;
+                first_barriered_thisp = thisp;
+        } while ((thisp = thisp->getProto()) != NULL);
+
+        if (!first_barriered_thisp)
+            return true;
 
-            /*
-             * At this point, we couldn't find an already-existing clone (or
-             * force to exist a fresh clone) created via thisp's method read
-             * barrier, so we must clone fun and store it in fp's callee to
-             * avoid re-cloning upon repeated foo.caller access.
-             *
-             * This must mean the code in js_DeleteProperty could not find this
-             * stack frame on the stack when the method was deleted. We've lost
-             * track of the method, so we associate it with the first barriered
-             * object found starting from thisp on the prototype chain.
-             */
-            JSObject *newfunobj = CloneFunctionObject(cx, fun);
-            if (!newfunobj)
-                return false;
-            newfunobj->setMethodObj(*first_barriered_thisp);
-            overwriteCallee(*newfunobj);
-            vp->setObject(*newfunobj);
-            return true;
-        }
+        /*
+         * At this point, we couldn't find an already-existing clone (or
+         * force to exist a fresh clone) created via thisp's method read
+         * barrier, so we must clone fun and store it in fp's callee to
+         * avoid re-cloning upon repeated foo.caller access.
+         *
+         * This must mean the code in js_DeleteProperty could not find this
+         * stack frame on the stack when the method was deleted. We've lost
+         * track of the method, so we associate it with the first barriered
+         * object found starting from thisp on the prototype chain.
+         */
+        JSFunction *newfunobj = CloneFunctionObject(cx, fun);
+        if (!newfunobj)
+            return false;
+        newfunobj->setMethodObj(*first_barriered_thisp);
+        overwriteCallee(*newfunobj);
+        vp->setObject(*newfunobj);
+        return true;
     }
 
     return true;
 }
 
 static JSBool
 fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     while (!obj->isFunction()) {
         obj = obj->getProto();
         if (!obj)
             return true;
     }
-    JSFunction *fun = obj->getFunctionPrivate();
+    JSFunction *fun = obj->toFunction();
 
     /*
      * Mark the function's script as uninlineable, to expand any of its
      * frames on the stack before we go looking for them. This allows the
      * below walk to only check each explicit frame rather than needing to
      * check any calls that were inlined.
      */
     if (fun->isInterpreted()) {
@@ -1174,17 +1178,17 @@ fun_getProperty(JSContext *cx, JSObject 
             return true;
         }
 
         /* Censor the caller if it is from another compartment. */
         JSObject &caller = vp->toObject();
         if (caller.compartment() != cx->compartment) {
             vp->setNull();
         } else if (caller.isFunction()) {
-            JSFunction *callerFun = caller.getFunctionPrivate();
+            JSFunction *callerFun = caller.toFunction();
             if (callerFun->isInterpreted() && callerFun->inStrictMode()) {
                 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                              JSMSG_CALLER_IS_STRICT);
                 return false;
             }
         }
 
         return true;
@@ -1234,38 +1238,37 @@ fun_enumerate(JSContext *cx, JSObject *o
 
     return true;
 }
 
 static JSObject *
 ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
 {
 #ifdef DEBUG
-    JSFunction *fun = obj->getFunctionPrivate();
+    JSFunction *fun = obj->toFunction();
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->isFunctionPrototype());
 #endif
 
     /*
      * Assert that fun is not a compiler-created function object, which
      * must never leak to script or embedding code and then be mutated.
      * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
      */
     JS_ASSERT(!IsInternalFunctionObject(obj));
     JS_ASSERT(!obj->isBoundFunction());
 
     /*
      * Make the prototype object an instance of Object with the same parent
      * as the function object itself.
      */
-    JSObject *parent = obj->getParent();
     JSObject *objProto;
-    if (!js_GetClassPrototype(cx, parent, JSProto_Object, &objProto))
+    if (!js_GetClassPrototype(cx, obj->getParent(), JSProto_Object, &objProto))
         return NULL;
-    JSObject *proto = NewNativeClassInstance(cx, &ObjectClass, objProto, parent);
+    JSObject *proto = NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL);
     if (!proto || !proto->setSingletonType(cx))
         return NULL;
 
     /*
      * Per ES5 15.3.5.2 a user-defined function's .prototype property is
      * initially non-configurable, non-enumerable, and writable.  Per ES5 13.2
      * the prototype's .constructor property is configurable, non-enumerable,
      * and writable.
@@ -1284,17 +1287,17 @@ ResolveInterpretedFunctionPrototype(JSCo
 
 static JSBool
 fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
             JSObject **objp)
 {
     if (!JSID_IS_ATOM(id))
         return true;
 
-    JSFunction *fun = obj->getFunctionPrivate();
+    JSFunction *fun = obj->toFunction();
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.classPrototypeAtom)) {
         /*
          * Native or "built-in" functions do not have a .prototype property per
          * ECMA-262, or (Object.prototype, Function.prototype, etc.) have that
          * property created eagerly.
          *
          * ES5 15.3.4: the non-native function object named Function.prototype
@@ -1374,34 +1377,36 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
     uint32 firstword;           /* flag telling whether fun->atom is non-null,
                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
                                    and 14 bits reserved for future use */
     uint32 flagsword;           /* word for argument count and fun->flags */
 
     cx = xdr->cx;
     JSScript *script;
     if (xdr->mode == JSXDR_ENCODE) {
-        fun = (*objp)->getFunctionPrivate();
+        fun = (*objp)->toFunction();
         if (!fun->isInterpreted()) {
             JSAutoByteString funNameBytes;
             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
                                      name);
             }
             return false;
         }
-        firstword = (fun->u.i.skipmin << 2) | !!fun->atom;
+        firstword = !!fun->atom;
         flagsword = (fun->nargs << 16) | fun->flags;
         script = fun->script();
     } else {
         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
         if (!fun)
             return false;
-        fun->clearParent();
-        fun->clearType();
+        if (!fun->clearParent(cx))
+            return false;
+        if (!fun->clearType(cx))
+            return false;
         script = NULL;
     }
 
     AutoObjectRooter tvr(cx, fun);
 
     if (!JS_XDRUint32(xdr, &firstword))
         return false;
     if ((firstword & 1U) && !js_XDRAtom(xdr, &fun->atom))
@@ -1411,17 +1416,16 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
 
     if (!js_XDRScript(xdr, &script))
         return false;
 
     if (xdr->mode == JSXDR_DECODE) {
         fun->nargs = flagsword >> 16;
         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         fun->flags = uint16(flagsword);
-        fun->u.i.skipmin = uint16(firstword >> 2);
         fun->setScript(script);
         if (!script->typeSetFunction(cx, fun))
             return false;
         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
         *objp = fun;
     }
 
@@ -1440,17 +1444,17 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
  * if v is an object) returning true if .prototype is found.
  */
 static JSBool
 fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
 {
     while (obj->isFunction()) {
         if (!obj->isBoundFunction())
             break;
-        obj = obj->getBoundFunctionTarget();
+        obj = obj->toFunction()->getBoundFunctionTarget();
     }
 
     Value pval;
     if (!obj->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &pval))
         return JS_FALSE;
 
     if (pval.isPrimitive()) {
         /*
@@ -1460,65 +1464,62 @@ fun_hasInstance(JSContext *cx, JSObject 
         js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL);
         return JS_FALSE;
     }
 
     *bp = js_IsDelegate(cx, &pval.toObject(), *v);
     return JS_TRUE;
 }
 
+inline void
+JSFunction::trace(JSTracer *trc)
+{
+    if (isFlatClosure() && hasFlatClosureUpvars()) {
+        if (HeapValue *upvars = getFlatClosureUpvars())
+            MarkValueRange(trc, script()->bindings.countUpvars(), upvars, "upvars");
+    }
+
+    if (isExtended()) {
+        MarkValueRange(trc, ArrayLength(toExtended()->extendedSlots),
+                       toExtended()->extendedSlots, "nativeReserved");
+    }
+
+    if (atom)
+        MarkAtom(trc, atom, "atom");
+
+    if (isInterpreted()) {
+        if (script())
+            MarkScript(trc, script(), "script");
+        if (environment())
+            MarkObjectUnbarriered(trc, environment(), "fun_callscope");
+    }
+}
+
 static void
 fun_trace(JSTracer *trc, JSObject *obj)
 {
-    /* A newborn function object may have a not yet initialized private slot. */
-    JSFunction *fun = (JSFunction *) obj->getPrivate();
-    if (!fun)
-        return;
-
-    if (fun != obj) {
-        /*
-         * obj is a cloned function object, trace the clone-parent, fun.
-         * This is safe to leave Unbarriered for incremental GC because any
-         * change to fun will trigger a setPrivate barrer. But we'll need to
-         * fix this for generational GC.
-         */
-        MarkObjectUnbarriered(trc, fun, "private");
-
-        /* The function could be a flat closure with upvar copies in the clone. */
-        if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars()) {
-            MarkValueRange(trc, fun->script()->bindings.countUpvars(),
-                           obj->getFlatClosureData()->upvars, "upvars");
-        }
-        return;
-    }
-
-    if (fun->atom)
-        MarkAtom(trc, fun->atom, "atom");
-
-    if (fun->isInterpreted() && fun->script())
-        MarkScript(trc, fun->script(), "script");
+    obj->toFunction()->trace(trc);
 }
 
 static void
 fun_finalize(JSContext *cx, JSObject *obj)
 {
-    obj->finalizeUpvarsIfFlatClosure();
+    if (obj->toFunction()->isFlatClosure())
+        obj->toFunction()->finalizeUpvars();
 }
 
 /*
  * Reserve two slots in all function objects for XPConnect.  Note that this
  * does not bloat every instance, only those on which reserved slots are set,
  * and those on which ad-hoc properties are defined.
  */
 JS_FRIEND_DATA(Class) js::FunctionClass = {
     js_Function_str,
-    JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
-    JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Function) |
-    JSCLASS_CONCURRENT_FINALIZER,
+    JSCLASS_NEW_RESOLVE |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     fun_enumerate,
     (JSResolveOp)fun_resolve,
     JS_ConvertStub,
     fun_finalize,
@@ -1539,17 +1540,17 @@ fun_toStringHelper(JSContext *cx, JSObje
             return Proxy::fun_toString(cx, obj, indent);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_INCOMPATIBLE_PROTO,
                              js_Function_str, js_toString_str,
                              "object");
         return NULL;
     }
 
-    JSFunction *fun = obj->getFunctionPrivate();
+    JSFunction *fun = obj->toFunction();
     if (!fun)
         return NULL;
 
     if (!indent && !cx->compartment->toSourceCache.empty()) {
         ToSourceCache::Ptr p = cx->compartment->toSourceCache.ref().lookup(fun);
         if (p)
             return p->value;
     }
@@ -1709,114 +1710,118 @@ js_fun_apply(JSContext *cx, uintN argc, 
 
 namespace js {
 
 JSBool
 CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp);
 
 }
 
+static const uint32 JSSLOT_BOUND_FUNCTION_THIS       = 0;
+static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
+
+static const uint32 BOUND_FUNCTION_RESERVED_SLOTS = 2;
+
 inline bool
-JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
-                            const Value *args, uintN argslen)
+JSFunction::initBoundFunction(JSContext *cx, const Value &thisArg,
+                              const Value *args, uintN argslen)
 {
     JS_ASSERT(isFunction());
 
-    flags |= JSObject::BOUND_FUNCTION;
+    /*
+     * Convert to a dictionary to set the BOUND_FUNCTION flag and increase
+     * the slot span to cover the arguments and additional slots for the 'this'
+     * value and arguments count.
+     */
+    if (!toDictionaryMode(cx))
+        return false;
+
+    lastProperty()->base()->setObjectFlag(BaseShape::BOUND_FUNCTION);
+
+    if (!setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
+        return false;
+
     setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
     setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
-    if (argslen != 0) {
-        /* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
-        EmptyShape *empty = EmptyShape::create(cx, getClass());
-        if (!empty)
-            return false;
 
-        empty->slotSpan += argslen;
-        setMap(empty);
+    copySlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen, false);
 
-        if (!ensureInstanceReservedSlots(cx, argslen))
-            return false;
-
-        JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
-        copySlotRange(FUN_CLASS_RESERVED_SLOTS, args, argslen, false);
-    }
     return true;
 }
 
 inline JSObject *
-JSObject::getBoundFunctionTarget() const
+JSFunction::getBoundFunctionTarget() const
 {
     JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
 
     /* Bound functions abuse |parent| to store their target function. */
     return getParent();
 }
 
 inline const js::Value &
-JSObject::getBoundFunctionThis() const
+JSFunction::getBoundFunctionThis() const
 {
     JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
 
     return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
 }
 
 inline const js::Value &
-JSObject::getBoundFunctionArgument(uintN which) const
+JSFunction::getBoundFunctionArgument(uintN which) const
 {
     JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
     JS_ASSERT(which < getBoundFunctionArgumentCount());
 
-    return getSlot(FUN_CLASS_RESERVED_SLOTS + which);
+    return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which);
 }
 
 inline size_t
-JSObject::getBoundFunctionArgumentCount() const
+JSFunction::getBoundFunctionArgumentCount() const
 {
     JS_ASSERT(isFunction());
     JS_ASSERT(isBoundFunction());
 
     return getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
 }
 
 namespace js {
 
 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
 JSBool
 CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = &vp[0].toObject();
-    JS_ASSERT(obj->isFunction());
-    JS_ASSERT(obj->isBoundFunction());
+    JSFunction *fun = vp[0].toObject().toFunction();
+    JS_ASSERT(fun->isBoundFunction());
 
     bool constructing = IsConstructing(vp);
 
     /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
-    uintN argslen = obj->getBoundFunctionArgumentCount();
+    uintN argslen = fun->getBoundFunctionArgumentCount();
 
     if (argc + argslen > StackSpace::ARGS_LENGTH_MAX) {
         js_ReportAllocationOverflow(cx);
         return false;
     }
 
     /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
-    JSObject *target = obj->getBoundFunctionTarget();
+    JSObject *target = fun->getBoundFunctionTarget();
 
     /* 15.3.4.5.1 step 2. */
-    const Value &boundThis = obj->getBoundFunctionThis();
+    const Value &boundThis = fun->getBoundFunctionThis();
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc + argslen, &args))
         return false;
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
     for (uintN i = 0; i < argslen; i++)
-        args[i] = obj->getBoundFunctionArgument(i);
+        args[i] = fun->getBoundFunctionArgument(i);
     memcpy(args.array() + argslen, vp + 2, argc * sizeof(Value));
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
     args.calleev().setObject(*target);
 
     if (!constructing)
         args.thisv() = boundThis;
 
@@ -1828,24 +1833,22 @@ CallOrConstructBoundFunction(JSContext *
 }
 
 }
 
 #if JS_HAS_GENERATORS
 static JSBool
 fun_isGenerator(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *funobj;
-    if (!IsFunctionObject(vp[1], &funobj)) {
+    JSFunction *fun;
+    if (!IsFunctionObject(vp[1], &fun)) {
         JS_SET_RVAL(cx, vp, BooleanValue(false));
         return true;
     }
 
-    JSFunction *fun = funobj->getFunctionPrivate();
-
     bool result = false;
     if (fun->isInterpreted()) {
         JSScript *script = fun->script();
         JS_ASSERT(script->length != 0);
         result = script->code[0] == JSOP_GENERATOR;
     }
 
     JS_SET_RVAL(cx, vp, BooleanValue(result));
@@ -1876,34 +1879,37 @@ fun_bind(JSContext *cx, uintN argc, Valu
     if (args.length() > 1) {
         boundArgs = args.array() + 1;
         argslen = args.length() - 1;
     }
 
     /* Steps 15-16. */
     uintN length = 0;
     if (target->isFunction()) {
-        uintN nargs = target->getFunctionPrivate()->nargs;
+        uintN nargs = target->toFunction()->nargs;
         if (nargs > argslen)
             length = nargs - argslen;
     }
 
     /* Step 4-6, 10-11. */
-    JSAtom *name = target->isFunction() ? target->getFunctionPrivate()->atom : NULL;
+    JSAtom *name = target->isFunction() ? target->toFunction()->atom : NULL;
 
-    /* NB: Bound functions abuse |parent| to store their target. */
     JSObject *funobj =
         js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
                        JSFUN_CONSTRUCTOR, target, name);
     if (!funobj)
         return false;
 
+    /* NB: Bound functions abuse |parent| to store their target. */
+    if (!funobj->setParent(cx, target))
+        return false;
+
     /* Steps 7-9. */
     Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue();
-    if (!funobj->initBoundFunction(cx, thisArg, boundArgs, argslen))
+    if (!funobj->toFunction()->initBoundFunction(cx, thisArg, boundArgs, argslen))
         return false;
 
     /* Steps 17, 19-21 are handled by fun_resolve. */
     /* Step 18 is the default for new functions. */
 
     /* Step 22. */
     args.rval().setObject(*funobj);
     return true;
@@ -2112,17 +2118,17 @@ IsBuiltinFunctionConstructor(JSFunction 
 {
     return fun->maybeNative() == Function;
 }
 
 const Shape *
 LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
 {
 #ifdef DEBUG
-    JSFunction *fun = funobj->getFunctionPrivate();
+    JSFunction *fun = funobj->toFunction();
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->isFunctionPrototype());
     JS_ASSERT(!funobj->isBoundFunction());
 #endif
 
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
     const Shape *shape = funobj->nativeLookup(cx, id);
     if (!shape) {
@@ -2136,180 +2142,182 @@ LookupInterpretedFunctionPrototype(JSCon
     JS_ASSERT(!shape->isMethod());
     return shape;
 }
 
 } /* namespace js */
 
 JSFunction *
 js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
-               uintN flags, JSObject *parent, JSAtom *atom)
+               uintN flags, JSObject *parent, JSAtom *atom, js::gc::AllocKind kind)
 {
+    JS_ASSERT(kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
+    JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
+    JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
+
     JSFunction *fun;
 
     if (funobj) {
         JS_ASSERT(funobj->isFunction());
-        funobj->setParent(parent);
+        JS_ASSERT(funobj->getParent() == parent);
     } else {
-        funobj = NewFunction(cx, parent);
+        funobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
         if (!funobj)
             return NULL;
-        if (native && !funobj->setSingletonType(cx))
-            return NULL;
     }
-    JS_ASSERT(!funobj->getPrivate());
     fun = static_cast<JSFunction *>(funobj);
 
     /* Initialize all function members. */
     fun->nargs = uint16(nargs);
     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK);
     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
         JS_ASSERT(!native);
-        JS_ASSERT(nargs == 0);
-        fun->u.i.skipmin = 0;
         fun->script().init(NULL);
+        fun->setEnvironment(parent);
     } else {
         fun->u.n.clasp = NULL;
         fun->u.n.native = native;
         JS_ASSERT(fun->u.n.native);
     }
+    if (kind == JSFunction::ExtendedFinalizeKind) {
+        fun->flags |= JSFUN_EXTENDED;
+        fun->initializeExtended();
+    }
     fun->atom = atom;
 
-    /* Set private to self to indicate non-cloned fully initialized function. */
-    fun->setPrivate(fun);
+    if (native && !fun->setSingletonType(cx))
+        return NULL;
+
     return fun;
 }
 
-JSObject * JS_FASTCALL
+JSFunction * JS_FASTCALL
 js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
-                       JSObject *proto)
+                       JSObject *proto, gc::AllocKind kind)
 {
     JS_ASSERT(parent);
     JS_ASSERT(proto);
 
-    JSObject *clone;
+    JSObject *cloneobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
+    if (!cloneobj)
+        return NULL;
+    JSFunction *clone = static_cast<JSFunction *>(cloneobj);
+
+    clone->nargs = fun->nargs;
+    clone->flags = fun->flags & ~JSFUN_EXTENDED;
+    clone->u = fun->toFunction()->u;
+    clone->atom = fun->atom;
+
+    if (kind == JSFunction::ExtendedFinalizeKind) {
+        clone->flags |= JSFUN_EXTENDED;
+        clone->initializeExtended();
+    }
+
+    if (clone->isInterpreted())
+        clone->setEnvironment(parent);
+
     if (cx->compartment == fun->compartment()) {
         /*
-         * The cloned function object does not need the extra JSFunction members
-         * beyond JSObject as it points to fun via the private slot.
-         */
-        clone = NewNativeClassInstance(cx, &FunctionClass, proto, parent);
-        if (!clone)
-            return NULL;
-
-        /*
          * We can use the same type as the original function provided that (a)
          * its prototype is correct, and (b) its type is not a singleton. The
          * first case will hold in all compileAndGo code, and the second case
          * will have been caught by CloneFunctionObject coming from function
          * definitions or read barriers, so will not get here.
          */
         if (fun->getProto() == proto && !fun->hasSingletonType())
-            clone->initType(fun->type());
-
-        clone->setPrivate(fun);
+            clone->setType(fun->type());
     } else {
         /*
-         * Across compartments we have to deep copy JSFunction and clone the
-         * script (for interpreted functions).
+         * Across compartments we have to clone the script for interpreted
+         * functions.
          */
-        clone = NewFunction(cx, parent);
-        if (!clone)
-            return NULL;
-
-        JSFunction *cfun = (JSFunction *) clone;
-        cfun->nargs = fun->nargs;
-        cfun->flags = fun->flags;
-        cfun->u = fun->getFunctionPrivate()->u;
-        cfun->atom = fun->atom;
-        clone->setPrivate(cfun);
-        if (cfun->isInterpreted()) {
-            JSScript *script = fun->script();