Merge m-c to m-i.
authorMs2ger <ms2ger@gmail.com>
Thu, 10 Nov 2011 20:26:10 +0100
changeset 80144 57aea6749943167710d4bfff28822db0a8989d7c
parent 80129 a41fa578cfc111f8d63a2ca38d0293f8cbde54c7 (current diff)
parent 80143 65dcb557b3f6752817db6e7e9d50043e4afb5ace (diff)
child 80145 33d34da275ed942822531afb7b3739579dfb67a5
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone11.0a1
Merge m-c to m-i.
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -233,17 +233,18 @@ nsAccDocManager::OnProgressChange(nsIWeb
                                   PRInt32 aMaxTotalProgress)
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccDocManager::OnLocationChange(nsIWebProgress *aWebProgress,
-                                  nsIRequest *aRequest, nsIURI *aLocation)
+                                  nsIRequest *aRequest, nsIURI *aLocation,
+                                  PRUint32 aFlags)
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccDocManager::OnStatusChange(nsIWebProgress *aWebProgress,
                                 nsIRequest *aRequest, nsresult aStatus,
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4581,17 +4581,17 @@ var XULBrowserWindow = {
           this.throbberElement.removeAttribute("busy");
 
         this.stopCommand.setAttribute("disabled", "true");
         CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest);
       }
     }
   },
 
-  onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
+  onLocationChange: function (aWebProgress, aRequest, aLocationURI, aFlags) {
     var location = aLocationURI ? aLocationURI.spec : "";
     this._hostChanged = true;
 
     // Hide the form invalid popup.
     if (gFormSubmitObserver.panelIsOpen()) {
       gFormSubmitObserver.panel.hidePopup();
     }
 
@@ -5047,17 +5047,18 @@ var TabsProgressListener = {
         aBrowser.removeEventListener("pagehide", arguments.callee, true);
       }, true);
 
       // We also want to make changes to page UI for unprivileged about pages.
       BrowserOnAboutPageLoad(aWebProgress.DOMWindow.document);
     }
   },
 
-  onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
+  onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI,
+                              aFlags) {
     // Filter out any sub-frame loads
     if (aBrowser.contentWindow == aWebProgress.DOMWindow)
       FullZoom.onLocationChange(aLocationURI, false, aBrowser);
   },
 
   onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) {
     if (gPrefService.getBoolPref("accessibility.blockautorefresh")) {
       let brandBundle = document.getElementById("bundle_brand");
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -603,17 +603,18 @@
                 // reset cached temporary values at beginning and end
                 this.mMessage = "";
                 this.mTotalProgress = 0;
               }
               this.mStateFlags = aStateFlags;
               this.mStatus = aStatus;
             },
 
-            onLocationChange: function (aWebProgress, aRequest, aLocation) {
+            onLocationChange: function (aWebProgress, aRequest, aLocation,
+                                        aFlags) {
               // OnLocationChange is called for both the top-level content
               // and the subframes.
               let topLevel = aWebProgress.DOMWindow == this.mBrowser.contentWindow;
 
               if (topLevel) {
                 // The document loaded correctly, clear the value if we should
                 if (this.mBrowser.userTypedClear > 0)
                   this.mBrowser.userTypedValue = null;
@@ -636,17 +637,18 @@
                 if (aLocation.spec != "about:blank") {
                   autocomplete.registerOpenPage(aLocation);
                   this.mBrowser.registeredOpenURI = aLocation;
                 }
               }
 
               if (!this.mBlank) {
                 this._callProgressListeners("onLocationChange",
-                                            [aWebProgress, aRequest, aLocation]);
+                                            [aWebProgress, aRequest, aLocation,
+                                             aFlags]);
               }
 
               if (topLevel)
                 this.mBrowser.lastURI = aLocation;
             },
 
             onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
               if (this.mBlank)
@@ -885,17 +887,18 @@
 #ifdef MOZ_E10S_COMPAT
             // Bug 666801 - WebProgress support for e10s and
             // Bug 666809 - SecurityUI support for e10s
 #else
             var webProgress = this.mCurrentBrowser.webProgress;
             var securityUI = this.mCurrentBrowser.securityUI;
 
             this._callProgressListeners(null, "onLocationChange",
-                                        [webProgress, null, loc], true, false);
+                                        [webProgress, null, loc, 0], true,
+                                        false);
 
             if (securityUI) {
               this._callProgressListeners(null, "onSecurityChange",
                                           [webProgress, null, securityUI.state], true, false);
             }
 #endif
 
             var listener = this.mTabListeners[this.tabContainer.selectedIndex] || null;
--- a/browser/base/content/test/browser_alltabslistener.js
+++ b/browser/base/content/test/browser_alltabslistener.js
@@ -12,17 +12,17 @@ var gFrontProgressListener = {
   onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
     var state = "onStateChange";
     info("FrontProgress: " + state + " 0x" + aStateFlags.toString(16));
     ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
     is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
     gFrontNotificationsPos++;
   },
 
-  onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
+  onLocationChange: function (aWebProgress, aRequest, aLocationURI, aFlags) {
     var state = "onLocationChange";
     info("FrontProgress: " + state + " " + aLocationURI.spec);
     ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
     is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
     gFrontNotificationsPos++;
   },
   
   onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
@@ -48,17 +48,18 @@ var gAllProgressListener = {
 
     if ((aStateFlags & gCompleteState) == gCompleteState) {
       ok(gAllNotificationsPos == gAllNotifications.length, "Saw the expected number of notifications");
       ok(gFrontNotificationsPos == gFrontNotifications.length, "Saw the expected number of frontnotifications");
       executeSoon(gNextTest);
     }
   },
 
-  onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
+  onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI,
+                              aFlags) {
     var state = "onLocationChange";
     info("AllProgress: " + state + " " + aLocationURI.spec);
     ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
     ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
     is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
     gAllNotificationsPos++;
   },
   
--- a/browser/base/content/test/browser_urlbarTrimURLs.js
+++ b/browser/base/content/test/browser_urlbarTrimURLs.js
@@ -27,17 +27,23 @@ function test() {
   testVal("http://mozilla.imaginatory/", "mozilla.imaginatory");
   testVal("http://www.mozilla.org/", "www.mozilla.org");
   testVal("http://sub.mozilla.org/", "sub.mozilla.org");
   testVal("http://sub1.sub2.sub3.mozilla.org/", "sub1.sub2.sub3.mozilla.org");
   testVal("http://mozilla.org/file.ext", "mozilla.org/file.ext");
   testVal("http://mozilla.org/sub/", "mozilla.org/sub/");
 
   testVal("http://ftp.mozilla.org/", "http://ftp.mozilla.org");
+  testVal("http://ftp1.mozilla.org/", "http://ftp1.mozilla.org");
+  testVal("http://ftp42.mozilla.org/", "http://ftp42.mozilla.org");
+  testVal("http://ftpx.mozilla.org/", "ftpx.mozilla.org");
   testVal("ftp://ftp.mozilla.org/", "ftp://ftp.mozilla.org");
+  testVal("ftp://ftp1.mozilla.org/", "ftp://ftp1.mozilla.org");
+  testVal("ftp://ftp42.mozilla.org/", "ftp://ftp42.mozilla.org");
+  testVal("ftp://ftpx.mozilla.org/", "ftp://ftpx.mozilla.org");
 
   testVal("https://user:pass@mozilla.org/", "https://user:pass@mozilla.org");
   testVal("http://user:pass@mozilla.org/", "http://user:pass@mozilla.org");
   testVal("http://sub.mozilla.org:666/", "sub.mozilla.org:666");
 
   testVal("https://[fe80::222:19ff:fe11:8c76]/file.ext");
   testVal("http://[fe80::222:19ff:fe11:8c76]/", "[fe80::222:19ff:fe11:8c76]");
   testVal("https://user:pass@[fe80::222:19ff:fe11:8c76]:666/file.ext");
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -630,13 +630,15 @@ function openPrefsHelp() {
   // since its probably behind the window.
   var instantApply = getBoolPref("browser.preferences.instantApply");
 
   var helpTopic = document.getElementsByTagName("prefwindow")[0].currentPane.helpTopic;
   openHelpLink(helpTopic, !instantApply);
 }
 
 function trimURL(aURL) {
+  // This function must not modify the given URL such that calling
+  // nsIURIFixup::createFixupURI with the result will produce a different URI.
   return aURL /* remove single trailing slash for http/https/ftp URLs */
              .replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1")
-              /* remove http:// unless the host starts with "ftp." or contains "@" */
-             .replace(/^http:\/\/((?!ftp\.)[^\/@]+(?:\/|$))/, "$1");
+              /* remove http:// unless the host starts with "ftp\d*\." or contains "@" */
+             .replace(/^http:\/\/((?!ftp\d*\.)[^\/@]+(?:\/|$))/, "$1");
 }
--- a/browser/base/content/web-panels.js
+++ b/browser/base/content/web-panels.js
@@ -67,17 +67,17 @@ var panelProgressListener = {
         }
         else if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
                 aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
             window.parent.document.getElementById('sidebar-throbber').removeAttribute("loading");
         }
     }
     ,
 
-    onLocationChange : function(aWebProgress, aRequest, aLocation) {
+    onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags) {
         UpdateBackForwardCommands(getPanelBrowser().webNavigation);
     },
 
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) {
     },
 
     onSecurityChange : function(aWebProgress, aRequest, aState) { 
     },
--- a/browser/components/places/tests/browser/browser_library_middleclick.js
+++ b/browser/components/places/tests/browser/browser_library_middleclick.js
@@ -59,17 +59,18 @@ var gTabsListener = {
          "We have opened " + gCurrentTest.URIs.length + " new tab(s)");
     }
 
     var tab = aEvent.target;
     is(tab.ownerDocument.defaultView, window,
        "Tab has been opened in current browser window");
   },
 
-  onLocationChange: function(aBrowser, aWebProgress, aRequest, aLocationURI) {
+  onLocationChange: function(aBrowser, aWebProgress, aRequest, aLocationURI,
+                             aFlags) {
     var spec = aLocationURI.spec;
     ok(true, spec);
     // When a new tab is opened, location is first set to "about:blank", so
     // we can ignore those calls.
     // Ignore multiple notifications for the same URI too.
     if (spec == "about:blank" || this._loadedURIs.indexOf(spec) != -1)
       return;
 
--- a/browser/components/shell/src/nsMacShellService.cpp
+++ b/browser/components/shell/src/nsMacShellService.cpp
@@ -230,17 +230,18 @@ nsMacShellService::OnProgressChange(nsIW
                                     PRInt32 aMaxTotalProgress)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMacShellService::OnLocationChange(nsIWebProgress* aWebProgress,
                                     nsIRequest* aRequest,
-                                    nsIURI* aLocation)
+                                    nsIURI* aLocation,
+                                    PRUint32 aFlags)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMacShellService::OnStatusChange(nsIWebProgress* aWebProgress,
                                   nsIRequest* aRequest,
                                   nsresult aStatus,
--- a/configure.in
+++ b/configure.in
@@ -7223,16 +7223,27 @@ MOZ_ARG_ENABLE_BOOL(tracevis,
 [  --enable-tracevis       Enable TraceVis tracing tool (default=no)],
     MOZ_TRACEVIS=1,
     MOZ_TRACEVIS= )
 if test -n "$MOZ_TRACEVIS"; then
     AC_DEFINE(MOZ_TRACEVIS)
 fi
 
 dnl ========================================================
+dnl = Use incremental GC
+dnl ========================================================
+JSGC_INCREMENTAL=1
+MOZ_ARG_DISABLE_BOOL(gcincremental,
+[  --disable-gcincremental Disable incremental GC],
+    JSGC_INCREMENTAL= )
+if test -n "$JSGC_INCREMENTAL"; then
+    AC_DEFINE(JSGC_INCREMENTAL)
+fi
+
+dnl ========================================================
 dnl ETW - Event Tracing for Windows
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(ETW,
 [  --enable-ETW            Enable ETW (Event Tracing for Windows) event reporting
                           (needs Windows Vista+ SDK)],
     MOZ_ETW=1,
     MOZ_ETW= )
 if test -n "$MOZ_ETW"; then
--- a/content/base/public/nsIDocumentEncoder.idl
+++ b/content/base/public/nsIDocumentEncoder.idl
@@ -46,17 +46,17 @@ interface nsIOutputStream;
 
 %{ C++
 class nsINode;
 class nsIDocument;
 %}
 [ptr] native nsINodePtr(nsINode);
 [ptr] native nsIDocumentPtr(nsIDocument);
 
-[scriptable, uuid(c0da5b87-0ba7-4d7c-8cb3-fcb02af4253d)]
+[scriptable, uuid(82adaeca-63ee-44eb-830a-e1678bb8745e)]
 interface nsIDocumentEncoderNodeFixup : nsISupports
 {
   /**
    * Create a fixed up version of a node. This method is called before
    * each node in a document is about to be persisted. The implementor
    * may return a new node with fixed up attributes or null. If null is
    * returned the node should be used as-is.
    * @param aNode Node to fixup.
@@ -267,16 +267,17 @@ interface nsIDocumentEncoder : nsISuppor
 
   /**
    *  If the node is set to a non-null value, then the
    *  node is used for encoding, otherwise the entire
    *  document or range or selection is encoded.
    * @param aNode The node to encode.
    */
   void setNode(in nsIDOMNode aNode);
+  [noscript] void setNativeNode(in nsINodePtr aNode);
 
   /**
    *  If the container is set to a non-null value, then its
    *  child nodes are used for encoding, otherwise the entire
    *  document or range or selection or node is encoded.
    *  @param aContainer The node which child nodes will be encoded.
    */
   void setContainerNode(in nsIDOMNode aContainer);
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -297,16 +297,24 @@ NS_IMETHODIMP
 nsDocumentEncoder::SetNode(nsIDOMNode* aNode)
 {
   mNodeIsContainer = false;
   mNode = do_QueryInterface(aNode);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocumentEncoder::SetNativeNode(nsINode* aNode)
+{
+  mNodeIsContainer = false;
+  mNode = aNode;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocumentEncoder::SetContainerNode(nsIDOMNode *aContainer)
 {
   mNodeIsContainer = true;
   mNode = do_QueryInterface(aContainer);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -115,16 +115,17 @@
 #include "nsHtml5Module.h"
 #include "nsITextControlElement.h"
 #include "mozilla/dom/Element.h"
 #include "nsHTMLFieldSetElement.h"
 #include "nsHTMLMenuElement.h"
 #include "nsPLDOMEvent.h"
 
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/FromParser.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #include "nsThreadUtils.h"
 
 class nsINodeInfo;
 class nsIDOMNodeList;
@@ -660,25 +661,23 @@ nsGenericHTMLElement::GetOffsetParent(ns
     CallQueryInterface(parent, aOffsetParent);
   } else {
     *aOffsetParent = nsnull;
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsGenericHTMLElement::GetInnerHTML(nsAString& aInnerHTML)
+nsresult
+nsGenericHTMLElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
 {
-  aInnerHTML.Truncate();
+  aMarkup.Truncate();
 
   nsIDocument* doc = OwnerDoc();
 
-  nsresult rv = NS_OK;
-
   nsAutoString contentType;
   if (IsInHTMLDocument()) {
     contentType.AssignLiteral("text/html");
   } else {
     doc->GetContentType(contentType);
   }
 
   nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
@@ -693,31 +692,47 @@ nsGenericHTMLElement::GetInnerHTML(nsASt
     // This could be some type for which we create a synthetic document.  Try
     // again as XML
     contentType.AssignLiteral("application/xml");
     docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "application/xml");
   }
 
   NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
 
-  rv = docEncoder->NativeInit(doc, contentType,
-                              nsIDocumentEncoder::OutputEncodeBasicEntities |
-                              // Output DOM-standard newlines
-                              nsIDocumentEncoder::OutputLFLineBreak |
-                              // Don't do linebreaking that's not present in
-                              // the source
-                              nsIDocumentEncoder::OutputRaw);
+  nsresult rv = docEncoder->NativeInit(doc, contentType,
+                                       nsIDocumentEncoder::OutputEncodeBasicEntities |
+                                       // Output DOM-standard newlines
+                                       nsIDocumentEncoder::OutputLFLineBreak |
+                                       // Don't do linebreaking that's not present in
+                                       // the source
+                                       nsIDocumentEncoder::OutputRaw);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  docEncoder->SetNativeContainerNode(this);
-  rv = docEncoder->EncodeToString(aInnerHTML);
-  doc->SetCachedEncoder(docEncoder.forget());
+  if (aIncludeSelf) {
+    docEncoder->SetNativeNode(this);
+  } else {
+    docEncoder->SetNativeContainerNode(this);
+  }
+  rv = docEncoder->EncodeToString(aMarkup);
+  if (!aIncludeSelf) {
+    doc->SetCachedEncoder(docEncoder.forget());
+  }
   return rv;
 }
 
+nsresult
+nsGenericHTMLElement::GetInnerHTML(nsAString& aInnerHTML) {
+  return GetMarkup(false, aInnerHTML);
+}
+
+NS_IMETHODIMP
+nsGenericHTMLElement::GetOuterHTML(nsAString& aOuterHTML) {
+  return GetMarkup(true, aOuterHTML);
+}
+
 void
 nsGenericHTMLElement::FireMutationEventsForDirectParsing(nsIDocument* aDoc,
                                                          nsIContent* aDest,
                                                          PRInt32 aOldChildCount)
 {
   // Fire mutation events. Optimize for the case when there are no listeners
   PRInt32 newChildCount = aDest->GetChildCount();
   if (newChildCount && nsContentUtils::
@@ -735,48 +750,46 @@ nsGenericHTMLElement::FireMutationEvents
   }
 }
 
 NS_IMETHODIMP
 nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
 {
   nsIDocument* doc = OwnerDoc();
 
-  nsresult rv = NS_OK;
-
   // Batch possible DOMSubtreeModified events.
   mozAutoSubtreeModified subtree(doc, nsnull);
 
   FireNodeRemovedForChildren();
 
   // Needed when innerHTML is used in combination with contenteditable
   mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
 
   // Remove childnodes.
   PRUint32 childCount = GetChildCount();
   for (PRUint32 i = 0; i < childCount; ++i) {
     RemoveChildAt(0, true);
   }
 
   nsAutoScriptLoaderDisabler sld(doc);
   
-  nsCOMPtr<nsIDOMDocumentFragment> df;
-
+  nsresult rv = NS_OK;
   if (doc->IsHTML()) {
     PRInt32 oldChildCount = GetChildCount();
     rv = nsContentUtils::ParseFragmentHTML(aInnerHTML,
                                            this,
                                            Tag(),
                                            GetNameSpaceID(),
                                            doc->GetCompatibilityMode() ==
                                              eCompatibility_NavQuirks,
                                            true);
     // HTML5 parser has notified, but not fired mutation events.
     FireMutationEventsForDirectParsing(doc, this, oldChildCount);
   } else {
+    nsCOMPtr<nsIDOMDocumentFragment> df;
     rv = nsContentUtils::CreateContextualFragment(this, aInnerHTML,
                                                   true,
                                                   getter_AddRefs(df));
     nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
     if (NS_SUCCEEDED(rv)) {
       // Suppress assertion about node removal mutation events that can't have
       // listeners anyway, because no one has had the chance to register mutation
       // listeners on the fragment that comes from the parser.
@@ -784,16 +797,81 @@ nsGenericHTMLElement::SetInnerHTML(const
 
       static_cast<nsINode*>(this)->AppendChild(fragment, &rv);
     }
   }
 
   return rv;
 }
 
+NS_IMETHODIMP
+nsGenericHTMLElement::SetOuterHTML(const nsAString& aOuterHTML)
+{
+  nsINode* parent = GetNodeParent();
+  if (!parent) {
+    return NS_OK;
+  }
+
+  if (parent->NodeType() == nsIDOMNode::DOCUMENT_NODE) {
+    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+  }
+
+  if (OwnerDoc()->IsHTML()) {
+    nsIAtom* localName;
+    PRInt32 namespaceID;
+    if (parent->IsElement()) {
+      localName = static_cast<nsIContent*>(parent)->Tag();
+      namespaceID = static_cast<nsIContent*>(parent)->GetNameSpaceID();
+    } else {
+      NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
+        "How come the parent isn't a document, a fragment or an element?");
+      localName = nsGkAtoms::body;
+      namespaceID = kNameSpaceID_XHTML;
+    }
+    nsCOMPtr<nsIDOMDocumentFragment> df;
+    nsresult rv = NS_NewDocumentFragment(getter_AddRefs(df),
+                                         OwnerDoc()->NodeInfoManager());
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIContent> fragment = do_QueryInterface(df);
+    nsContentUtils::ParseFragmentHTML(aOuterHTML,
+                                      fragment,
+                                      localName,
+                                      namespaceID,
+                                      OwnerDoc()->GetCompatibilityMode() ==
+                                        eCompatibility_NavQuirks,
+                                      PR_TRUE);
+    parent->ReplaceChild(fragment, this, &rv);
+    return rv;
+  }
+
+  nsCOMPtr<nsINode> context;
+  if (parent->IsElement()) {
+    context = parent;
+  } else {
+    NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
+      "How come the parent isn't a document, a fragment or an element?");
+    nsCOMPtr<nsINodeInfo> info =
+      OwnerDoc()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::body,
+                                                 nsnull,
+                                                 kNameSpaceID_XHTML,
+                                                 nsIDOMNode::ELEMENT_NODE);
+    context = NS_NewHTMLBodyElement(info.forget(), FROM_PARSER_FRAGMENT);
+  }
+
+  nsCOMPtr<nsIDOMDocumentFragment> df;
+  nsresult rv = nsContentUtils::CreateContextualFragment(context,
+                                                         aOuterHTML,
+                                                         PR_TRUE,
+                                                         getter_AddRefs(df));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
+  parent->ReplaceChild(fragment, this, &rv);
+  return rv;
+}
+
 enum nsAdjacentPosition {
   eBeforeBegin,
   eAfterBegin,
   eBeforeEnd,
   eAfterEnd
 };
 
 NS_IMETHODIMP
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -127,16 +127,18 @@ public:
   nsresult SetClassName(const nsAString& aClassName);
   nsresult GetOffsetTop(PRInt32* aOffsetTop);
   nsresult GetOffsetLeft(PRInt32* aOffsetLeft);
   nsresult GetOffsetWidth(PRInt32* aOffsetWidth);
   nsresult GetOffsetHeight(PRInt32* aOffsetHeight);
   nsresult GetOffsetParent(nsIDOMElement** aOffsetParent);
   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
   NS_IMETHOD SetInnerHTML(const nsAString& aInnerHTML);
+  NS_IMETHOD GetOuterHTML(nsAString& aOuterHTML);
+  NS_IMETHOD SetOuterHTML(const nsAString& aOuterHTML);
   NS_IMETHOD InsertAdjacentHTML(const nsAString& aPosition,
                                 const nsAString& aText);
   nsresult ScrollIntoView(bool aTop, PRUint8 optional_argc);
   nsresult MozRequestFullScreen();
   // Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetHidden(),
   // SetHidden(), GetSpellcheck(), SetSpellcheck(), and GetDraggable() such that
   // classes that inherit interfaces with those methods properly override them.
   NS_IMETHOD Focus();
@@ -156,16 +158,20 @@ public:
   nsresult GetContentEditable(nsAString& aContentEditable);
   nsresult GetIsContentEditable(bool* aContentEditable);
   nsresult SetContentEditable(const nsAString &aContentEditable);
   nsresult GetDataset(nsIDOMDOMStringMap** aDataset);
   // Callback for destructor of of dataset to ensure to null out weak pointer.
   nsresult ClearDataset();
   nsresult GetContextMenu(nsIDOMHTMLMenuElement** aContextMenu);
 
+protected:
+  nsresult GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
+
+public:
   // Implementation for nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true);
   nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                    const nsAString& aValue, bool aNotify)
@@ -1566,16 +1572,22 @@ protected:
     return _to GetContextMenu(aContextMenu); \
   } \
   NS_SCRIPTABLE NS_IMETHOD GetSpellcheck(bool* aSpellcheck) { \
     return _to GetSpellcheck(aSpellcheck); \
   } \
   NS_SCRIPTABLE NS_IMETHOD SetSpellcheck(bool aSpellcheck) { \
     return _to SetSpellcheck(aSpellcheck); \
   } \
+  NS_SCRIPTABLE NS_IMETHOD GetOuterHTML(nsAString& aOuterHTML) { \
+    return _to GetOuterHTML(aOuterHTML); \
+  } \
+  NS_SCRIPTABLE NS_IMETHOD SetOuterHTML(const nsAString& aOuterHTML) { \
+    return _to SetOuterHTML(aOuterHTML); \
+  } \
   NS_SCRIPTABLE NS_IMETHOD InsertAdjacentHTML(const nsAString& position, const nsAString& text) { \
     return _to InsertAdjacentHTML(position, text); \
   } \
   NS_SCRIPTABLE NS_IMETHOD ScrollIntoView(bool top, PRUint8 _argc) { \
     return _to ScrollIntoView(top, _argc); \
   } \
   NS_SCRIPTABLE NS_IMETHOD GetOffsetParent(nsIDOMElement** aOffsetParent) { \
     return _to GetOffsetParent(aOffsetParent); \
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -496,18 +496,18 @@ nsHTMLCanvasElement::GetContext(const ns
       // note: if any contexts end up supporting something other
       // than objects, e.g. plain strings, then we'll need to expand
       // this to know how to create nsISupportsStrings etc.
       if (JSVAL_IS_OBJECT(aContextOptions)) {
         contextProps = do_CreateInstance("@mozilla.org/hash-property-bag;1");
 
         JSObject *opts = JSVAL_TO_OBJECT(aContextOptions);
         JSIdArray *props = JS_Enumerate(cx, opts);
-        for (int i = 0; props && i < props->length; ++i) {
-          jsid propid = props->vector[i];
+        for (int i = 0; props && i < JS_IdArrayLength(cx, props); ++i) {
+          jsid propid = JS_IdArrayGet(cx, props, i);
           jsval propname, propval;
           if (!JS_IdToValue(cx, propid, &propname) ||
               !JS_GetPropertyById(cx, opts, propid, &propval))
           {
             continue;
           }
 
           JSString *propnameString = JS_ValueToString(cx, propname);
--- a/content/html/content/src/nsHTMLDNSPrefetch.cpp
+++ b/content/html/content/src/nsHTMLDNSPrefetch.cpp
@@ -390,17 +390,18 @@ nsHTMLDNSPrefetch::nsDeferrals::OnProgre
                                                  PRInt32 maxTotalProgress)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDNSPrefetch::nsDeferrals::OnLocationChange(nsIWebProgress* aWebProgress,
                                                  nsIRequest* aRequest,
-                                                 nsIURI *location)
+                                                 nsIURI *location,
+                                                 PRUint32 aFlags)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsHTMLDNSPrefetch::nsDeferrals::OnStatusChange(nsIWebProgress* aWebProgress,
                                                nsIRequest* aRequest,
                                                nsresult aStatus,
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -1838,17 +1838,18 @@ nsHTMLFormElement::OnProgressChange(nsIW
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress,
                                     nsIRequest* aRequest,
-                                    nsIURI* location)
+                                    nsIURI* location,
+                                    PRUint32 aFlags)
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress,
                                   nsIRequest* aRequest,
--- a/content/xslt/tests/buster/buster-test.js
+++ b/content/xslt/tests/buster/buster-test.js
@@ -216,17 +216,17 @@ runItem.prototype =
             aProg.removeProgressListener(this);
             this.mRefDoc = document.getElementById('hiddenHtml').contentDocument;
             this.fileLoaded(4);
         }
     },
     onProgressChange: function(aProg, b,c,d,e,f)
     {
     },
-    onLocationChange: function(aProg, aRequest, aURI)
+    onLocationChange: function(aProg, aRequest, aURI, aFlags)
     {
     },
     onStatusChange: function(aProg, aRequest, aStatus, aMessage)
     {
     },
     onSecurityChange: function(aWebProgress, aRequest, aState)
     {
     },
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1765,27 +1765,29 @@ NS_IMETHODIMP
 nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
 {
     NS_ENSURE_ARG_POINTER(aChromeEventHandler);
     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mChromeEventHandler);
     target.swap(*aChromeEventHandler);
     return NS_OK;
 }
 
-/* [noscript] void setCurrentURI (in nsIURI uri); */
+/* void setCurrentURI (in nsIURI uri); */
 NS_IMETHODIMP
 nsDocShell::SetCurrentURI(nsIURI *aURI)
 {
-    SetCurrentURI(aURI, nsnull, true);
+    // Note that securityUI will set STATE_IS_INSECURE, even if
+    // the scheme of |aURI| is "https".
+    SetCurrentURI(aURI, nsnull, true, 0);
     return NS_OK;
 }
 
 bool
 nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
-                          bool aFireOnLocationChange)
+                          bool aFireOnLocationChange, PRUint32 aLocationFlags)
 {
 #ifdef PR_LOGGING
     if (gDocShellLeakLog && PR_LOG_TEST(gDocShellLeakLog, PR_LOG_DEBUG)) {
         nsCAutoString spec;
         if (aURI)
             aURI->GetSpec(spec);
         PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n", this, spec.get());
     }
@@ -1819,17 +1821,17 @@ nsDocShell::SetCurrentURI(nsIURI *aURI, 
        * We don't want to send OnLocationChange notifications when
        * a subframe is being loaded for the first time, while
        * visiting a frameset page
        */
       return false; 
     }
 
     if (aFireOnLocationChange) {
-        FireOnLocationChange(this, aRequest, aURI);
+        FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
     }
     return !aFireOnLocationChange;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetCharset(char** aCharset)
 {
     NS_ENSURE_ARG_POINTER(aCharset);
@@ -5923,17 +5925,17 @@ nsDocShell::OnStateChange(nsIWebProgress
                 }
 
                 // This is a document.write(). Get the made-up url
                 // from the channel and store it in session history.
                 // Pass false for aCloneChildren, since we're creating
                 // a new DOM here.
                 rv = AddToSessionHistory(uri, wcwgChannel, nsnull, false,
                                          getter_AddRefs(mLSHE));
-                SetCurrentURI(uri, aRequest, true);
+                SetCurrentURI(uri, aRequest, true, 0);
                 // Save history state of the previous page
                 rv = PersistLayoutHistoryState();
                 // We'll never get an Embed() for this load, so just go ahead
                 // and SetHistoryEntry now.
                 SetHistoryEntry(&mOSHE, mLSHE);
             }
         
         }
@@ -5979,18 +5981,18 @@ nsDocShell::OnStateChange(nsIWebProgress
     }
     // note that redirect state changes will go through here as well, but it
     // is better to handle those in OnRedirectStateChange where more
     // information is available.
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShell::OnLocationChange(nsIWebProgress * aProgress,
-                             nsIRequest * aRequest, nsIURI * aURI)
+nsDocShell::OnLocationChange(nsIWebProgress * aProgress, nsIRequest * aRequest,
+                             nsIURI * aURI, PRUint32 aFlags)
 {
     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
     return NS_OK;
 }
 
 void
 nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
                                   nsIChannel* aNewChannel,
@@ -6510,17 +6512,17 @@ nsDocShell::CreateAboutBlankContentViewe
       docFactory->CreateInstanceForDocument(NS_ISUPPORTS_CAST(nsIDocShell *, this),
                     blankDoc, "view", getter_AddRefs(viewer));
 
       // hook 'em up
       if (viewer) {
         viewer->SetContainer(static_cast<nsIContentViewerContainer *>(this));
         Embed(viewer, "", 0);
 
-        SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, true);
+        SetCurrentURI(blankDoc->GetDocumentURI(), nsnull, true, 0);
         rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
       }
     }
   }
   mCreatingDocument = false;
 
   // The transient about:blank viewer doesn't have a session history entry.
   SetHistoryEntry(&mOSHE, nsnull);
@@ -7161,17 +7163,17 @@ nsDocShell::RestoreFromHistory()
 
         // Use the uri from the mLSHE we had when we entered this function
         // (which need not match the document's URI if anchors are involved),
         // since that's the history entry we're loading.  Note that if we use
         // origLSHE we don't have to worry about whether the entry in question
         // is still mLSHE or whether it's now mOSHE.
         nsCOMPtr<nsIURI> uri;
         origLSHE->GetURI(getter_AddRefs(uri));
-        SetCurrentURI(uri, document->GetChannel(), true);
+        SetCurrentURI(uri, document->GetChannel(), true, 0);
     }
 
     // This is the end of our CreateContentViewer() replacement.
     // Now we simulate a load.  First, we restore the state of the javascript
     // window object.
     nsCOMPtr<nsPIDOMWindow> privWin =
         do_GetInterface(static_cast<nsIInterfaceRequestor*>(this));
     NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
@@ -7500,17 +7502,17 @@ nsDocShell::CreateContentViewer(const ch
     if (++gNumberOfDocumentsLoading == 1) {
       // Hint to favor performance for the plevent notification mechanism.
       // We want the pages to load as fast as possible even if its means 
       // native messages might be starved.
       FavorPerformanceHint(true, NS_EVENT_STARVATION_DELAY_HINT);
     }
 
     if (onLocationChangeNeeded) {
-      FireOnLocationChange(this, request, mCurrentURI);
+      FireOnLocationChange(this, request, mCurrentURI, 0);
     }
   
     return NS_OK;
 }
 
 nsresult
 nsDocShell::NewContentViewerObj(const char *aContentType,
                                 nsIRequest * request, nsILoadGroup * aLoadGroup,
@@ -8360,16 +8362,21 @@ nsDocShell::InternalLoad(nsIURI * aURI,
              */
             nsCOMPtr<nsISupports> owner;
             if (mOSHE) {
                 mOSHE->GetOwner(getter_AddRefs(owner));
             }
             // Pass true for aCloneSHChildren, since we're not
             // changing documents here, so all of our subframes are
             // still relevant to the new session history entry.
+            //
+            // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
+            // flag on firing onLocationChange(...).
+            // Anyway, aCloneSHChildren param is simply reflecting
+            // doShortCircuitedLoad in this scope.
             OnNewURI(aURI, nsnull, owner, mLoadType, true, true, true);
 
             nsCOMPtr<nsIInputStream> postData;
             nsCOMPtr<nsISupports> cacheKey;
 
             if (mOSHE) {
                 /* save current position of scroller(s) (bug 59774) */
                 mOSHE->SetScrollPosition(cx, cy);
@@ -9413,18 +9420,24 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
             shInternal->UpdateIndex();
             rootSH->GetIndex(&mLoadedTransIndex);
 #ifdef DEBUG_PAGE_CACHE
             printf("Previous index: %d, Loaded index: %d\n\n",
                    mPreviousTransIndex, mLoadedTransIndex);
 #endif
         }
     }
+
+    // aCloneSHChildren exactly means "we are not loading a new document".
+    PRUint32 locationFlags = aCloneSHChildren?
+                                 PRUint32(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
+
     bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
-                                                  aFireOnLocationChange);
+                                                aFireOnLocationChange,
+                                                locationFlags);
     // Make sure to store the referrer from the channel, if any
     SetupReferrerFromChannel(aChannel);
     return onLocationChangeNeeded;
 }
 
 bool
 nsDocShell::OnLoadingSite(nsIChannel * aChannel, bool aFireOnLocationChange,
                           bool aAddToGlobalHistory)
@@ -9722,18 +9735,24 @@ nsDocShell::AddState(nsIVariant *aData, 
 
     // Step 6: If the document's URI changed, update document's URI and update
     // global history.
     //
     // We need to call FireOnLocationChange so that the browser's address bar
     // gets updated and the back button is enabled, but we only need to
     // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
     // since SetCurrentURI will call FireOnLocationChange for us.
+    //
+    // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
+    // nsnull for aRequest param to FireOnLocationChange(...). Such an update
+    // notification is allowed only when we know docshell is not loading a new
+    // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
+    // FireOnLocationChange(...) breaks security UI.
     if (!equalURIs) {
-        SetCurrentURI(newURI, nsnull, true);
+        SetCurrentURI(newURI, nsnull, true, LOCATION_CHANGE_SAME_DOCUMENT);
         document->SetDocumentURI(newURI);
 
         AddURIVisit(newURI, oldURI, oldURI, 0);
 
         // AddURIVisit doesn't set the title for the new URI in global history,
         // so do that here.
         if (mUseGlobalHistory) {
             nsCOMPtr<IHistory> history = services::GetHistoryService();
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -264,20 +264,22 @@ public:
     // ForceRefreshURI method on nsIRefreshURI, but makes sure to take
     // the timer involved out of mRefreshURIList if it's there.
     // aTimer must not be null.
     nsresult ForceRefreshURIFromTimer(nsIURI * aURI, PRInt32 aDelay,
                                       bool aMetaRefresh, nsITimer* aTimer);
 
     friend class OnLinkClickEvent;
 
-    // We need dummy OnLocationChange in some cases to update the UI.
+    // We need dummy OnLocationChange in some cases to update the UI without
+    // updating security info.
     void FireDummyOnLocationChange()
     {
-      FireOnLocationChange(this, nsnull, mCurrentURI);
+        FireOnLocationChange(this, nsnull, mCurrentURI,
+                             LOCATION_CHANGE_SAME_DOCUMENT);
     }
 
     nsresult HistoryTransactionRemoved(PRInt32 aIndex);
 protected:
     // Object Management
     virtual ~nsDocShell();
     virtual void DestroyChildren();
 
@@ -588,17 +590,18 @@ protected:
                                  nsIDocShellTreeItem* aTargetTreeItem);
 
     // Returns true if would have called FireOnLocationChange,
     // but did not because aFireOnLocationChange was false on entry.
     // In this case it is the caller's responsibility to ensure
     // FireOnLocationChange is called.
     // In all other cases false is returned.
     bool SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest,
-                         bool aFireOnLocationChange);
+                       bool aFireOnLocationChange,
+                       PRUint32 aLocationFlags);
 
     // The following methods deal with saving and restoring content viewers
     // in session history.
 
     // mContentViewer points to the current content viewer associated with
     // this docshell.  When loading a new document, the content viewer is
     // either destroyed or stored into a session history entry.  To make sure
     // that destruction happens in a controlled fashion, a given content viewer
--- a/docshell/test/chrome/Makefile.in
+++ b/docshell/test/chrome/Makefile.in
@@ -117,16 +117,18 @@ include $(topsrcdir)/config/rules.mk
 		test_bug456980.xul \
 		test_bug662200.xul \
 		bug662200_window.xul \
 		662200a.html \
 		662200b.html \
 		662200c.html \
 		test_bug690056.xul \
 		bug690056_window.xul \
+		test_bug311007.xul \
+		bug311007_window.xul \
 		$(NULL)
 
 _DOCSHELL_SUBHARNESS = \
     docshell_helpers.js \
     generic.html \
     $(NULL)
 
 libs:: $(_HTTP_FILES)
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/bug311007_window.xul
@@ -0,0 +1,186 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window id="311007Test"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        width="600"
+        height="600"
+        onload="startup();"
+        title="bug 311007 test">
+
+  <script type="application/javascript" src="docshell_helpers.js"></script>
+  <script type="application/javascript"><![CDATA[
+/*
+   Regression test for bug 283733 and bug 307027.
+
+   Bug 283733
+     "accessing a relative anchor in a secure page removes the
+      locked icon and yellow background UI"
+
+   Bug 307027
+     "Going back from secure page to error page does not clear yellow bar"
+
+ */
+
+const kDNSErrorURI = "https://example/err.html";
+const kSecureURI =
+  "https://example.com/tests/docshell/test/navigation/blank.html";
+
+/*
+  Step 1: load a network error page.   <err.html>       Not Secure
+  Step 2: load a secure page.          <blank.html>     Secure
+  Step 3: a secure page + hashchange.  <blank.html#foo> Secure     (bug 283733)
+  Step 4: go back to the error page.   <err.html>       Not Secure (bug 307027)
+ */
+
+var gListener = null;
+
+function WebProgressListener() {
+  this._callback = null;
+}
+
+WebProgressListener.prototype = {
+  QueryInterface: function(aIID) {
+    if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
+        aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
+        aIID.equals(Components.interfaces.nsISupports))
+      return this;
+    throw Components.results.NS_NOINTERFACE;
+  },
+
+  onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
+    setTimeout(this._callback, 0, aWebProgress, aRequest, aLocation, aFlags);
+  },
+
+  set callback(aVal) {
+    this._callback = aVal;
+  }
+};
+
+function startup() {
+  gListener = new WebProgressListener();
+
+  document.getElementById("content")
+          .webProgress
+          .addProgressListener(gListener,
+                               Components.interfaces.nsIWebProgress
+                                         .NOTIFY_LOCATION);
+
+  setTimeout(step1A, 0);
+}
+
+/******************************************************************************
+ * Step 1: Load an error page, and confirm UA knows it's insecure.
+ ******************************************************************************/
+
+function step1A() {
+  gListener.callback = step1B;
+  content.location = kDNSErrorURI;
+}
+
+function step1B(aWebProgress, aRequest, aLocation, aFlags) {
+  /* XXX Here we receive 2 notifications, due to bug 673752. */
+  if (!aRequest) {
+    return;
+  }
+
+  is(aLocation.spec, kDNSErrorURI, "Error page's URI (1)");
+
+  ok(!(aFlags & Components.interfaces.nsIWebProgressListener
+                          .LOCATION_CHANGE_SAME_DOCUMENT),
+     "DocShell loaded a document (1)");
+
+  ok(!(aWebProgress.QueryInterface(Components.interfaces.nsIDocShell)
+                   .securityUI.state &
+       Components.interfaces.nsIWebProgressListener.STATE_IS_SECURE),
+     "This is not a secure page (1)");
+
+  /* Go to step 2. */
+  setTimeout(step2A, 0);
+}
+
+/******************************************************************************
+ * Step 2: Load a HTTPS page, and confirm it's secure. 
+ ******************************************************************************/
+
+function step2A() {
+  gListener.callback = step2B;
+  content.location = kSecureURI;
+}
+
+function step2B(aWebProgress, aRequest, aLocation, aFlags) {
+  is(aLocation.spec, kSecureURI, "A URI on HTTPS (2)");
+
+  ok(!(aFlags & Components.interfaces.nsIWebProgressListener
+                          .LOCATION_CHANGE_SAME_DOCUMENT),
+     "DocShell loaded a document (2)");
+
+  ok((aWebProgress.QueryInterface(Components.interfaces.nsIDocShell)
+                  .securityUI.state &
+      Components.interfaces.nsIWebProgressListener.STATE_IS_SECURE),
+     "This is a secure page (2)");
+
+  /* Go to step 3. */
+  setTimeout(step3A, 0);
+}
+
+/*****************************************************************************
+ * Step 3: Trigger hashchange within a secure page, and confirm UA knows
+ *         it's secure. (Bug 283733)
+ *****************************************************************************/
+
+function step3A() {
+  gListener.callback = step3B;
+  content.location += "#foo";
+}
+
+function step3B(aWebProgress, aRequest, aLocation, aFlags) {
+  is(aLocation.spec, kSecureURI + "#foo", "hashchange on HTTPS (3)");
+
+  ok((aFlags & Components.interfaces.nsIWebProgressListener
+                         .LOCATION_CHANGE_SAME_DOCUMENT),
+     "We are in the same document as before (3)");
+
+  ok((aWebProgress.QueryInterface(Components.interfaces.nsIDocShell)
+                  .securityUI.state &
+      Components.interfaces.nsIWebProgressListener.STATE_IS_SECURE),
+     "This is a secure page (3)");
+
+  /* Go to step 4. */
+  setTimeout(step4A, 0);
+}
+
+/*****************************************************************************
+ * Step 4: Go back from a secure page to an error page, and confirm UA knows
+ *         it's not secure. (Bug 307027)
+ *****************************************************************************/
+
+function step4A() {
+  gListener.callback = step4B;
+  content.history.go(-2);
+}
+
+function step4B(aWebProgress, aRequest, aLocation, aFlags) {
+  if (!aRequest) // See step1B(...) and bug 673752.
+    return;
+
+  is(aLocation.spec, kDNSErrorURI, "Go back to the error URI (4)");
+
+  ok(!(aFlags & Components.interfaces.nsIWebProgressListener
+                          .LOCATION_CHANGE_SAME_DOCUMENT),
+       "DocShell loaded a document (4)");
+
+  ok(!(aWebProgress.QueryInterface(Components.interfaces.nsIDocShell)
+                   .securityUI.state &
+       Components.interfaces.nsIWebProgressListener.STATE_IS_SECURE),
+     "This is not a secure page (4)");
+
+  /* End. */
+  aWebProgress.removeProgressListener(gListener);
+  delete(gListener);
+  finish();
+}
+  ]]></script>
+
+  <browser type="content-primary" flex="1" id="content" src="about:blank"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/test_bug311007.xul
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+  href="chrome://mochikit/content/tests/SimpleTest/test.css"
+  type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=311007.xul
+-->
+<window title="Mozilla Bug 311007"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <title>Test for Bug 311007</title>
+  <script type="application/javascript"
+    src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+    src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body  xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank"
+   href="https://bugzilla.mozilla.org/show_bug.cgi?id=311007">
+   Mozilla Bug 311007</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 311007 **/
+
+SimpleTest.waitForExplicitFinish();
+window.open("bug311007_window.xul", "bug311007",
+            "chrome,width=600,height=600");
+
+]]>
+</script>
+
+</window>
--- a/docshell/test/chrome/window.template.txt
+++ b/docshell/test/chrome/window.template.txt
@@ -1,12 +1,12 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 
-<window id="303267Test"
+<window id="{BUGNUMBER}Test"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         width="600"
         height="600"
         onload="setTimeout(nextTest,0);"
         title="bug {BUGNUMBER} test">
 
   <script type="application/javascript"
   src="docshell_helpers.js">
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -461,16 +461,29 @@ nsFocusManager::SetFocus(nsIDOMElement* 
   NS_ENSURE_ARG(newFocus);
 
   SetFocusInner(newFocus, aFlags, true, true);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsFocusManager::ElementIsFocusable(nsIDOMElement* aElement, PRUint32 aFlags,
+                                   bool* aIsFocusable)
+{
+  NS_ENSURE_TRUE(aElement, NS_ERROR_INVALID_ARG);
+
+  nsCOMPtr<nsIContent> aContent = do_QueryInterface(aElement);
+
+  *aIsFocusable = CheckIfFocusable(aContent, aFlags) != nsnull;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsFocusManager::MoveFocus(nsIDOMWindow* aWindow, nsIDOMElement* aStartElement,
                           PRUint32 aType, PRUint32 aFlags, nsIDOMElement** aElement)
 {
   *aElement = nsnull;
 
 #ifdef DEBUG_FOCUS
   printf("<<MoveFocus Type: %d Flags: %x>>\n<<", aType, aFlags);
 
--- a/dom/interfaces/base/nsIFocusManager.idl
+++ b/dom/interfaces/base/nsIFocusManager.idl
@@ -161,16 +161,21 @@ interface nsIFocusManager : nsISupports
   nsIDOMElement getFocusedElementForWindow(in nsIDOMWindow aWindow, in boolean aDeep,
                                            out nsIDOMWindow aFocusedWindow);
 
   /**
    * Moves the selection caret within aWindow to the current focus.
    */
   void moveCaretToFocus(in nsIDOMWindow aWindow);
 
+  /***
+   * Check if given element is focusable.
+   */
+  boolean elementIsFocusable(in nsIDOMElement aElement, in unsigned long aFlags);
+
   /*
    * Raise the window when switching focus
    */
   const unsigned long FLAG_RAISE = 1;
 
   /**
    * Do not scroll the element to focus into view
    */
--- a/dom/interfaces/html/nsIDOMHTMLAnchorElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLAnchorElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(2da904fa-83da-426d-a320-a6868192583e)]
+[scriptable, uuid(bcb54394-d9f8-4bcb-bbbb-eca9826cdbca)]
 interface nsIDOMHTMLAnchorElement : nsIDOMHTMLElement
 {
            attribute DOMString        href;
            attribute DOMString        target;
 
            attribute DOMString        ping;
 
            attribute DOMString        rel;
--- a/dom/interfaces/html/nsIDOMHTMLAppletElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLAppletElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(c874e500-a185-4d69-96dd-474d1137e21f)]
+[scriptable, uuid(a06bca18-791f-474e-a031-bf6c2bd14994)]
 interface nsIDOMHTMLAppletElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
            attribute DOMString        alt;
            attribute DOMString        archive;
            attribute DOMString        code;
            attribute DOMString        codeBase;
            attribute DOMString        height;
--- a/dom/interfaces/html/nsIDOMHTMLAreaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLAreaElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(d88c8515-5a27-4955-8ca5-18c908433cfd)]
+[scriptable, uuid(7e607c36-aecc-4dee-a93a-95e22a374bfb)]
 interface nsIDOMHTMLAreaElement : nsIDOMHTMLElement
 {
            attribute DOMString        alt;
            attribute DOMString        coords;
            attribute DOMString        shape;
            attribute DOMString        href;
            attribute DOMString        target;
 
--- a/dom/interfaces/html/nsIDOMHTMLAudioElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLAudioElement.idl
@@ -47,17 +47,17 @@
  * <audio> element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#audio
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(f4115c13-bc51-4c3b-a5c0-9106af9f7368)]
+[scriptable, uuid(756e2792-b937-4a70-bd1f-9d6820473e7e)]
 interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement
 {
   // Setup the audio stream for writing
   void mozSetup(in PRUint32 channels, in PRUint32 rate);
 
   // Write audio to the audio stream
   [implicit_jscontext]
   unsigned long mozWriteAudio(in jsval data);
--- a/dom/interfaces/html/nsIDOMHTMLBRElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLBRElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(a4f319d7-442d-4154-8c60-b9acdca87523)]
+[scriptable, uuid(7eefd466-7c4d-499a-a076-e33204e69dc3)]
 interface nsIDOMHTMLBRElement : nsIDOMHTMLElement
 {
            attribute DOMString        clear;
 };
--- a/dom/interfaces/html/nsIDOMHTMLBaseElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLBaseElement.idl
@@ -45,14 +45,14 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(1ba4957f-629e-4410-b5fd-64f2b7eeb32c)]
+[scriptable, uuid(e55cd224-b603-4976-892a-20b11d469394)]
 interface nsIDOMHTMLBaseElement : nsIDOMHTMLElement
 {
            attribute DOMString        href;
            attribute DOMString        target;
 };
--- a/dom/interfaces/html/nsIDOMHTMLBodyElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLBodyElement.idl
@@ -49,17 +49,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(dcf343a9-fa7f-4e16-b122-0ece0d8bdea9)]
+[scriptable, uuid(6c377d44-a5d1-4f0f-860a-9858d2cb5679)]
 interface nsIDOMHTMLBodyElement : nsIDOMHTMLElement
 {
            attribute DOMString        aLink;
            attribute DOMString        background;
            attribute DOMString        bgColor;
            attribute DOMString        link;
            attribute DOMString        text;
            attribute DOMString        vLink;
--- a/dom/interfaces/html/nsIDOMHTMLButtonElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLButtonElement.idl
@@ -47,17 +47,17 @@
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
 interface nsIDOMValidityState;
 
-[scriptable, uuid(4b48e075-a05b-480f-9e37-fcd88e7aebdd)]
+[scriptable, uuid(79f034f0-5c13-4101-9598-412e1eac1986)]
 interface nsIDOMHTMLButtonElement : nsIDOMHTMLElement
 {
            attribute boolean               autofocus;
            attribute boolean               disabled;
   readonly attribute nsIDOMHTMLFormElement form;
            attribute DOMString             formAction;
            attribute DOMString             formEnctype;
            attribute DOMString             formMethod;
--- a/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
@@ -50,17 +50,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#graphics
  *
  * @status UNDER_DEVELOPMENT
  */
 
 interface nsIDOMFile;
 interface nsIVariant;
 
-[scriptable, uuid(e1ea26e6-4141-487f-a9cf-d7e9344b571c)]
+[scriptable, uuid(dbbeeba1-3c20-4d9d-ac82-98b69fd819a9)]
 interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
 {
   attribute unsigned long width;
   attribute unsigned long height;
   attribute boolean mozOpaque;
 
   nsISupports getContext(in DOMString contextId,
                          [optional] in jsval contextOptions);
--- a/dom/interfaces/html/nsIDOMHTMLCommandElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLCommandElement.idl
@@ -41,17 +41,17 @@
  * <command> element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#the-command-element
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(4c466da8-5c6d-427f-95f5-bba96ab99c96)]
+[scriptable, uuid(13032f74-4150-4768-ab5e-51f4de39a300)]
 interface nsIDOMHTMLCommandElement : nsIDOMHTMLElement
 {
            attribute DOMString        type;
            attribute DOMString        label;
            attribute DOMString        icon;
            attribute boolean          disabled;
            attribute boolean          defaultChecked;
            attribute boolean          checked;
--- a/dom/interfaces/html/nsIDOMHTMLDListElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDListElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(f3e65e2b-e079-4970-bb5d-f96ac9cd18c5)]
+[scriptable, uuid(50e9ff30-0982-4074-bc65-313f41be8624)]
 interface nsIDOMHTMLDListElement : nsIDOMHTMLElement
 {
            attribute boolean          compact;
 };
--- a/dom/interfaces/html/nsIDOMHTMLDataListElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDataListElement.idl
@@ -44,14 +44,14 @@
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#the-datalist-element
  *
  * @status UNDER_DEVELOPMENT
  */
 
 interface nsIDOMHTMLCollection;
 
-[scriptable, uuid(312ed7c1-8c62-4d80-bbd9-99d7ea4377e6)]
+[scriptable, uuid(3bace78b-9eca-4990-a5d6-9c2b8c32cc8a)]
 interface nsIDOMHTMLDataListElement : nsIDOMHTMLElement
 {
   readonly attribute nsIDOMHTMLCollection options;
 };
 
--- a/dom/interfaces/html/nsIDOMHTMLDirectoryElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDirectoryElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(1e04cd43-edc0-4658-bd77-d67661af6c9c)]
+[scriptable, uuid(a99e86ae-7761-4145-b8a4-5a91186051f1)]
 interface nsIDOMHTMLDirectoryElement : nsIDOMHTMLElement
 {
            attribute boolean          compact;
 };
--- a/dom/interfaces/html/nsIDOMHTMLDivElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDivElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(771be9ee-b883-4556-bf90-2d7c904fe94d)]
+[scriptable, uuid(6815b902-8e04-49dd-977b-0a8785e5ffaf)]
 interface nsIDOMHTMLDivElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
 };
--- a/dom/interfaces/html/nsIDOMHTMLElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLElement.idl
@@ -48,17 +48,17 @@ interface nsIDOMHTMLMenuElement;
  * tree.
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
-[scriptable, uuid(0a21bb68-d8bd-4b2a-a3db-048a02e81c62)]
+[scriptable, uuid(4eccf8a3-8bf5-43f3-a728-f5b632f7db3a)]
 interface nsIDOMHTMLElement : nsIDOMElement
 {
   // metadata attributes
            attribute DOMString        id;
            attribute DOMString        title;
            attribute DOMString        lang;
            attribute DOMString        dir;
            attribute DOMString        className;
@@ -81,16 +81,17 @@ interface nsIDOMHTMLElement : nsIDOMElem
            attribute DOMString        contentEditable;
   readonly attribute boolean          isContentEditable;
   readonly attribute nsIDOMHTMLMenuElement contextMenu;
            attribute boolean          spellcheck;
 
 
   // DOM Parsing and Serialization
            attribute DOMString        innerHTML;
+           attribute DOMString        outerHTML;
   void insertAdjacentHTML(in DOMString position,
                           in DOMString text);
 
 
   // CSSOM View
   [optional_argc] void scrollIntoView([optional] in boolean top);
   readonly attribute nsIDOMElement    offsetParent;
   readonly attribute long             offsetTop;
--- a/dom/interfaces/html/nsIDOMHTMLEmbedElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLEmbedElement.idl
@@ -42,17 +42,17 @@
 /**
  * The nsIDOMHTMLEmbedElement interface is the interface to a [X]HTML
  * embed element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#the-embed-element
  */
 
-[scriptable, uuid(d6309fc7-e9d2-4087-b452-490ed84f2dc2)]
+[scriptable, uuid(940a15c2-0d48-4186-b4d8-067fa1ce5675)]
 interface nsIDOMHTMLEmbedElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
            attribute DOMString        height;
            attribute DOMString        name;
            attribute DOMString        src;
            attribute DOMString        type;
            attribute DOMString        width;
--- a/dom/interfaces/html/nsIDOMHTMLFieldSetElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLFieldSetElement.idl
@@ -47,17 +47,17 @@
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
 interface nsIDOMValidityState;
 
-[scriptable, uuid(e153c20e-7a3d-4184-865c-ee7c6d9b65df)]
+[scriptable, uuid(781ae103-b030-4aad-b2d5-96e5c2317dec)]
 interface nsIDOMHTMLFieldSetElement : nsIDOMHTMLElement
 {
            attribute boolean                disabled;
   readonly attribute nsIDOMHTMLFormElement  form;
            attribute DOMString              name;
 
   readonly attribute DOMString              type;
 
--- a/dom/interfaces/html/nsIDOMHTMLFontElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLFontElement.idl
@@ -45,15 +45,15 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(8a205975-86cb-44db-b20e-df7f2d200580)]
+[scriptable, uuid(1c9778ee-a49c-40ee-9b93-c0ff15630431)]
 interface nsIDOMHTMLFontElement : nsIDOMHTMLElement
 {
            attribute DOMString        color;
            attribute DOMString        face;
            attribute DOMString        size;
 };
--- a/dom/interfaces/html/nsIDOMHTMLFormElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLFormElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(8fe67952-6f7b-4d6e-b17b-79a454687e5f)]
+[scriptable, uuid(d873b251-6f96-4e70-baf5-aaa935aabe59)]
 interface nsIDOMHTMLFormElement : nsIDOMHTMLElement
 {
            attribute DOMString            acceptCharset;
            attribute DOMString            action;
            attribute DOMString            autocomplete;
            attribute DOMString            enctype;
            attribute DOMString            encoding;
            attribute DOMString            method;
--- a/dom/interfaces/html/nsIDOMHTMLFrameElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLFrameElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(6de9d59d-42fd-44df-bb41-22cd64a85d4f)]
+[scriptable, uuid(318fdc4a-3fca-4099-94aa-c9a1c30ca2b9)]
 interface nsIDOMHTMLFrameElement : nsIDOMHTMLElement
 {
            attribute DOMString        frameBorder;
            attribute DOMString        longDesc;
            attribute DOMString        marginHeight;
            attribute DOMString        marginWidth;
            attribute DOMString        name;
            attribute boolean          noResize;
--- a/dom/interfaces/html/nsIDOMHTMLFrameSetElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLFrameSetElement.idl
@@ -49,17 +49,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(a9423392-0f92-4b25-8700-49d28752c092)]
+[scriptable, uuid(6eefbe6d-182c-42e9-9850-af1892b6f2e4)]
 interface nsIDOMHTMLFrameSetElement : nsIDOMHTMLElement
 {
            attribute DOMString        cols;
            attribute DOMString        rows;
 
            [implicit_jscontext] attribute jsval            onafterprint;
            [implicit_jscontext] attribute jsval            onbeforeprint;
            [implicit_jscontext] attribute jsval            onbeforeunload;
--- a/dom/interfaces/html/nsIDOMHTMLHRElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLHRElement.idl
@@ -46,17 +46,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(a6950d69-a376-4ad5-a911-8f91abb2b15d)]
+[scriptable, uuid(b94bff8f-dfa7-4dd8-8d97-c301dd9de729)]
 interface nsIDOMHTMLHRElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
            attribute boolean          noShade;
            attribute DOMString        size;
            attribute DOMString        width;
            attribute DOMString        color;
 };
--- a/dom/interfaces/html/nsIDOMHTMLHeadElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLHeadElement.idl
@@ -45,12 +45,12 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(6d049c37-2cee-4c04-816c-270973e58ccf)]
+[scriptable, uuid(628fe597-6408-4387-9fcb-75381e2b2dd0)]
 interface nsIDOMHTMLHeadElement : nsIDOMHTMLElement
 {
 };
--- a/dom/interfaces/html/nsIDOMHTMLHeadingElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLHeadingElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(c3c30a05-1dc0-413a-85f6-3c4d5af5f2b6)]
+[scriptable, uuid(964c94b0-5571-44e7-9b29-f81c6ea7828a)]
 interface nsIDOMHTMLHeadingElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
 };
--- a/dom/interfaces/html/nsIDOMHTMLHtmlElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLHtmlElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(84825a7d-d5c7-4b1a-9d2a-b3e5df055824)]
+[scriptable, uuid(4bafbc15-aa88-4021-9ad6-e14189b7227b)]
 interface nsIDOMHTMLHtmlElement : nsIDOMHTMLElement
 {
            attribute DOMString        version;
 };
--- a/dom/interfaces/html/nsIDOMHTMLIFrameElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLIFrameElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(166c1cdb-9af5-4217-9a2f-f9dae0923e85)]
+[scriptable, uuid(5ef30718-fe45-43a2-a478-a9e3cbf3a118)]
 interface nsIDOMHTMLIFrameElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
            attribute DOMString        frameBorder;
            attribute DOMString        height;
            attribute DOMString        longDesc;
            attribute DOMString        marginHeight;
            attribute DOMString        marginWidth;
--- a/dom/interfaces/html/nsIDOMHTMLImageElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLImageElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(02dbe3c7-e75e-4a35-989c-b6f6d7a3108f)]
+[scriptable, uuid(56d9191f-5a94-432f-af70-6fccdeaf614b)]
 interface nsIDOMHTMLImageElement : nsIDOMHTMLElement
 {
            attribute DOMString        alt;
            attribute DOMString        src;
            attribute DOMString        crossOrigin;
            attribute DOMString        useMap;
            attribute boolean          isMap;
            attribute unsigned long    width;
--- a/dom/interfaces/html/nsIDOMHTMLInputElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLInputElement.idl
@@ -49,17 +49,17 @@ interface nsIDOMValidityState;
   *
   * This interface is trying to follow the DOM Level 2 HTML specification:
   * http://www.w3.org/TR/DOM-Level-2-HTML/
   *
   * with changes from the work-in-progress WHATWG HTML specification:
   * http://www.whatwg.org/specs/web-apps/current-work/
   */
 
-[scriptable, uuid(81cc1b30-02e1-4779-ac9e-0091933478a4)]
+[scriptable, uuid(7330cd35-c930-4f45-ae61-f5380c30222d)]
 interface nsIDOMHTMLInputElement : nsIDOMHTMLElement
 {
            attribute DOMString             accept;
            attribute DOMString             alt;
 
            attribute DOMString             autocomplete;
            attribute boolean               autofocus;
            attribute boolean               defaultChecked;
--- a/dom/interfaces/html/nsIDOMHTMLLIElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLLIElement.idl
@@ -45,14 +45,14 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(cb9bbac6-3198-4159-9ee9-262eef35f265)]
+[scriptable, uuid(85b15d13-be6d-4653-9c70-22a13d510247)]
 interface nsIDOMHTMLLIElement : nsIDOMHTMLElement
 {
            attribute DOMString           type;
            attribute long                value;
 };
--- a/dom/interfaces/html/nsIDOMHTMLLabelElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLLabelElement.idl
@@ -45,15 +45,15 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(0c36c887-04e3-4926-a916-8e3596130f9a)]
+[scriptable, uuid(ddbca449-625d-467c-a22d-7887474f9eb9)]
 interface nsIDOMHTMLLabelElement : nsIDOMHTMLElement
 {
   readonly attribute nsIDOMHTMLFormElement form;
            attribute DOMString             htmlFor;
   readonly attribute nsIDOMHTMLElement     control;
 };
--- a/dom/interfaces/html/nsIDOMHTMLLegendElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLLegendElement.idl
@@ -45,14 +45,14 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(cabacc5f-5179-4c97-be60-0af8feafb4c9)]
+[scriptable, uuid(dac72753-6919-414b-b771-9e1e86e7749c)]
 interface nsIDOMHTMLLegendElement : nsIDOMHTMLElement
 {
   readonly attribute nsIDOMHTMLFormElement form;
            attribute DOMString             align;
 };
--- a/dom/interfaces/html/nsIDOMHTMLLinkElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLLinkElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(2f238f84-1b45-4ef9-9cda-bd1430ce9304)]
+[scriptable, uuid(2ece79f4-83d7-499c-946f-ae9ab93147b7)]
 interface nsIDOMHTMLLinkElement : nsIDOMHTMLElement
 {
            attribute boolean          disabled;
            attribute DOMString        charset;
            attribute DOMString        href;
            attribute DOMString        hreflang;
            attribute DOMString        media;
            attribute DOMString        rel;
--- a/dom/interfaces/html/nsIDOMHTMLMapElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMapElement.idl
@@ -45,14 +45,14 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(3fb8ec10-8778-418d-9c83-556e46f115a9)]
+[scriptable, uuid(c919bc49-bd49-4b89-ba70-5c74c4ef504a)]
 interface nsIDOMHTMLMapElement : nsIDOMHTMLElement
 {
   readonly attribute nsIDOMHTMLCollection areas;
            attribute DOMString            name;
 };
--- a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
@@ -52,17 +52,17 @@
 
 // undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
 %{C++
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 %}
 
-[scriptable, uuid(85baaa10-73ab-4a48-a57a-b3951b67e494)]
+[scriptable, uuid(642a3b85-4edb-4c01-a162-06b5d88171e7)]
 interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
 {
   // error state
   readonly attribute nsIDOMMediaError error;
 
   // network state
            attribute DOMString src;
   readonly attribute DOMString currentSrc;
--- a/dom/interfaces/html/nsIDOMHTMLMenuElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMenuElement.idl
@@ -45,16 +45,16 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(12de9196-b164-43e0-9347-f23e1bffbede)]
+[scriptable, uuid(06d48250-45e0-4f26-9a07-d9b5a3f08bb6)]
 interface nsIDOMHTMLMenuElement : nsIDOMHTMLElement
 {
            attribute boolean          compact;
 
            attribute DOMString        type;
            attribute DOMString        label;
 };
--- a/dom/interfaces/html/nsIDOMHTMLMenuItemElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMenuItemElement.idl
@@ -38,12 +38,12 @@
 
 /**
  * The nsIDOMHTMLMenuItemElement interface is the interface to a HTML
  * <menuitem> element.
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(e0469d92-a137-4329-9d4b-9f2ba5ce8e77)]
+[scriptable, uuid(4680ec24-94f0-4eb7-9413-98f9a857de72)]
 interface nsIDOMHTMLMenuItemElement : nsIDOMHTMLCommandElement
 {
 };
--- a/dom/interfaces/html/nsIDOMHTMLMetaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMetaElement.idl
@@ -45,16 +45,16 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(c883b92b-5ae0-4563-894a-fa7f0e9aacda)]
+[scriptable, uuid(db476657-5f59-4e29-84a6-50afe6f85ac7)]
 interface nsIDOMHTMLMetaElement : nsIDOMHTMLElement
 {
            attribute DOMString        content;
            attribute DOMString        httpEquiv;
            attribute DOMString        name;
            attribute DOMString        scheme;
 };
--- a/dom/interfaces/html/nsIDOMHTMLModElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLModElement.idl
@@ -45,14 +45,14 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(417626fa-191c-41e5-aed5-f6157b408e72)]
+[scriptable, uuid(170733d4-aad5-4f6e-86c0-94845ea6116d)]
 interface nsIDOMHTMLModElement : nsIDOMHTMLElement
 {
            attribute DOMString        cite;
            attribute DOMString        dateTime;
 };
--- a/dom/interfaces/html/nsIDOMHTMLOListElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLOListElement.idl
@@ -45,15 +45,15 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(11e66686-b1ef-47be-9025-ffc20b875e4a)]
+[scriptable, uuid(31a5f083-59a6-41c3-8a0b-e58e484c6516)]
 interface nsIDOMHTMLOListElement : nsIDOMHTMLElement
 {
            attribute boolean          compact;
            attribute long             start;
            attribute DOMString        type;
 };
--- a/dom/interfaces/html/nsIDOMHTMLObjectElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLObjectElement.idl
@@ -47,17 +47,17 @@
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
 interface nsIDOMValidityState;
 
-[scriptable, uuid(5d873128-d4e3-4e89-8900-599155167105)]
+[scriptable, uuid(40037f4a-5bae-476f-977b-bbd8e78aaefe)]
 interface nsIDOMHTMLObjectElement : nsIDOMHTMLElement
 {
   readonly attribute nsIDOMHTMLFormElement form;
            attribute DOMString             code;
            attribute DOMString             align;
            attribute DOMString             archive;
            attribute DOMString             border;
            attribute DOMString             codeBase;
--- a/dom/interfaces/html/nsIDOMHTMLOptGroupElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLOptGroupElement.idl
@@ -45,14 +45,14 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(7b585d49-1da3-4fc6-a50c-b661063c2edc)]
+[scriptable, uuid(ab55d67a-aabb-4441-b182-8ff2bd7d157e)]
 interface nsIDOMHTMLOptGroupElement : nsIDOMHTMLElement
 {
            attribute boolean          disabled;
            attribute DOMString        label;
 };
--- a/dom/interfaces/html/nsIDOMHTMLOptionElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLOptionElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(c20ead8a-cb89-43b1-89ed-8f4713bf8452)]
+[scriptable, uuid(7c5bf0ac-6230-4ee0-8b82-e7ebf211af03)]
 interface nsIDOMHTMLOptionElement : nsIDOMHTMLElement
 {
            attribute boolean               disabled;
   readonly attribute nsIDOMHTMLFormElement form;
            attribute DOMString             label;
            attribute boolean               defaultSelected;
            attribute boolean               selected;
            attribute DOMString             value;
--- a/dom/interfaces/html/nsIDOMHTMLOutputElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLOutputElement.idl
@@ -45,17 +45,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#the-output-element
  *
  * @status UNDER_DEVELOPMENT
  */
 
 interface nsIDOMDOMSettableTokenList;
 interface nsIDOMValidityState;
 
-[scriptable, uuid(7d1fb2a9-7678-409e-8eb5-9216c47c233b)]
+[scriptable, uuid(f2074cdb-19cb-447a-935c-9f4402dc1b5e)]
 interface nsIDOMHTMLOutputElement : nsIDOMHTMLElement
 {
   readonly attribute nsIDOMDOMSettableTokenList htmlFor;
   readonly attribute nsIDOMHTMLFormElement      form;
            attribute DOMString                  name;
 
   readonly attribute DOMString                  type;
            attribute DOMString                  defaultValue;
--- a/dom/interfaces/html/nsIDOMHTMLParagraphElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLParagraphElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(d5d3eb33-0925-4555-be2f-4078dec49f59)]
+[scriptable, uuid(e4f498f4-e3c5-46fe-92d0-c9957ccab530)]
 interface nsIDOMHTMLParagraphElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
 };
--- a/dom/interfaces/html/nsIDOMHTMLParamElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLParamElement.idl
@@ -45,16 +45,16 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(ccffedb8-f234-474e-9af4-576eba766023)]
+[scriptable, uuid(d832b1ac-9bb6-4df0-9d9e-f7c040759672)]
 interface nsIDOMHTMLParamElement : nsIDOMHTMLElement
 {
            attribute DOMString        name;
            attribute DOMString        type;
            attribute DOMString        value;
            attribute DOMString        valueType;
 };
--- a/dom/interfaces/html/nsIDOMHTMLPreElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLPreElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(c9d9b45a-e7d9-4dfb-abae-f3b9e6addbaa)]
+[scriptable, uuid(f4088dff-649c-4eff-a3a4-dbd6333cdc44)]
 interface nsIDOMHTMLPreElement : nsIDOMHTMLElement
 {
            attribute long             width;
 };
--- a/dom/interfaces/html/nsIDOMHTMLProgressElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLProgressElement.idl
@@ -42,17 +42,17 @@
  * <progress> element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#the-progress-element
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(aa830aa2-a4ea-455e-8285-8344cadb4c6d)]
+[scriptable, uuid(9b1d2263-b60f-4d18-b4d1-66e8c3867c79)]
 interface nsIDOMHTMLProgressElement : nsIDOMHTMLElement
 {
            attribute double value;
            attribute double max;
   readonly attribute double position;
   readonly attribute nsIDOMHTMLFormElement form;
   /**
    * The labels attribute will be done with bug 567740.
--- a/dom/interfaces/html/nsIDOMHTMLQuoteElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLQuoteElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(820ccd14-2479-4e4a-99d3-76d138caf7ec)]
+[scriptable, uuid(55643647-2eda-4a45-af55-b2ba6c40c5f5)]
 interface nsIDOMHTMLQuoteElement : nsIDOMHTMLElement
 {
            attribute DOMString        cite;
 };
--- a/dom/interfaces/html/nsIDOMHTMLScriptElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLScriptElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(e6252d3b-521a-4f79-9d57-2721a81e7cc2)]
+[scriptable, uuid(4b6a0957-5466-4134-8a0a-dd7e4675c106)]
 interface nsIDOMHTMLScriptElement : nsIDOMHTMLElement
 {
            attribute DOMString        src;
            attribute boolean          async;
            attribute boolean          defer;
            attribute DOMString        type;
            attribute DOMString        charset;
            attribute DOMString        text;
--- a/dom/interfaces/html/nsIDOMHTMLSelectElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLSelectElement.idl
@@ -48,17 +48,17 @@
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
 interface nsIDOMValidityState;
 
-[scriptable, uuid(30a948a3-61a0-453c-a1e4-de67a1664746)]
+[scriptable, uuid(98f111e0-2b7e-4abd-984b-2cc1d174fe44)]
 interface nsIDOMHTMLSelectElement : nsIDOMHTMLElement
 {
            attribute boolean                     autofocus;
            attribute boolean                     disabled;
   readonly attribute nsIDOMHTMLFormElement       form;
            attribute boolean                     multiple;
            attribute DOMString                   name;
            attribute long                        size;
--- a/dom/interfaces/html/nsIDOMHTMLSourceElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLSourceElement.idl
@@ -43,14 +43,14 @@
  * <source> element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#source
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(dcac4414-37e2-409f-b0a6-8231007e585b)]
+[scriptable, uuid(c49d9a78-fa02-49c9-b239-9cd51e99f866)]
 interface nsIDOMHTMLSourceElement : nsIDOMHTMLElement
 {
            attribute DOMString src;
            attribute DOMString type;
 };
--- a/dom/interfaces/html/nsIDOMHTMLStyleElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLStyleElement.idl
@@ -45,15 +45,15 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(e72a6069-4987-480b-a349-ffd5fbebd59f)]
+[scriptable, uuid(247fc8c4-92f3-427b-af6f-41b13f28287d)]
 interface nsIDOMHTMLStyleElement : nsIDOMHTMLElement
 {
            attribute boolean          disabled;
            attribute DOMString        media;
            attribute DOMString        type;
 };
--- a/dom/interfaces/html/nsIDOMHTMLTableCaptionElem.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTableCaptionElem.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(cbd44d29-3120-470d-a7fb-fac4730c8b4b)]
+[scriptable, uuid(db0e641f-ba2b-4c67-8da1-4e418cc5fbf7)]
 interface nsIDOMHTMLTableCaptionElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
 };
--- a/dom/interfaces/html/nsIDOMHTMLTableCellElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTableCellElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(03dd5118-7eaf-4bd3-a4a7-77f3f7eb8539)]
+[scriptable, uuid(4caa7af0-fec4-44c1-9a81-e1f14166e60c)]
 interface nsIDOMHTMLTableCellElement : nsIDOMHTMLElement
 {
   readonly attribute long             cellIndex;
            attribute DOMString        abbr;
            attribute DOMString        align;
            attribute DOMString        axis;
            attribute DOMString        bgColor;
            attribute DOMString        ch;
--- a/dom/interfaces/html/nsIDOMHTMLTableColElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTableColElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(d221534a-d13c-43b2-9ba0-7e0dd7452856)]
+[scriptable, uuid(9a4d1f6a-fb19-4886-b0d8-dcd201566580)]
 interface nsIDOMHTMLTableColElement : nsIDOMHTMLElement
 {
            attribute DOMString        align;
            attribute DOMString        ch;
            attribute DOMString        chOff;
            attribute long             span;
            attribute DOMString        vAlign;
            attribute DOMString        width;
--- a/dom/interfaces/html/nsIDOMHTMLTableElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTableElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(bba4b8b2-d01c-4c9b-abc8-3df28d048e68)]
+[scriptable, uuid(0f809b97-9311-45c4-a44e-7145f354438b)]
 interface nsIDOMHTMLTableElement : nsIDOMHTMLElement
 {
   // Modified in DOM Level 2:
            attribute nsIDOMHTMLTableCaptionElement caption;
                                              // raises(DOMException) on setting
 
   // Modified in DOM Level 2:
            attribute nsIDOMHTMLTableSectionElement tHead;
--- a/dom/interfaces/html/nsIDOMHTMLTableRowElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTableRowElement.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(b0199f36-9e76-4ec6-867f-850e388d6244)]
+[scriptable, uuid(d24a80d4-491d-4e36-9349-afd3c6999b3e)]
 interface nsIDOMHTMLTableRowElement : nsIDOMHTMLElement
 {
   // Modified in DOM Level 2:
   readonly attribute long                 rowIndex;
   // Modified in DOM Level 2:
   readonly attribute long                 sectionRowIndex;
   // Modified in DOM Level 2:
   readonly attribute nsIDOMHTMLCollection cells;
--- a/dom/interfaces/html/nsIDOMHTMLTableSectionElem.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTableSectionElem.idl
@@ -45,17 +45,17 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(ac2e2719-71f1-4485-ac1e-694e7e49bd2a)]
+[scriptable, uuid(6acc106e-96a2-4519-8f3a-142ebbdc1bb1)]
 interface nsIDOMHTMLTableSectionElement : nsIDOMHTMLElement
 {
            attribute DOMString            align;
            attribute DOMString            ch;
            attribute DOMString            chOff;
            attribute DOMString            vAlign;
   readonly attribute nsIDOMHTMLCollection rows;
   // Modified in DOM Level 2:
--- a/dom/interfaces/html/nsIDOMHTMLTextAreaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTextAreaElement.idl
@@ -48,17 +48,17 @@ interface nsIDOMValidityState;
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(88d09917-d2da-4737-a887-277a2f9750c7)]
+[scriptable, uuid(16db703d-4816-440c-bcb3-c1ae0cae6532)]
 interface nsIDOMHTMLTextAreaElement : nsIDOMHTMLElement
 {
            attribute boolean               autofocus;
            attribute unsigned long         cols;
            attribute boolean               disabled;
   readonly attribute nsIDOMHTMLFormElement form;
            attribute long                  maxLength;
            attribute DOMString             name;
--- a/dom/interfaces/html/nsIDOMHTMLTitleElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLTitleElement.idl
@@ -45,13 +45,13 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(5cb8cfaf-7551-422b-9b03-58d756e54339)]
+[scriptable, uuid(e20fd651-6240-4f20-b8f0-6cc25cb699b7)]
 interface nsIDOMHTMLTitleElement : nsIDOMHTMLElement
 {
            attribute DOMString        text;
 };
--- a/dom/interfaces/html/nsIDOMHTMLUListElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLUListElement.idl
@@ -45,14 +45,14 @@
  *
  * This interface is trying to follow the DOM Level 2 HTML specification:
  * http://www.w3.org/TR/DOM-Level-2-HTML/
  *
  * with changes from the work-in-progress WHATWG HTML specification:
  * http://www.whatwg.org/specs/web-apps/current-work/
  */
 
-[scriptable, uuid(1f409357-8cea-4f69-9f0c-4149886b63a1)]
+[scriptable, uuid(2467d39c-2c30-407e-9b67-ea5f231b7809)]
 interface nsIDOMHTMLUListElement : nsIDOMHTMLElement
 {
            attribute boolean          compact;
            attribute DOMString        type;
 };
--- a/dom/interfaces/html/nsIDOMHTMLUnknownElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLUnknownElement.idl
@@ -38,12 +38,12 @@
 #include "nsIDOMHTMLElement.idl"
 
 /**
  * The nsIDOMHTMLUnknownElement interface is the interface to an unknown HTML
  * element.
  *
  * @see <http://www.whatwg.org/html/#htmlunknownelement>
  */
-[scriptable, uuid(0d69049f-8181-47f1-a7f7-e5417dd54136)]
+[scriptable, uuid(5f922c13-c2c1-4c49-b7c2-0e4e5c8e6860)]
 interface nsIDOMHTMLUnknownElement : nsIDOMHTMLElement
 {
 };
--- a/dom/interfaces/html/nsIDOMHTMLVideoElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLVideoElement.idl
@@ -43,17 +43,17 @@
  * <video> element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#video
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(5e1e4453-96fe-4cc0-9c32-7e9355b4f917)]
+[scriptable, uuid(390b974b-1c3a-4700-8001-5ef832c4b4bf)]
 interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
 {
            attribute long width; 
            attribute long height;
   readonly attribute unsigned long videoWidth;
   readonly attribute unsigned long videoHeight;
            attribute DOMString poster;
            
--- a/dom/tests/mochitest/general/Makefile.in
+++ b/dom/tests/mochitest/general/Makefile.in
@@ -40,16 +40,18 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = dom/tests/mochitest/general
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
+		test_outerHTML.html \
+		test_outerHTML.xhtml \
 		497633.html \
 		489127.html \
 		historyframes.html \
 		test_497898.html \
 		test_bug504220.html \
 		test_bug628069_1.html \
 		test_bug628069_2.html \
 		file_bug628069.html \
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_outerHTML.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=92264
+-->
+<head>
+  <title>Test for Bug 92264</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=92264">Mozilla Bug 92264</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<div id="wrap"><dl></dl><p id="thep">foo<span>bar</span></p><ol></ol></div>
+<table id="thetable"><tbody><tr><td>1</td></tr><tr id="thetr"><td>2</td></tr><tr><td>3</td></tr></tbody></table>
+<iframe></iframe>
+<div id="fragmentwrap"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 92264 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+
+  var thep = document.getElementById("thep");
+  var wrap = document.getElementById("wrap");
+  is(thep.outerHTML, '<p id="thep">foo<span>bar</span></p>', "Unexpected thep outerHTML");
+  thep.outerHTML = "<ul></ul><tr></tr><p></p>";
+  is(wrap.innerHTML, "<dl></dl><ul></ul><p></p><ol></ol>", "Bad outerHTML parsing inside wrap");
+
+  var thetr = document.getElementById("thetr");
+  thetr.outerHTML = "<tr><td>a</td></tr><div></div><tr><td>b</td></tr>";
+  var thetable = document.getElementById("thetable");
+  is(thetable.innerHTML, "<tbody><tr><td>1</td></tr><tr><td>a</td></tr><div></div><tr><td>b</td></tr><tr><td>3</td></tr></tbody>", "Wrong outerHTML parsing inside table");
+
+  var iframe = document.getElementsByTagName("iframe")[0];
+  var oldbody = iframe.contentDocument.body;
+  iframe.contentDocument.body.outerHTML = "<body></body>";
+  isnot(oldbody, iframe.contentDocument.body, "Failed to replace body");
+  is(iframe.contentDocument.getElementsByTagName("body").length, 1, "Should have gotten one body");
+  // Yes, two heads per spec. Also Ragnarök and Chrome produce two heads.
+  is(iframe.contentDocument.getElementsByTagName("head").length, 2, "Should have gotten two heads");
+
+  try {
+    document.documentElement.outerHTML = "<html></html>";
+    ok(false, "Should have thrown an exception");
+  } catch(e) {
+    is(e.code, 7, "outerHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+  }
+
+  var f = document.createDocumentFragment();
+  var dl = document.createElement("dl");
+  var p = document.createElement("p");
+  var ol = document.createElement("ol");
+  f.appendChild(dl);
+  f.appendChild(p);
+  f.appendChild(ol);
+  p.outerHTML = "<ul></ul><tr></tr><body></body><p></p>";
+  var fragmentwrap = document.getElementById("fragmentwrap");
+  fragmentwrap.appendChild(f);
+  is(fragmentwrap.innerHTML, "<dl></dl><ul></ul><p></p><ol></ol>", "Bad outerHTML parsing in fragment");
+
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_outerHTML.xhtml
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=92264
+-->
+<head>
+  <title>Test for Bug 92264</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=92264">Mozilla Bug 92264</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<div id="wrap"><dl></dl><p id="thep">foo<span>bar</span></p><ol></ol></div>
+<table id="thetable"><tbody><tr><td>1</td></tr><tr id="thetr"><td>2</td></tr><tr><td>3</td></tr></tbody></table>
+<iframe></iframe>
+<div id="fragmentwrap"></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 92264 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+
+  var thep = document.getElementById("thep");
+  var wrap = document.getElementById("wrap");
+  is(thep.outerHTML, '<p xmlns="http://www.w3.org/1999/xhtml" id="thep">foo<span>bar</span></p>', "Unexpected thep outerHTML");
+  thep.outerHTML = "<ul></ul><tr></tr><p></p>";
+  is(wrap.innerHTML, '<dl xmlns="http://www.w3.org/1999/xhtml"></dl><ul xmlns="http://www.w3.org/1999/xhtml"></ul><tr xmlns="http://www.w3.org/1999/xhtml"></tr><p xmlns="http://www.w3.org/1999/xhtml"></p><ol xmlns="http://www.w3.org/1999/xhtml"></ol>', "Bad outerHTML parsing inside wrap");
+
+  var thetr = document.getElementById("thetr");
+  thetr.outerHTML = "<tr><td>a</td></tr><div></div><tr><td>b</td></tr>";
+  var thetable = document.getElementById("thetable");
+  is(thetable.innerHTML, '<tbody xmlns="http://www.w3.org/1999/xhtml"><tr><td>1</td></tr><tr><td>a</td></tr><div></div><tr><td>b</td></tr><tr><td>3</td></tr></tbody>', "Wrong outerHTML parsing inside table");
+
+  var iframe = document.getElementsByTagName("iframe")[0];
+  var oldbody = iframe.contentDocument.body;
+  iframe.contentDocument.body.outerHTML = "<body></body>";
+  isnot(oldbody, iframe.contentDocument.body, "Failed to replace body");
+  is(iframe.contentDocument.getElementsByTagName("body").length, 1, "Should have gotten one body");
+  // Yes, two heads per spec. Also Ragnarök and Chrome produce two heads.
+  is(iframe.contentDocument.getElementsByTagName("head").length, 2, "Should have gotten two heads");
+
+  try {
+    document.documentElement.outerHTML = "<html></html>";
+    ok(false, "Should have thrown an exception");
+  } catch(e) {
+    is(e.code, 7, "outerHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+  }
+
+  var f = document.createDocumentFragment();
+  var dl = document.createElement("dl");
+  var p = document.createElement("p");
+  var ol = document.createElement("ol");
+  f.appendChild(dl);
+  f.appendChild(p);
+  f.appendChild(ol);
+  p.outerHTML = "<ul></ul><tr></tr><body></body><p></p>";
+  var fragmentwrap = document.getElementById("fragmentwrap");
+  fragmentwrap.appendChild(f);
+  is(fragmentwrap.innerHTML, '<dl xmlns="http://www.w3.org/1999/xhtml"></dl><ul xmlns="http://www.w3.org/1999/xhtml"></ul><tr xmlns="http://www.w3.org/1999/xhtml"></tr><body xmlns="http://www.w3.org/1999/xhtml"></body><p xmlns="http://www.w3.org/1999/xhtml"></p><ol xmlns="http://www.w3.org/1999/xhtml"></ol>', "Bad outerHTML parsing in fragment");
+
+  SimpleTest.finish();
+}
+]]>
+</script>
+</pre>
+</body>
+</html>
--- a/editor/composer/src/nsEditingSession.cpp
+++ b/editor/composer/src/nsEditingSession.cpp
@@ -832,17 +832,18 @@ nsEditingSession::OnProgressChange(nsIWe
 
 /*---------------------------------------------------------------------------
 
   OnLocationChange
 
 ----------------------------------------------------------------------------*/
 NS_IMETHODIMP
 nsEditingSession::OnLocationChange(nsIWebProgress *aWebProgress, 
-                                   nsIRequest *aRequest, nsIURI *aURI)
+                                   nsIRequest *aRequest, nsIURI *aURI,
+                                   PRUint32 aFlags)
 {
   nsCOMPtr<nsIDOMWindow> domWindow;
   nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDOMDocument> domDoc;
   rv = domWindow->GetDocument(getter_AddRefs(domDoc));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/editor/composer/test/test_bug434998.xul
+++ b/editor/composer/test/test_bug434998.xul
@@ -73,17 +73,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 
     onProgressChange : function(aWebProgress, aRequest,
                                 aCurSelfProgress, aMaxSelfProgress,
                                 aCurTotalProgress, aMaxTotalProgress)
     {
     },
 
-    onLocationChange : function(aWebProgress, aRequest, aLocation)
+    onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags)
     {
     },
 
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
     {
     },
 
     onSecurityChange : function(aWebProgress, aRequest, aState)
--- a/editor/libeditor/html/tests/test_bug607584.xul
+++ b/editor/libeditor/html/tests/test_bug607584.xul
@@ -78,17 +78,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   
   
     onProgressChange : function(aWebProgress, aRequest,
                                 aCurSelfProgress, aMaxSelfProgress,
                                 aCurTotalProgress, aMaxTotalProgress)
       {
       },
   
-    onLocationChange : function(aWebProgress, aRequest, aLocation)
+    onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags)
       {
       },
   
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
       {
       },
   
     onSecurityChange : function(aWebProgress, aRequest, aState)
--- a/editor/libeditor/html/tests/test_bug616590.xul
+++ b/editor/libeditor/html/tests/test_bug616590.xul
@@ -68,17 +68,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 
     onProgressChange : function(aWebProgress, aRequest,
                                 aCurSelfProgress, aMaxSelfProgress,
                                 aCurTotalProgress, aMaxTotalProgress)
     {
     },
 
-    onLocationChange : function(aWebProgress, aRequest, aLocation)
+    onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags)
     {
     },
 
     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
     {
     },
 
     onSecurityChange : function(aWebProgress, aRequest, aState)
--- a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
@@ -718,17 +718,18 @@ nsDocShellTreeOwner::OnStateChange(nsIWe
                                    nsresult aStatus)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress,
                                       nsIRequest* aRequest,
-                                      nsIURI* aURI)
+                                      nsIURI* aURI,
+                                      PRUint32 aFlags)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress,
                                     nsIRequest* aRequest,
                                     nsresult aStatus,
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -847,22 +847,22 @@ NS_IMETHODIMP nsWebBrowser::OnProgressCh
     }
     if (mProgressListener)
     {
         return mProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
     }
     return NS_OK;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
-NS_IMETHODIMP nsWebBrowser::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
+NS_IMETHODIMP nsWebBrowser::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
     if (mProgressListener)
     {
-        return mProgressListener->OnLocationChange(aWebProgress, aRequest, location);
+        return mProgressListener->OnLocationChange(aWebProgress, aRequest, location, aFlags);
     }
     return NS_OK;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP nsWebBrowser::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
     if (mProgressListener)
--- a/embedding/components/printingui/src/mac/nsPrintProgress.cpp
+++ b/embedding/components/printingui/src/mac/nsPrintProgress.cpp
@@ -252,18 +252,18 @@ NS_IMETHODIMP nsPrintProgress::OnProgres
       if (aProgressListener)
         aProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
     }
   }
   
   return rv;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
-NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
+NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
     return NS_OK;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP nsPrintProgress::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
   nsresult rv = NS_OK;
--- a/embedding/components/printingui/src/mac/nsPrintingPromptServiceX.mm
+++ b/embedding/components/printingui/src/mac/nsPrintingPromptServiceX.mm
@@ -131,19 +131,19 @@ nsPrintingPromptService::OnStateChange(n
 
 /* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
 NS_IMETHODIMP 
 nsPrintingPromptService::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
 {
     return NS_OK;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
 NS_IMETHODIMP 
-nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
     return NS_OK;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP 
 nsPrintingPromptService::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
--- a/embedding/components/printingui/src/os2/nsPrintProgress.cpp
+++ b/embedding/components/printingui/src/os2/nsPrintProgress.cpp
@@ -249,18 +249,18 @@ NS_IMETHODIMP nsPrintProgress::OnProgres
       if (aProgressListener)
         aProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
     }
   }
   
   return rv;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
-NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
+NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
     return NS_OK;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP nsPrintProgress::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
   nsresult rv = NS_OK;
--- a/embedding/components/printingui/src/os2/nsPrintingPromptService.cpp
+++ b/embedding/components/printingui/src/os2/nsPrintingPromptService.cpp
@@ -284,22 +284,22 @@ NS_IMETHODIMP
 nsPrintingPromptService::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
 {
   if (mWebProgressListener) {
     return mWebProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
   }
   return NS_OK;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
 NS_IMETHODIMP 
-nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
   if (mWebProgressListener) {
-    return mWebProgressListener->OnLocationChange(aWebProgress, aRequest, location);
+    return mWebProgressListener->OnLocationChange(aWebProgress, aRequest, location, aFlags);
   }
   return NS_OK;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP 
 nsPrintingPromptService::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
--- a/embedding/components/printingui/src/unixshared/nsPrintProgress.cpp
+++ b/embedding/components/printingui/src/unixshared/nsPrintProgress.cpp
@@ -252,18 +252,18 @@ NS_IMETHODIMP nsPrintProgress::OnProgres
       if (aProgressListener)
         aProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
     }
   }
   
   return rv;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
-NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
+NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP nsPrintProgress::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
   nsresult rv = NS_OK;
--- a/embedding/components/printingui/src/unixshared/nsPrintingPromptService.cpp
+++ b/embedding/components/printingui/src/unixshared/nsPrintingPromptService.cpp
@@ -303,22 +303,22 @@ NS_IMETHODIMP
 nsPrintingPromptService::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
 {
   if (mWebProgressListener) {
     return mWebProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
   }
   return NS_OK;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
 NS_IMETHODIMP 
-nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
   if (mWebProgressListener) {
-    return mWebProgressListener->OnLocationChange(aWebProgress, aRequest, location);
+    return mWebProgressListener->OnLocationChange(aWebProgress, aRequest, location, aFlags);
   }
   return NS_OK;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP 
 nsPrintingPromptService::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
--- a/embedding/components/printingui/src/win/nsPrintProgress.cpp
+++ b/embedding/components/printingui/src/win/nsPrintProgress.cpp
@@ -280,18 +280,18 @@ NS_IMETHODIMP nsPrintProgress::OnProgres
       if (aProgressListener)
         aProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
     }
   }
   
   return rv;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
-NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
+NS_IMETHODIMP nsPrintProgress::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
     return NS_OK;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP nsPrintProgress::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
   nsresult rv = NS_OK;
--- a/embedding/components/printingui/src/win/nsPrintingPromptService.cpp
+++ b/embedding/components/printingui/src/win/nsPrintingPromptService.cpp
@@ -352,23 +352,23 @@ nsPrintingPromptService::OnProgressChang
 {
   if (mWebProgressListener) 
   {
       return mWebProgressListener->OnProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress);
   }
   return NS_ERROR_FAILURE;
 }
 
-/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location, in unsigned long aFlags); */
 NS_IMETHODIMP 
-nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+nsPrintingPromptService::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location, PRUint32 aFlags)
 {
   if (mWebProgressListener) 
   {
-      return mWebProgressListener->OnLocationChange(aWebProgress, aRequest, location);
+      return mWebProgressListener->OnLocationChange(aWebProgress, aRequest, location, aFlags);
   }
   return NS_ERROR_FAILURE;
 }
 
 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
 NS_IMETHODIMP 
 nsPrintingPromptService::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
 {
--- a/embedding/tests/winEmbed/WebBrowserChrome.cpp
+++ b/embedding/tests/winEmbed/WebBrowserChrome.cpp
@@ -271,17 +271,18 @@ NS_IMETHODIMP WebBrowserChrome::OnStateC
     }
 
     return NS_OK;
 }
 
 
 NS_IMETHODIMP WebBrowserChrome::OnLocationChange(nsIWebProgress* aWebProgress,
                                                  nsIRequest* aRequest,
-                                                 nsIURI *location)
+                                                 nsIURI *location,
+                                                 PRUint32 aFlags)
 {
   bool isSubFrameLoad = false; // Is this a subframe load
   if (aWebProgress) {
     nsCOMPtr<nsIDOMWindow>  domWindow;
     nsCOMPtr<nsIDOMWindow>  topDomWindow;
     aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
     if (domWindow) { // Get root domWindow
       domWindow->GetTop(getter_AddRefs(topDomWindow));
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -907,17 +907,20 @@ class HashMapEntry
     template <class> friend class detail::HashTableEntry;
     void operator=(const HashMapEntry &rhs) {
         const_cast<Key &>(key) = rhs.key;
         value = rhs.value;
     }
 
   public:
     HashMapEntry() : key(), value() {}
-    HashMapEntry(const Key &k, const Value &v) : key(k), value(v) {}
+
+    template<typename KeyInput, typename ValueInput>
+    HashMapEntry(const KeyInput &k, const ValueInput &v) : key(k), value(v) {}
+
     HashMapEntry(MoveRef<HashMapEntry> rhs) 
       : key(Move(rhs->key)), value(Move(rhs->value)) { }
     void operator=(MoveRef<HashMapEntry> rhs) {
         const_cast<Key &>(key) = Move(rhs->key);
         value = Move(rhs->value);
     }
 
     const Key key;
@@ -1043,17 +1046,18 @@ class HashMap
      *    assert(p->key == 3);
      *    char val = p->value;
      */
     typedef typename Impl::AddPtr AddPtr;
     AddPtr lookupForAdd(const Lookup &l) const {
         return impl.lookupForAdd(l);
     }
 
-    bool add(AddPtr &p, const Key &k, const Value &v) {
+    template<typename KeyInput, typename ValueInput>
+    bool add(AddPtr &p, const KeyInput &k, const ValueInput &v) {
         Entry *pentry;
         if (!impl.add(p, &pentry))
             return false;
         const_cast<Key &>(pentry->key) = k;
         pentry->value = v;
         return true;
     }
 
@@ -1069,17 +1073,18 @@ class HashMap
     bool add(AddPtr &p, const Key &k) {
         Entry *pentry;
         if (!impl.add(p, &pentry))
             return false;
         const_cast<Key &>(pentry->key) = k;
         return true;
     }
 
-    bool relookupOrAdd(AddPtr &p, const Key &k, const Value &v) {
+    template<typename KeyInput, typename ValueInput>
+    bool relookupOrAdd(AddPtr &p, const KeyInput &k, const ValueInput &v) {
         return impl.relookupOrAdd(p, k, Entry(k, v));
     }
 
     /*
      * |all()| returns a Range containing |count()| elements. E.g.:
      *
      *   typedef HashMap<int,char> HM;
      *   HM h;
@@ -1132,17 +1137,18 @@ class HashMap
 
     /* Shorthand operations: */
 
     bool has(const Lookup &l) const {
         return impl.lookup(l) != NULL;
     }
 
     /* Overwrite existing value with v. Return NULL on oom. */
-    Entry *put(const Key &k, const Value &v) {
+    template<typename KeyInput, typename ValueInput>
+    Entry *put(const KeyInput &k, const ValueInput &v) {
         AddPtr p = lookupForAdd(k);
         if (p) {
             p->value = v;
             return &*p;
         }
         return add(p, k, v) ? &*p : NULL;
     }
 
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -245,16 +245,17 @@ EXPORTS_vm = \
 
 EXPORTS_ds = \
 		LifoAlloc.h \
 		BitArray.h \
 		$(NULL)
 
 EXPORTS_gc = \
 		Statistics.h \
+		Barrier.h \
 		$(NULL)
 
 ######################################################
 # BEGIN include exported headers from the JS engine
 #
 #       Ultimately, after cleansing INSTALLED_HEADERS,
 #       these will be the ONLY headers exported by
 #       the js engine
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4438,16 +4438,27 @@ MOZ_ARG_ENABLE_BOOL(tracevis,
 if test -n "$MOZ_TRACEVIS"; then
     AC_DEFINE(MOZ_TRACEVIS)
     if test -z "$ENABLE_TRACEJIT"; then
        AC_MSG_ERROR([--enable-tracevis is incompatible with --disable-tracejit])
     fi
 fi
 
 dnl ========================================================
+dnl = Use incremental GC
+dnl ========================================================
+JSGC_INCREMENTAL=1
+MOZ_ARG_DISABLE_BOOL(gcincremental,
+[  --disable-gcincremental Disable incremental GC],
+    JSGC_INCREMENTAL= )
+if test -n "$JSGC_INCREMENTAL"; then
+    AC_DEFINE(JSGC_INCREMENTAL)
+fi
+
+dnl ========================================================
 dnl = Use Valgrind
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(valgrind,
 [  --enable-valgrind       Enable Valgrind integration hooks (default=no)],
     MOZ_VALGRIND=1,
     MOZ_VALGRIND= )
 if test -n "$MOZ_VALGRIND"; then
     AC_CHECK_HEADER([valgrind/valgrind.h], [],
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BytecodeEmitter-inl.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** 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 Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * 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 ***** */
+
+#ifndef BytecodeEmitter_inl_h__
+#define BytecodeEmitter_inl_h__
+
+#include "frontend/ParseNode.h"
+#include "frontend/TokenStream.h"
+
+namespace js {
+
+inline
+TreeContext::TreeContext(Parser *prs)
+  : flags(0), bodyid(0), blockidGen(0), parenDepth(0), yieldCount(0), argumentsCount(0),
+    topStmt(NULL), topScopeStmt(NULL), blockChainBox(NULL), blockNode(NULL),
+    decls(prs->context), parser(prs), yieldNode(NULL), argumentsNode(NULL), scopeChain_(NULL),
+    lexdeps(prs->context), parent(prs->tc), staticLevel(0), funbox(NULL), functionList(NULL),
+    innermostWith(NULL), bindings(prs->context), sharpSlotBase(-1)
+{
+    prs->tc = this;
+}
+
+/*
+ * For functions the tree context is constructed and destructed a second
+ * time during code generation. To avoid a redundant stats update in such
+ * cases, we store uint16(-1) in maxScopeDepth.
+ */
+inline
+TreeContext::~TreeContext()
+{
+    parser->tc = this->parent;
+}
+
+} /* namespace js */
+
+#endif /* BytecodeEmitter_inl_h__ */
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -66,20 +66,20 @@
 #include "ds/LifoAlloc.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "vm/RegExpObject.h"
 
 #include "jsatominlines.h"
-#include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
+#include "frontend/BytecodeEmitter-inl.h"
 #include "frontend/ParseMaps-inl.h"
 
 /* Allocation chunk counts, must be powers of two in general. */
 #define BYTECODE_CHUNK_LENGTH  1024    /* initial bytecode chunk length */
 #define SRCNOTE_CHUNK_LENGTH   1024    /* initial srcnote chunk length */
 
 /* Macros to compute byte sizes from typed element counts. */
 #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
@@ -7772,32 +7772,32 @@ CGObjectList::index(ObjectBox *objbox)
 }
 
 void
 CGObjectList::finish(JSObjectArray *array)
 {
     JS_ASSERT(length <= INDEX_LIMIT);
     JS_ASSERT(length == array->length);
 
-    JSObject **cursor = array->vector + array->length;
+    js::HeapPtrObject *cursor = array->vector + array->length;
     ObjectBox *objbox = lastbox;
     do {
         --cursor;
         JS_ASSERT(!*cursor);
         *cursor = objbox->object;
     } while ((objbox = objbox->emitLink) != NULL);
     JS_ASSERT(cursor == array->vector);
 }
 
 void
 GCConstList::finish(JSConstArray *array)
 {
     JS_ASSERT(array->length == list.length());
     Value *src = list.begin(), *srcend = list.end();
-    Value *dst = array->vector;
+    HeapValue *dst = array->vector;
     for (; src != srcend; ++src, ++dst)
         *dst = *src;
 }
 
 /*
  * We should try to get rid of offsetBias (always 0 or 1, where 1 is
  * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL.
  */
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -354,34 +354,18 @@ struct TreeContext {                /* t
 
     ParseNode       *innermostWith; /* innermost WITH parse node */
 
     Bindings        bindings;       /* bindings in this code, including
                                        arguments if we're compiling a function */
 
     void trace(JSTracer *trc);
 
-    TreeContext(Parser *prs)
-      : flags(0), bodyid(0), blockidGen(0), parenDepth(0), yieldCount(0), argumentsCount(0),
-        topStmt(NULL), topScopeStmt(NULL), blockChainBox(NULL), blockNode(NULL),
-        decls(prs->context), parser(prs), yieldNode(NULL), argumentsNode(NULL), scopeChain_(NULL),
-        lexdeps(prs->context), parent(prs->tc), staticLevel(0), funbox(NULL), functionList(NULL),
-        innermostWith(NULL), bindings(prs->context), sharpSlotBase(-1)
-    {
-        prs->tc = this;
-    }
-
-    /*
-     * For functions the tree context is constructed and destructed a second
-     * time during code generation. To avoid a redundant stats update in such
-     * cases, we store uint16(-1) in maxScopeDepth.
-     */
-    ~TreeContext() {
-        parser->tc = this->parent;
-    }
+    inline TreeContext(Parser *prs);
+    inline ~TreeContext();
 
     /*
      * js::BytecodeEmitter derives from js::TreeContext; however, only the
      * top-level BytecodeEmitters are actually used as full-fledged tree contexts
      * (to hold decls and lexdeps). We can avoid allocation overhead by making
      * this distinction explicit.
      */
     enum InitBehavior {
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -87,19 +87,19 @@
 #include "jsxml.h"
 #endif
 
 #if JS_HAS_DESTRUCTURING
 #include "jsdhash.h"
 #endif
 
 #include "jsatominlines.h"
-#include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
+#include "frontend/BytecodeEmitter-inl.h"
 #include "frontend/ParseMaps-inl.h"
 #include "frontend/ParseNode-inl.h"
 #include "vm/RegExpObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
@@ -241,17 +241,17 @@ Parser::newFunctionBox(JSObject *obj, Pa
     return funbox;
 }
 
 void
 Parser::trace(JSTracer *trc)
 {
     ObjectBox *objbox = traceListHead;
     while (objbox) {
-        MarkObject(trc, *objbox->object, "parser.object");
+        MarkRoot(trc, objbox->object, "parser.object");
         if (objbox->isFunctionBox)
             static_cast<FunctionBox *>(objbox)->bindings.trace(trc);
         objbox = objbox->traceLink;
     }
 
     for (TreeContext *tc = this->tc; tc; tc = tc->parent)
         tc->trace(trc);
 }
--- a/js/src/frontend/SemanticAnalysis.cpp
+++ b/js/src/frontend/SemanticAnalysis.cpp
@@ -40,16 +40,17 @@
 
 #include "frontend/SemanticAnalysis.h"
 
 #include "jsfun.h"
 
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 
+#include "jsobjinlines.h"
 #include "jsfuninlines.h"
 
 using namespace js;
 using namespace js::frontend;
 
 /*
  * Walk the function box list at |*funboxHead|, removing boxes for deleted
  * functions and cleaning up method lists. We do this once, before
new file mode 100644
--- /dev/null
+++ b/js/src/gc/Barrier-inl.h
@@ -0,0 +1,259 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * ***** 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 SpiderMonkey global object code.
+ *
+ * The Initial Developer of the Original Code is
+ * the 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 ***** */
+
+#include "jsgcmark.h"
+
+#include "gc/Barrier.h"
+
+#ifndef jsgc_barrier_inl_h___
+#define jsgc_barrier_inl_h___
+
+namespace js {
+
+static JS_ALWAYS_INLINE void
+ClearValueRange(JSCompartment *comp, HeapValue *vec, uintN len, bool useHoles)
+{
+    if (useHoles) {
+        for (uintN i = 0; i < len; i++)
+            vec[i].set(comp, MagicValue(JS_ARRAY_HOLE));
+    } else {
+        for (uintN i = 0; i < len; i++)
+            vec[i].set(comp, UndefinedValue());
+    }
+}
+
+static JS_ALWAYS_INLINE void
+InitValueRange(HeapValue *vec, uintN len, bool useHoles)
+{
+    if (useHoles) {
+        for (uintN i = 0; i < len; i++)
+            vec[i].init(MagicValue(JS_ARRAY_HOLE));
+    } else {
+        for (uintN i = 0; i < len; i++)
+            vec[i].init(UndefinedValue());
+    }
+}
+
+static JS_ALWAYS_INLINE void
+DestroyValueRange(HeapValue *vec, uintN len)
+{
+    for (uintN i = 0; i < len; i++)
+        vec[i].~HeapValue();
+}
+
+inline
+HeapValue::HeapValue(const Value &v)
+    : value(v)
+{
+    post();
+}
+
+inline
+HeapValue::HeapValue(const HeapValue &v)
+    : value(v.value)
+{
+    post();
+}
+
+inline
+HeapValue::~HeapValue()
+{
+    pre();
+}
+
+inline void
+HeapValue::init(const Value &v)
+{
+    value = v;
+    post();
+}
+
+inline void
+HeapValue::writeBarrierPre(const Value &value)
+{
+#ifdef JSGC_INCREMENTAL
+    if (value.isMarkable()) {
+        js::gc::Cell *cell = (js::gc::Cell *)value.toGCThing();
+        writeBarrierPre(cell->compartment(), value);
+    }
+#endif
+}
+
+inline void
+HeapValue::writeBarrierPost(const Value &value, void *addr)
+{
+}
+
+inline void
+HeapValue::writeBarrierPre(JSCompartment *comp, const Value &value)
+{
+#ifdef JSGC_INCREMENTAL
+    if (comp->needsBarrier())
+        js::gc::MarkValueUnbarriered(comp->barrierTracer(), value, "write barrier");
+#endif
+}
+
+inline void
+HeapValue::writeBarrierPost(JSCompartment *comp, const Value &value, void *addr)
+{
+}
+
+inline void
+HeapValue::pre()
+{
+    writeBarrierPre(value);
+}
+
+inline void
+HeapValue::post()
+{
+}
+
+inline void
+HeapValue::pre(JSCompartment *comp)
+{
+    writeBarrierPre(comp, value);
+}
+
+inline void
+HeapValue::post(JSCompartment *comp)
+{
+}
+
+inline HeapValue &
+HeapValue::operator=(const Value &v)
+{
+    pre();
+    value = v;
+    post();
+    return *this;
+}
+
+inline HeapValue &
+HeapValue::operator=(const HeapValue &v)
+{
+    pre();
+    value = v.value;
+    post();
+    return *this;
+}
+
+inline void
+HeapValue::set(JSCompartment *comp, const Value &v)
+{
+#ifdef DEBUG
+    if (value.isMarkable()) {
+        js::gc::Cell *cell = (js::gc::Cell *)value.toGCThing();
+        JS_ASSERT(cell->compartment() == comp ||
+                  cell->compartment() == comp->rt->atomsCompartment);
+    }
+#endif
+
+    pre(comp);
+    value = v;
+    post(comp);
+}
+
+inline void
+HeapValue::boxNonDoubleFrom(JSValueType type, uint64 *out)
+{
+    pre();
+    value.boxNonDoubleFrom(type, out);
+    post();
+}
+
+inline
+HeapId::HeapId(jsid id)
+    : value(id)
+{
+    post();
+}
+
+inline
+HeapId::~HeapId()
+{
+    pre();
+}
+
+inline void
+HeapId::init(jsid id)
+{
+    value = id;
+    post();
+}
+
+inline void
+HeapId::pre()
+{
+#ifdef JSGC_INCREMENTAL
+    if (JS_UNLIKELY(JSID_IS_OBJECT(value))) {
+        JSObject *obj = JSID_TO_OBJECT(value);
+        JSCompartment *comp = obj->compartment();
+        if (comp->needsBarrier())
+            js::gc::MarkObjectUnbarriered(comp->barrierTracer(), obj, "write barrier");
+    }
+#endif
+}
+
+inline void
+HeapId::post()
+{
+}
+
+inline HeapId &
+HeapId::operator=(jsid id)
+{
+    pre();
+    value = id;
+    post();
+    return *this;
+}
+
+inline HeapId &
+HeapId::operator=(const HeapId &v)
+{
+    pre();
+    value = v.value;
+    post();
+    return *this;
+}
+
+} /* namespace js */
+
+#endif /* jsgc_barrier_inl_h___ */
new file mode 100644
--- /dev/null
+++ b/js/src/gc/Barrier.h
@@ -0,0 +1,450 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * ***** 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 SpiderMonkey global object code.
+ *
+ * The Initial Developer of the Original Code is
+ * the 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 ***** */
+
+#ifndef jsgc_barrier_h___
+#define jsgc_barrier_h___
+
+#include "jsapi.h"
+#include "jscell.h"
+
+#include "js/HashTable.h"
+
+/*
+ * A write barrier is a mechanism used by incremental or generation GCs to
+ * ensure that every value that needs to be marked is marked. In general, the
+ * write barrier should be invoked whenever a write can cause the set of things
+ * traced through by the GC to change. This includes:
+ *   - writes to object properties
+ *   - writes to array slots
+ *   - writes to fields like JSObject::lastProp that we trace through
+ *   - writes to fields in private data, like JSGenerator::obj
+ *   - writes to non-markable fields like JSObject::private that point to
+ *     markable data
+ * The last category is the trickiest. Even though the private pointers does not
+ * point to a GC thing, changing the private pointer may change the set of
+ * objects that are traced by the GC. Therefore it needs a write barrier.
+ *
+ * Every barriered write should have the following form:
+ *   <pre-barrier>
+ *   obj->field = value; // do the actual write
+ *   <post-barrier>
+ * The pre-barrier is used for incremental GC and the post-barrier is for
+ * generational GC.
+ *
+ *                               PRE-BARRIER
+ *
+ * To understand the pre-barrier, let's consider how incremental GC works. The
+ * GC itself is divided into "slices". Between each slice, JS code is allowed to
+ * run. Each slice should be short so that the user doesn't notice the
+ * interruptions. In our GC, the structure of the slices is as follows:
+ *
+ * 1. ... JS work, which leads to a request to do GC ...
+ * 2. [first GC slice, which performs all root marking and possibly more marking]
+ * 3. ... more JS work is allowed to run ...
+ * 4. [GC mark slice, which runs entirely in drainMarkStack]
+ * 5. ... more JS work ...
+ * 6. [GC mark slice, which runs entirely in drainMarkStack]
+ * 7. ... more JS work ...
+ * 8. [GC marking finishes; sweeping done non-incrementally; GC is done]
+ * 9. ... JS continues uninterrupted now that GC is finishes ...
+ *
+ * Of course, there may be a different number of slices depending on how much
+ * marking is to be done.
+ *
+ * The danger inherent in this scheme is that the JS code in steps 3, 5, and 7
+ * might change the heap in a way that causes the GC to collect an object that
+ * is actually reachable. The write barrier prevents this from happening. We use
+ * a variant of incremental GC called "snapshot at the beginning." This approach
+ * guarantees the invariant that if an object is reachable in step 2, then we
+ * will mark it eventually. The name comes from the idea that we take a
+ * theoretical "snapshot" of all reachable objects in step 2; all objects in
+ * that snapshot should eventually be marked. (Note that the write barrier
+ * verifier code takes an actual snapshot.)
+ *
+ * The basic correctness invariant of a snapshot-at-the-beginning collector is
+ * that any object reachable at the end of the GC (step 9) must either:
+ *   (1) have been reachable at the beginning (step 2) and thus in the snapshot
+ *   (2) or must have been newly allocated, in steps 3, 5, or 7.
+ * To deal with case (2), any objects allocated during an incremental GC are
+ * automatically marked black.
+ *
+ * This strategy is actually somewhat conservative: if an object becomes
+ * unreachable between steps 2 and 8, it would be safe to collect it. We won't,
+ * mainly for simplicity. (Also, note that the snapshot is entirely
+ * theoretical. We don't actually do anything special in step 2 that we wouldn't
+ * do in a non-incremental GC.
+ *
+ * It's the pre-barrier's job to maintain the snapshot invariant. Consider the
+ * write "obj->field = value". Let the prior value of obj->field be
+ * value0. Since it's possible that value0 may have been what obj->field
+ * contained in step 2, when the snapshot was taken, the barrier marks
+ * value0. Note that it only does this if we're in the middle of an incremental
+ * GC. Since this is rare, the cost of the write barrier is usually just an
+ * extra branch.
+ *
+ * In practice, we implement the pre-barrier differently based on the type of
+ * value0. E.g., see JSObject::writeBarrierPre, which is used if obj->field is
+ * a JSObject*. It takes value0 as a parameter.
+ *
+ *                                POST-BARRIER
+ *
+ * These are not yet implemented. Once we get generational GC, they will allow
+ * us to keep track of pointers from non-nursery space into the nursery.
+ *
+ *                            IMPLEMENTATION DETAILS
+ *
+ * Since it would be awkward to change every write to memory into a function
+ * call, this file contains a bunch of C++ classes and templates that use
+ * operator overloading to take care of barriers automatically. In many cases,
+ * all that's necessary to make some field be barriered is to replace
+ *     Type *field;
+ * with
+ *     HeapPtr<Type> field;
+ * There are also special classes HeapValue and HeapId, which barrier js::Value
+ * and jsid, respectively.
+ *
+ * One additional note: not all object writes need to be barriered. Writes to
+ * newly allocated objects do not need a barrier as long as the GC is not
+ * allowed to run in between the allocation and the write. In these cases, we
+ * use the "obj->field.init(value)" method instead of "obj->field = value".
+ * We use the init naming idiom in many places to signify that a field is being
+ * assigned for the first time, and that no GCs have taken place between the
+ * object allocation and the assignment.
+ */
+
+namespace js {
+
+/*
+ * Ideally, we would like to make the argument to functions like MarkShape be a
+ * HeapPtr<const js::Shape>. That would ensure that we don't forget to
+ * barrier any fields that we mark through. However, that would prohibit us from
+ * passing in a derived class like HeapPtr<js::EmptyShape>.
+ *
+ * To overcome the problem, we make the argument to MarkShape be a
+ * MarkablePtr<const js::Shape>. And we allow conversions from HeapPtr<T>
+ * to MarkablePtr<U> as long as T can be converted to U.
+ */
+template<class T>
+class MarkablePtr
+{
+  public:
+    T *value;
+
+    explicit MarkablePtr(T *value) : value(value) {}
+};
+
+template<class T, typename Unioned = uintptr_t>
+class HeapPtr
+{
+    union {
+        T *value;
+        Unioned other;
+    };
+
+  public:
+    HeapPtr() : value(NULL) {}
+    explicit HeapPtr(T *v) : value(v) { post(); }
+    explicit HeapPtr(const HeapPtr<T> &v) : value(v.value) { post(); }
+
+    ~HeapPtr() { pre(); }
+
+    /* Use this to install a ptr into a newly allocated object. */
+    void init(T *v) {
+        value = v;
+        post();
+    }
+
+    /* Use to set the pointer to NULL. */
+    void clear() {
+	pre();
+	value = NULL;
+    }
+
+    /* Use this if the automatic coercion to T* isn't working. */
+    T *get() const { return value; }
+
+    /*
+     * Use these if you want to change the value without invoking the barrier.
+     * Obviously this is dangerous unless you know the barrier is not needed.
+     */
+    T **unsafeGet() { return &value; }
+    void unsafeSet(T *v) { value = v; }
+
+    Unioned *unsafeGetUnioned() { return &other; }
+
+    HeapPtr<T, Unioned> &operator=(T *v) {
+        pre();
+        value = v;
+        post();
+        return *this;
+    }
+
+    HeapPtr<T, Unioned> &operator=(const HeapPtr<T> &v) {
+        pre();
+        value = v.value;
+        post();
+        return *this;
+    }
+
+    T &operator*() const { return *value; }
+    T *operator->() const { return value; }
+
+    operator T*() const { return value; }
+
+    /*
+     * This coerces to MarkablePtr<U> as long as T can coerce to U. See the
+     * comment for MarkablePtr above.
+     */
+    template<class U>
+    operator MarkablePtr<U>() const { return MarkablePtr<U>(value); }
+
+  private:
+    void pre() { T::writeBarrierPre(value); }
+    void post() { T::writeBarrierPost(value, (void *)&value); }
+
+    /* Make this friend so it can access pre() and post(). */
+    template<class T1, class T2>
+    friend inline void
+    BarrieredSetPair(JSCompartment *comp,
+                     HeapPtr<T1> &v1, T1 *val1,
+                     HeapPtr<T2> &v2, T2 *val2);
+};
+
+/*
+ * This is a hack for RegExpStatics::updateFromMatch. It allows us to do two
+ * barriers with only one branch to check if we're in an incremental GC.
+ */
+template<class T1, class T2>
+static inline void
+BarrieredSetPair(JSCompartment *comp,
+                 HeapPtr<T1> &v1, T1 *val1,
+                 HeapPtr<T2> &v2, T2 *val2)
+{
+    if (T1::needWriteBarrierPre(comp)) {
+        v1.pre();
+        v2.pre();
+    }
+    v1.unsafeSet(val1);
+    v2.unsafeSet(val2);
+    v1.post();
+    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<JSXML> HeapPtrXML;
+
+/* Useful for hashtables with a HeapPtr as key. */
+template<class T>
+struct HeapPtrHasher
+{
+    typedef HeapPtr<T> Key;
+    typedef T *Lookup;
+
+    static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
+    static bool match(const Key &k, Lookup l) { return k.get() == l; }
+};
+
+/* Specialized hashing policy for HeapPtrs. */
+template <class T>
+struct DefaultHasher< HeapPtr<T> >: HeapPtrHasher<T> { };
+
+class HeapValue
+{
+    Value value;
+
+  public:
+    explicit HeapValue() : value(UndefinedValue()) {}
+    explicit inline HeapValue(const Value &v);
+    explicit inline HeapValue(const HeapValue &v);
+
+    inline ~HeapValue();
+
+    inline void init(const Value &v);
+
+    inline HeapValue &operator=(const Value &v);
+    inline HeapValue &operator=(const HeapValue &v);
+
+    /*
+     * This is a faster version of operator=. Normally, operator= has to
+     * determine the compartment of the value before it can decide whether to do
+     * the barrier. If you already know the compartment, it's faster to pass it
+     * in.
+     */
+    inline void set(JSCompartment *comp, const Value &v);
+
+    const Value &get() const { return value; }
+    operator const Value &() const { return value; }
+
+    bool isMarkable() const { return value.isMarkable(); }
+    bool isMagic(JSWhyMagic why) const { return value.isMagic(why); }
+    bool isUndefined() const { return value.isUndefined(); }
+    bool isObject() const { return value.isObject(); }
+    bool isGCThing() const { return value.isGCThing(); }
+    bool isTrue() const { return value.isTrue(); }
+    bool isFalse() const { return value.isFalse(); }
+    bool isInt32() const { return value.isInt32(); }
+    bool isNull() const { return value.isNull(); }
+
+    JSObject &toObject() const { return value.toObject(); }
+    JSObject *toObjectOrNull() const { return value.toObjectOrNull(); }
+    void *toGCThing() const { return value.toGCThing(); }
+    double toDouble() const { return value.toDouble(); }
+    int32 toInt32() const { return value.toInt32(); }
+    JSString *toString() const { return value.toString(); }
+    bool toBoolean() const { return value.toBoolean(); }
+    double toNumber() const { return value.toNumber(); }
+
+    unsigned gcKind() const { return value.gcKind(); }
+
+    inline void boxNonDoubleFrom(JSValueType type, uint64 *out);
+
+    uint64 asRawBits() const { return value.asRawBits(); }
+
+#ifdef DEBUG
+    JSWhyMagic whyMagic() const { return value.whyMagic(); }
+#endif
+
+    static inline void writeBarrierPre(const Value &v);
+    static inline void writeBarrierPost(const Value &v, void *addr);
+
+    static inline void writeBarrierPre(JSCompartment *comp, const Value &v);
+    static inline void writeBarrierPost(JSCompartment *comp, const Value &v, void *addr);
+
+  private:
+    inline void pre();
+    inline void post();
+
+    inline void pre(JSCompartment *comp);
+    inline void post(JSCompartment *comp);
+};
+
+static inline const Value *
+Valueify(const HeapValue *array)
+{
+    JS_ASSERT(sizeof(HeapValue) == sizeof(Value));
+    return (const Value *)array;
+}
+
+class HeapValueArray
+{
+    HeapValue *array;
+
+  public:
+    HeapValueArray(HeapValue *array) : array(array) {}
+
+    operator const Value *() const { return Valueify(array); }
+    operator HeapValue *() const { return array; }
+
+    HeapValueArray operator +(int offset) const { return HeapValueArray(array + offset); }
+    HeapValueArray operator +(uint32 offset) const { return HeapValueArray(array + offset); }
+};
+
+class HeapId
+{
+    jsid value;
+
+  public:
+    explicit HeapId() : value(JSID_VOID) {}
+    explicit inline HeapId(jsid id);
+
+    inline ~HeapId();
+
+    inline void init(jsid id);
+
+    inline HeapId &operator=(jsid id);
+    inline HeapId &operator=(const HeapId &v);
+
+    bool operator==(jsid id) const { return value == id; }
+    bool operator!=(jsid id) const { return value != id; }
+
+    jsid get() const { return value; }
+    operator jsid() const { return value; }
+
+  private:
+    inline void pre();
+    inline void post();
+
+    HeapId(const HeapId &v);
+};
+
+/*
+ * Incremental GC requires that weak pointers have read barriers. This is mostly
+ * an issue for empty shapes stored in JSCompartment. The problem happens when,
+ * during an incremental GC, some JS code stores one of the compartment's empty
+ * shapes into an object already marked black. Normally, this would not be a
+ * problem, because the empty shape would have been part of the initial snapshot
+ * when the GC started. However, since this is a weak pointer, it isn't. So we
+ * may collect the empty shape even though a live object points to it. To fix
+ * this, we mark these empty shapes black whenever they get read out.
+ */
+template<class T>
+class ReadBarriered
+{
+    T *value;
+
+  public:
+    ReadBarriered(T *value) : value(value) {}
+
+    T *get() const {
+        if (!value)
+            return NULL;
+        T::readBarrier(value);
+        return value;
+    }
+
+    operator T*() const { return get(); }
+
+    T *unsafeGet() { return value; }
+
+    void set(T *v) { value = v; }
+
+    operator bool() { return !!value; }
+
+    template<class U>
+    operator MarkablePtr<U>() const { return MarkablePtr<U>(value); }
+};
+
+}
+
+#endif /* jsgc_barrier_h___ */
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -262,47 +262,50 @@ def print_tinderbox(label, test, message
         result += ": " + message
     print result
 
 def run_tests(tests, test_dir, lib_dir, shell_args):
     pb = None
     if not OPTIONS.hide_progress and not OPTIONS.show_cmd:
         try:
             from progressbar import ProgressBar
-            pb = ProgressBar('', len(tests), 16)
+            pb = ProgressBar('', len(tests), 24)
         except ImportError:
             pass
 
     failures = []
+    timeouts = 0
     complete = False
     doing = 'before starting'
     try:
         for i, test in enumerate(tests):
             doing = 'on %s'%test.path
             ok, out, err, code, timed_out = run_test(test, lib_dir, shell_args)
             doing = 'after %s'%test.path
 
             if not ok:
                 failures.append([ test, out, err, code, timed_out ])
+            if timed_out:
+                timeouts += 1
 
             if OPTIONS.tinderbox:
                 if ok:
                     print_tinderbox("TEST-PASS", test);
                 else:
                     lines = [ _ for _ in out.split('\n') + err.split('\n')
                               if _ != '' ]
                     if len(lines) >= 1:
                         msg = lines[-1]
                     else:
                         msg = ''
                     print_tinderbox("TEST-UNEXPECTED-FAIL", test, msg);
 
             n = i + 1
             if pb:
-                pb.label = '[%4d|%4d|%4d]'%(n - len(failures), len(failures), n)
+                pb.label = '[%4d|%4d|%4d|%4d]'%(n - len(failures), len(failures), timeouts, n)
                 pb.update(n)
         complete = True
     except KeyboardInterrupt:
         print_tinderbox("TEST-UNEXPECTED-FAIL", test);
 
     if pb:
         pb.finish()
 
--- a/js/src/jsapi-tests/testArgumentsObject.cpp
+++ b/js/src/jsapi-tests/testArgumentsObject.cpp
@@ -1,16 +1,18 @@
 /* -*- 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,16 +3,18 @@
  *
  * 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
@@ -2,28 +2,30 @@
 #include "jsobj.h"
 #include "vm/String.h"
 
 BEGIN_TEST(testConservativeGC)
 {
     jsval v2;
     EVAL("({foo: 'bar'});", &v2);
     CHECK(JSVAL_IS_OBJECT(v2));
-    JSObject objCopy = *JSVAL_TO_OBJECT(v2);
+    char objCopy[sizeof(JSObject)];
+    memcpy(&objCopy, JSVAL_TO_OBJECT(v2), sizeof(JSObject));
 
     jsval v3;
     EVAL("String(Math.PI);", &v3);
     CHECK(JSVAL_IS_STRING(v3));
     JSString strCopy = *JSVAL_TO_STRING(v3);
 
     jsval tmp;
     EVAL("({foo2: 'bar2'});", &tmp);
     CHECK(JSVAL_IS_OBJECT(tmp));
     JSObject *obj2 = JSVAL_TO_OBJECT(tmp);
-    JSObject obj2Copy = *obj2;
+    char obj2Copy[sizeof(JSObject)];
+    memcpy(&obj2Copy, obj2, sizeof(JSObject));
 
     EVAL("String(Math.sqrt(3));", &tmp);
     CHECK(JSVAL_IS_STRING(tmp));
     JSString *str2 = JSVAL_TO_STRING(tmp);
     JSString str2Copy = *str2;
 
     tmp = JSVAL_NULL;
 
@@ -31,20 +33,20 @@ BEGIN_TEST(testConservativeGC)
 
     EVAL("var a = [];\n"
          "for (var i = 0; i != 10000; ++i) {\n"
          "a.push(i + 0.1, [1, 2], String(Math.sqrt(i)), {a: i});\n"
          "}", &tmp);
 
     JS_GC(cx);
 
-    checkObjectFields(&objCopy, JSVAL_TO_OBJECT(v2));
+    checkObjectFields((JSObject *)objCopy, JSVAL_TO_OBJECT(v2));
     CHECK(!memcmp(&strCopy, JSVAL_TO_STRING(v3), sizeof(strCopy)));
 
-    checkObjectFields(&obj2Copy, obj2);
+    checkObjectFields((JSObject *)obj2Copy, obj2);
     CHECK(!memcmp(&str2Copy, str2, sizeof(str2Copy)));
 
     return true;
 }
 
 bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
 {
     /* Ignore fields which are unstable across GCs. */
--- a/js/src/jsapi-tests/testIndexToString.cpp
+++ b/js/src/jsapi-tests/testIndexToString.cpp
@@ -4,16 +4,18 @@
 
 #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.cpp
+++ b/js/src/jsapi.cpp
@@ -91,16 +91,17 @@
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/RegExpObject-inl.h"
+#include "vm/RegExpStatics-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 #if ENABLE_YARR_JIT
 #include "assembler/jit/ExecutableAllocator.h"
 #include "methodjit/Logging.h"
 #endif
 
@@ -652,17 +653,18 @@ JSRuntime::JSRuntime()
     gcKeepAtoms(0),
     gcBytes(0),
     gcTriggerBytes(0),
     gcLastBytes(0),
     gcMaxBytes(0),
     gcMaxMallocBytes(0),
     gcEmptyArenaPoolLifespan(0),
     gcNumber(0),
-    gcMarkingTracer(NULL),
+    gcIncrementalTracer(NULL),
+    gcVerifyData(NULL),
     gcChunkAllocationSinceLastGC(false),
     gcNextFullGCTime(0),
     gcJitReleaseTime(0),
     gcMode(JSGC_MODE_GLOBAL),
     gcIsNeeded(0),
     gcWeakMapList(NULL),
     gcStats(thisFromCtor()),
     gcTriggerCompartment(NULL),
@@ -1322,17 +1324,17 @@ Class dummy_class = {
 
 } /*namespace js */
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
 {
     CHECK_REQUEST(cx);
     JS_ASSERT(!target->isCachedEval);
-    GlobalObject *global = target->u.globalObject;
+    GlobalObject *global = target->globalObject;
     if (!global) {
         SwitchToCompartment sc(cx, target->compartment());
         global = GlobalObject::create(cx, &dummy_class);
         if (!global)
             return NULL;
     }
     return JS_EnterCrossCompartmentCall(cx, global);
 }
@@ -1947,32 +1949,28 @@ JS_EnumerateStandardClasses(JSContext *c
         {
                 return JS_FALSE;
         }
     }
 
     return JS_TRUE;
 }
 
-namespace js {
-
-JSIdArray *
+static JSIdArray *
 NewIdArray(JSContext *cx, jsint length)
 {
     JSIdArray *ida;
 
     ida = (JSIdArray *)
         cx->calloc_(offsetof(JSIdArray, vector) + length * sizeof(jsval));
     if (ida)
         ida->length = length;
     return ida;
 }
 
-}
-
 /*
  * Unlike realloc(3), this function frees ida on failure.
  */
 static JSIdArray *
 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
 {
     JSIdArray *rida;
 
@@ -1995,17 +1993,17 @@ AddAtomToArray(JSContext *cx, JSAtom *at
     i = *ip;
     length = ida->length;
     if (i >= length) {
         ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
         if (!ida)
             return NULL;
         JS_ASSERT(i < ida->length);
     }
-    ida->vector[i] = ATOM_TO_JSID(atom);
+    ida->vector[i].init(ATOM_TO_JSID(atom));
     *ip = i + 1;
     return ida;
 }
 
 static JSIdArray *
 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
                     jsint *ip, JSBool *foundp)
 {
@@ -2326,20 +2324,25 @@ JS_SetExtraGCRootsTracer(JSRuntime *rt, 
 
 JS_PUBLIC_API(void)
 JS_TraceRuntime(JSTracer *trc)
 {
     TraceRuntime(trc);
 }
 
 JS_PUBLIC_API(void)
+JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
+{
+    js::TraceChildren(trc, thing, kind);
+}
+
+JS_PUBLIC_API(void)
 JS_CallTracer(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
-    JS_ASSERT(thing);
-    MarkKind(trc, thing, kind);
+    js::CallTracer(trc, thing, kind);
 }
 
 #ifdef DEBUG
 
 #ifdef HAVE_XPCONNECT
 #include "dump_xpc.h"
 #endif
 
@@ -2739,16 +2742,17 @@ JS_IsGCMarkingTracer(JSTracer *trc)
 JS_PUBLIC_API(void)
 JS_CompartmentGC(JSContext *cx, JSCompartment *comp)
 {
     /* We cannot GC the atoms compartment alone; use a full GC instead. */
     JS_ASSERT(comp != cx->runtime->atomsCompartment);
 
     LeaveTrace(cx);
 
+    js::gc::VerifyBarriers(cx, true);
     js_GC(cx, comp, GC_NORMAL, gcstats::PUBLIC_API);
 }
 
 JS_PUBLIC_API(void)
 JS_GC(JSContext *cx)
 {
     JS_CompartmentGC(cx, NULL);
 }
@@ -2777,18 +2781,18 @@ JS_SetGCCallbackRT(JSRuntime *rt, JSGCCa
     rt->gcCallback = cb;
     return oldcb;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
 {
     JS_ASSERT(thing);
-    JS_ASSERT(!cx->runtime->gcMarkingTracer);
-    return IsAboutToBeFinalized(cx, thing);
+    JS_ASSERT(!cx->runtime->gcIncrementalTracer);
+    return IsAboutToBeFinalized(cx, (gc::Cell *)thing);
 }
 
 JS_PUBLIC_API(void)
 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
 {
     switch (key) {
       case JSGC_MAX_BYTES:
         rt->gcMaxBytes = value;
@@ -2937,16 +2941,29 @@ JS_SetNativeStackQuota(JSContext *cx, si
         JS_ASSERT(stackBase >= stackSize);
         cx->stackLimit = stackBase - (stackSize - 1);
     }
 #endif
 }
 
 /************************************************************************/
 
+JS_PUBLIC_API(jsint)
+JS_IdArrayLength(JSContext *cx, JSIdArray *ida)
+{
+    return ida->length;
+}
+
+JS_PUBLIC_API(jsid)
+JS_IdArrayGet(JSContext *cx, JSIdArray *ida, jsint index)
+{
+    JS_ASSERT(index >= 0 && index < ida->length);
+    return ida->vector[index];
+}
+
 JS_PUBLIC_API(void)
 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
 {
     cx->free_(ida);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
@@ -4100,22 +4117,26 @@ prop_iter_finalize(JSContext *cx, JSObje
 static void
 prop_iter_trace(JSTracer *trc, JSObject *obj)
 {
     void *pdata = obj->getPrivate();
     if (!pdata)
         return;
 
     if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
-        /* Native case: just mark the next property to visit. */
-        MarkShape(trc, (Shape *)pdata, "prop iter shape");
+        /*
+         * Native case: just mark the next property to visit. We don't need a
+         * barrier here because the pointer is updated via setPrivate, which
+         * always takes a barrier.
+         */
+        MarkShapeUnbarriered(trc, (Shape *)pdata, "prop iter shape");
     } else {
         /* Non-native case: mark each id in the JSIdArray private. */
         JSIdArray *ida = (JSIdArray *) pdata;
-        MarkIdRange(trc, ida->length, ida->vector, "prop iter");
+        MarkIdRange(trc, ida->vector, ida->vector + ida->length, "prop iter");
     }
 }
 
 static Class prop_iter_class = {
     "PropertyIterator",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
@@ -4133,29 +4154,29 @@ static Class prop_iter_class = {
     NULL,           /* hasInstance */
     prop_iter_trace
 };
 
 JS_PUBLIC_API(JSObject *)
 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
 {
     JSObject *iterobj;
-    const void *pdata;
+    void *pdata;
     jsint index;
     JSIdArray *ida;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
     if (!iterobj)
         return NULL;
 
     if (obj->isNative()) {
         /* Native case: start with the last property in obj. */
-        pdata = obj->lastProperty();
+        pdata = (void *)obj->lastProperty();
         index = -1;
     } else {
         /*
          * Non-native case: enumerate a JSIdArray and keep it via private.
          *
          * Note: we have to make sure that we root obj around the call to
          * JS_Enumerate to protect against multiple allocations under it.
          */
@@ -4163,17 +4184,17 @@ JS_NewPropertyIterator(JSContext *cx, JS
         ida = JS_Enumerate(cx, obj);
         if (!ida)
             return NULL;
         pdata = ida;
         index = ida->length;
     }
 
     /* iterobj cannot escape to other threads here. */
-    iterobj->setPrivate(const_cast<void *>(pdata));
+    iterobj->setPrivate(pdata);
     iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index));
     return iterobj;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
 {
     jsint i;
@@ -4426,17 +4447,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
                 return NULL;
             }
             obj = obj->getParent();
         }
 
         Value v;
         if (!obj->getGeneric(cx, r.front().propid, &v))
             return NULL;
-        clone->getFlatClosureUpvars()[i] = v;
+        clone->setFlatClosureUpvar(i, v);
     }
 
     return clone;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun)
 {
@@ -4877,19 +4898,19 @@ JS_CompileFileHandle(JSContext *cx, JSOb
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalFromScript(JSScript *script)
 {
     JS_ASSERT(!script->isCachedEval);
-    JS_ASSERT(script->u.globalObject);
-
-    return script->u.globalObject;
+    JS_ASSERT(script->globalObject);
+
+    return script->globalObject;
 }
 
 static JSFunction *
 CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
                                      JSPrincipals *principals, const char *name,
                                      uintN nargs, const char **argnames,
                                      const jschar *chars, size_t length,
                                      const char *filename, uintN lineno, JSVersion version)
@@ -6340,19 +6361,20 @@ JS_ClearContextThread(JSContext *cx)
     return 0;
 #endif
 }
 
 #ifdef JS_GC_ZEAL
 JS_PUBLIC_API(void)
 JS_SetGCZeal(JSContext *cx, uint8 zeal, uint32 frequency, JSBool compartment)
 {
+    bool schedule = zeal >= js::gc::ZealAllocThreshold && zeal < js::gc::ZealVerifierThreshold;
     cx->runtime->gcZeal_ = zeal;
     cx->runtime->gcZealFrequency = frequency;
-    cx->runtime->gcNextScheduled = zeal >= 2 ? frequency : 0;
+    cx->runtime->gcNextScheduled = schedule ? frequency : 0;
     cx->runtime->gcDebugCompartmentGC = !!compartment;
 }
 
 JS_PUBLIC_API(void)
 JS_ScheduleGC(JSContext *cx, uint32 count, JSBool compartment)
 {
     cx->runtime->gcNextScheduled = count;
     cx->runtime->gcDebugCompartmentGC = !!compartment;
@@ -6362,16 +6384,73 @@ JS_ScheduleGC(JSContext *cx, uint32 coun
 JS_FRIEND_API(void *)
 js_GetCompartmentPrivate(JSCompartment *compartment)
 {
     return compartment->data;
 }
 
 /************************************************************************/
 
+JS_PUBLIC_API(void)
+JS_RegisterReference(void **ref)
+{
+}
+
+JS_PUBLIC_API(void)
+JS_ModifyReference(void **ref, void *newval)
+{
+    // XPConnect uses the lower bits of its JSObject refs for evil purposes,
+    // so we need to fix this.
+    void *thing = *ref;
+    *ref = newval;
+    thing = (void *)((uintptr_t)thing & ~7);
+    if (!thing)
+        return;
+    uint32 kind = GetGCThingTraceKind(thing);
+    if (kind == JSTRACE_OBJECT)
+        JSObject::writeBarrierPre((JSObject *) thing);
+    else if (kind == JSTRACE_STRING)
+        JSString::writeBarrierPre((JSString *) thing);
+    else
+        JS_NOT_REACHED("invalid trace kind");
+}
+
+JS_PUBLIC_API(void)
+JS_UnregisterReference(void **ref)
+{
+    // For now we just want to trigger a write barrier.
+    JS_ModifyReference(ref, NULL);
+}
+
+JS_PUBLIC_API(void)
+JS_RegisterValue(jsval *val)
+{
+}
+
+JS_PUBLIC_API(void)
+JS_ModifyValue(jsval *val, jsval newval)
+{
+    HeapValue::writeBarrierPre(*val);
+    *val = newval;
+}
+
+JS_PUBLIC_API(void)
+JS_UnregisterValue(jsval *val)
+{
+    JS_ModifyValue(val, JSVAL_VOID);
+}
+
+JS_PUBLIC_API(JSTracer *)
+JS_GetIncrementalGCTracer(JSRuntime *rt)
+{
+    return rt->gcIncrementalTracer;
+}
+
+/************************************************************************/
+
 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
 
 #include "jswin.h"
 
 /*
  * Initialization routine for the JS DLL.
  */
 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2693,16 +2693,17 @@ JSVAL_TRACE_KIND(jsval v)
  * If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all
  * of its mappings.  This should be used in cases where the tracer
  * wants to use the existing liveness of entries.
  */
 typedef void
 (* JSTraceCallback)(JSTracer *trc, void *thing, JSGCTraceKind kind);
 
 struct JSTracer {
+    JSRuntime           *runtime;
     JSContext           *context;
     JSTraceCallback     callback;
     JSTraceNamePrinter  debugPrinter;
     const void          *debugPrintArg;
     size_t              debugPrintIndex;
     JSBool              eagerlyTraceWeakMaps;
 };
 
@@ -2793,16 +2794,17 @@ JS_CallTracer(JSTracer *trc, void *thing
         JS_CALL_TRACER((trc), str_, JSTRACE_STRING, name);                    \
     JS_END_MACRO
 
 /*
  * API for JSTraceCallback implementations.
  */
 # define JS_TRACER_INIT(trc, cx_, callback_)                                  \
     JS_BEGIN_MACRO                                                            \
+        (trc)->runtime = (cx_)->runtime;                                      \
         (trc)->context = (cx_);                                               \
         (trc)->callback = (callback_);                                        \
         (trc)->debugPrinter = NULL;                                           \
         (trc)->debugPrintArg = NULL;                                          \
         (trc)->debugPrintIndex = (size_t)-1;                                  \
         (trc)->eagerlyTraceWeakMaps = JS_TRUE;                                \
     JS_END_MACRO
 
@@ -2838,16 +2840,98 @@ JS_GetTraceEdgeName(JSTracer *trc, char 
  */
 extern JS_PUBLIC_API(JSBool)
 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, JSGCTraceKind kind,
             void *thingToFind, size_t maxDepth, void *thingToIgnore);
 
 #endif
 
 /*
+ * Write barrier API.
+ *
+ * This API is used to inform SpiderMonkey of pointers to JS GC things in the
+ * malloc heap. There is no need to use this API unless incremental GC is
+ * enabled. When they are, the requirements for using the API are as follows:
+ *
+ * All pointers to JS GC things from the malloc heap must be registered and
+ * unregistered with the API functions below. This is *in addition* to the
+ * normal rooting and tracing that must be done normally--these functions will
+ * not take care of rooting for you.
+ *
+ * Besides registration, the JS_ModifyReference function must be called to
+ * change the value of these references. You should not change them using
+ * assignment.
+ *
+ * To avoid the headache of using these API functions, the JSBarrieredObjectPtr
+ * C++ class is provided--simply replace your JSObject* with a
+ * JSBarrieredObjectPtr. It will take care of calling the registration and
+ * modification APIs.
+ *
+ * For more explanation, see the comment in gc/Barrier.h.
+ */
+
+/* These functions are to be used for objects and strings. */
+extern JS_PUBLIC_API(void)
+JS_RegisterReference(void **ref);
+
+extern JS_PUBLIC_API(void)
+JS_ModifyReference(void **ref, void *newval);
+
+extern JS_PUBLIC_API(void)
+JS_UnregisterReference(void **ref);
+
+/* These functions are for values. */
+extern JS_PUBLIC_API(void)
+JS_RegisterValue(jsval *val);
+
+extern JS_PUBLIC_API(void)
+JS_ModifyValue(jsval *val, jsval newval);
+
+extern JS_PUBLIC_API(void)
+JS_UnregisterValue(jsval *val);
+
+extern JS_PUBLIC_API(JSTracer *)
+JS_GetIncrementalGCTracer(JSRuntime *rt);
+
+#ifdef __cplusplus
+JS_END_EXTERN_C
+
+namespace JS {
+
+class HeapPtrObject
+{
+    JSObject *value;
+
+  public:
+    HeapPtrObject() : value(NULL) { JS_RegisterReference((void **) &value); }
+
+    HeapPtrObject(JSObject *obj) : value(obj) { JS_RegisterReference((void **) &value); }
+
+    ~HeapPtrObject() { JS_UnregisterReference((void **) &value); }
+
+    void init(JSObject *obj) { value = obj; }
+
+    JSObject *get() const { return value; }
+
+    HeapPtrObject &operator=(JSObject *obj) {
+        JS_ModifyReference((void **) &value, obj);
+        return *this;
+    }
+
+    JSObject &operator*() const { return *value; }
+    JSObject *operator->() const { return value; }
+    operator JSObject *() const { return value; }
+};
+
+} /* namespace JS */
+
+JS_BEGIN_EXTERN_C
+#endif
+
+/*
  * Garbage collector API.
  */
 extern JS_PUBLIC_API(void)
 JS_GC(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_CompartmentGC(JSContext *cx, JSCompartment *comp);
 
@@ -3110,20 +3194,21 @@ struct JSClass {
                                          (((clasp)->flags                     \
                                            >> JSCLASS_CACHED_PROTO_SHIFT)     \
                                           & JSCLASS_CACHED_PROTO_MASK))
 
 /* Initializer for unused members of statically initialized JSClass structs. */
 #define JSCLASS_NO_INTERNAL_MEMBERS     0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
 #define JSCLASS_NO_OPTIONAL_MEMBERS     0,0,0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
 
-struct JSIdArray {
-    jsint length;
-    jsid  vector[1];    /* actually, length jsid words */
-};
+extern JS_PUBLIC_API(jsint)
+JS_IdArrayLength(JSContext *cx, JSIdArray *ida);
+
+extern JS_PUBLIC_API(jsid)
+JS_IdArrayGet(JSContext *cx, JSIdArray *ida, jsint index);
 
 extern JS_PUBLIC_API(void)
 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida);
 
 extern JS_PUBLIC_API(JSBool)
 JS_ValueToId(JSContext *cx, jsval v, jsid *idp);
 
 extern JS_PUBLIC_API(JSBool)
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -644,24 +644,23 @@ array_length_setter(JSContext *cx, JSObj
     if (obj->isDenseArray()) {
         /*
          * Don't reallocate if we're not actually shrinking our slots. If we do
          * shrink slots here, shrink the initialized length too.  This permits us
          * 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);
-        jsuint oldinit = obj->getDenseArrayInitializedLength();
-        if (oldinit > newlen) {
-            obj->setDenseArrayInitializedLength(newlen);
-            if (!cx->typeInferenceEnabled())
-                obj->backfillDenseArrayHoles(cx);
-        }
+        if (oldinit > newlen && !cx->typeInferenceEnabled())
+            obj->backfillDenseArrayHoles(cx);
     } 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);
@@ -1335,18 +1334,21 @@ JSObject::makeDenseArraySlow(JSContext *
      * 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;
 
     /* Create a native scope. */
     gc::AllocKind kind = getAllocKind();
-    if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind))
+    js::EmptyShape *empty = InitScopeForObject(cx, this, &SlowArrayClass,
+                                               getProto()->getNewType(cx), kind);
+    if (!empty)
         return false;
+    setMap(empty);
 
     backfillDenseArrayHoles(cx);
 
     uint32 arrayCapacity = getDenseArrayCapacity();
     uint32 arrayInitialized = getDenseArrayInitializedLength();
 
     /*
      * Adjust the slots to account for the different layout between dense
@@ -1362,30 +1364,30 @@ JSObject::makeDenseArraySlow(JSContext *
     }
     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, slots, arrayInitialized);
+    AutoValueArray autoArray(cx, Valueify(slots), arrayInitialized);
 
     /* The initialized length is used iff this is a dense array. */
-    initializedLength = 0;
+    initializedLength() = 0;
     JS_ASSERT(newType == NULL);
 
     /*
      * 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;
+        initializedLength() = arrayInitialized;
         clasp = &ArrayClass;
         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).
      */
@@ -1398,17 +1400,17 @@ JSObject::makeDenseArraySlow(JSContext *
         if (slots[i].isMagic(JS_ARRAY_HOLE))
             continue;
 
         setSlot(next, slots[i]);
 
         if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
             setMap(oldMap);
             capacity = arrayCapacity;
-            initializedLength = arrayInitialized;
+            initializedLength() = arrayInitialized;
             clasp = &ArrayClass;
             return false;
         }
 
         next++;
     }
 
     clearSlotRange(next, capacity - next);
@@ -2492,17 +2494,17 @@ NewbornArrayPushImpl(JSContext *cx, JSOb
     JS_ASSERT(length <= obj->getDenseArrayCapacity());
 
     if (length == obj->getDenseArrayCapacity() && !obj->ensureSlots(cx, length + 1))
         return false;
 
     if (cx->typeInferenceEnabled())
         obj->setDenseArrayInitializedLength(length + 1);
     obj->setDenseArrayLength(length + 1);
-    obj->setDenseArrayElementWithType(cx, length, v);
+    obj->initDenseArrayElementWithType(cx, length, v);
     return true;
 }
 
 JSBool
 js_NewbornArrayPush(JSContext *cx, JSObject *obj, const Value &vp)
 {
     return NewbornArrayPushImpl(cx, obj, vp);
 }
@@ -2888,26 +2890,26 @@ array_splice(JSContext *cx, uintN argc, 
         uint32 sourceIndex = actualStart + actualDeleteCount;
         uint32 targetIndex = actualStart + itemCount;
         uint32 finalLength = len - actualDeleteCount + itemCount;
 
         if (CanOptimizeForDenseStorage(obj, 0, len, cx)) {
             /* Steps 12(a)-(b). */
             obj->moveDenseArrayElements(targetIndex, sourceIndex, len - sourceIndex);
 
-            /* Steps 12(c)-(d). */
-            obj->shrinkDenseArrayElements(cx, finalLength);
-
             /*
-             * The array's initialized length is now out of sync with the array
-             * elements: resynchronize it.
+             * 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);
+
             /* 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
              * pessimistic thing and let JS_CHECK_OPERATION_LIMIT handle the
@@ -3014,20 +3016,22 @@ mjit::stubs::ArrayConcatTwoArrays(VMFram
     JS_ASSERT(initlen2 == obj2->getArrayLength());
 
     /* No overflow here due to nslots limit. */
     uint32 len = initlen1 + initlen2;
 
     if (!result->ensureSlots(f.cx, len))
         THROW();
 
-    result->copyDenseArrayElements(0, obj1->getDenseArrayElements(), initlen1);
-    result->copyDenseArrayElements(initlen1, obj2->getDenseArrayElements(), initlen2);
-
+    JS_ASSERT(!result->getDenseArrayInitializedLength());
     result->setDenseArrayInitializedLength(len);
+
+    result->initDenseArrayElements(0, obj1->getDenseArrayElements(), initlen1);
+    result->initDenseArrayElements(initlen1, obj2->getDenseArrayElements(), initlen2);
+
     result->setDenseArrayLength(len);
 }
 #endif /* JS_METHODJIT */
 
 /*
  * Python-esque sequence operations.
  */
 JSBool
@@ -3915,17 +3919,17 @@ NewDenseCopiedArray(JSContext *cx, uint3
         return NULL;
 
     JS_ASSERT(obj->getDenseArrayCapacity() >= length);
 
     if (cx->typeInferenceEnabled())
         obj->setDenseArrayInitializedLength(vp ? length : 0);
 
     if (vp)
-        obj->copyDenseArrayElements(0, vp, length);
+        obj->initDenseArrayElements(0, vp, length);
 
     return obj;
 }
 
 #ifdef JS_TRACER
 JS_DEFINE_CALLINFO_2(extern, OBJECT, NewDenseEmptyArray, CONTEXT, OBJECT, 0,
                      nanojit::ACCSET_STORE_ANY)
 JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedArray, CONTEXT, UINT32, OBJECT, 0,
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -50,17 +50,17 @@
 
 /* Small arrays are dense, no matter what. */
 const uintN MIN_SPARSE_INDEX = 256;
 
 inline uint32
 JSObject::getDenseArrayInitializedLength()
 {
     JS_ASSERT(isDenseArray());
-    return initializedLength;
+    return initializedLength();
 }
 
 inline bool
 JSObject::isPackedDenseArray()
 {
     JS_ASSERT(isDenseArray());
     return flags & PACKED_ARRAY;
 }
--- a/js/src/jsarrayinlines.h
+++ b/js/src/jsarrayinlines.h
@@ -43,17 +43,19 @@
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 inline void
 JSObject::setDenseArrayInitializedLength(uint32 length)
 {
     JS_ASSERT(isDenseArray());
     JS_ASSERT(length <= getDenseArrayCapacity());
-    initializedLength = length;
+    uint32 cur = initializedLength();
+    prepareSlotRangeForOverwrite(length, cur);
+    initializedLength() = length;
 }
 
 inline void
 JSObject::markDenseArrayNotPacked(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
     if (flags & PACKED_ARRAY) {
         flags ^= PACKED_ARRAY;
@@ -72,22 +74,23 @@ 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) {
+    if (initializedLength() < index)
         markDenseArrayNotPacked(cx);
-        js::ClearValueRange(slots + initializedLength, index - initializedLength, true);
+
+    if (initializedLength() < index + extra) {
+        js::InitValueRange(slots + initializedLength(), index + extra - initializedLength(), true);
+        initializedLength() = index + extra;
     }
-    if (initializedLength < index + extra)
-        initializedLength = index + extra;
 }
 
 inline JSObject::EnsureDenseResult
 JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
 {
     JS_ASSERT(isDenseArray());
 
     uintN currentCapacity = numSlots();
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -384,36 +384,36 @@ js_FinishCommonAtoms(JSContext *cx)
 {
     cx->runtime->emptyString = NULL;
     cx->runtime->atomState.junkAtoms();
 }
 
 void
 js_TraceAtomState(JSTracer *trc)
 {
-    JSRuntime *rt = trc->context->runtime;
+    JSRuntime *rt = trc->runtime;
     JSAtomState *state = &rt->atomState;
 
 #ifdef DEBUG
     size_t number = 0;
 #endif
 
     if (rt->gcKeepAtoms) {
         for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
             JS_SET_TRACING_INDEX(trc, "locked_atom", number++);
-            MarkString(trc, r.front().asPtr());
+            MarkAtom(trc, r.front().asPtr());
         }
     } else {
         for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
             AtomStateEntry entry = r.front();
             if (!entry.isTagged())
                 continue;
 
             JS_SET_TRACING_INDEX(trc, "interned_atom", number++);
-            MarkString(trc, entry.asPtr());
+            MarkAtom(trc, entry.asPtr());
         }
     }
 }
 
 void
 js_SweepAtomState(JSContext *cx)
 {
     JSAtomState *state = &cx->runtime->atomState;
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -44,19 +44,25 @@
 #include "jsversion.h"
 #include "jsalloc.h"
 #include "jsapi.h"
 #include "jsprvtd.h"
 #include "jshash.h"
 #include "jspubtd.h"
 #include "jslock.h"
 
+#include "gc/Barrier.h"
 #include "js/HashTable.h"
 #include "vm/String.h"
 
+struct JSIdArray {
+    jsint length;
+    js::HeapId vector[1];    /* actually, length jsid words */
+};
+
 /* Engine-internal extensions of jsid */
 
 static JS_ALWAYS_INLINE jsid
 JSID_FROM_BITS(size_t bits)
 {
     jsid id;
     JSID_BITS(id) = bits;
     return id;
--- a/js/src/jscell.h
+++ b/js/src/jscell.h
@@ -61,30 +61,30 @@ enum AllocKind {
     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_TYPE_OBJECT,
 #if JS_HAS_XML_SUPPORT
     FINALIZE_XML,
 #endif
     FINALIZE_SHORT_STRING,
     FINALIZE_STRING,
-    FINALIZE_EXTERNAL_STRING,
-    FINALIZE_LAST = FINALIZE_EXTERNAL_STRING
+    FINALIZE_EXTERNAL_STRING
 };
 
-const size_t FINALIZE_LIMIT = FINALIZE_LAST + 1;
+static const unsigned FINALIZE_LIMIT = FINALIZE_EXTERNAL_STRING + 1;
+static const unsigned FINALIZE_OBJECT_LIMIT = FINALIZE_OBJECT16_BACKGROUND + 1;
+static const unsigned FINALIZE_FUNCTION_AND_OBJECT_LIMIT = FINALIZE_FUNCTION + 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/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -455,21 +455,23 @@ struct JSRuntime
     uint32              gcTriggerBytes;
     size_t              gcLastBytes;
     size_t              gcMaxBytes;
     size_t              gcMaxMallocBytes;
     uint32              gcEmptyArenaPoolLifespan;
     /* We access this without the GC lock, however a race will not affect correctness */
     volatile uint32     gcNumFreeArenas;
     uint32              gcNumber;
-    js::GCMarker        *gcMarkingTracer;
+    js::GCMarker        *gcIncrementalTracer;
+    void                *gcVerifyData;
     bool                gcChunkAllocationSinceLastGC;
     int64               gcNextFullGCTime;
     int64               gcJitReleaseTime;
     JSGCMode            gcMode;
+    volatile jsuword    gcBarrierFailed;
     volatile jsuword    gcIsNeeded;
     js::WeakMapBase     *gcWeakMapList;
     js::gcstats::Statistics gcStats;
 
     /* The reason that an interrupt-triggered GC should be called. */
     js::gcstats::Reason gcTriggerReason;
 
     /* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */
@@ -517,28 +519,31 @@ struct JSRuntime
      * You can control these values in several ways:
      *   - Pass the -Z flag to the shell (see the usage info for details)
      *   - Call gczeal() or schedulegc() from inside shell-executed JS code
      *     (see the help for details)
      *
      * Additionally, if gzZeal_ == 1 then we perform GCs in select places
      * (during MaybeGC and whenever a GC poke happens). This option is mainly
      * useful to embedders.
+     *
+     * We use gcZeal_ == 4 to enable write barrier verification. See the comment
+     * in jsgc.cpp for more information about this.
      */
 #ifdef JS_GC_ZEAL
     int                 gcZeal_;
     int                 gcZealFrequency;
     int                 gcNextScheduled;
     bool                gcDebugCompartmentGC;
 
     int gcZeal() { return gcZeal_; }
 
     bool needZealousGC() {
         if (gcNextScheduled > 0 && --gcNextScheduled == 0) {
-            if (gcZeal() >= 2)
+            if (gcZeal() >= js::gc::ZealAllocThreshold && gcZeal() < js::gc::ZealVerifierThreshold)
                 gcNextScheduled = gcZealFrequency;
             return true;
         }
         return false;
     }
 #else
     int gcZeal() { return 0; }
     bool needZealousGC() { return false; }
@@ -2211,28 +2216,16 @@ js_RegenerateShapeForGC(JSRuntime *rt)
     return shape;
 }
 
 namespace js {
 
 /************************************************************************/
 
 static JS_ALWAYS_INLINE void
-ClearValueRange(Value *vec, uintN len, bool useHoles)
-{
-    if (useHoles) {
-        for (uintN i = 0; i < len; i++)
-            vec[i].setMagic(JS_ARRAY_HOLE);
-    } else {
-        for (uintN i = 0; i < len; i++)
-            vec[i].setUndefined();
-    }
-}
-
-static JS_ALWAYS_INLINE void
 MakeRangeGCSafe(Value *vec, size_t len)
 {
     PodZero(vec, len);
 }
 
 static JS_ALWAYS_INLINE void
 MakeRangeGCSafe(Value *beg, Value *end)
 {
@@ -2411,36 +2404,33 @@ class AutoShapeVector : public AutoVecto
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class AutoValueArray : public AutoGCRooter
 {
-    js::Value *start_;
+    const js::Value *start_;
     unsigned length_;
 
   public:
-    AutoValueArray(JSContext *cx, js::Value *start, unsigned length
+    AutoValueArray(JSContext *cx, const js::Value *start, unsigned length
                    JS_GUARD_OBJECT_NOTIFIER_PARAM)
         : AutoGCRooter(cx, VALARRAY), start_(start), length_(length)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
-    Value *start() const { return start_; }
+    const Value *start() const { return start_; }
     unsigned length() const { return length_; }
 
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-JSIdArray *
-NewIdArray(JSContext *cx, jsint length);
-
 /*
  * Allocation policy that uses JSRuntime::malloc_ and friends, so that
  * memory pressure is properly accounted for. This is suitable for
  * long-lived objects owned by the JSRuntime.
  *
  * Since it doesn't hold a JSContext (those may not live long enough), it
  * can't report out-of-memory conditions itself; the caller must check for
  * OOM and take the appropriate action.
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -110,17 +110,17 @@ class AutoNamespaceArray : protected Aut
         array.finish(context);
     }
 
     uint32 length() const { return array.length; }
 
   public:
     friend void AutoGCRooter::trace(JSTracer *trc);
 
-    JSXMLArray array;
+    JSXMLArray<JSObject> array;
 };
 
 #ifdef DEBUG
 class CompartmentChecker
 {
   private:
     JSContext *context;
     JSCompartment *compartment;
@@ -203,18 +203,18 @@ class CompartmentChecker
                     check(ida->vector[i]);
             }
         }
     }
 
     void check(JSScript *script) {
         if (script) {
             check(script->compartment());
-            if (!script->isCachedEval && script->u.globalObject)
-                check(script->u.globalObject);
+            if (!script->isCachedEval && script->globalObject)
+                check(script->globalObject);
         }
     }
 
     void check(StackFrame *fp) {
         check(&fp->scopeChain());
     }
 };
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -53,29 +53,32 @@
 #include "assembler/jit/ExecutableAllocator.h"
 #include "yarr/BumpPointerAllocator.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
 #include "vm/Debugger.h"
 
 #include "jsgcinlines.h"
+#include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 
 #if ENABLE_YARR_JIT
 #include "assembler/jit/ExecutableAllocator.h"
 #endif
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 
 JSCompartment::JSCompartment(JSRuntime *rt)
   : rt(rt),
     principals(NULL),
+    needsBarrier_(false),
+    gcIncrementalTracer(NULL),
     gcBytes(0),
     gcTriggerBytes(0),
     gcLastBytes(0),
     hold(false),
     typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
 #ifdef JS_TRACER
     traceMonitor_(NULL),
 #endif
@@ -344,16 +347,26 @@ JSCompartment::wrap(JSContext *cx, JSStr
     AutoValueRooter tvr(cx, StringValue(*strp));
     if (!wrap(cx, tvr.addr()))
         return false;
     *strp = tvr.value().toString();
     return true;
 }
 
 bool
+JSCompartment::wrap(JSContext *cx, HeapPtrString *strp)
+{
+    AutoValueRooter tvr(cx, StringValue(*strp));
+    if (!wrap(cx, tvr.addr()))
+        return false;
+    *strp = tvr.value().toString();
+    return true;
+}
+
+bool
 JSCompartment::wrap(JSContext *cx, JSObject **objp)
 {
     if (!*objp)
         return true;
     AutoValueRooter tvr(cx, ObjectValue(**objp));
     if (!wrap(cx, tvr.addr()))
         return false;
     *objp = &tvr.value().toObject();
@@ -415,61 +428,61 @@ JSCompartment::wrap(JSContext *cx, AutoI
 /*
  * This method marks pointers that cross compartment boundaries. It should be
  * called only for per-compartment GCs, since full GCs naturally follow pointers
  * across compartments.
  */
 void
 JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
 {
-    JS_ASSERT(trc->context->runtime->gcCurrentCompartment);
+    JS_ASSERT(trc->runtime->gcCurrentCompartment);
 
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront())
-        MarkValue(trc, e.front().key, "cross-compartment wrapper");
+        MarkRoot(trc, e.front().key, "cross-compartment wrapper");
 }
 
 void
 JSCompartment::markTypes(JSTracer *trc)
 {
     /*
      * Mark all scripts, type objects and singleton JS objects in the
      * compartment. These can be referred to directly by type sets, which we
      * cannot modify while code which depends on these type sets is active.
      */
     JS_ASSERT(activeAnalysis);
 
     for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
         JSScript *script = i.get<JSScript>();
-        MarkScript(trc, script, "mark_types_script");
+        MarkRoot(trc, script, "mark_types_script");
     }
 
     for (size_t thingKind = FINALIZE_OBJECT0;
-         thingKind <= FINALIZE_FUNCTION_AND_OBJECT_LAST;
+         thingKind < FINALIZE_FUNCTION_AND_OBJECT_LIMIT;
          thingKind++) {
         for (CellIterUnderGC i(this, AllocKind(thingKind)); !i.done(); i.next()) {
             JSObject *object = i.get<JSObject>();
             if (!object->isNewborn() && object->hasSingletonType())
-                MarkObject(trc, *object, "mark_types_singleton");
+                MarkRoot(trc, object, "mark_types_singleton");
         }
     }
 
     for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next())
-        MarkTypeObject(trc, i.get<types::TypeObject>(), "mark_types_scan");
+        MarkRoot(trc, i.get<types::TypeObject>(), "mark_types_scan");
 }
 
 void
 JSCompartment::sweep(JSContext *cx, bool releaseTypes)
 {
     /* Remove dead wrappers from the table. */
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
-        JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) &&
-                     !IsAboutToBeFinalized(cx, e.front().value.toGCThing()),
+        JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key) &&
+                     !IsAboutToBeFinalized(cx, e.front().value),
                      e.front().key.isString());
-        if (IsAboutToBeFinalized(cx, e.front().key.toGCThing()) ||
-            IsAboutToBeFinalized(cx, e.front().value.toGCThing())) {
+        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))
@@ -579,17 +592,17 @@ JSCompartment::purge(JSContext *cx)
      * not null when we have script owned by an object and not from the eval
      * cache.
      */
     for (size_t i = 0; i < ArrayLength(evalCache); ++i) {
         for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) {
             JSScript *script = *listHeadp;
             JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
             *listHeadp = NULL;
-            listHeadp = &script->u.evalHashLink;
+            listHeadp = &script->evalHashLink();
         }
     }
 
     nativeIterCache.purge();
     toSourceCache.destroyIfConstructed();
 
 #ifdef JS_TRACER
     /*
@@ -822,17 +835,17 @@ JSCompartment::markTrapClosuresIterative
     bool markedAny = false;
     JSContext *cx = trc->context;
     for (BreakpointSiteMap::Range r = breakpointSites.all(); !r.empty(); r.popFront()) {
         BreakpointSite *site = r.front().value;
 
         // Put off marking trap state until we know the script is live.
         if (site->trapHandler && !IsAboutToBeFinalized(cx, site->script)) {
             if (site->trapClosure.isMarkable() &&
-                IsAboutToBeFinalized(cx, site->trapClosure.toGCThing()))
+                IsAboutToBeFinalized(cx, site->trapClosure))
             {
                 markedAny = true;
             }
             MarkValue(trc, site->trapClosure, "trap closure");
         }
     }
     return markedAny;
 }
@@ -853,8 +866,15 @@ JSCompartment::sweepBreakpoints(JSContex
             if (scriptGone || IsAboutToBeFinalized(cx, bp->debugger->toJSObject()))
                 bp->destroy(cx, &e);
         }
         
         if (clearTrap)
             site->clearTrap(cx, &e);
     }
 }
+
+GCMarker *
+JSCompartment::createBarrierTracer()
+{
+    JS_ASSERT(!gcIncrementalTracer);
+    return NULL;
+}
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -392,16 +392,30 @@ typedef HashSet<ScriptFilenameEntry *,
 } /* namespace js */
 
 struct JS_FRIEND_API(JSCompartment) {
     JSRuntime                    *rt;
     JSPrincipals                 *principals;
 
     js::gc::ArenaLists           arenas;
 
+    bool                         needsBarrier_;
+    js::GCMarker                 *gcIncrementalTracer;
+
+    bool needsBarrier() {
+        return needsBarrier_;
+    }
+
+    js::GCMarker *barrierTracer() {
+        JS_ASSERT(needsBarrier_);
+        if (gcIncrementalTracer)
+            return gcIncrementalTracer;
+        return createBarrierTracer();
+    }
+
     uint32                       gcBytes;
     uint32                       gcTriggerBytes;
     size_t                       gcLastBytes;
 
     bool                         hold;
     bool                         isSystemCompartment;
 
     /*
@@ -469,44 +483,47 @@ 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;
+
     /*
      * Runtime-shared empty scopes for well-known built-in objects that lack
      * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW
      */
-    js::EmptyShape               *emptyArgumentsShape;
-    js::EmptyShape               *emptyBlockShape;
-    js::EmptyShape               *emptyCallShape;
-    js::EmptyShape               *emptyDeclEnvShape;
-    js::EmptyShape               *emptyEnumeratorShape;
-    js::EmptyShape               *emptyWithShape;
+    BarrieredEmptyShape          emptyArgumentsShape;
+    BarrieredEmptyShape          emptyBlockShape;
+    BarrieredEmptyShape          emptyCallShape;
+    BarrieredEmptyShape          emptyDeclEnvShape;
+    BarrieredEmptyShape          emptyEnumeratorShape;
+    BarrieredEmptyShape          emptyWithShape;
 
     typedef js::HashSet<js::EmptyShape *,
                         js::DefaultHasher<js::EmptyShape *>,
                         js::SystemAllocPolicy> EmptyShapeSet;
 
     EmptyShapeSet                emptyShapes;
 
     /*
      * 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.
      */
-    const js::Shape              *initialRegExpShape;
-    const js::Shape              *initialStringShape;
+    BarrieredShape               initialRegExpShape;
+    BarrieredShape               initialStringShape;
 
   private:
     enum { DebugFromC = 1, DebugFromJS = 2 };
 
     uintN                        debugModeBits;  // see debugMode() below
 
   public:
     js::NativeIterCache          nativeIterCache;
@@ -521,16 +538,17 @@ struct JS_FRIEND_API(JSCompartment) {
 
     bool init(JSContext *cx);
 
     /* Mark cross-compartment wrappers. */
     void markCrossCompartmentWrappers(JSTracer *trc);
 
     bool wrap(JSContext *cx, js::Value *vp);
     bool wrap(JSContext *cx, JSString **strp);
+    bool wrap(JSContext *cx, js::HeapPtrString *strp);
     bool wrap(JSContext *cx, JSObject **objp);
     bool wrapId(JSContext *cx, jsid *idp);
     bool wrap(JSContext *cx, js::PropertyOp *op);
     bool wrap(JSContext *cx, js::StrictPropertyOp *op);
     bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
     bool wrap(JSContext *cx, js::AutoIdVector &props);
 
     void markTypes(JSTracer *trc);
@@ -619,16 +637,18 @@ struct JS_FRIEND_API(JSCompartment) {
                                                   js::GlobalObject *scriptGlobal);
     void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script, JSObject *handler);
     void clearTraps(JSContext *cx, JSScript *script);
     bool markTrapClosuresIteratively(JSTracer *trc);
 
   private:
     void sweepBreakpoints(JSContext *cx);
 
+    js::GCMarker *createBarrierTracer();
+
   public:
     js::WatchpointMap *watchpointMap;
 };
 
 #define JS_PROPERTY_TREE(cx)    ((cx)->compartment->propertyTree)
 
 /*
  * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -64,18 +64,20 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jswrapper.h"
 
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
+#include "jsstrinlines.h"
 
 #include "vm/Stack-inl.h"
+#include "vm/String-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 /* Forward declarations for ErrorClass's initializer. */
 static JSBool
@@ -108,27 +110,27 @@ Class js::ErrorClass = {
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     NULL,                 /* hasInstance */
     exn_trace
 };
 
 typedef struct JSStackTraceElem {
-    JSString            *funName;
+    js::HeapPtrString   funName;
     size_t              argc;
     const char          *filename;
     uintN               ulineno;
 } JSStackTraceElem;
 
 typedef struct JSExnPrivate {
     /* A copy of the JSErrorReport originally generated. */
     JSErrorReport       *errorReport;
-    JSString            *message;
-    JSString            *filename;
+    js::HeapPtrString   message;
+    js::HeapPtrString   filename;
     uintN               lineno;
     size_t              stackDepth;
     intN                exnType;
     JSStackTraceElem    stackElems[1];
 } JSExnPrivate;
 
 static JSString *
 StackTraceToString(JSContext *cx, JSExnPrivate *priv);
@@ -323,22 +325,22 @@ InitExnPrivate(JSContext *cx, JSObject *
                 if (!checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v))
                     break;
             }
 
             if (!frames.growBy(1))
                 return false;
             JSStackTraceElem &frame = frames.back();
             if (fp->isNonEvalFunctionFrame()) {
-                frame.funName = fp->fun()->atom ? fp->fun()->atom : cx->runtime->emptyString;
+                frame.funName.init(fp->fun()->atom ? fp->fun()->atom : cx->runtime->emptyString);
                 frame.argc = fp->numActualArgs();
                 if (!fp->forEachCanonicalActualArg(AppendArg(values)))
                     return false;
             } else {
-                frame.funName = NULL;
+                frame.funName.init(NULL);
                 frame.argc = 0;
             }
             if (fp->isScriptFrame()) {
                 frame.filename = fp->script()->filename;
                 frame.ulineno = js_FramePCToLineNumber(cx, fp, i.pc());
             } else {
                 frame.ulineno = 0;
                 frame.filename = NULL;
@@ -352,34 +354,37 @@ InitExnPrivate(JSContext *cx, JSObject *
     size_t nbytes = offsetof(JSExnPrivate, stackElems) +
                     frames.length() * sizeof(JSStackTraceElem) +
                     values.length() * sizeof(Value);
 
     JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes);
     if (!priv)
         return false;
 
+    /* Initialize to zero so that write barriers don't witness undefined values. */
+    memset(priv, 0, nbytes);
+
     if (report) {
         /*
          * Construct a new copy of the error report struct. We can't use the
          * error report struct that was passed in, because it's allocated on
          * the stack, and also because it may point to transient data in the
          * TokenStream.
          */
         priv->errorReport = CopyErrorReport(cx, report);
         if (!priv->errorReport) {
             cx->free_(priv);
             return false;
         }
     } else {
         priv->errorReport = NULL;
     }
 
-    priv->message = message;
-    priv->filename = filename;
+    priv->message.init(message);
+    priv->filename.init(filename);
     priv->lineno = lineno;
     priv->stackDepth = frames.length();
     priv->exnType = exnType;
 
     JSStackTraceElem *framesDest = priv->stackElems;
     Value *valuesDest = reinterpret_cast<Value *>(framesDest + frames.length());
     JS_ASSERT(valuesDest == GetStackTraceValueBuffer(priv));
 
@@ -417,18 +422,19 @@ exn_trace(JSTracer *trc, JSObject *obj)
             if (elem->funName)
                 MarkString(trc, elem->funName, "stack trace function name");
             if (IS_GC_MARKING_TRACER(trc) && elem->filename)
                 js_MarkScriptFilename(elem->filename);
             vcount += elem->argc;
         }
         vp = GetStackTraceValueBuffer(priv);
         for (i = 0; i != vcount; ++i, ++vp) {
+            /* This value is read-only, so it's okay for it to be Unbarriered. */
             v = *vp;
-            JS_CALL_VALUE_TRACER(trc, v, "stack trace argument");
+            MarkValueUnbarriered(trc, v, "stack trace argument");
         }
     }
 }
 
 static void
 exn_finalize(JSContext *cx, JSObject *obj)
 {
     if (JSExnPrivate *priv = GetExnPrivate(obj)) {
@@ -489,18 +495,16 @@ exn_resolve(JSContext *cx, JSObject *obj
         }
 
         atom = cx->runtime->atomState.stackAtom;
         if (str == atom) {
             stack = StackTraceToString(cx, priv);
             if (!stack)
                 return false;
 
-            /* Allow to GC all things that were used to build stack trace. */
-            priv->stackDepth = 0;
             prop = js_stack_str;
             v = STRING_TO_JSVAL(stack);
             attrs = JSPROP_ENUMERATE;
             goto define;
         }
     }
     return true;
 
@@ -1337,21 +1341,21 @@ js_CopyErrorObject(JSContext *cx, JSObje
     // Copy each field. Don't bother copying the stack elements.
     if (priv->errorReport) {
         copy->errorReport = CopyErrorReport(cx, priv->errorReport);
         if (!copy->errorReport)
             return NULL;
     } else {
         copy->errorReport = NULL;
     }
-    copy->message = priv->message;
+    copy->message.init(priv->message);
     if (!cx->compartment->wrap(cx, &copy->message))
         return NULL;
     JS::Anchor<JSString *> messageAnchor(copy->message);
-    copy->filename = priv->filename;
+    copy->filename.init(priv->filename);
     if (!cx->compartment->wrap(cx, &copy->filename))
         return NULL;
     JS::Anchor<JSString *> filenameAnchor(copy->filename);
     copy->lineno = priv->lineno;
     copy->stackDepth = 0;
     copy->exnType = priv->exnType;
 
     // Create the Error object.
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -146,42 +146,45 @@ ArgumentsObject::create(JSContext *cx, u
     EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx);
     if (!emptyArgumentsShape)
         return NULL;
 
     ArgumentsData *data = (ArgumentsData *)
         cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
-    SetValueRangeToUndefined(data->slots, argc);
+
+    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->setMap(emptyArgumentsShape);
+    obj->initMap(emptyArgumentsShape);
 
     ArgumentsObject *argsobj = obj->asArguments();
 
     JS_ASSERT(UINT32_MAX > (uint64(argc) << PACKED_BITS_COUNT));
-    argsobj->setInitialLength(argc);
-
-    argsobj->setCalleeAndData(callee, data);
+    argsobj->initInitialLength(argc);
+    argsobj->initData(data);
 
     return argsobj;
 }
 
 struct STATIC_SKIP_INFERENCE PutArg
 {
-    PutArg(Value *dst) : dst(dst) {}
-    Value *dst;
+    PutArg(JSCompartment *comp, HeapValue *dst) : dst(dst), compartment(comp) {}
+    HeapValue *dst;
+    JSCompartment *compartment;
     bool operator()(uintN, Value *src) {
+        JS_ASSERT(dst->isMagic(JS_ARGS_HOLE) || dst->isUndefined());
         if (!dst->isMagic(JS_ARGS_HOLE))
-            *dst = *src;
+            dst->set(compartment, *src);
         ++dst;
         return true;
     }
 };
 
 JSObject *
 js_GetArgsObject(JSContext *cx, StackFrame *fp)
 {
@@ -215,31 +218,32 @@ js_GetArgsObject(JSContext *cx, StackFra
      * 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
      * strict mode function that contains an assignment to a parameter, or
      * that calls eval.)  Non-strict mode arguments use the frame pointer to
      * retrieve up-to-date parameter values.
      */
     if (argsobj->isStrictArguments())
-        fp->forEachCanonicalActualArg(PutArg(argsobj->data()->slots));
+        fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
     else
         argsobj->setStackFrame(fp);
 
     fp->setArgsObj(*argsobj);
     return argsobj;
 }
 
 void
 js_PutArgsObject(StackFrame *fp)
 {
     ArgumentsObject &argsobj = fp->argsObj();
     if (argsobj.isNormalArguments()) {
         JS_ASSERT(argsobj.maybeStackFrame() == fp);
-        fp->forEachCanonicalActualArg(PutArg(argsobj.data()->slots));
+        JSCompartment *comp = fp->scopeChain().compartment();
+        fp->forEachCanonicalActualArg(PutArg(comp, argsobj.data()->slots));
         argsobj.setStackFrame(NULL);
     } else {
         JS_ASSERT(!argsobj.maybeStackFrame());
     }
 }
 
 #ifdef JS_TRACER
 
@@ -277,20 +281,21 @@ js_PutArgumentsOnTrace(JSContext *cx, JS
     JS_ASSERT(argsobj->onTrace());
 
     /*
      * TraceRecorder::putActivationObjects builds a single, contiguous array of
      * the arguments, regardless of whether #actuals > #formals so there is no
      * need to worry about actual vs. formal arguments.
      */
     Value *srcend = argv + argsobj->initialLength();
-    Value *dst = argsobj->data()->slots;
+    HeapValue *dst = argsobj->data()->slots;
+    JSCompartment *comp = cx->compartment;
     for (Value *src = argv; src < srcend; ++src, ++dst) {
         if (!dst->isMagic(JS_ARGS_HOLE))
-            *dst = *src;
+            dst->set(comp, *src);
     }
 
     argsobj->clearOnTrace();
     return true;
 }
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
                      nanojit::ACCSET_STORE_ANY)
 
@@ -596,35 +601,32 @@ args_finalize(JSContext *cx, JSObject *o
  * 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()) {
-        JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
-        MarkObject(trc, *genobj, "generator object");
-    }
+    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();
     if (argsobj->onTrace()) {
         JS_ASSERT(!argsobj->isStrictArguments());
         return;
     }
 
     ArgumentsData *data = argsobj->data();
-    if (data->callee.isObject())
-        MarkObject(trc, data->callee.toObject(), js_callee_str);
+    MarkValue(trc, data->callee, js_callee_str);
     MarkValueRange(trc, argsobj->initialLength(), data->slots, js_arguments_str);
 
     MaybeMarkGenerator(trc, argsobj);
 }
 
 /*
  * The classes below collaborate to lazily reflect and synchronize actual
  * argument values, argument count, and callee function object stored in a
@@ -702,17 +704,17 @@ NewDeclEnvObject(JSContext *cx, StackFra
     JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!envobj)
         return NULL;
 
     EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
     if (!emptyDeclEnvShape)
         return NULL;
     envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false);
-    envobj->setMap(emptyDeclEnvShape);
+    envobj->initMap(emptyDeclEnvShape);
 
     return envobj;
 }
 
 namespace js {
 
 CallObject *
 CreateFunCallObject(JSContext *cx, StackFrame *fp)
@@ -781,17 +783,17 @@ js_PutCallObject(StackFrame *fp)
     CallObject &callobj = fp->callObj().asCall();
     JS_ASSERT(callobj.maybeStackFrame() == fp);
     JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
     JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
 
     /* Get the arguments object to snapshot fp's actual argument values. */
     if (fp->hasArgsObj()) {
         if (!fp->hasOverriddenArgs())
-            callobj.setArguments(ObjectValue(fp->argsObj()));
+            callobj.initArguments(ObjectValue(fp->argsObj()));
         js_PutArgsObject(fp);
     }
 
     JSScript *script = fp->script();
     Bindings &bindings = script->bindings;
 
     if (callobj.isForEval()) {
         JS_ASSERT(script->strictModeCode);
@@ -818,28 +820,39 @@ js_PutCallObject(StackFrame *fp)
 #ifdef JS_METHODJIT
                 || script->debugMode
 #endif
                 ) {
                 callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
             } else {
                 /*
                  * For each arg & var that is closed over, copy it from the stack
-                 * into the call object.
+                 * into the call object. We use initArg/VarUnchecked because,
+                 * when you call a getter on a call object, js_NativeGetInline
+                 * caches the return value in the slot, so we can't assert that
+                 * it's undefined.
                  */
                 uint32 nclosed = script->nClosedArgs;
                 for (uint32 i = 0; i < nclosed; i++) {
                     uint32 e = script->getClosedArg(i);
+#ifdef JS_GC_ZEAL
                     callobj.setArg(e, fp->formalArg(e));
+#else
+                    callobj.initArgUnchecked(e, fp->formalArg(e));
+#endif
                 }
 
                 nclosed = script->nClosedVars;
                 for (uint32 i = 0; i < nclosed; i++) {
                     uint32 e = script->getClosedVar(i);
+#ifdef JS_GC_ZEAL
                     callobj.setVar(e, fp->slots()[e]);
+#else
+                    callobj.initVarUnchecked(e, fp->slots()[e]);
+#endif
                 }
             }
 
             /*
              * Update the args and vars for the active call if this is an outer
              * function in a script nesting.
              */
             types::TypeScriptNesting *nesting = script->nesting();
@@ -1587,29 +1600,34 @@ 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. */
-        MarkObject(trc, *fun, "private");
+        /*
+         * 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->getFlatClosureUpvars(), "upvars");
+                           obj->getFlatClosureData()->upvars, "upvars");
         }
         return;
     }
 
     if (fun->atom)
-        MarkString(trc, fun->atom, "atom");
+        MarkAtom(trc, fun->atom, "atom");
 
     if (fun->isInterpreted() && fun->script())
         MarkScript(trc, fun->script(), "script");
 }
 
 static void
 fun_finalize(JSContext *cx, JSObject *obj)
 {
@@ -1844,17 +1862,17 @@ JSObject::initBoundFunction(JSContext *c
 
         empty->slotSpan += argslen;
         setMap(empty);
 
         if (!ensureInstanceReservedSlots(cx, argslen))
             return false;
 
         JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
-        copySlotRange(FUN_CLASS_RESERVED_SLOTS, args, argslen);
+        copySlotRange(FUN_CLASS_RESERVED_SLOTS, args, argslen, false);
     }
     return true;
 }
 
 inline JSObject *
 JSObject::getBoundFunctionTarget() const
 {
     JS_ASSERT(isFunction());
@@ -2273,17 +2291,17 @@ js_NewFunction(JSContext *cx, JSObject *
 
     /* Initialize all function members. */
     fun->nargs = uint16(nargs);
     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO);
     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
         JS_ASSERT(!native);
         JS_ASSERT(nargs == 0);
         fun->u.i.skipmin = 0;
-        fun->u.i.script_ = NULL;
+        fun->script().init(NULL);
     } else {
         fun->u.n.clasp = NULL;
         if (flags & JSFUN_TRCINFO) {
 #ifdef JS_TRACER
             JSNativeTraceInfo *trcinfo =
                 JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native);
             fun->u.n.native = (Native) trcinfo->native;
             fun->u.n.trcinfo = trcinfo;
@@ -2323,17 +2341,17 @@ js_CloneFunctionObject(JSContext *cx, JS
         /*
          * 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->setType(fun->type());
+            clone->initType(fun->type());
 
         clone->setPrivate(fun);
     } else {
         /*
          * Across compartments we have to deep copy JSFunction and clone the
          * script (for interpreted functions).
          */
         clone = NewFunction(cx, parent);
@@ -2347,21 +2365,21 @@ js_CloneFunctionObject(JSContext *cx, JS
         cfun->atom = fun->atom;
         clone->setPrivate(cfun);
         if (cfun->isInterpreted()) {
             JSScript *script = fun->script();
             JS_ASSERT(script);
             JS_ASSERT(script->compartment() == fun->compartment());
             JS_ASSERT(script->compartment() != cx->compartment);
 
-            cfun->u.i.script_ = NULL;
+            cfun->script().init(NULL);
             JSScript *cscript = js_CloneScript(cx, script);
             if (!cscript)
                 return NULL;
-            cscript->u.globalObject = cfun->getGlobal();
+            cscript->globalObject = cfun->getGlobal();
             cfun->setScript(cscript);
             if (!cscript->typeSetFunction(cx, cfun))
                 return NULL;
 
             js_CallNewScriptHook(cx, cfun->script(), cfun);
             Debugger::onNewScript(cx, cfun->script(), NULL);
         }
     }
@@ -2390,21 +2408,21 @@ js_AllocFlatClosure(JSContext *cx, JSFun
     JSObject *closure = CloneFunctionObject(cx, fun, scopeChain, true);
     if (!closure)
         return closure;
 
     uint32 nslots = fun->script()->bindings.countUpvars();
     if (nslots == 0)
         return closure;
 
-    Value *upvars = (Value *) cx->malloc_(nslots * sizeof(Value));
-    if (!upvars)
+    FlatClosureData *data = (FlatClosureData *) cx->malloc_(nslots * sizeof(HeapValue));
+    if (!data)
         return NULL;
 
-    closure->setFlatClosureUpvars(upvars);
+    closure->setFlatClosureData(data);
     return closure;
 }
 
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure,
                      CONTEXT, FUNCTION, OBJECT, 0, nanojit::ACCSET_STORE_ANY)
 
 JSObject *
 js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
@@ -2420,22 +2438,22 @@ js_NewFlatClosure(JSContext *cx, JSFunct
      */
     VOUCH_DOES_NOT_REQUIRE_STACK();
     JSObject *scopeChain = &cx->fp()->scopeChain();
 
     JSObject *closure = js_AllocFlatClosure(cx, fun, scopeChain);
     if (!closure || !fun->script()->bindings.hasUpvars())
         return closure;
 
-    Value *upvars = closure->getFlatClosureUpvars();
+    FlatClosureData *data = closure->getFlatClosureData();
     uintN level = fun->script()->staticLevel;
     JSUpvarArray *uva = fun->script()->upvars();
 
     for (uint32 i = 0, n = uva->length; i < n; i++)
-        upvars[i] = GetUpvar(cx, level, uva->vector[i]);
+        data->upvars[i].init(GetUpvar(cx, level, uva->vector[i]));
 
     return closure;
 }
 
 JSFunction *
 js_DefineFunction(JSContext *cx, JSObject *obj, jsid id, Native native,
                   uintN nargs, uintN attrs)
 {
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -45,16 +45,18 @@
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsobj.h"
 #include "jsatom.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsopcode.h"
 
+#include "gc/Barrier.h"
+
 /*
  * The high two bits of JSFunction.flags encode whether the function is native
  * or interpreted, and if interpreted, what kind of optimized closure form (if
  * any) it might be.
  *
  *   00   not interpreted
  *   01   interpreted, neither flat nor null closure
  *   10   interpreted, flat closure
@@ -190,28 +192,26 @@ struct JSFunction : public JSObject_Slot
     JSAtom *methodAtom() const {
         return (joinable() && getSlot(METHOD_ATOM_SLOT).isString())
                ? &getSlot(METHOD_ATOM_SLOT).toString()->asAtom()
                : NULL;
     }
 
     inline void setMethodAtom(JSAtom *atom);
 
-    JSScript *script() const {
+    js::HeapPtrScript &script() const {
         JS_ASSERT(isInterpreted());
-        return u.i.script_;
+        return *(js::HeapPtrScript *)&u.i.script_;
     }
 
-    void setScript(JSScript *script) {
-        JS_ASSERT(isInterpreted());
-        u.i.script_ = script;
-    }
+    inline void setScript(JSScript *script_);
+    inline void initScript(JSScript *script_);
 
     JSScript *maybeScript() const {
-        return isInterpreted() ? script() : NULL;
+        return isInterpreted() ? script().get() : NULL;
     }
 
     JSNative native() const {
         JS_ASSERT(isNative());
         return u.n.native;
     }
 
     JSNative maybeNative() const {
@@ -264,16 +264,20 @@ inline JSFunction *
 JSObject::getFunctionPrivate() const
 {
     JS_ASSERT(isFunction());
     return reinterpret_cast<JSFunction *>(getPrivate());
 }
 
 namespace js {
 
+struct FlatClosureData {
+    HeapValue upvars[1];
+};
+
 static JS_ALWAYS_INLINE bool
 IsFunctionObject(const js::Value &v)
 {
     return v.isObject() && v.toObject().isFunction();
 }
 
 static JS_ALWAYS_INLINE bool
 IsFunctionObject(const js::Value &v, JSObject **funobj)
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -92,9 +92,23 @@ CloneFunctionObject(JSContext *cx, JSFun
         JS_ASSERT(fun->getProto() == proto);
         fun->setParent(parent);
         return fun;
     }
 
     return js_CloneFunctionObject(cx, fun, parent, proto);
 }
 
+inline void
+JSFunction::setScript(JSScript *script_)
+{
+    JS_ASSERT(isInterpreted());
+    script() = script_;
+}
+
+inline void
+JSFunction::initScript(JSScript *script_)
+{
+    JS_ASSERT(isInterpreted());
+    script().init(script_);
+}
+
 #endif /* jsfuninlines_h___ */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -106,16 +106,24 @@
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 
 namespace js {
 namespace gc {
 
+#ifdef JS_GC_ZEAL
+static void
+StartVerifyBarriers(JSContext *cx);
+
+static void
+EndVerifyBarriers(JSContext *cx);
+#endif
+
 /* This array should be const, but that doesn't link right under GCC. */
 AllocKind slotsToThingKind[] = {
     /* 0 */  FINALIZE_OBJECT0,  FINALIZE_OBJECT2,  FINALIZE_OBJECT2,  FINALIZE_OBJECT4,
     /* 4 */  FINALIZE_OBJECT4,  FINALIZE_OBJECT8,  FINALIZE_OBJECT8,  FINALIZE_OBJECT8,
     /* 8 */  FINALIZE_OBJECT8,  FINALIZE_OBJECT12, FINALIZE_OBJECT12, FINALIZE_OBJECT12,
     /* 12 */ FINALIZE_OBJECT12, FINALIZE_OBJECT16, FINALIZE_OBJECT16, FINALIZE_OBJECT16,
     /* 16 */ FINALIZE_OBJECT16
 };
@@ -783,29 +791,36 @@ PickChunk(JSCompartment *comp)
     chunk->info.prevp = NULL;
     chunk->info.next = NULL;
     chunk->addToAvailableList(comp);
 
     return chunk;
 }
 
 JS_FRIEND_API(bool)
-IsAboutToBeFinalized(JSContext *cx, const void *thing)
+IsAboutToBeFinalized(JSContext *cx, const Cell *thing)
 {
     JS_ASSERT(cx);
 
     JSCompartment *thingCompartment = reinterpret_cast<const Cell *>(thing)->compartment();
     JSRuntime *rt = cx->runtime;
     JS_ASSERT(rt == thingCompartment->rt);
     if (rt->gcCurrentCompartment != NULL && rt->gcCurrentCompartment != thingCompartment)
         return false;
 
     return !reinterpret_cast<const Cell *>(thing)->isMarked();
 }
 
+bool
+IsAboutToBeFinalized(JSContext *cx, const Value &v)
+{
+    JS_ASSERT(v.isMarkable());
+    return IsAboutToBeFinalized(cx, (Cell *)v.toGCThing());
+}
+
 JS_FRIEND_API(bool)
 js_GCThingIsMarked(void *thing, uintN color = BLACK)
 {
     JS_ASSERT(thing);
     AssertValidColor(thing, color);
     return reinterpret_cast<Cell *>(thing)->isMarked(color);
 }
 
@@ -913,17 +928,17 @@ MarkIfGCThingWord(JSTracer *trc, jsuword
 #if JS_BITS_PER_WORD == 32
     jsuword addr = w & JSID_PAYLOAD_MASK;
 #elif JS_BITS_PER_WORD == 64
     jsuword addr = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK;
 #endif
 
     Chunk *chunk = Chunk::fromAddress(addr);
 
-    if (!trc->context->runtime->gcChunkSet.has(chunk))
+    if (!trc->runtime->gcChunkSet.has(chunk))
         return CGCT_NOTCHUNK;
 
     /*
      * We query for pointers outside the arena array after checking for an
      * allocated chunk. Such pointers are rare and we want to reject them
      * after doing more likely rejections.
      */
     if (!Chunk::withinArenasRange(addr))
@@ -934,17 +949,17 @@ MarkIfGCThingWord(JSTracer *trc, jsuword
     if (chunk->decommittedArenas.get(arenaOffset))
         return CGCT_FREEARENA;
 
     ArenaHeader *aheader = &chunk->arenas[arenaOffset].aheader;
 
     if (!aheader->allocated())
         return CGCT_FREEARENA;
 
-    JSCompartment *curComp = trc->context->runtime->gcCurrentCompartment;
+    JSCompartment *curComp = trc->runtime->gcCurrentCompartment;
     if (curComp && curComp != aheader->compartment)
         return CGCT_OTHERCOMPARTMENT;
 
     AllocKind thingKind = aheader->getAllocKind();
     uintptr_t offset = addr & ArenaMask;
     uintptr_t minOffset = Arena::firstThingOffset(thingKind);
     if (offset < minOffset)
         return CGCT_NOTARENA;
@@ -1040,17 +1055,17 @@ MarkStackRangeConservatively(JSTracer *t
         JSRuntime *runtime;
         JSCompartment *savedCompartment;
 
         AutoSkipChecking(JSRuntime *rt)
           : runtime(rt), savedCompartment(rt->gcCheckCompartment) {
             rt->gcCheckCompartment = NULL;
         }
         ~AutoSkipChecking() { runtime->gcCheckCompartment = savedCompartment; }
-    } as(trc->context->runtime);
+    } as(trc->runtime);
 
     const jsuword *begin = beginv->payloadWord();
     const jsuword *end = endv->payloadWord();
 #ifdef JS_NUNBOX32
     /*
      * With 64-bit jsvals on 32-bit systems, we can optimize a bit by
      * scanning only the payloads.
      */
@@ -1061,29 +1076,29 @@ MarkStackRangeConservatively(JSTracer *t
     MarkRangeConservatively(trc, begin, end);
 #endif
 }
 
 void
 MarkConservativeStackRoots(JSTracer *trc)
 {
 #ifdef JS_THREADSAFE
-    for (JSThread::Map::Range r = trc->context->runtime->threads.all(); !r.empty(); r.popFront()) {
+    for (JSThread::Map::Range r = trc->runtime->threads.all(); !r.empty(); r.popFront()) {
         JSThread *thread = r.front().value;
         ConservativeGCThreadData *ctd = &thread->data.conservativeGC;
         if (ctd->hasStackToScan()) {
             JS_ASSERT_IF(!thread->data.requestDepth, thread->suspendCount);
             MarkThreadDataConservatively(trc, &thread->data);
         } else {
             JS_ASSERT(!thread->suspendCount);
             JS_ASSERT(thread->data.requestDepth <= ctd->requestThreshold);
         }
     }
 #else
-    MarkThreadDataConservatively(trc, &trc->context->runtime->threadData);
+    MarkThreadDataConservatively(trc, &trc->runtime->threadData);
 #endif
 }
 
 JS_NEVER_INLINE void
 ConservativeGCThreadData::recordStackTop()
 {
     /* Update the native stack pointer if it points to a bigger stack. */
     jsuword dummy;
@@ -1817,17 +1832,17 @@ gc_root_traversal(JSTracer *trc, const R
     void *ptr;
     if (entry.value.type == JS_GC_ROOT_GCTHING_PTR) {
         ptr = *reinterpret_cast<void **>(entry.key);
     } else {
         Value *vp = reinterpret_cast<Value *>(entry.key);
         ptr = vp->isGCThing() ? vp->toGCThing() : NULL;
     }
 
-    if (ptr && !trc->context->runtime->gcCurrentCompartment) {
+    if (ptr && !trc->runtime->gcCurrentCompartment) {
         /*
          * Use conservative machinery to find if ptr is a valid GC thing.
          * We only do this during global GCs, to preserve the invariant
          * that mark callbacks are not in place during compartment GCs.
          */
         JSTracer checker;
         JS_TRACER_INIT(&checker, trc->context, EmptyMarkCallback);
         ConservativeGCTest test = MarkIfGCThingWord(&checker, reinterpret_cast<jsuword>(ptr));
@@ -1836,190 +1851,191 @@ gc_root_traversal(JSTracer *trc, const R
 "JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n"
 "invalid gcthing.  This is usually caused by a missing call to JS_RemoveRoot.\n"
 "The root's name is \"%s\".\n",
                     entry.value.name);
         }
         JS_ASSERT(test == CGCT_VALID);
     }
 #endif
-    JS_SET_TRACING_NAME(trc, entry.value.name ? entry.value.name : "root");
+    const char *name = entry.value.name ? entry.value.name : "root";
     if (entry.value.type == JS_GC_ROOT_GCTHING_PTR)
-        MarkGCThing(trc, *reinterpret_cast<void **>(entry.key));
+        MarkRootGCThing(trc, *reinterpret_cast<void **>(entry.key), name);
     else
-        MarkValueRaw(trc, *reinterpret_cast<Value *>(entry.key));
+        MarkRoot(trc, *reinterpret_cast<Value *>(entry.key), name);
 }
 
 static void
 gc_lock_traversal(const GCLocks::Entry &entry, JSTracer *trc)
 {
     JS_ASSERT(entry.value >= 1);
-    MarkGCThing(trc, entry.key, "locked object");
+    MarkRootGCThing(trc, entry.key, "locked object");
 }
 
 void
 js_TraceStackFrame(JSTracer *trc, StackFrame *fp)
 {
-    MarkObject(trc, fp->scopeChain(), "scope chain");
+    MarkRoot(trc, &fp->scopeChain(), "scope chain");
     if (fp->isDummyFrame())
         return;
     if (fp->hasArgsObj())
-        MarkObject(trc, fp->argsObj(), "arguments");
-    MarkScript(trc, fp->script(), "script");
+        MarkRoot(trc, &fp->argsObj(), "arguments");
+    MarkRoot(trc, fp->script(), "script");
     fp->script()->compartment()->active = true;
-    MarkValue(trc, fp->returnValue(), "rval");
+    MarkRoot(trc, fp->returnValue(), "rval");
 }
 
 void
 AutoIdArray::trace(JSTracer *trc)
 {
     JS_ASSERT(tag == IDARRAY);
-    gc::MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
+    gc::MarkIdRange(trc, idArray->vector, idArray->vector + idArray->length,
+                    "JSAutoIdArray.idArray");
 }
 
 void
 AutoEnumStateRooter::trace(JSTracer *trc)
 {
-    gc::MarkObject(trc, *obj, "js::AutoEnumStateRooter.obj");
+    gc::MarkRoot(trc, obj, "js::AutoEnumStateRooter.obj");
 }
 
 inline void
 AutoGCRooter::trace(JSTracer *trc)
 {
     switch (tag) {
       case JSVAL:
-        MarkValue(trc, static_cast<AutoValueRooter *>(this)->val, "js::AutoValueRooter.val");
+        MarkRoot(trc, static_cast<AutoValueRooter *>(this)->val, "js::AutoValueRooter.val");
         return;
 
       case PARSER:
         static_cast<Parser *>(this)->trace(trc);
         return;
 
       case ENUMERATOR:
         static_cast<AutoEnumStateRooter *>(this)->trace(trc);
         return;
 
       case IDARRAY: {
         JSIdArray *ida = static_cast<AutoIdArray *>(this)->idArray;
-        MarkIdRange(trc, ida->length, ida->vector, "js::AutoIdArray.idArray");
+        MarkIdRange(trc, ida->vector, ida->vector + ida->length, "js::AutoIdArray.idArray");
         return;
       }
 
       case DESCRIPTORS: {
         PropDescArray &descriptors =
             static_cast<AutoPropDescArrayRooter *>(this)->descriptors;
         for (size_t i = 0, len = descriptors.length(); i < len; i++) {
             PropDesc &desc = descriptors[i];
-            MarkValue(trc, desc.pd, "PropDesc::pd");
-            MarkValue(trc, desc.value, "PropDesc::value");
-            MarkValue(trc, desc.get, "PropDesc::get");
-            MarkValue(trc, desc.set, "PropDesc::set");
+            MarkRoot(trc, desc.pd, "PropDesc::pd");
+            MarkRoot(trc, desc.value, "PropDesc::value");
+            MarkRoot(trc, desc.get, "PropDesc::get");
+            MarkRoot(trc, desc.set, "PropDesc::set");
         }
         return;
       }
 
       case DESCRIPTOR : {
         PropertyDescriptor &desc = *static_cast<AutoPropertyDescriptorRooter *>(this);
         if (desc.obj)
-            MarkObject(trc, *desc.obj, "Descriptor::obj");
-        MarkValue(trc, desc.value, "Descriptor::value");
+            MarkRoot(trc, desc.obj, "Descriptor::obj");
+        MarkRoot(trc, desc.value, "Descriptor::value");
         if ((desc.attrs & JSPROP_GETTER) && desc.getter)
-            MarkObject(trc, *CastAsObject(desc.getter), "Descriptor::get");
+            MarkRoot(trc, CastAsObject(desc.getter), "Descriptor::get");
         if (desc.attrs & JSPROP_SETTER && desc.setter)
-            MarkObject(trc, *CastAsObject(desc.setter), "Descriptor::set");
+            MarkRoot(trc, CastAsObject(desc.setter), "Descriptor::set");
         return;
       }
 
       case NAMESPACES: {
-        JSXMLArray &array = static_cast<AutoNamespaceArray *>(this)->array;
-        MarkObjectRange(trc, array.length, reinterpret_cast<JSObject **>(array.vector),
-                        "JSXMLArray.vector");
+        JSXMLArray<JSObject> &array = static_cast<AutoNamespaceArray *>(this)->array;
+        MarkObjectRange(trc, array.length, array.vector, "JSXMLArray.vector");
         array.cursors->trace(trc);
         return;
       }
 
       case XML:
         js_TraceXML(trc, static_cast<AutoXMLRooter *>(this)->xml);
         return;
 
       case OBJECT:
         if (JSObject *obj = static_cast<AutoObjectRooter *>(this)->obj)
-            MarkObject(trc, *obj, "js::AutoObjectRooter.obj");
+            MarkRoot(trc, obj, "js::AutoObjectRooter.obj");
         return;
 
       case ID:
-        MarkId(trc, static_cast<AutoIdRooter *>(this)->id_, "js::AutoIdRooter.val");
+        MarkRoot(trc, static_cast<AutoIdRooter *>(this)->id_, "js::AutoIdRooter.val");
         return;
 
       case VALVECTOR: {
         AutoValueVector::VectorImpl &vector = static_cast<AutoValueVector *>(this)->vector;
-        MarkValueRange(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector");
+        MarkRootRange(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector");
         return;
       }
 
       case STRING:
         if (JSString *str = static_cast<AutoStringRooter *>(this)->str)
-            MarkString(trc, str, "js::AutoStringRooter.str");
+            MarkRoot(trc, str, "js::AutoStringRooter.str");
         return;
 
       case IDVECTOR: {
         AutoIdVector::VectorImpl &vector = static_cast<AutoIdVector *>(this)->vector;
-        MarkIdRange(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector");
+        MarkRootRange(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector");
         return;
       }
 
       case SHAPEVECTOR: {
         AutoShapeVector::VectorImpl &vector = static_cast<js::AutoShapeVector *>(this)->vector;
-        MarkShapeRange(trc, vector.length(), vector.begin(), "js::AutoShapeVector.vector");
+        MarkRootRange(trc, vector.length(), vector.begin(), "js::AutoShapeVector.vector");
         return;
       }
 
       case OBJVECTOR: {
         AutoObjectVector::VectorImpl &vector = static_cast<AutoObjectVector *>(this)->vector;
-        MarkObjectRange(trc, vector.length(), vector.begin(), "js::AutoObjectVector.vector");
+        MarkRootRange(trc, vector.length(), vector.begin(), "js::AutoObjectVector.vector");
         return;
       }
 
       case VALARRAY: {
         AutoValueArray *array = static_cast<AutoValueArray *>(this);
-        MarkValueRange(trc, array->length(), array->start(), "js::AutoValueArray");
+        MarkRootRange(trc, array->length(), array->start(), "js::AutoValueArray");
         return;
       }
     }
 
     JS_ASSERT(tag >= 0);
-    MarkValueRange(trc, tag, static_cast<AutoArrayRooter *>(this)->array, "js::AutoArrayRooter.array");
+    MarkRootRange(trc, tag, static_cast<AutoArrayRooter *>(this)->array,
+                  "js::AutoArrayRooter.array");
 }
 
 namespace js {
 
 JS_FRIEND_API(void)
 MarkContext(JSTracer *trc, JSContext *acx)
 {
     /* Stack frames and slots are traced by StackSpace::mark. */
 
     /* Mark other roots-by-definition in acx. */
     if (acx->globalObject && !acx->hasRunOption(JSOPTION_UNROOTED_GLOBAL))
-        MarkObject(trc, *acx->globalObject, "global object");
+        MarkRoot(trc, acx->globalObject, "global object");
     if (acx->isExceptionPending())
-        MarkValue(trc, acx->getPendingException(), "exception");
+        MarkRoot(trc, acx->getPendingException(), "exception");
 
     for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down)
         gcr->trace(trc);
 
     if (acx->sharpObjectMap.depth > 0)
         js_TraceSharpMap(trc, &acx->sharpObjectMap);
 
-    MarkValue(trc, acx->iterValue, "iterValue");
+    MarkRoot(trc, acx->iterValue, "iterValue");
 }
 
 JS_REQUIRES_STACK void
 MarkRuntime(JSTracer *trc)
 {
-    JSRuntime *rt = trc->context->runtime;
+    JSRuntime *rt = trc->runtime;
 
     if (rt->state != JSRTS_LANDING)
         MarkConservativeStackRoots(trc);
 
     for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront())
         gc_root_traversal(trc, r.front());
 
     for (GCLocks::Range r = rt->gcLocksHash.all(); !r.empty(); r.popFront())
@@ -2511,17 +2527,17 @@ EndMarkPhase(JSContext *cx, GCMarker *gc
      */
     while (WatchpointMap::markAllIteratively(gcmarker) ||
            WeakMapBase::markAllIteratively(gcmarker) ||
            Debugger::markAllIteratively(gcmarker))
     {
         gcmarker->drainMarkStack();
     }
 
-    rt->gcMarkingTracer = NULL;
+    rt->gcIncrementalTracer = NULL;
 
     rt->gcStats.endPhase(gcstats::PHASE_MARK);
 
     if (rt->gcCallback)
         (void) rt->gcCallback(cx, JSGC_MARK_END);
 
 #ifdef DEBUG
     /* Make sure that we didn't mark an object in another compartment */
@@ -2662,17 +2678,17 @@ MarkAndSweep(JSContext *cx, JSGCInvocati
     /* Reset malloc counter. */
     rt->resetGCMallocBytes();
 
     AutoUnlockGC unlock(rt);
 
     GCMarker gcmarker(cx);
     JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker));
     JS_ASSERT(gcmarker.getMarkColor() == BLACK);
-    rt->gcMarkingTracer = &gcmarker;
+    rt->gcIncrementalTracer = &gcmarker;
 
     BeginMarkPhase(cx, &gcmarker, gckind);
     gcmarker.drainMarkStack();
     EndMarkPhase(cx, &gcmarker, gckind);
     SweepPhase(cx, &gcmarker, gckind);
 }
 
 #ifdef JS_THREADSAFE
@@ -2956,16 +2972,27 @@ js_GC(JSContext *cx, JSCompartment *comp
     if (rt->state != JSRTS_UP && gckind != GC_LAST_CONTEXT)
         return;
 
     if (JS_ON_TRACE(cx)) {
         JS_ASSERT(gckind != GC_LAST_CONTEXT);
         return;
     }
 
+#ifdef JS_GC_ZEAL
+    struct AutoVerifyBarriers {
+        JSContext *cx;
+        bool inVerify;
+        AutoVerifyBarriers(JSContext *cx) : cx(cx), inVerify(cx->runtime->gcVerifyData) {
+            if (inVerify) EndVerifyBarriers(cx);
+        }
+        ~AutoVerifyBarriers() { if (inVerify) StartVerifyBarriers(cx); }
+    } av(cx);
+#endif
+
     RecordNativeStackTopForGC(cx);
 
     gcstats::AutoGC agc(rt->gcStats, comp, reason);
 
     do {
         /*
          * Let the API user decide to defer a GC if it wants to (unless this
          * is the last context).  Invoke the callback regardless. Sample the
@@ -3036,17 +3063,17 @@ TraceRuntime(JSTracer *trc)
 
             AutoCopyFreeListToArenas copy(rt);
             RecordNativeStackTopForGC(trc->context);
             MarkRuntime(trc);
             return;
         }
     }
 #else
-    AutoCopyFreeListToArenas copy(trc->context->runtime);
+    AutoCopyFreeListToArenas copy(trc->runtime);
     RecordNativeStackTopForGC(trc->context);
 #endif
 
     /*
      * Calls from inside a normal GC or a recursive calls are OK and do not
      * require session setup.
      */
     MarkRuntime(trc);
@@ -3221,16 +3248,348 @@ RunDebugGC(JSContext *cx)
         if (rt->gcTriggerCompartment == rt->atomsCompartment)
             rt->gcTriggerCompartment = NULL;
 
         RunLastDitchGC(cx);
     }
 #endif
 }
 
+#ifdef JS_GC_ZEAL
+
+/*
+ * Write barrier verification
+ *
+ * The next few functions are for incremental write barrier verification. When
+ * StartVerifyBarriers is called, a snapshot is taken of all objects in the GC
+ * heap and saved in an explicit graph data structure. Later, EndVerifyBarriers
+ * traverses the heap again. Any pointer values that were in the snapshot and
+ * are no longer found must be marked; otherwise an assertion triggers. Note
+ * that we must not GC in between starting and finishing a verification phase.
+ *
+ * The VerifyBarriers function is a shorthand. It checks if a verification phase
+ * is currently running. If not, it starts one. Otherwise, it ends the current
+ * phase and starts a new one.
+ *
+ * The user can adjust the frequency of verifications, which causes
+ * VerifyBarriers to be a no-op all but one out of N calls. However, if the
+ * |always| parameter is true, it starts a new phase no matter what.
+ */
+
+struct EdgeValue
+{
+    void *thing;
+    JSGCTraceKind kind;
+    char *label;
+};
+
+struct VerifyNode
+{
+    void *thing;
+    JSGCTraceKind kind;
+    uint32 count;
+    EdgeValue edges[1];
+};
+
+typedef HashMap<void *, VerifyNode *> NodeMap;
+
+/*
+ * The verifier data structures are simple. The entire graph is stored in a
+ * single block of memory. At the beginning is a VerifyNode for the root
+ * node. It is followed by a sequence of EdgeValues--the exact number is given
+ * in the node. After the edges come more nodes and their edges.
+ *
+ * The edgeptr and term fields are used to allocate out of the block of memory
+ * for the graph. If we run out of memory (i.e., if edgeptr goes beyond term),
+ * we just abandon the verification.
+ *
+ * The nodemap field is a hashtable that maps from the address of the GC thing
+ * to the VerifyNode that represents it.
+ */
+struct VerifyTracer : JSTracer {
+    /* The gcNumber when the verification began. */
+    uint32 number;
+
+    /* This counts up to JS_VERIFIER_FREQ to decide whether to verify. */
+    uint32 count;
+
+    /* This graph represents the initial GC "snapshot". */
+    VerifyNode *curnode;
+    VerifyNode *root;
+    char *edgeptr;
+    char *term;
+    NodeMap nodemap;
+
+    /* A dummy marker used for the write barriers; stored in gcMarkingTracer. */
+    GCMarker gcmarker;
+
+    VerifyTracer(JSContext *cx) : nodemap(cx), gcmarker(cx) {}
+};
+
+/*
+ * This function builds up the heap snapshot by adding edges to the current
+ * node.
+ */
+static void
+AccumulateEdge(JSTracer *jstrc, void *thing, JSGCTraceKind kind)
+{
+    VerifyTracer *trc = (VerifyTracer *)jstrc;
+
+    trc->edgeptr += sizeof(EdgeValue);
+    if (trc->edgeptr >= trc->term) {
+        trc->edgeptr = trc->term;
+        return;
+    }
+
+    VerifyNode *node = trc->curnode;
+    uint32 i = node->count;
+
+    node->edges[i].thing = thing;
+    node->edges[i].kind = kind;
+    node->edges[i].label = trc->debugPrinter ? NULL : (char *)trc->debugPrintArg;
+    node->count++;
+}
+
+static VerifyNode *
+MakeNode(VerifyTracer *trc, void *thing, JSGCTraceKind kind)
+{
+    NodeMap::AddPtr p = trc->nodemap.lookupForAdd(thing);
+    if (!p) {
+        VerifyNode *node = (VerifyNode *)trc->edgeptr;
+        trc->edgeptr += sizeof(VerifyNode) - sizeof(EdgeValue);
+        if (trc->edgeptr >= trc->term) {
+            trc->edgeptr = trc->term;
+            return NULL;
+        }
+
+        node->thing = thing;
+        node->count = 0;
+        node->kind = kind;
+        trc->nodemap.add(p, thing, node);
+        return node;
+    }
+    return NULL;
+}
+
+static
+VerifyNode *
+NextNode(VerifyNode *node)
+{
+    if (node->count == 0)
+        return (VerifyNode *)((char *)node + sizeof(VerifyNode) - sizeof(EdgeValue));
+    else
+        return (VerifyNode *)((char *)node + sizeof(VerifyNode) +
+			      sizeof(EdgeValue)*(node->count - 1));
+}
+
+static void
+StartVerifyBarriers(JSContext *cx)
+{
+    JSRuntime *rt = cx->runtime;
+
+    if (rt->gcVerifyData)
+        return;
+
+    LeaveTrace(cx);
+
+    AutoLockGC lock(rt);
+    AutoGCSession gcsession(cx);
+
+#ifdef JS_THREADSAFE
+    rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
+#endif
+
+    AutoUnlockGC unlock(rt);
+
+    AutoCopyFreeListToArenas copy(rt);
+    RecordNativeStackTopForGC(cx);
+
+    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
+        r.front()->bitmap.clear();
+
+    /*
+     * Kick all frames on the stack into the interpreter, and release all JIT
+     * code in the compartment.
+     */
+#ifdef JS_METHODJIT
+    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
+        mjit::ClearAllFrames(*c);
+
+        for (CellIterUnderGC i(*c, FINALIZE_SCRIPT); !i.done(); i.next()) {
+            JSScript *script = i.get<JSScript>();
+            mjit::ReleaseScriptCode(cx, script);
+
+            /*
+             * Use counts for scripts are reset on GC. After discarding code we
+             * need to let it warm back up to get information like which opcodes
+             * are setting array holes or accessing getter properties.
+             */
+            script->resetUseCount();
+        }
+    }
+#endif
+
+    VerifyTracer *trc = new (js_malloc(sizeof(VerifyTracer))) VerifyTracer(cx);
+
+    rt->gcNumber++;
+    trc->number = rt->gcNumber;
+    trc->count = 0;
+
+    JS_TRACER_INIT(trc, cx, AccumulateEdge);
+
+    const size_t size = 64 * 1024 * 1024;
+    trc->root = (VerifyNode *)js_malloc(size);
+    JS_ASSERT(trc->root);
+    trc->edgeptr = (char *)trc->root;
+    trc->term = trc->edgeptr + size;
+
+    trc->nodemap.init();
+
+    /* Create the root node. */
+    trc->curnode = MakeNode(trc, NULL, JSGCTraceKind(0));
+
+    /* Make all the roots be edges emanating from the root node. */
+    MarkRuntime(trc);
+
+    VerifyNode *node = trc->curnode;
+    if (trc->edgeptr == trc->term)
+        goto oom;
+
+    /* For each edge, make a node for it if one doesn't already exist. */
+    while ((char *)node < trc->edgeptr) {
+        for (uint32 i = 0; i < node->count; i++) {
+            EdgeValue &e = node->edges[i];
+            VerifyNode *child = MakeNode(trc, e.thing, e.kind);
+            if (child) {
+                trc->curnode = child;
+                JS_TraceChildren(trc, e.thing, e.kind);
+            }
+            if (trc->edgeptr == trc->term)
+                goto oom;
+        }
+
+        node = NextNode(node);
+    }
+
+    rt->gcVerifyData = trc;
+    rt->gcIncrementalTracer = &trc->gcmarker;
+    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
+        (*c)->gcIncrementalTracer = &trc->gcmarker;
+        (*c)->needsBarrier_ = true;
+    }
+
+    return;
+
+oom:
+    js_free(trc->root);
+    trc->~VerifyTracer();
+    js_free(trc);
+}
+
+/*
+ * This function is called by EndVerifyBarriers for every heap edge. If the edge
+ * already existed in the original snapshot, we "cancel it out" by overwriting
+ * it with NULL. EndVerifyBarriers later asserts that the remaining non-NULL
+ * edges (i.e., the ones from the original snapshot that must have been
+ * modified) must point to marked objects.
+ */
+static void
+CheckEdge(JSTracer *jstrc, void *thing, JSGCTraceKind kind)
+{
+    VerifyTracer *trc = (VerifyTracer *)jstrc;
+    VerifyNode *node = trc->curnode;
+
+    for (uint32 i = 0; i < node->count; i++) {
+        if (node->edges[i].thing == thing) {
+            JS_ASSERT(node->edges[i].kind == kind);
+            node->edges[i].thing = NULL;
+            return;
+        }
+    }
+}
+
+static void
+EndVerifyBarriers(JSContext *cx)
+{
+    LeaveTrace(cx);
+
+    JSRuntime *rt = cx->runtime;
+
+    AutoLockGC lock(rt);
+    AutoGCSession gcsession(cx);
+
+#ifdef JS_THREADSAFE
+    rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
+#endif
+
+    AutoUnlockGC unlock(rt);
+
+    AutoCopyFreeListToArenas copy(rt);
+    RecordNativeStackTopForGC(cx);
+
+    VerifyTracer *trc = (VerifyTracer *)rt->gcVerifyData;
+
+    if (!trc)
+        return;
+
+    JS_ASSERT(trc->number == rt->gcNumber);
+
+    rt->gcIncrementalTracer->markDelayedChildren();
+
+    rt->gcVerifyData = NULL;
+    rt->gcIncrementalTracer = NULL;
+    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
+        (*c)->gcIncrementalTracer = NULL;
+        (*c)->needsBarrier_ = false;
+    }
+
+    JS_TRACER_INIT(trc, cx, CheckEdge);
+
+    /* Start after the roots. */
+    VerifyNode *node = NextNode(trc->root);
+    int count = 0;
+
+    while ((char *)node < trc->edgeptr) {
+        trc->curnode = node;
+        JS_TraceChildren(trc, node->thing, node->kind);
+
+        for (uint32 i = 0; i < node->count; i++) {
+            void *thing = node->edges[i].thing;
+            JS_ASSERT_IF(thing, static_cast<Cell *>(thing)->isMarked());
+        }
+
+        count++;
+        node = NextNode(node);
+    }
+
+    js_free(trc->root);
+    trc->~VerifyTracer();
+    js_free(trc);
+}
+
+void
+VerifyBarriers(JSContext *cx, bool always)
+{
+    if (cx->runtime->gcZeal() < ZealVerifierThreshold)
+        return;
+
+    uint32 freq = cx->runtime->gcZealFrequency;
+
+    JSRuntime *rt = cx->runtime;
+    if (VerifyTracer *trc = (VerifyTracer *)rt->gcVerifyData) {
+        if (++trc->count < freq && !always)
+            return;
+
+        EndVerifyBarriers(cx);
+    }
+    StartVerifyBarriers(cx);
+}
+
+#endif /* JS_GC_ZEAL */
+
 } /* namespace gc */
 
 } /* namespace js */
 
 #if JS_HAS_XML_SUPPORT
 extern size_t sE4XObjectsCreated;
 
 JSXML *
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -83,17 +83,17 @@ struct Shape;
 namespace gc {
 
 struct Arena;
 
 /*
  * This must be an upper bound, but we do not need the least upper bound, so
  * we just exclude non-background objects.
  */
-const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - (FINALIZE_OBJECT_LAST + 1) / 2;
+const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - FINALIZE_OBJECT_LIMIT / 2;
 
 const size_t ArenaShift = 12;
 const size_t ArenaSize = size_t(1) << ArenaShift;
 const size_t ArenaMask = ArenaSize - 1;
 
 /*
  * This is the maximum number of arenas we allow in the FreeCommitted state
  * before we trigger a GC_SHRINK to release free arenas to the OS.
@@ -1322,17 +1322,20 @@ js_ReserveObjects(JSContext *cx, size_t 
 
 extern JSBool
 js_LockGCThingRT(JSRuntime *rt, void *thing);
 
 extern void
 js_UnlockGCThingRT(JSRuntime *rt, void *thing);
 
 extern JS_FRIEND_API(bool)
-IsAboutToBeFinalized(JSContext *cx, const void *thing);
+IsAboutToBeFinalized(JSContext *cx, const js::gc::Cell *thing);
+
+extern bool
+IsAboutToBeFinalized(JSContext *cx, const js::Value &value);
 
 extern JS_FRIEND_API(bool)
 js_GCThingIsMarked(void *thing, uintN color);
 
 extern void
 js_TraceStackFrame(JSTracer *trc, js::StackFrame *fp);
 
 namespace js {
@@ -1773,16 +1776,35 @@ namespace gc {
 
 JSCompartment *
 NewCompartment(JSContext *cx, JSPrincipals *principals);
 
 /* Tries to run a GC no matter what (used for GC zeal). */
 void
 RunDebugGC(JSContext *cx);
 
+const int ZealPokeThreshold = 1;
+const int ZealAllocThreshold = 2;
+const int ZealVerifierThreshold = 4;
+
+#ifdef JS_GC_ZEAL
+
+/* Check that write barriers have been used correctly. See jsgc.cpp. */
+void
+VerifyBarriers(JSContext *cx, bool always = false);
+
+#else
+
+static inline void
+VerifyBarriers(JSContext *cx, bool always = false)
+{
+}
+
+#endif
+
 } /* namespace gc */
 
 static inline JSCompartment *
 GetObjectCompartment(JSObject *obj) { return reinterpret_cast<js::gc::Cell *>(obj)->compartment(); }
 
 } /* namespace js */
 
 #endif /* jsgc_h___ */
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -91,17 +91,17 @@ GetGCObjectFixedSlotsKind(size_t numFixe
 
     JS_ASSERT(numFixedSlots < SLOTS_TO_THING_KIND_LIMIT);
     return slotsToThingKind[numFixedSlots];
 }
 
 static inline bool
 IsBackgroundAllocKind(AllocKind kind)
 {
-    JS_ASSERT(kind <= FINALIZE_OBJECT_LAST);
+    JS_ASSERT(kind < FINALIZE_OBJECT_LIMIT);
     return kind % 2 == 1;
 }
 
 static inline AllocKind
 GetBackgroundAllocKind(AllocKind kind)
 {
     JS_ASSERT(!IsBackgroundAllocKind(kind));
     return (AllocKind) (kind + 1);
@@ -110,17 +110,17 @@ GetBackgroundAllocKind(AllocKind kind)
 /*
  * Try to get the next larger size for an object, keeping BACKGROUND
  * consistent.
  */
 static inline bool
 TryIncrementAllocKind(AllocKind *kindp)
 {
     size_t next = size_t(*kindp) + 2;
-    if (next > size_t(FINALIZE_OBJECT_LAST))
+    if (next >= size_t(FINALIZE_OBJECT_LIMIT))
         return false;
     *kindp = AllocKind(next);
     return true;
 }
 
 /* Get the number of fixed slots and initial capacity associated with a kind. */
 static inline size_t
 GetGCKindSlots(AllocKind thingKind)
@@ -162,17 +162,17 @@ GCPoke(JSContext *cx, Value oldval)
 #if 1
     cx->runtime->gcPoke = JS_TRUE;
 #else
     cx->runtime->gcPoke = oldval.isGCThing();
 #endif
 
 #ifdef JS_GC_ZEAL
     /* Schedule a GC to happen "soon" after a GC poke. */
-    if (cx->runtime->gcZeal())
+    if (cx->runtime->gcZeal() >= js::gc::ZealPokeThreshold)
         cx->runtime->gcNextScheduled = 1;
 #endif
 }
 
 /*
  * Invoke ArenaOp and CellOp on every arena and cell in a compartment which
  * have the specified thing kind.
  */
@@ -346,24 +346,27 @@ NewGCThing(JSContext *cx, js::gc::AllocK
     JS_ASSERT(!cx->runtime->gcRunning);
     JS_ASSERT(!JS_THREAD_DATA(cx)->noGCOrAllocationCheck);
 
 #ifdef JS_GC_ZEAL
     if (cx->runtime->needZealousGC())
         js::gc::RunDebugGC(cx);
 #endif
 
-    void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize);
-    return static_cast<T *>(t ? t : js::gc::ArenaLists::refillFreeList(cx, kind));
+    JSCompartment *comp = cx->compartment;
+    void *t = comp->arenas.allocateFromFreeList(kind, thingSize);
+    if (!t)
+        t = js::gc::ArenaLists::refillFreeList(cx, kind);
+    return static_cast<T *>(t);
 }
 
 inline JSObject *
 js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
 {
-    JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
+    JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind < js::gc::FINALIZE_OBJECT_LIMIT);
     JSObject *obj = NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
     if (obj)
         obj->earlyInit(js::gc::GetGCKindSlots(kind));
     return obj;
 }
 
 inline JSString *
 js_NewGCString(JSContext *cx)
@@ -383,20 +386,18 @@ js_NewGCExternalString(JSContext *cx)
     return NewGCThing<JSExternalString>(cx, js::gc::FINALIZE_EXTERNAL_STRING,
                                         sizeof(JSExternalString));
 }
 
 inline JSFunction*
 js_NewGCFunction(JSContext *cx)
 {
     JSFunction *fun = NewGCThing<JSFunction>(cx, js::gc::FINALIZE_FUNCTION, sizeof(JSFunction));
-    if (fun) {
-        fun->capacity = JSObject::FUN_CLASS_RESERVED_SLOTS;
-        fun->lastProp = NULL; /* Stops fun from being scanned until initializated. */
-    }
+    if (fun)
+        fun->earlyInit(JSObject::FUN_CLASS_RESERVED_SLOTS);
     return fun;
 }
 
 inline JSScript *
 js_NewGCScript(JSContext *cx)
 {
     return NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
 }
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -105,31 +105,31 @@ static inline void
 PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing);
 
 template<typename T>
 static inline void
 CheckMarkedThing(JSTracer *trc, T *thing)
 {
     JS_ASSERT(thing);
     JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
-    JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
+    JS_ASSERT_IF(trc->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
 
     JS_ASSERT(thing->isAligned());
 
     JS_ASSERT(thing->compartment());
-    JS_ASSERT(thing->compartment()->rt == trc->context->runtime);
+    JS_ASSERT(thing->compartment()->rt == trc->runtime);
 }
 
 template<typename T>
 void
 Mark(JSTracer *trc, T *thing)
 {
     CheckMarkedThing(trc, thing);
 
-    JSRuntime *rt = trc->context->runtime;
+    JSRuntime *rt = trc->runtime;
 
     JS_OPT_ASSERT_IF(rt->gcCheckCompartment,
                      thing->compartment() == rt->gcCheckCompartment ||
                      thing->compartment() == rt->atomsCompartment);
 
     /*
      * Don't mark things outside a compartment if we are in a per-compartment
      * GC.
@@ -143,175 +143,208 @@ Mark(JSTracer *trc, T *thing)
 
 #ifdef DEBUG
     trc->debugPrinter = NULL;
     trc->debugPrintArg = NULL;
 #endif
 }
 
 void
-MarkString(JSTracer *trc, JSString *str)
+MarkStringUnbarriered(JSTracer *trc, JSString *str, const char *name)
 {
     JS_ASSERT(str);
+    JS_SET_TRACING_NAME(trc, name);
     Mark(trc, str);
 }
 
 void
-MarkString(JSTracer *trc, JSString *str, const char *name)
+MarkString(JSTracer *trc, const MarkablePtr<JSString> &str, const char *name)
 {
-    JS_ASSERT(str);
-    JS_SET_TRACING_NAME(trc, name);
-    MarkString(trc, str);
+    MarkStringUnbarriered(trc, str.value, name);
 }
 
 void
-MarkObject(JSTracer *trc, JSObject &obj, const char *name)
+MarkAtom(JSTracer *trc, JSAtom *atom)
 {
     JS_ASSERT(trc);
-    JS_ASSERT(&obj);
-    JS_SET_TRACING_NAME(trc, name);
-    Mark(trc, &obj);
+    JS_ASSERT(atom);
+    Mark(trc, atom);
+}
+
+void
+MarkAtom(JSTracer *trc, JSAtom *atom, const char *name)
+{
+    MarkStringUnbarriered(trc, atom, name);
 }
 
 void
-MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name)
+MarkObjectUnbarriered(JSTracer *trc, JSObject *obj, const char *name)
 {
-    JSRuntime *rt = trc->context->runtime;
-    if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != obj.compartment())
-        return;
-
-    MarkObject(trc, obj, name);
+    JS_ASSERT(trc);
+    JS_ASSERT(obj);
+    JS_SET_TRACING_NAME(trc, name);
+    Mark(trc, obj);
 }
 
 void
-MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
-                      const void *arg, size_t index)
+MarkObjectWithPrinterUnbarriered(JSTracer *trc, JSObject *obj, JSTraceNamePrinter printer,
+                                 const void *arg, size_t index)
 {
     JS_ASSERT(trc);
-    JS_ASSERT(&obj);
+    JS_ASSERT(obj);
     JS_SET_TRACING_DETAILS(trc, printer, arg, index);
-    Mark(trc, &obj);
+    Mark(trc, obj);
 }
 
 void
-MarkScript(JSTracer *trc, JSScript *script, const char *name)
+MarkObject(JSTracer *trc, const MarkablePtr<JSObject> &obj, const char *name)
+{
+    MarkObjectUnbarriered(trc, obj.value, name);
+}
+
+void
+MarkScriptUnbarriered(JSTracer *trc, JSScript *script, const char *name)
 {
     JS_ASSERT(trc);
     JS_ASSERT(script);
     JS_SET_TRACING_NAME(trc, name);
     Mark(trc, script);
 }
 
 void
-MarkShape(JSTracer *trc, const Shape *shape, const char *name)
+MarkScript(JSTracer *trc, const MarkablePtr<JSScript> &script, const char *name)
+{
+    MarkScriptUnbarriered(trc, script.value, name);
+}
+
+void
+MarkShapeUnbarriered(JSTracer *trc, const Shape *shape, const char *name)
 {
     JS_ASSERT(trc);
     JS_ASSERT(shape);
     JS_SET_TRACING_NAME(trc, name);
     Mark(trc, shape);
 }
 
 void
-MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name)
+MarkShape(JSTracer *trc, const MarkablePtr<const Shape> &shape, const char *name)
+{
+    MarkShapeUnbarriered(trc, shape.value, name);
+}
+
+void
+MarkTypeObjectUnbarriered(JSTracer *trc, types::TypeObject *type, const char *name)
 {
     JS_ASSERT(trc);
     JS_ASSERT(type);
     JS_SET_TRACING_NAME(trc, name);
     if (type == &types::emptyTypeObject)
         return;
     Mark(trc, type);
 
     /*
      * Mark parts of a type object skipped by ScanTypeObject. ScanTypeObject is
      * only used for marking tracers; for tracers with a callback, if we
      * reenter through JS_TraceChildren then MarkChildren will *not* skip these
      * members, and we don't need to handle them here.
      */
     if (IS_GC_MARKING_TRACER(trc)) {
         if (type->singleton)
-            MarkObject(trc, *type->singleton, "type_singleton");
+            MarkObject(trc, type->singleton, "type_singleton");
         if (type->interpretedFunction)
-            MarkObject(trc, *type->interpretedFunction, "type_function");
+            MarkObject(trc, type->interpretedFunction, "type_function");
     }
 }
 
+void
+MarkTypeObject(JSTracer *trc, const MarkablePtr<types::TypeObject> &type, const char *name)
+{
+    MarkTypeObjectUnbarriered(trc, type.value, name);
+}
+
 #if JS_HAS_XML_SUPPORT
 void
-MarkXML(JSTracer *trc, JSXML *xml, const char *name)
+MarkXMLUnbarriered(JSTracer *trc, JSXML *xml, const char *name)
 {
     JS_ASSERT(trc);
     JS_ASSERT(xml);
     JS_SET_TRACING_NAME(trc, name);
     Mark(trc, xml);
 }
+
+void
+MarkXML(JSTracer *trc, const MarkablePtr<JSXML> &xml, const char *name)
+{
+    MarkXMLUnbarriered(trc, xml.value, name);
+}
 #endif
 
 void
 PushMarkStack(GCMarker *gcmarker, JSXML *thing)
 {
-    JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                     thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+    JS_OPT_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                     thing->compartment() == gcmarker->runtime->gcCurrentCompartment);
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushXML(thing);
 }
 
 void
 PushMarkStack(GCMarker *gcmarker, JSObject *thing)
 {
-    JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                     thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+    JS_OPT_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                     thing->compartment() == gcmarker->runtime->gcCurrentCompartment);
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 void
 PushMarkStack(GCMarker *gcmarker, JSFunction *thing)
 {
-    JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                     thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+    JS_OPT_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                     thing->compartment() == gcmarker->runtime->gcCurrentCompartment);
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 void
 PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
 {
-    JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                 thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+    JS_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                 thing->compartment() == gcmarker->runtime->gcCurrentCompartment);
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushType(thing);
 }
 
 void
 PushMarkStack(GCMarker *gcmarker, JSScript *thing)
 {
-    JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                 thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+    JS_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                 thing->compartment() == gcmarker->runtime->gcCurrentCompartment);
 
     /*
      * We mark scripts directly rather than pushing on the stack as they can
      * refer to other scripts only indirectly (like via nested functions) and
      * we cannot get to deep recursion.
      */
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         MarkChildren(gcmarker, thing);
 }
 
 static void
 ScanShape(GCMarker *gcmarker, const Shape *shape);
 
 void
 PushMarkStack(GCMarker *gcmarker, const Shape *thing)
 {
-    JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                     thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+    JS_OPT_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                     thing->compartment() == gcmarker->runtime->gcCurrentCompartment);
 
     /* We mark shapes directly rather than pushing on the stack. */
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         ScanShape(gcmarker, thing);
 }
 
 static void
 MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
@@ -320,88 +353,104 @@ MarkAtomRange(JSTracer *trc, size_t len,
         if (JSAtom *atom = vec[i]) {
             JS_SET_TRACING_INDEX(trc, name, i);
             Mark(trc, atom);
         }
     }
 }
 
 void
-MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name)
+MarkObjectRange(JSTracer *trc, size_t len, HeapPtr<JSObject> *vec, const char *name)
 {
     for (uint32 i = 0; i < len; i++) {
         if (JSObject *obj = vec[i]) {
             JS_SET_TRACING_INDEX(trc, name, i);
             Mark(trc, obj);
         }
     }
 }
 
 void
-MarkXMLRange(JSTracer *trc, size_t len, JSXML **vec, const char *name)
+MarkXMLRange(JSTracer *trc, size_t len, HeapPtr<JSXML> *vec, const char *name)
 {
     for (size_t i = 0; i < len; i++) {
         if (JSXML *xml = vec[i]) {
             JS_SET_TRACING_INDEX(trc, "xml_vector", i);
             Mark(trc, xml);
         }
     }
 }
 
 void
-MarkId(JSTracer *trc, jsid id)
+MarkIdUnbarriered(JSTracer *trc, jsid id)
 {
     if (JSID_IS_STRING(id))
         Mark(trc, JSID_TO_STRING(id));
     else if (JS_UNLIKELY(JSID_IS_OBJECT(id)))
         Mark(trc, JSID_TO_OBJECT(id));
 }
 
 void
-MarkId(JSTracer *trc, jsid id, const char *name)
+MarkIdUnbarriered(JSTracer *trc, jsid id, const char *name)
 {
     JS_SET_TRACING_NAME(trc, name);
-    MarkId(trc, id);
+    MarkIdUnbarriered(trc, id);
 }
 
 void
-MarkIdRange(JSTracer *trc, jsid *beg, jsid *end, const char *name)
+MarkId(JSTracer *trc, const HeapId &id, const char *name)
+{
+    JS_SET_TRACING_NAME(trc, name);
+    MarkIdUnbarriered(trc, id.get(), name);
+}
+
+void
+MarkIdRangeUnbarriered(JSTracer *trc, jsid *beg, jsid *end, const char *name)
 {
     for (jsid *idp = beg; idp != end; ++idp) {
         JS_SET_TRACING_INDEX(trc, name, (idp - beg));
-        MarkId(trc, *idp);
+        MarkIdUnbarriered(trc, *idp);
     }
 }
 
 void
-MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
+MarkIdRangeUnbarriered(JSTracer *trc, size_t len, jsid *vec, const char *name)
 {
-    MarkIdRange(trc, vec, vec + len, name);
+    MarkIdRangeUnbarriered(trc, vec, vec + len, name);
+}
+
+void
+MarkIdRange(JSTracer *trc, HeapId *beg, HeapId *end, const char *name)
+{
+    for (HeapId *idp = beg; idp != end; ++idp) {
+        JS_SET_TRACING_INDEX(trc, name, (idp - beg));
+        MarkIdUnbarriered(trc, *idp);
+    }
 }
 
 void
 MarkKind(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
     JS_ASSERT(thing);
     JS_ASSERT(kind == GetGCThingTraceKind(thing));
     switch (kind) {
       case JSTRACE_OBJECT:
         Mark(trc, reinterpret_cast<JSObject *>(thing));
         break;
       case JSTRACE_STRING:
-        MarkString(trc, reinterpret_cast<JSString *>(thing));
+        Mark(trc, reinterpret_cast<JSString *>(thing));
         break;
       case JSTRACE_SCRIPT:
         Mark(trc, static_cast<JSScript *>(thing));
         break;
       case JSTRACE_SHAPE:
         Mark(trc, reinterpret_cast<Shape *>(thing));
         break;
       case JSTRACE_TYPE_OBJECT:
-        MarkTypeObject(trc, reinterpret_cast<types::TypeObject *>(thing), "type_stack");
+        MarkTypeObjectUnbarriered(trc, reinterpret_cast<types::TypeObject *>(thing), "type_stack");
         break;
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_XML:
         Mark(trc, static_cast<JSXML *>(thing));
         break;
 #endif
     }
 }
@@ -412,65 +461,56 @@ MarkValueRaw(JSTracer *trc, const js::Va
 {
     if (v.isMarkable()) {
         JS_ASSERT(v.toGCThing());
         return MarkKind(trc, v.toGCThing(), v.gcKind());
     }
 }
 
 void
-MarkValue(JSTracer *trc, const js::Value &v, const char *name)
+MarkValueUnbarriered(JSTracer *trc, const js::Value &v, const char *name)
 {
     JS_SET_TRACING_NAME(trc, name);
     MarkValueRaw(trc, v);
 }
 
 void
-MarkCrossCompartmentValue(JSTracer *trc, const js::Value &v, const char *name)
+MarkValue(JSTracer *trc, const js::HeapValue &v, const char *name)
+{
+    MarkValueUnbarriered(trc, v, name);
+}
+
+void
+MarkCrossCompartmentValue(JSTracer *trc, const js::HeapValue &v, const char *name)
 {
     if (v.isMarkable()) {
         js::gc::Cell *cell = (js::gc::Cell *)v.toGCThing();
-        JSRuntime *rt = trc->context->runtime;
+        JSRuntime *rt = trc->runtime;
         if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
             return;
 
         MarkValue(trc, v, name);
     }
 }
 
 void
-MarkValueRange(JSTracer *trc, const Value *beg, const Value *end, const char *name)
+MarkValueRange(JSTracer *trc, const HeapValue *beg, const HeapValue *end, const char *name)
 {
-    for (const Value *vp = beg; vp < end; ++vp) {
+    for (const HeapValue *vp = beg; vp < end; ++vp) {
         JS_SET_TRACING_INDEX(trc, name, vp - beg);
-        MarkValueRaw(trc, *vp);
+        MarkValueRaw(trc, vp->get());
     }
 }
 
 void
-MarkValueRange(JSTracer *trc, size_t len, const Value *vec, const char *name)
+MarkValueRange(JSTracer *trc, size_t len, const HeapValue *vec, const char *name)
 {
     MarkValueRange(trc, vec, vec + len, name);
 }
 
-void
-MarkShapeRange(JSTracer *trc, const Shape **beg, const Shape **end, const char *name)
-{
-    for (const Shape **sp = beg; sp < end; ++sp) {
-        JS_SET_TRACING_INDEX(trc, name, sp - beg);
-        MarkShape(trc, *sp, name);
-    }
-}
-
-void
-MarkShapeRange(JSTracer *trc, size_t len, const Shape **vec, const char *name)
-{
-    MarkShapeRange(trc, vec, vec + len, name);
-}
-
 /* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
 void
 MarkGCThing(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
     if (!thing)
         return;
 
     MarkKind(trc, thing, kind);
@@ -480,23 +520,16 @@ void
 MarkGCThing(JSTracer *trc, void *thing)
 {
     if (!thing)
         return;
     MarkKind(trc, thing, GetGCThingTraceKind(thing));
 }
 
 void
-MarkGCThing(JSTracer *trc, void *thing, const char *name)
-{
-    JS_SET_TRACING_NAME(trc, name);
-    MarkGCThing(trc, thing);
-}
-
-void
 MarkGCThing(JSTracer *trc, void *thing, const char *name, size_t index)
 {
     JS_SET_TRACING_INDEX(trc, name, index);
     MarkGCThing(trc, thing);
 }
 
 void
 Mark(JSTracer *trc, void *thing, JSGCTraceKind kind, const char *name)
@@ -504,47 +537,114 @@ Mark(JSTracer *trc, void *thing, JSGCTra
     JS_ASSERT(thing);
     JS_SET_TRACING_NAME(trc, name);
     MarkKind(trc, thing, kind);
 }
 
 void
 MarkRoot(JSTracer *trc, JSObject *thing, const char *name)
 {
-    MarkObject(trc, *thing, name);
+    MarkObjectUnbarriered(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, JSString *thing, const char *name)
 {
-    MarkString(trc, thing, name);
+    MarkStringUnbarriered(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, JSScript *thing, const char *name)
 {
-    MarkScript(trc, thing, name);
+    MarkScriptUnbarriered(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, const Shape *thing, const char *name)
 {
-    MarkShape(trc, thing, name);
+    MarkShapeUnbarriered(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, types::TypeObject *thing, const char *name)
 {
-    MarkTypeObject(trc, thing, name);
+    MarkTypeObjectUnbarriered(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, JSXML *thing, const char *name)
 {
-    MarkXML(trc, thing, name);
+    MarkXMLUnbarriered(trc, thing, name);
+}
+
+void
+MarkRoot(JSTracer *trc, const Value &v, const char *name)
+{
+    MarkValueUnbarriered(trc, v, name);
+}
+
+void
+MarkRoot(JSTracer *trc, jsid id, const char *name)
+{
+    JS_SET_TRACING_NAME(trc, name);
+    MarkIdUnbarriered(trc, id);
+}
+
+void
+MarkRootGCThing(JSTracer *trc, void *thing, const char *name)
+{
+    JS_SET_TRACING_NAME(trc, name);
+    MarkGCThing(trc, thing);
+}
+
+void
+MarkRootRange(JSTracer *trc, size_t len, const Shape **vec, const char *name)
+{
+    const Shape **end = vec + len;
+    for (const Shape **sp = vec; sp < end; ++sp) {
+        JS_SET_TRACING_INDEX(trc, name, sp - vec);
+        MarkShapeUnbarriered(trc, *sp, name);
+    }
+}
+
+void
+MarkRootRange(JSTracer *trc, size_t len, JSObject **vec, const char *name)
+{
+    JSObject **end = vec + len;
+    for (JSObject **sp = vec; sp < end; ++sp) {
+        JS_SET_TRACING_INDEX(trc, name, sp - vec);
+        MarkObjectUnbarriered(trc, *sp, name);
+    }
+}
+
+void
+MarkRootRange(JSTracer *trc, const Value *beg, const Value *end, const char *name)
+{
+    for (const Value *vp = beg; vp < end; ++vp) {
+        JS_SET_TRACING_INDEX(trc, name, vp - beg);
+        MarkValueRaw(trc, *vp);
+    }
+}
+
+void
+MarkRootRange(JSTracer *trc, size_t len, const Value *vec, const char *name)
+{
+    MarkRootRange(trc, vec, vec + len, name);
+}
+
+void
+MarkRootRange(JSTracer *trc, jsid *beg, jsid *end, const char *name)
+{
+    MarkIdRangeUnbarriered(trc, beg, end, name);
+}
+
+void
+MarkRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
+{
+    MarkIdRangeUnbarriered(trc, len, vec, name);
 }
 
 static void
 PrintPropertyId(char *buf, size_t bufsize, jsid propid, const char *label)
 {
     JS_ASSERT(!JSID_IS_VOID(propid));
     if (JSID_IS_ATOM(propid)) {
         size_t n = PutEscapedString(buf, bufsize, JSID_TO_ATOM(propid), 0);
@@ -587,17 +687,17 @@ ScanValue(GCMarker *gcmarker, const Valu
         }
     }
 }
 
 static void
 ScanShape(GCMarker *gcmarker, const Shape *shape)
 {
 restart:
-    JSRuntime *rt = gcmarker->context->runtime;
+    JSRuntime *rt = gcmarker->runtime;
     if (rt->gcRegenShapes)
         shape->shapeid = js_RegenerateShapeForGC(rt);
 
     if (JSID_IS_STRING(shape->propid))
         PushMarkStack(gcmarker, JSID_TO_STRING(shape->propid));
     else if (JS_UNLIKELY(JSID_IS_OBJECT(shape->propid)))
         PushMarkStack(gcmarker, JSID_TO_OBJECT(shape->propid));
 
@@ -612,19 +712,19 @@ restart:
     shape = shape->previous();
     if (shape && shape->markIfUnmarked(gcmarker->getMarkColor()))
         goto restart;
 }
 
 static inline void
 ScanRope(GCMarker *gcmarker, JSRope *rope)
 {
-    JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                     rope->compartment() == gcmarker->context->runtime->gcCurrentCompartment
-                     || rope->compartment() == gcmarker->context->runtime->atomsCompartment);
+    JS_OPT_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                     rope->compartment() == gcmarker->runtime->gcCurrentCompartment
+                     || rope->compartment() == gcmarker->runtime->atomsCompartment);
     JS_ASSERT(rope->isMarked());
 
     JSString *leftChild = NULL;
     do {
         JSString *rightChild = rope->rightChild();
 
         if (rightChild->isRope()) {
             if (rightChild->markIfUnmarked())
@@ -640,19 +740,19 @@ ScanRope(GCMarker *gcmarker, JSRope *rop
         }
         rope = &leftChild->asRope();
     } while (leftChild->markIfUnmarked());
 }
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSString *str)
 {
-    JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
-                     str->compartment() == gcmarker->context->runtime->gcCurrentCompartment
-                     || str->compartment() == gcmarker->context->runtime->atomsCompartment);
+    JS_OPT_ASSERT_IF(gcmarker->runtime->gcCurrentCompartment,
+                     str->compartment() == gcmarker->runtime->gcCurrentCompartment
+                     || str->compartment() == gcmarker->runtime->atomsCompartment);
 
     if (str->isLinear()) {
         str->asLinear().mark(gcmarker);
     } else {
         JS_ASSERT(str->isRope());
         if (str->markIfUnmarked())
             ScanRope(gcmarker, &str->asRope());
     }
@@ -695,21 +795,21 @@ ScanObject(GCMarker *gcmarker, JSObject 
         if (obj->newType)
             PushMarkStack(gcmarker, obj->newType);
     }
 
     if (obj->isNative()) {
         js::Shape *shape = obj->lastProp;
         PushMarkStack(gcmarker, shape);
 
-        if (gcmarker->context->runtime->gcRegenShapes) {
+        if (gcmarker->runtime->gcRegenShapes) {
             /* We need to regenerate our shape if hasOwnShape(). */
             uint32 newShape = shape->shapeid;
             if (obj->hasOwnShape()) {
-                newShape = js_RegenerateShapeForGC(gcmarker->context->runtime);
+                newShape = js_RegenerateShapeForGC(gcmarker->runtime);
                 JS_ASSERT(newShape != shape->shapeid);
             }
             obj->objShape = newShape;
         }
 
         uint32 nslots = obj->slotSpan();
         JS_ASSERT(obj->slotSpan() <= obj->numSlots());
         if (nslots > LARGE_OBJECT_CHUNK_SIZE) {
@@ -756,18 +856,18 @@ MarkChildren(JSTracer *trc, JSObject *ob
     if (obj->isNewborn())
         return;
 
     MarkTypeObject(trc, obj->typeFromGC(), "type");
 
     /* Trace universal (ops-independent) members. */
     if (!obj->isDenseArray() && obj->newType)
         MarkTypeObject(trc, obj->newType, "new_type");
-    if (JSObject *parent = obj->getParent())
-        MarkObject(trc, *parent, "parent");
+    if (obj->parent)
+        MarkObject(trc, obj->parent, "parent");
 
     Class *clasp = obj->getClass();
     if (clasp->trace)
         clasp->trace(trc, obj);
 
     if (obj->isNative()) {
         MarkShape(trc, obj->lastProp, "shape");
 
@@ -778,36 +878,40 @@ MarkChildren(JSTracer *trc, JSObject *ob
             MarkValueRaw(trc, obj->nativeGetSlot(i));
         }
     }
 }
 
 void
 MarkChildren(JSTracer *trc, JSString *str)
 {
+    /*
+     * We use custom barriers in JSString, so it's safe to use unbarriered
+     * marking here.
+     */
     if (str->isDependent()) {
-        MarkString(trc, str->asDependent().base(), "base");
+        MarkStringUnbarriered(trc, str->asDependent().base(), "base");
     } else if (str->isRope()) {
         JSRope &rope = str->asRope();
-        MarkString(trc, rope.leftChild(), "left child");
-        MarkString(trc, rope.rightChild(), "right child");
+        MarkStringUnbarriered(trc, rope.leftChild(), "left child");
+        MarkStringUnbarriered(trc, rope.rightChild(), "right child");
     }
 }
 
 
 void
 MarkChildren(JSTracer *trc, JSScript *script)
 {
     CheckScript(script, NULL);
 
 #ifdef JS_CRASH_DIAGNOSTICS
-    JSRuntime *rt = trc->context->runtime;
+    JSRuntime *rt = trc->runtime;
     JS_OPT_ASSERT_IF(rt->gcCheckCompartment, script->compartment() == rt->gcCheckCompartment);
 #endif
-    
+
     MarkAtomRange(trc, script->natoms, script->atoms, "atoms");
 
     if (JSScript::isValidOffset(script->objectsOffset)) {
         JSObjectArray *objarray = script->objects();
         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
     }
 
     if (JSScript::isValidOffset(script->regexpsOffset)) {
@@ -815,18 +919,18 @@ MarkChildren(JSTracer *trc, JSScript *sc
         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
     }
 
     if (JSScript::isValidOffset(script->constOffset)) {
         JSConstArray *constarray = script->consts();
         MarkValueRange(trc, constarray->length, constarray->vector, "consts");
     }
 
-    if (!script->isCachedEval && script->u.globalObject)
-        MarkObject(trc, *script->u.globalObject, "object");
+    if (!script->isCachedEval && script->globalObject)
+        MarkObject(trc, script->globalObject, "object");
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 
     script->bindings.trace(trc);
 
     if (script->types)
         script->types->trace(trc);
@@ -834,22 +938,25 @@ MarkChildren(JSTracer *trc, JSScript *sc
 
 void
 MarkChildren(JSTracer *trc, const Shape *shape)
 {
 restart:
     MarkId(trc, shape->propid, "propid");
 
     if (shape->hasGetterValue() && shape->getter())
-        MarkObjectWithPrinter(trc, *shape->getterObject(), PrintPropertyGetterOrSetter, shape, 0);
+        MarkObjectWithPrinterUnbarriered(trc, shape->getterObject(),
+                                         PrintPropertyGetterOrSetter, shape, 0);
     if (shape->hasSetterValue() && shape->setter())
-        MarkObjectWithPrinter(trc, *shape->setterObject(), PrintPropertyGetterOrSetter, shape, 1);
+        MarkObjectWithPrinterUnbarriered(trc, shape->setterObject(),
+                                         PrintPropertyGetterOrSetter, shape, 1);
 
     if (shape->isMethod())
-        MarkObjectWithPrinter(trc, shape->methodObject(), PrintPropertyMethod, shape, 0);
+        MarkObjectWithPrinterUnbarriered(trc, &shape->methodObject(),
+                                         PrintPropertyMethod, shape, 0);
 
     shape = shape->previous();
     if (shape)
         goto restart;
 }
 
 static void
 ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
@@ -859,18 +966,17 @@ ScanTypeObject(GCMarker *gcmarker, types
         for (unsigned i = 0; i < count; i++) {
             types::Property *prop = type->getProperty(i);
             if (prop && JSID_IS_STRING(prop->id))
                 PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
         }
     }
 
     if (type->emptyShapes) {
-        int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
-        for (int i = 0; i < count; i++) {
+        for (unsigned i = 0; i < FINALIZE_OBJECT_LIMIT; i++) {
             if (type->emptyShapes[i])
                 PushMarkStack(gcmarker, type->emptyShapes[i]);
         }
     }
 
     if (type->proto)
         PushMarkStack(gcmarker, type->proto);
 
@@ -896,52 +1002,51 @@ MarkChildren(JSTracer *trc, types::TypeO
         for (unsigned i = 0; i < count; i++) {
             types::Property *prop = type->getProperty(i);
             if (prop)
                 MarkId(trc, prop->id, "type_prop");
         }
     }
 
     if (type->emptyShapes) {
-        int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
-        for (int i = 0; i < count; i++) {
+        for (unsigned i = 0; i < FINALIZE_OBJECT_LIMIT; i++) {
             if (type->emptyShapes[i])
                 MarkShape(trc, type->emptyShapes[i], "empty_shape");
         }
     }
 
     if (type->proto)
-        MarkObject(trc, *type->proto, "type_proto");
+        MarkObject(trc, type->proto, "type_proto");
 
     if (type->singleton)
-        MarkObject(trc, *type->singleton, "type_singleton");
+        MarkObject(trc, type->singleton, "type_singleton");
 
     if (type->newScript) {
-        MarkObject(trc, *type->newScript->fun, "type_new_function");
+        MarkObject(trc, type->newScript->fun, "type_new_function");
         MarkShape(trc, type->newScript->shape, "type_new_shape");
     }
 
     if (type->interpretedFunction)
-        MarkObject(trc, *type->interpretedFunction, "type_function");
+        MarkObject(trc, type->interpretedFunction, "type_function");
 }
 
 #ifdef JS_HAS_XML_SUPPORT
 void
 MarkChildren(JSTracer *trc, JSXML *xml)
 {
     js_TraceXML(trc, xml);
 }
 #endif
 
 } /* namespace gc */
 
 void
 GCMarker::drainMarkStack()
 {
-    JSRuntime *rt = context->runtime;
+    JSRuntime *rt = runtime;
     rt->gcCheckCompartment = rt->gcCurrentCompartment;
 
     while (!isMarkStackEmpty()) {
         while (!ropeStack.isEmpty())
             ScanRope(this, ropeStack.pop());
 
         while (!objStack.isEmpty())
             ScanObject(this, objStack.pop());
@@ -965,20 +1070,18 @@ GCMarker::drainMarkStack()
              */
             markDelayedChildren();
         }
     }
 
     rt->gcCheckCompartment = NULL;
 }
 
-} /* namespace js */
-
-JS_PUBLIC_API(void)
-JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
+void
+TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
     switch (kind) {
       case JSTRACE_OBJECT:
         MarkChildren(trc, static_cast<JSObject *>(thing));
         break;
 
       case JSTRACE_STRING:
         MarkChildren(trc, static_cast<JSString *>(thing));
@@ -999,34 +1102,43 @@ JS_TraceChildren(JSTracer *trc, void *th
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_XML:
         MarkChildren(trc, static_cast<JSXML *>(thing));
         break;
 #endif
     }
 }
 
+void
+CallTracer(JSTracer *trc, void *thing, JSGCTraceKind kind)
+{
+    JS_ASSERT(thing);
+    MarkKind(trc, thing, kind);
+}
+
+} /* namespace js */
+
 inline void
 JSObject::scanSlots(GCMarker *gcmarker)
 {
     /*
      * Scan the fixed slots and the dynamic slots separately, to avoid
      * branching inside nativeGetSlot().
      */
     JS_ASSERT(slotSpan() <= numSlots());
     unsigned i, nslots = slotSpan();
     if (slots) {
         unsigned nfixed = numFixedSlots();
         if (nslots > nfixed) {
-            Value *vp = fixedSlots();
+            HeapValue *vp = fixedSlots();
             for (i = 0; i < nfixed; i++, vp++)
                 ScanValue(gcmarker, *vp);
             vp = slots;
             for (; i < nslots; i++, vp++)
                 ScanValue(gcmarker, *vp);
             return;
         }
     }
     JS_ASSERT(nslots <= numFixedSlots());
-    Value *vp = fixedSlots();
+    HeapValue *vp = fixedSlots();
     for (i = 0; i < nslots; i++, vp++)
         ScanValue(gcmarker, *vp);
 }
--- a/js/src/jsgcmark.h
+++ b/js/src/jsgcmark.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * ***** 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/
@@ -40,115 +40,103 @@
 #ifndef jsgcmark_h___
 #define jsgcmark_h___
 
 #include "jsgc.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jslock.h"
 
-
+#include "gc/Barrier.h"
 #include "js/TemplateLib.h"
 
 namespace js {
 namespace gc {
 
 void
-MarkString(JSTracer *trc, JSString *str);
+MarkAtom(JSTracer *trc, JSAtom *str);
 
 void
-MarkString(JSTracer *trc, JSString *str, const char *name);
+MarkAtom(JSTracer *trc, JSAtom *str, const char *name);
+
+void
+MarkObjectUnbarriered(JSTracer *trc, JSObject *obj, const char *name);
+
+void
+MarkObject(JSTracer *trc, const MarkablePtr<JSObject> &obj, const char *name);
 
 void
-MarkObject(JSTracer *trc, JSObject &obj, const char *name);
+MarkStringUnbarriered(JSTracer *trc, JSString *str, const char *name);
 
-/*
- * Mark an object that may be in a different compartment from the compartment
- * being GC'd. (Although it won't be marked if it's in the wrong compartment.)
- */
 void
-MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name);
+MarkString(JSTracer *trc, const MarkablePtr<JSString> &str, const char *name);
 
 void
-MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
-		      const void *arg, size_t index);
+MarkScriptUnbarriered(JSTracer *trc, JSScript *script, const char *name);
 
 void
-MarkScript(JSTracer *trc, JSScript *script, const char *name);
+MarkScript(JSTracer *trc, const MarkablePtr<JSScript> &script, const char *name);
+
+void
+MarkShapeUnbarriered(JSTracer *trc, const Shape *shape, const char *name);
 
 void
-MarkShape(JSTracer *trc, const Shape *shape, const char *name);
+MarkShape(JSTracer *trc, const MarkablePtr<const Shape> &shape, const char *name);
+
+void
+MarkTypeObjectUnbarriered(JSTracer *trc, types::TypeObject *type, const char *name);
 
 void
-MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name);
+MarkTypeObject(JSTracer *trc, const MarkablePtr<types::TypeObject> &type, const char *name);
 
 void
-MarkXML(JSTracer *trc, JSXML *xml, const char *name);
+MarkXMLUnbarriered(JSTracer *trc, JSXML *xml, const char *name);
 
 void
-MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name);
+MarkXML(JSTracer *trc, const MarkablePtr<JSXML> &xml, const char *name);
 
 void
-MarkXMLRange(JSTracer *trc, size_t len, JSXML **vec, const char *name);
+MarkObjectRange(JSTracer *trc, size_t len, HeapPtr<JSObject> *vec, const char *name);
 
 void
-MarkId(JSTracer *trc, jsid id);
+MarkXMLRange(JSTracer *trc, size_t len, HeapPtr<JSXML> *vec, const char *name);
 
 void
-MarkId(JSTracer *trc, jsid id, const char *name);
+MarkId(JSTracer *trc, const HeapId &id, const char *name);
 
 void
-MarkIdRange(JSTracer *trc, jsid *beg, jsid *end, const char *name);
+MarkIdRange(JSTracer *trc, js::HeapId *beg, js::HeapId *end, const char *name);
 
 void
-MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
+MarkIdRangeUnbarriered(JSTracer *trc, size_t len, jsid *vec, const char *name);
+
+void
+MarkIdRangeUnbarriered(JSTracer *trc, jsid *beg, jsid *end, const char *name);
 
 void
 MarkKind(JSTracer *trc, void *thing, JSGCTraceKind kind);
 
 void
-MarkValueRaw(JSTracer *trc, const js::Value &v);
+MarkValueUnbarriered(JSTracer *trc, const js::Value &v, const char *name);
 
 void
-MarkValue(JSTracer *trc, const js::Value &v, const char *name);
+MarkValue(JSTracer *trc, const js::HeapValue &v, const char *name);
 
 /*
  * Mark a value that may be in a different compartment from the compartment
  * being GC'd. (Although it won't be marked if it's in the wrong compartment.)
  */
 void
-MarkCrossCompartmentValue(JSTracer *trc, const js::Value &v, const char *name);
-
-void
-MarkValueRange(JSTracer *trc, const Value *beg, const Value *end, const char *name);
-
-void
-MarkValueRange(JSTracer *trc, size_t len, const Value *vec, const char *name);
-
-void
-MarkShapeRange(JSTracer *trc, const Shape **beg, const Shape **end, const char *name);
+MarkCrossCompartmentValue(JSTracer *trc, const js::HeapValue &v, const char *name);
 
 void
-MarkShapeRange(JSTracer *trc, size_t len, const Shape **vec, const char *name);
-
-/* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
-void
-MarkGCThing(JSTracer *trc, void *thing, uint32 kind);
+MarkValueRange(JSTracer *trc, const HeapValue *beg, const HeapValue *end, const char *name);
 
 void
-MarkGCThing(JSTracer *trc, void *thing);
-
-void
-MarkGCThing(JSTracer *trc, void *thing, const char *name);
-
-void
-MarkGCThing(JSTracer *trc, void *thing, const char *name, size_t index);
-
-void
-Mark(JSTracer *trc, void *thing, uint32 kind, const char *name);
+MarkValueRange(JSTracer *trc, size_t len, const HeapValue *vec, const char *name);
 
 void
 MarkRoot(JSTracer *trc, JSObject *thing, const char *name);
 
 void
 MarkRoot(JSTracer *trc, JSString *thing, const char *name);
 
 void
@@ -159,16 +147,43 @@ MarkRoot(JSTracer *trc, const Shape *thi
 
 void
 MarkRoot(JSTracer *trc, types::TypeObject *thing, const char *name);
 
 void
 MarkRoot(JSTracer *trc, JSXML *thing, const char *name);
 
 void
+MarkRoot(JSTracer *trc, const Value &v, const char *name);
+
+void
+MarkRoot(JSTracer *trc, jsid id, const char *name);
+
+void
+MarkRootGCThing(JSTracer *trc, void *thing, const char *name);
+
+void
+MarkRootRange(JSTracer *trc, size_t len, const Shape **vec, const char *name);
+
+void
+MarkRootRange(JSTracer *trc, size_t len, JSObject **vec, const char *name);
+
+void
+MarkRootRange(JSTracer *trc, const Value *beg, const Value *end, const char *name);
+
+void
+MarkRootRange(JSTracer *trc, size_t len, const Value *vec, const char *name);
+
+void
+MarkRootRange(JSTracer *trc, jsid *beg, jsid *end, const char *name);
+
+void
+MarkRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
+
+void
 MarkChildren(JSTracer *trc, JSObject *obj);
 
 void
 MarkChildren(JSTracer *trc, JSString *str);
 
 void
 MarkChildren(JSTracer *trc, const Shape *shape);
 
@@ -179,43 +194,50 @@ void
 MarkChildren(JSTracer *trc, JSXML *xml);
 
 /*
  * Use function overloading to decide which function should be called based on
  * the type of the object. The static type is used at compile time to link to
  * the corresponding Mark/IsMarked function.
  */
 inline void
-Mark(JSTracer *trc, const js::Value &v, const char *name)
+Mark(JSTracer *trc, const js::HeapValue &v, const char *name)
 {
     MarkValue(trc, v, name);
 }
 
 inline void
-Mark(JSTracer *trc, JSObject *o, const char *name)
+Mark(JSTracer *trc, const MarkablePtr<JSObject> &o, const char *name)
 {
-    MarkObject(trc, *o, name);
+    MarkObject(trc, o, name);
 }
 
 inline bool
 IsMarked(JSContext *cx, const js::Value &v)
 {
     if (v.isMarkable())
-        return !IsAboutToBeFinalized(cx, v.toGCThing());
+        return !IsAboutToBeFinalized(cx, v);
     return true;
 }
 
 inline bool
 IsMarked(JSContext *cx, JSObject *o)
 {
     return !IsAboutToBeFinalized(cx, o);
 }
 
 inline bool
 IsMarked(JSContext *cx, Cell *cell)
 {
     return !IsAboutToBeFinalized(cx, cell);
 }
 
-}
-}
+} /* namespace gc */
+
+void
+TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind);
+
+void
+CallTracer(JSTracer *trc, void *thing, JSGCTraceKind kind);
+
+} /* namespace js */
 
 #endif
--- a/js/src/jsgcstats.cpp
+++ b/js/src/jsgcstats.cpp
@@ -42,16 +42,17 @@
 #include "jscntxt.h"
 #include "jsgcstats.h"
 #include "jsgc.h"
 #include "jsxml.h"
 #include "jsbuiltins.h"
 #include "jscompartment.h"
 
 #include "jsgcinlines.h"
+#include "jsobjinlines.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 
 #define UL(x)       ((unsigned long)(x))
 #define PERCENT(x,y)  (100.0 * (double) (x) / (double) (y))
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -469,16 +469,43 @@ TypeSet::print(JSContext *cx)
         for (unsigned i = 0; i < count; i++) {
             TypeObjectKey *object = getObject(i);
             if (object)
                 printf(" %s", TypeString(Type::ObjectType(object)));
         }
     }
 }
 
+bool
+TypeSet::propertyNeedsBarrier(JSContext *cx, jsid id)
+{
+    id = MakeTypeId(cx, id);
+
+    if (unknownObject())
+        return true;
+
+    for (unsigned i = 0; i < getObjectCount(); i++) {
+        if (getSingleObject(i))
+            return true;
+
+        if (types::TypeObject *otype = getTypeObject(i)) {
+            if (otype->unknownProperties())
+                return true;
+
+            if (types::TypeSet *propTypes = otype->maybeGetProperty(cx, id)) {
+                if (propTypes->needsBarrier(cx))
+                    return true;
+            }
+        }
+    }
+
+    addFreeze(cx);
+    return false;
+}
+
 /////////////////////////////////////////////////////////////////////
 // TypeSet constraints
 /////////////////////////////////////////////////////////////////////
 
 /* Standard subset constraint, propagate all types from one set to another. */
 class TypeConstraintSubset : public TypeConstraint
 {
 public:
@@ -1914,16 +1941,27 @@ TypeSet::hasGlobalObject(JSContext *cx, 
     }
 
     add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeGlobal>(
               cx->compartment->types.compiledScript, global), false);
 
     return true;
 }
 
+bool
+TypeSet::needsBarrier(JSContext *cx)
+{
+    bool result = unknownObject()
+               || getObjectCount() > 0
+               || hasAnyFlag(TYPE_FLAG_STRING);
+    if (!result)
+        addFreeze(cx);
+    return result;
+}
+
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
 TypeObject types::emptyTypeObject(NULL, false, true);
 
 void
 TypeCompartment::init(JSContext *cx)
@@ -2541,17 +2579,17 @@ struct types::ObjectTableKey
     jsid *ids;
     uint32 nslots;
     uint32 nfixed;
     JSObject *proto;
 
     typedef JSObject * Lookup;
 
     static inline uint32 hash(JSObject *obj) {
-        return (uint32) (JSID_BITS(obj->lastProperty()->propid) ^
+        return (uint32) (JSID_BITS(obj->lastProperty()->propid.get()) ^
                          obj->slotSpan() ^ obj->numFixedSlots() ^
                          ((uint32)(size_t)obj->getProto() >> 2));
     }
 
     static inline bool match(const ObjectTableKey &v, JSObject *obj) {
         if (obj->slotSpan() != v.nslots ||
             obj->numFixedSlots() != v.nfixed ||
             obj->getProto() != v.proto) {
@@ -3079,18 +3117,20 @@ TypeObject::clearNewScript(JSContext *cx
                 }
             }
 
             if (!finished)
                 obj->rollbackProperties(cx, numProperties);
         }
     }
 
-    cx->free_(newScript);
+    /* We NULL out newScript *before* freeing it so the write barrier works. */
+    TypeNewScript *savedNewScript = newScript;
     newScript = NULL;
+    cx->free_(savedNewScript);
 
     markStateChange(cx);
 }
 
 void
 TypeObject::print(JSContext *cx)
 {
     printf("%s : %s",
@@ -4735,17 +4775,17 @@ CheckNewScriptProperties(JSContext *cx, 
         return;
     }
 
     type->newScript->fun = fun;
     type->newScript->allocKind = kind;
     type->newScript->shape = baseobj->lastProperty();
 
     type->newScript->initializerList = (TypeNewScript::Initializer *)
-        ((char *) type->newScript + sizeof(TypeNewScript));
+        ((char *) type->newScript.get() + sizeof(TypeNewScript));
     PodCopy(type->newScript->initializerList, initializerList.begin(), initializerList.length());
 }
 
 /////////////////////////////////////////////////////////////////////
 // Printing
 /////////////////////////////////////////////////////////////////////
 
 void
@@ -5196,18 +5236,18 @@ TypeScript::SetScope(JSContext *cx, JSSc
      * marked as reentrant.
      */
     if (!parent->ensureHasTypes(cx, parentFun))
         return false;
     if (!parent->types->hasScope()) {
         if (!SetScope(cx, parent, scope->getParent()))
             return false;
         parent->nesting()->activeCall = scope;
-        parent->nesting()->argArray = call.argArray();
-        parent->nesting()->varArray = call.varArray();
+        parent->nesting()->argArray = Valueify(call.argArray());
+        parent->nesting()->varArray = Valueify(call.varArray());
     }
 
     JS_ASSERT(!script->types->nesting);
 
     /* Construct and link nesting information for the two functions. */
 
     script->types->nesting = cx->new_<TypeScriptNesting>();
     if (!script->types->nesting)
@@ -5714,17 +5754,17 @@ JSObject::makeNewType(JSContext *cx, JSF
 {
     JS_ASSERT(!newType);
 
     TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
                                                             JSProto_Object, this, unknown);
     if (!type)
         return;
 
-    newType = type;
+    newType.init(type);
     setDelegate();
 
     if (!cx->typeInferenceEnabled())
         return;
 
     AutoEnterTypeInference enter(cx);
 
     /*
@@ -6259,17 +6299,17 @@ JS_GetTypeInferenceObjectStats(void *obj
                     break;
             }
         }
     }
 
     if (object->emptyShapes) {
         size_t usable = usf(object->emptyShapes);
         stats->emptyShapes +=
-            usable ? usable : sizeof(EmptyShape*) * gc::FINALIZE_FUNCTION_AND_OBJECT_LAST;
+            usable ? usable : sizeof(EmptyShape*) * gc::FINALIZE_OBJECT_LIMIT;
     }
 
     /*
      * This counts memory that is in the temp pool but gets attributed
      * elsewhere.  See JS_GetTypeInferenceMemoryStats for more details.
      */
     size_t bytes = object->dynamicSize();
     stats->objects += bytes;
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -43,16 +43,17 @@
 #define jsinfer_h___
 
 #include "jsalloc.h"
 #include "jscell.h"
 #include "jsfriendapi.h"
 #include "jsprvtd.h"
 
 #include "ds/LifoAlloc.h"
+#include "gc/Barrier.h"
 #include "js/HashTable.h"
 
 namespace js {
 namespace types {
 
 /* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
 struct TypeObjectKey {
     static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
@@ -503,16 +504,25 @@ class TypeSet
     /* Get the single value which can appear in this type set, otherwise NULL. */
     JSObject *getSingleton(JSContext *cx, bool freeze = true);
 
     /* Whether all objects in this set are parented to a particular global. */
     bool hasGlobalObject(JSContext *cx, JSObject *global);
 
     inline void clearObjects();
 
+    /*
+     * Whether a location with this TypeSet needs a write barrier (i.e., whether
+     * it can hold GC things). The type set is frozen if no barrier is needed.
+     */
+    bool needsBarrier(JSContext *cx);
+
+    /* The type set is frozen if no barrier is needed. */
+    bool propertyNeedsBarrier(JSContext *cx, jsid id);
+
   private:
     uint32 baseObjectCount() const {
         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
     }
     inline void setBaseObjectCount(uint32 count);
 };
 
 /*
@@ -616,28 +626,23 @@ struct TypeBarrier
           singleton(singleton), singletonId(singletonId)
     {}
 };
 
 /* Type information about a property. */
 struct Property
 {
     /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
-    jsid id;
+    HeapId id;
 
     /* Possible types for this property, including types inherited from prototypes. */
     TypeSet types;
 
-    Property(jsid id)
-        : id(id)
-    {}
-
-    Property(const Property &o)
-        : id(o.id), types(o.types)
-    {}
+    inline Property(jsid id);
+    inline Property(const Property &o);
 
     static uint32 keyBits(jsid id) { return (uint32) JSID_BITS(id); }
     static jsid getKey(Property *p) { return p->id; }
 };
 
 /*
  * Information attached to a TypeObject if it is always constructed using 'new'
  * on a particular script. This is used to manage state related to the definite
@@ -645,26 +650,26 @@ struct Property
  * information which could change as the script executes (e.g. a scripted
  * setter is added to a prototype object), and we need to ensure both that the
  * appropriate type constraints are in place when necessary, and that we can
  * remove the definite property information and repair the JS stack if the
  * constraints are violated.
  */
 struct TypeNewScript
 {
-    JSFunction *fun;
+    HeapPtrFunction fun;
 
     /* Allocation kind to use for newly constructed objects. */
     gc::AllocKind allocKind;
 
     /*
      * Shape to use for newly constructed objects. Reflects all definite
      * properties the object will have.
      */
-    const Shape *shape;
+    HeapPtr<const Shape> shape;
 
     /*
      * Order in which properties become initialized. We need this in case a
      * scripted setter is added to one of the object's prototypes while it is
      * in the middle of being initialized, so we can walk the stack and fixup
      * any objects which look for in-progress objects which were prematurely
      * set with their final shape. Initialization can traverse stack frames,
      * in which case FRAME_PUSH/FRAME_POP are used.
@@ -677,16 +682,19 @@ struct TypeNewScript
             DONE
         } kind;
         uint32 offset;
         Initializer(Kind kind, uint32 offset)
           : kind(kind), offset(offset)
         {}
     };
     Initializer *initializerList;
+
+    static inline void writeBarrierPre(TypeNewScript *newScript);
+    static inline void writeBarrierPost(TypeNewScript *newScript, void *addr);
 };
 
 /*
  * Lazy type objects overview.
  *
  * Type objects which represent at most one JS object are constructed lazily.
  * These include types for native functions, standard classes, scripted
  * functions defined at the top level of global/eval scripts, and in some
@@ -709,37 +717,37 @@ struct TypeNewScript
  * type object itself, the type object is also destroyed, and the JS object
  * reverts to having a lazy type.
  */
 
 /* Type information about an object accessed by a script. */
 struct TypeObject : gc::Cell
 {
     /* Prototype shared by objects using this type. */
-    JSObject *proto;
+    HeapPtrObject proto;
 
     /*
      * Whether there is a singleton JS object with this type. That JS object
      * must appear in type sets instead of this; we include the back reference
      * here to allow reverting the JS object to a lazy type.
      */
-    JSObject *singleton;
+    HeapPtrObject singleton;
 
     /* Lazily filled array of empty shapes for each size of objects with this type. */
-    js::EmptyShape **emptyShapes;
+    HeapPtr<EmptyShape> *emptyShapes;
 
     /* Flags for this object. */
     TypeObjectFlags flags;
 
     /*
      * If non-NULL, objects of this type have always been constructed using
      * 'new' on the specified script, which adds some number of properties to
      * the object in a definite order before the object escapes.
      */
-    TypeNewScript *newScript;
+    HeapPtr<TypeNewScript> newScript;
 
     /*
      * Estimate of the contribution of this object to the type sets it appears in.
      * This is the sum of the sizes of those sets at the point when the object
      * was added.
      *
      * When the contribution exceeds the CONTRIBUTION_LIMIT, any type sets the
      * object is added to are instead marked as unknown. If we get to this point
@@ -778,17 +786,17 @@ struct TypeObject : gc::Cell
      *
      * We establish these by using write barriers on calls to setProperty and
      * defineProperty which are on native properties, and by using the inference
      * analysis to determine the side effects of code which is JIT-compiled.
      */
     Property **propertySet;
 
     /* If this is an interpreted function, the function object. */
-    JSFunction *interpretedFunction;
+    HeapPtrFunction interpretedFunction;
 
     inline TypeObject(JSObject *proto, bool isFunction, bool unknown);
 
     bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); }
 
     bool hasAnyFlags(TypeObjectFlags flags) {
         JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
         return !!(this->flags & flags);
@@ -863,16 +871,19 @@ struct TypeObject : gc::Cell
 
     /*
      * Type objects don't have explicit finalizers. Memory owned by a type
      * object pending deletion is released when weak references are sweeped
      * from all the compartment's type objects.
      */
     void finalize(JSContext *cx) {}
 
+    static inline void writeBarrierPre(TypeObject *type);
+    static inline void writeBarrierPost(TypeObject *type, void *addr);
+
   private:
     inline uint32 basePropertyCount() const;
     inline void setBasePropertyCount(uint32 count);
 
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(TypeObject, proto) == offsetof(js::shadow::TypeObject, proto));
     }
 };
@@ -979,18 +990,18 @@ struct TypeScriptNesting
     /*
      * If this is an outer function, pointers to the most recent activation's
      * arguments and variables arrays. These could be referring either to stack
      * values in activeCall's frame (if it has not finished yet) or to the
      * internal slots of activeCall (if the frame has finished). Pointers to
      * these fields can be embedded directly in JIT code (though remember to
      * use 'addDependency == true' when calling resolveNameAccess).
      */
-    Value *argArray;
-    Value *varArray;
+    const Value *argArray;
+    const Value *varArray;
 
     /* Number of frames for this function on the stack. */
     uint32 activeFrames;
 
     TypeScriptNesting() { PodZero(this); }
     ~TypeScriptNesting();
 };
 
@@ -1005,42 +1016,40 @@ void NestingEpilogue(StackFrame *fp);
 class TypeScript
 {
     friend struct ::JSScript;
 
     /* Analysis information for the script, cleared on each GC. */
     analyze::ScriptAnalysis *analysis;
 
     /* Function for the script, if it has one. */
-    JSFunction *function;
+    HeapPtrFunction function;
 
     /*
      * Information about the scope in which a script executes. This information
      * is not set until the script has executed at least once and SetScope
      * called, before that 'global' will be poisoned per GLOBAL_MISSING_SCOPE.
      */
     static const size_t GLOBAL_MISSING_SCOPE = 0x1;
 
     /* Global object for the script, if compileAndGo. */
-    js::GlobalObject *global;
+    HeapPtr<GlobalObject> global;
 
   public:
 
     /* Nesting state for outer or inner function scripts. */
     TypeScriptNesting *nesting;
 
     /* Dynamic types generated at points within this script. */
     TypeResult *dynamicList;
 
-    TypeScript(JSFunction *fun) {
-        this->function = fun;
-        this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
-    }
+    inline TypeScript(JSFunction *fun);
+    inline ~TypeScript();
 
-    bool hasScope() { return size_t(global) != GLOBAL_MISSING_SCOPE; }
+    bool hasScope() { return size_t(global.get()) != GLOBAL_MISSING_SCOPE; }
 
     /* Array of type type sets for variables and JOF_TYPESET ops. */
     TypeSet *typeArray() { return (TypeSet *) (jsuword(this) + sizeof(TypeScript)); }
 
     static inline unsigned NumTypeSets(JSScript *script);
 
     static bool SetScope(JSContext *cx, JSScript *script, JSObject *scope);
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -66,17 +66,17 @@ Type::ObjectType(JSObject *obj)
         return Type((jsuword) obj | 1);
     return Type((jsuword) obj->type());
 }
 
 /* static */ inline Type
 Type::ObjectType(TypeObject *obj)
 {
     if (obj->singleton)
-        return Type((jsuword) obj->singleton | 1);
+        return Type((jsuword) obj->singleton.get() | 1);
     return Type((jsuword) obj);
 }
 
 /* static */ inline Type
 Type::ObjectType(TypeObjectKey *obj)
 {
     return Type((jsuword) obj);
 }
@@ -454,16 +454,28 @@ UseNewTypeAtEntry(JSContext *cx, StackFr
            fp->prev() && fp->prev()->isScriptFrame() &&
            UseNewType(cx, fp->prev()->script(), fp->prev()->pcQuadratic(cx->stack, fp));
 }
 
 /////////////////////////////////////////////////////////////////////
 // Script interface functions
 /////////////////////////////////////////////////////////////////////
 
+inline
+TypeScript::TypeScript(JSFunction *fun)
+  : function(fun),
+    global((js::GlobalObject *) GLOBAL_MISSING_SCOPE)
+{
+}
+
+inline
+TypeScript::~TypeScript()
+{
+}
+
 /* static */ inline unsigned
 TypeScript::NumTypeSets(JSScript *script)
 {
     return script->nTypeSets + analyze::TotalSlots(script);
 }
 
 /* static */ inline TypeSet *
 TypeScript::ReturnTypes(JSScript *script)
@@ -684,19 +696,19 @@ TypeScript::SetArgument(JSContext *cx, J
         SetArgument(cx, script, arg, type);
     }
 }
 
 void
 TypeScript::trace(JSTracer *trc)
 {
     if (function)
-        gc::MarkObject(trc, *function, "script_fun");
+        gc::MarkObject(trc, function, "script_fun");
     if (hasScope() && global)
-        gc::MarkObject(trc, *global, "script_global");
+        gc::MarkObject(trc, global, "script_global");
 
     /* Note: nesting does not keep anything alive. */
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
@@ -1247,16 +1259,66 @@ TypeObject::getGlobal()
 {
     if (singleton)
         return singleton->getGlobal();
     if (interpretedFunction && interpretedFunction->script()->compileAndGo)
         return interpretedFunction->getGlobal();
     return NULL;
 }
 
+inline void
+TypeObject::writeBarrierPre(TypeObject *type)
+{
+#ifdef JSGC_INCREMENTAL
+    if (!type || type == &js::types::emptyTypeObject)
+        return;
+
+    JSCompartment *comp = type->compartment();
+    if (comp->needsBarrier())
+        MarkTypeObjectUnbarriered(comp->barrierTracer(), type, "write barrier");
+#endif
+}
+
+inline void
+TypeObject::writeBarrierPost(TypeObject *type, void *addr)
+{
+}
+
+inline void
+TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
+{
+#ifdef JSGC_INCREMENTAL
+    if (!newScript)
+        return;
+
+    JSCompartment *comp = newScript->fun->compartment();
+    if (comp->needsBarrier()) {
+        MarkObjectUnbarriered(comp->barrierTracer(), newScript->fun, "write barrier");
+        MarkShapeUnbarriered(comp->barrierTracer(), newScript->shape, "write barrier");
+    }
+#endif
+}
+
+inline void
+TypeNewScript::writeBarrierPost(TypeNewScript *newScript, void *addr)
+{
+}
+
+inline
+Property::Property(jsid id)
+  : id(id)
+{
+}
+
+inline
+Property::Property(const Property &o)
+  : id(o.id.get()), types(o.types)
+{
+}
+
 } } /* namespace js::types */
 
 inline bool
 JSScript::ensureHasTypes(JSContext *cx, JSFunction *fun)
 {
     return types || makeTypes(cx, fun);
 }
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -447,18 +447,18 @@ js::BoxNonStrictThis(JSContext *cx, cons
 #if JS_HAS_NO_SUCH_METHOD
 
 const uint32 JSSLOT_FOUND_FUNCTION  = 0;
 const uint32 JSSLOT_SAVED_ID        = 1;
 
 static void
 no_such_method_trace(JSTracer *trc, JSObject *obj)
 {
-    gc::MarkValue(trc, obj->getSlot(JSSLOT_FOUND_FUNCTION), "found function");
-    gc::MarkValue(trc, obj->getSlot(JSSLOT_SAVED_ID), "saved id");
+    gc::MarkValue(trc, obj->getSlotRef(JSSLOT_FOUND_FUNCTION), "found function");
+    gc::MarkValue(trc, obj->getSlotRef(JSSLOT_SAVED_ID), "saved id");
 }
 
 Class js_NoSuchMethodClass = {
     "NoSuchMethod",
     JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
@@ -1585,16 +1585,18 @@ TypeCheckNextBytecode(JSContext *cx, JSS
 JS_NEVER_INLINE bool
 js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
 {
 #ifdef MOZ_TRACEVIS
     TraceVisStateObj tvso(cx, S_INTERP);
 #endif
     JSAutoResolveFlags rf(cx, RESOLVE_INFER);
 
+    gc::VerifyBarriers(cx, true);
+
     JS_ASSERT(!cx->compartment->activeAnalysis);
 
 #define ENABLE_PCCOUNT_INTERRUPTS()     JS_BEGIN_MACRO                        \
                                             if (pcCounts)                     \
                                                 ENABLE_INTERRUPTS();          \
                                         JS_END_MACRO
 
 #if JS_THREADED_INTERP
@@ -1631,16 +1633,17 @@ js::Interpret(JSContext *cx, StackFrame 
     JS_ASSERT_IF(TRACE_RECORDER(cx), jumpTable == interruptJumpTable)
 # else
 #  define CHECK_RECORDER()  ((void)0)
 # endif
 
 # define DO_OP()            JS_BEGIN_MACRO                                    \
                                 CHECK_RECORDER();                             \
                                 CHECK_PCCOUNT_INTERRUPTS();                   \
+                                js::gc::VerifyBarriers(cx);                   \
                                 JS_EXTENSION_(goto *jumpTable[op]);           \
                             JS_END_MACRO
 # define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
                                 TypeCheckNextBytecode(cx, script, n, regs);   \
                                 op = (JSOp) *(regs.pc += (n));                \
                                 DO_OP();                                      \
                             JS_END_MACRO
 
@@ -1962,16 +1965,17 @@ js::Interpret(JSContext *cx, StackFrame 
         len = 1;
       advance_pc:
         regs.pc += len;
         op = (JSOp) *regs.pc;
 
       do_op:
         CHECK_RECORDER();
         CHECK_PCCOUNT_INTERRUPTS();
+        js::gc::VerifyBarriers(cx);
         switchOp = intN(op) | switchMask;
       do_switch:
         switch (switchOp) {
 #endif
 
 #if JS_THREADED_INTERP
   interrupt:
 #else /* !JS_THREADED_INTERP */
@@ -6123,16 +6127,17 @@ END_CASE(JSOP_ARRAYPUSH)
 #ifdef JS_METHODJIT
     /*
      * This path is used when it's guaranteed the method can be finished
      * inside the JIT.
      */
   leave_on_safe_point:
 #endif
 
+    gc::VerifyBarriers(cx, true);
     return interpReturnOK;
 
   atom_not_defined:
     {
         JSAutoByteString printable;
         if (js_AtomToPrintableString(cx, atomNotDefined, &printable))
             js_ReportIsNotDefined(cx, printable.ptr());
     }
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -119,28 +119,28 @@ Class js::IteratorClass = {
     }
 };
 
 void
 NativeIterator::mark(JSTracer *trc)
 {
     MarkIdRange(trc, begin(), end(), "props");
     if (obj)
-        MarkObject(trc, *obj, "obj");
+        MarkObject(trc, obj, "obj");
 }
 
 static void
 iterator_finalize(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isIterator());
 
     NativeIterator *ni = obj->getNativeIterator();
     if (ni) {
+        obj->setPrivate(NULL);
         cx->free_(ni);
-        obj->setNativeIterator(NULL);
     }
 }
 
 static void
 iterator_trace(JSTracer *trc, JSObject *obj)
 {
     NativeIterator *ni = obj->getNativeIterator();
 
@@ -332,17 +332,19 @@ js::VectorToIdArray(JSContext *cx, AutoI
     size_t len = props.length();
     size_t idsz = len * sizeof(jsid);
     size_t sz = (sizeof(JSIdArray) - sizeof(jsid)) + idsz;
     JSIdArray *ida = static_cast<JSIdArray *>(cx->malloc_(sz));
     if (!ida)
         return false;
 
     ida->length = static_cast<jsint>(len);
-    memcpy(ida->vector, props.begin(), idsz);
+    jsid *v = props.begin();
+    for (jsint i = 0; i < ida->length; i++)
+        ida->vector[i].init(v[i]);
     *idap = ida;
     return true;
 }
 
 JS_FRIEND_API(bool)
 js::GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props)
 {
     return Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props);
@@ -436,27 +438,29 @@ NewIteratorObject(JSContext *cx, uintN f
 NativeIterator *
 NativeIterator::allocateIterator(JSContext *cx, uint32 slength, const AutoIdVector &props)
 {
     size_t plength = props.length();
     NativeIterator *ni = (NativeIterator *)
         cx->malloc_(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32));
     if (!ni)
         return NULL;
-    ni->props_array = ni->props_cursor = (jsid *) (ni + 1);
-    ni->props_end = (jsid *)ni->props_array + plength;
-    if (plength)
-        memcpy(ni->props_array, props.begin(), plength * sizeof(jsid));
+    ni->props_array = ni->props_cursor = (HeapId *) (ni + 1);
+    ni->props_end = ni->props_array + plength;
+    if (plength) {
+        for (size_t i = 0; i < plength; i++)
+            ni->props_array[i].init(props[i]);
+    }
     return ni;
 }
 
 inline void
 NativeIterator::init(JSObject *obj, uintN flags, uint32 slength, uint32 key)
 {
-    this->obj = obj;
+    this->obj.init(obj);
     this->flags = flags;
     this->shapes_array = (uint32 *) this->props_end;
     this->shapes_length = slength;
     this->shapes_key = key;
 }
 
 static inline void
 RegisterEnumerator(JSContext *cx, JSObject *iterobj, NativeIterator *ni)
@@ -848,19 +852,19 @@ SuppressDeletedPropertyHelper(JSContext 
 {
     JSObject *iterobj = cx->enumerators;
     while (iterobj) {
       again:
         NativeIterator *ni = iterobj->getNativeIterator();
         /* This only works for identified surpressed keys, not values. */
         if (ni->isKeyIter() && ni->obj == obj && ni->props_cursor < ni->props_end) {
             /* Check whether id is still to come. */
-            jsid *props_cursor = ni->current();
-            jsid *props_end = ni->end();
-            for (jsid *idp = props_cursor; idp < props_end; ++idp) {
+            HeapId *props_cursor = ni->current();
+            HeapId *props_end = ni->end();
+            for (HeapId *idp = props_cursor; idp < props_end; ++idp) {
                 if (predicate(*idp)) {
                     /*
                      * Check whether another property along the prototype chain
                      * became visible as a result of this deletion.
                      */
                     if (obj->getProto()) {
                         AutoObjectRooter proto(cx, obj->getProto());
                         AutoObjectRooter obj2(cx);
@@ -889,17 +893,18 @@ SuppressDeletedPropertyHelper(JSContext 
                     /*
                      * No property along the prototype chain stepped in to take the
                      * property's place, so go ahead and delete id from the list.
                      * If it is the next property to be enumerated, just skip it.
                      */
                     if (idp == props_cursor) {
                         ni->incCursor();
                     } else {
-                        memmove(idp, idp + 1, (props_end - (idp + 1)) * sizeof(jsid));
+                        for (HeapId *p = idp; p + 1 != props_end; p++)
+                            *p = *(p + 1);
                         ni->props_end = ni->end() - 1;
                     }
 
                     /* Don't reuse modified native iterators. */
                     ni->flags |= JSITER_UNREUSABLE;
 
                     if (predicate.matchesAtMostOne())
                         break;
@@ -1105,42 +1110,62 @@ generator_finalize(JSContext *cx, JSObje
      */
     JS_ASSERT(gen->state == JSGEN_NEWBORN ||
               gen->state == JSGEN_CLOSED ||
               gen->state == JSGEN_OPEN);
     cx->free_(gen);
 }
 
 static void
+MarkGenerator(JSTracer *trc, JSGenerator *gen)
+{
+    StackFrame *fp = gen->floatingFrame();
+
+    /*
+     * MarkGenerator should only be called when regs is based on the floating frame.
+     * See calls to RebaseRegsFromTo.
+     */
+    JS_ASSERT(size_t(gen->regs.sp - fp->slots()) <= fp->numSlots());
+
+    /*
+     * Currently, generators are not mjitted. Still, (overflow) args can be
+     * pushed by the mjit and need to be conservatively marked. Technically, the
+     * formal args and generator slots are safe for exact marking, but since the
+     * plan is to eventually mjit generators, it makes sense to future-proof
+     * this code and save someone an hour later.
+     */
+    MarkStackRangeConservatively(trc, gen->floatingStack, fp->formalArgsEnd());
+    js_TraceStackFrame(trc, fp);
+    MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp);
+}
+
+static void
+GeneratorWriteBarrierPre(JSContext *cx, JSGenerator *gen)
+{
+    JSCompartment *comp = cx->compartment;
+    if (comp->needsBarrier())
+        MarkGenerator(comp->barrierTracer(), gen);
+}
+
+static void
 generator_trace(JSTracer *trc, JSObject *obj)
 {
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen)
         return;
 
     /*
      * Do not mark if the generator is running; the contents may be trash and
      * will be replaced when the generator stops.
      */
     if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING)
         return;
 
-    StackFrame *fp = gen->floatingFrame();
-    JS_ASSERT(gen->liveFrame() == fp);
-
-    /*
-     * Currently, generators are not mjitted. Still, (overflow) args can be
-     * pushed by the mjit and need to be conservatively marked. Technically, the
-     * formal args and generator slots are safe for exact marking, but since the
-     * plan is to eventually mjit generators, it makes sense to future-proof
-     * this code and save someone an hour later.
-     */
-    MarkStackRangeConservatively(trc, gen->floatingStack, fp->formalArgsEnd());
-    js_TraceStackFrame(trc, fp);
-    MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp);
+    JS_ASSERT(gen->liveFrame() == gen->floatingFrame());
+    MarkGenerator(trc, gen);
 }
 
 Class js::GeneratorClass = {
     "Generator",
     JSCLASS_HAS_PRIVATE,
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
@@ -1204,17 +1229,17 @@ js_NewGenerator(JSContext *cx)
     if (!gen)
         return NULL;
 
     /* Cut up floatingStack space. */
     Value *genvp = gen->floatingStack;
     StackFrame *genfp = reinterpret_cast<StackFrame *>(genvp + vplen);
 
     /* Initialize JSGenerator. */
-    gen->obj = obj;
+    gen->obj.init(obj);
     gen->state = JSGEN_NEWBORN;
     gen->enumerators = NULL;
     gen->floating = genfp;
 
     /* Copy from the stack to the generator's floating frame. */
     gen->regs.rebaseFromTo(stackRegs, *genfp);
     genfp->stealFrameAndSlots(genvp, stackfp, stackvp, stackRegs.sp);
     genfp->initFloatingGenerator();
@@ -1253,16 +1278,29 @@ SendToGenerator(JSContext *cx, JSGenerat
                             JS_GetFunctionId(gen->floatingFrame()->fun()));
         return JS_FALSE;
     }
 
     /* Check for OOM errors here, where we can fail easily. */
     if (!cx->ensureGeneratorStackSpace())
         return JS_FALSE;
 
+    /*
+     * Write barrier is needed since the generator stack can be updated,
+     * and it's not barriered in any other way. We need to do it before
+     * gen->state changes, which can cause us to trace the generator
+     * differently.
+     *
+     * We could optimize this by setting a bit on the generator to signify
+     * that it has been marked. If this bit has already been set, there is no
+     * need to mark again. The bit would have to be reset before the next GC,
+     * or else some kind of epoch scheme would have to be used.
+     */
+    GeneratorWriteBarrierPre(cx, gen);
+
     JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
     switch (op) {
       case JSGENOP_NEXT:
       case JSGENOP_SEND:
         if (gen->state == JSGEN_OPEN) {
             /*
              * Store the argument to send as the result of the yield
              * expression.
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -43,53 +43,54 @@
 /*
  * JavaScript iterators.
  */
 #include "jscntxt.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsversion.h"
 
+#include "gc/Barrier.h"
 #include "vm/Stack.h"
 
 /*
  * For cacheable native iterators, whether the iterator is currently active.
  * Not serialized by XDR.
  */
 #define JSITER_ACTIVE       0x1000
 #define JSITER_UNREUSABLE   0x2000
 
 namespace js {
 
 struct NativeIterator {
-    JSObject  *obj;
-    jsid      *props_array;
-    jsid      *props_cursor;
-    jsid      *props_end;
+    HeapPtrObject  obj;
+    HeapId    *props_array;
+    HeapId    *props_cursor;
+    HeapId    *props_end;
     uint32    *shapes_array;
     uint32    shapes_length;
     uint32    shapes_key;
     uint32    flags;
     JSObject  *next;  /* Forms cx->enumerators list, garbage otherwise. */
 
     bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
 
-    inline jsid *begin() const {
+    inline HeapId *begin() const {
         return props_array;
     }
 
-    inline jsid *end() const {
+    inline HeapId *end() const {
         return props_end;
     }
 
     size_t numKeys() const {
         return end() - begin();
     }
 
-    jsid *current() const {
+    HeapId *current() const {
         JS_ASSERT(props_cursor < props_end);
         return props_cursor;
     }
 
     void incCursor() {
         props_cursor = props_cursor + 1;
     }
 
@@ -165,17 +166,17 @@ typedef enum JSGeneratorState {
     JSGEN_NEWBORN,  /* not yet started */
     JSGEN_OPEN,     /* started by a .next() or .send(undefined) call */
     JSGEN_RUNNING,  /* currently executing via .next(), etc., call */
     JSGEN_CLOSING,  /* close method is doing asynchronous return */
     JSGEN_CLOSED    /* closed, cannot be started or closed again */
 } JSGeneratorState;
 
 struct JSGenerator {
-    JSObject            *obj;
+    js::HeapPtrObject   obj;
     JSGeneratorState    state;
     js::FrameRegs       regs;
     JSObject            *enumerators;
     js::StackFrame      *floating;
     js::Value           floatingStack[1];
 
     js::StackFrame *floatingFrame() {
         return floating;
--- a/js/src/jslock.cpp
+++ b/js/src/jslock.cpp
@@ -56,16 +56,18 @@
 #include "jsutil.h"
 #include "jsstdint.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jslock.h"
 #include "jsscope.h"
 #include "jsstr.h"
 
+#include "jsscopeinlines.h"
+
 using namespace js;
 
 #define ReadWord(W) (W)
 
 #if !defined(__GNUC__)
 # define __asm__ asm
 # define __volatile__ volatile
 #endif
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -458,17 +458,17 @@ js_LeaveSharpObject(JSContext *cx, JSIdA
             *idap = NULL;
         }
     }
 }
 
 static intN
 gc_sharp_table_entry_marker(JSHashEntry *he, intN i, void *arg)
 {
-    MarkObject((JSTracer *)arg, *(JSObject *)he->key, "sharp table entry");
+    MarkRoot((JSTracer *)arg, (JSObject *)he->key, "sharp table entry");
     return JS_DHASH_NEXT;
 }
 
 void
 js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map)
 {
     JS_ASSERT(map->depth > 0);
     JS_ASSERT(map->table);
@@ -1056,41 +1056,41 @@ EvalCacheLookup(JSContext *cx, JSLinearS
                             i = 0;
                         } else {
                             i = -1;
                         }
                     }
                     if (i < 0 ||
                         objarray->vector[i]->getParent() == &scopeobj) {
                         JS_ASSERT(staticLevel == script->staticLevel);
-                        *scriptp = script->u.evalHashLink;
-                        script->u.evalHashLink = NULL;
+                        *scriptp = script->evalHashLink();
+                        script->evalHashLink() = NULL;
                         return script;
                     }
                 }
             }
         }
 
         if (++count == EVAL_CACHE_CHAIN_LIMIT)
             return NULL;
-        scriptp = &script->u.evalHashLink;
+        scriptp = &script->evalHashLink();
     }
     return NULL;
 }
 
 /*
  * There are two things we want to do with each script executed in EvalKernel:
  *  1. notify jsdbgapi about script creation/destruction
  *  2. add the script to the eval cache when EvalKernel is finished
  *
  * NB: Although the eval cache keeps a script alive wrt to the JS engine, from
  * a jsdbgapi user's perspective, we want each eval() to create and destroy a
  * script. This hides implementation details and means we don't have to deal
  * with calls to JS_GetScriptObject for scripts in the eval cache (currently,
- * script->u.object aliases script->u.evalHashLink).
+ * script->object aliases script->evalHashLink()).
  */
 class EvalScriptGuard
 {
     JSContext *cx_;
     JSLinearString *str_;
     JSScript **bucket_;
     JSScript *script_;
 
@@ -1102,17 +1102,17 @@ class EvalScriptGuard
         bucket_ = EvalCacheHash(cx, str);
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             js_CallDestroyScriptHook(cx_, script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
-            script_->u.evalHashLink = *bucket_;
+            script_->evalHashLink() = *bucket_;
             *bucket_ = script_;
         }
     }
 
     void lookupInEvalCache(StackFrame *caller, uintN staticLevel,
                            JSPrincipals *principals, JSObject &scopeobj) {
         if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
                                               principals, scopeobj, bucket_)) {
@@ -2999,17 +2999,17 @@ CreateThisForFunctionWithType(JSContext 
         /*
          * Make an object with the type's associated finalize kind and shape,
          * which reflects any properties that will definitely be added to the
          * object before it is read from.
          */
         gc::AllocKind kind = type->newScript->allocKind;
         JSObject *res = NewObjectWithType(cx, type, parent, kind);
         if (res)
-            res->setMap((Shape *) type->newScript->shape);
+            res->initMap((Shape *) type->newScript->shape.get());
         return res;
     }
 
     gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
     return NewObjectWithType(cx, type, parent, kind);
 }
 
 JSObject *
@@ -3499,17 +3499,17 @@ js_NewWithObject(JSContext *cx, JSObject
     StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
 
     obj->init(cx, &WithClass, type, parent, priv, false);
 
     EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
     if (!emptyWithShape)
         return NULL;
 
-    obj->setMap(emptyWithShape);
+    obj->initMap(emptyWithShape);
     OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
 
     AutoObjectRooter tvr(cx, obj);
     JSObject *thisp = proto->thisObject(cx);
     if (!thisp)
         return NULL;
 
     assertSameCompartment(cx, obj, thisp);
@@ -3528,17 +3528,17 @@ js_NewBlockObject(JSContext *cx)
     JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!blockObj)
         return NULL;
 
     EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx);
     if (!emptyBlockShape)
         return NULL;
     blockObj->init(cx, &BlockClass, &emptyTypeObject, NULL, NULL, false);
-    blockObj->setMap(emptyBlockShape);
+    blockObj->initMap(emptyBlockShape);
 
     return blockObj;
 }
 
 JSObject *
 js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
 {
     JS_ASSERT(proto->isStaticBlock());
@@ -3586,17 +3586,17 @@ js_PutBlockObject(JSContext *cx, JSBool 
     JS_ASSERT(count <= size_t(cx->regs().sp - fp->base() - depth));
 
     /* See comments in CheckDestructuring in frontend/Parser.cpp. */
     JS_ASSERT(count >= 1);
 
     if (normalUnwind) {
         uintN slot = JSSLOT_BLOCK_FIRST_FREE_SLOT;
         depth += fp->numFixed();
-        obj->copySlotRange(slot, fp->slots() + depth, count);
+        obj->copySlotRange(slot, fp->slots() + depth, count, true);
     }
 
     /* We must clear the private slot even with errors. */
     obj->setPrivate(NULL);
     fp->setScopeChainNoCallObj(*obj->getParent());
     return normalUnwind;
 }
 
@@ -3789,18 +3789,18 @@ JS_CloneObject(JSContext *cx, JSObject *
 
     return clone;
 }
 
 struct JSObject::TradeGutsReserved {
     JSContext *cx;
     Vector<Value> avals;
     Vector<Value> bvals;
-    Value *newaslots;
-    Value *newbslots;
+    HeapValue *newaslots;
+    HeapValue *newbslots;
 
     TradeGutsReserved(JSContext *cx)
         : cx(cx), avals(cx), bvals(cx), newaslots(NULL), newbslots(NULL)
     {}
 
     ~TradeGutsReserved()
     {
         if (newaslots)
@@ -3838,22 +3838,22 @@ JSObject::ReserveForTradeGuts(JSContext 
      * if they do not have enough fixed slots to accomodate the slots in the
      * other object.
      */
 
     unsigned afixed = a->numFixedSlots();
     unsigned bfixed = b->numFixedSlots();
 
     if (afixed < bcap) {
-        reserved.newaslots = (Value *) cx->malloc_(sizeof(Value) * (bcap - afixed));
+        reserved.newaslots = (HeapValue *) cx->malloc_(sizeof(HeapValue) * (bcap - afixed));
         if (!reserved.newaslots)
             return false;
     }
     if (bfixed < acap) {
-        reserved.newbslots = (Value *) cx->malloc_(sizeof(Value) * (acap - bfixed));
+        reserved.newbslots = (HeapValue *) cx->malloc_(sizeof(HeapValue) * (acap - bfixed));
         if (!reserved.newbslots)
             return false;
     }
 
     return true;
 }
 
 void
@@ -3880,16 +3880,29 @@ JSObject::TradeGuts(JSContext *cx, JSObj
 
     /*
      * Callers should not try to swap dense arrays or ArrayBuffer objects,
      * these use a different slot representation from other objects.
      */
     JS_ASSERT(!a->isDenseArray() && !b->isDenseArray());
     JS_ASSERT(!a->isArrayBuffer() && !b->isArrayBuffer());
 
+#ifdef JSGC_INCREMENTAL
+    /*
+     * We need a write barrier here. If |a| was marked and |b| was not, then
+     * after the swap, |b|'s guts would never be marked. The write barrier
+     * solves this.
+     */
+    JSCompartment *comp = a->compartment();
+    if (comp->needsBarrier()) {
+        MarkChildren(comp->barrierTracer(), a);
+        MarkChildren(comp->barrierTracer(), b);
+    }
+#endif
+
     /* New types for a JSObject need to be stable when trading guts. */
     TypeObject *newTypeA = a->newType;
     TypeObject *newTypeB = b->newType;
 
     /* Trade the guts of the objects. */
     const size_t size = a->structSize();
     if (size == b->structSize()) {
         /*
@@ -3933,31 +3946,31 @@ JSObject::TradeGuts(JSContext *cx, JSObj
         if (a->hasSlotsArray())
             cx->free_(a->slots);
         if (b->hasSlotsArray())
             cx->free_(b->slots);
 
         unsigned afixed = a->numFixedSlots();
         unsigned bfixed = b->numFixedSlots();
 
-        JSObject tmp;
+        char tmp[sizeof(JSObject)];
         memcpy(&tmp, a, sizeof tmp);
         memcpy(a, b, sizeof tmp);
         memcpy(b, &tmp, sizeof tmp);
 
         a->updateFixedSlots(afixed);
         a->slots = reserved.newaslots;
         a->capacity = Max(afixed, bcap);
-        a->copySlotRange(0, reserved.bvals.begin(), bcap);
+        a->copySlotRange(0, reserved.bvals.begin(), bcap, false);
         a->clearSlotRange(bcap, a->capacity - bcap);
 
         b->updateFixedSlots(bfixed);
         b->slots = reserved.newbslots;
         b->capacity = Max(bfixed, acap);
-        b->copySlotRange(0, reserved.avals.begin(), acap);
+        b->copySlotRange(0, reserved.avals.begin(), acap, false);
         b->clearSlotRange(acap, b->capacity - acap);
 
         /* Make sure the destructor for reserved doesn't free the slots. */
         reserved.newaslots = NULL;
         reserved.newbslots = NULL;
     }
 
     a->newType = newTypeA;
@@ -4443,37 +4456,41 @@ js_InitClass(JSContext *cx, JSObject *ob
                                          ps, fs, static_ps, static_fs, ctorp);
 }
 
 void
 JSObject::clearSlotRange(size_t start, size_t length)
 {
     JS_ASSERT(start + length <= capacity);
     if (isDenseArray()) {
-        ClearValueRange(slots + start, length, true);
+        ClearValueRange(compartment(), slots + start, length, true);
     } else {
         size_t fixed = numFixedSlots();
         if (start < fixed) {
             if (start + length < fixed) {
-                ClearValueRange(fixedSlots() + start, length, false);
+                ClearValueRange(compartment(), fixedSlots() + start, length, false);
             } else {
                 size_t localClear = fixed - start;
-                ClearValueRange(fixedSlots() + start, localClear, false);
-                ClearValueRange(slots, length - localClear, false);
+                ClearValueRange(compartment(), fixedSlots() + start, localClear, false);
+                ClearValueRange(compartment(), slots, length - localClear, false);
             }
         } else {
-            ClearValueRange(slots + start - fixed, length, false);
+            ClearValueRange(compartment(), slots + start - fixed, length, false);
         }
     }
 }
 
 void
-JSObject::copySlotRange(size_t start, const Value *vector, size_t length)
+JSObject::copySlotRange(size_t start, const Value *vector, size_t length, bool valid)
 {
     JS_ASSERT(start + length <= capacity);
+
+    if (valid)
+        prepareSlotRangeForOverwrite(start, start + length);
+
     if (isDenseArray()) {
         memcpy(slots + start, vector, length * sizeof(Value));
     } else {
         size_t fixed = numFixedSlots();
         if (start < fixed) {
             if (start + length < fixed) {
                 memcpy(fixedSlots() + start, vector, length * sizeof(Value));
             } else {
@@ -4517,30 +4534,30 @@ JSObject::allocSlots(JSContext *cx, size
     if (newcap > NSLOTS_LIMIT) {
         if (!JS_ON_TRACE(cx))
             js_ReportAllocationOverflow(cx);
         return false;
     }
 
     uint32 allocCount = numDynamicSlots(newcap);
 
-    Value *tmpslots = (Value*) cx->malloc_(allocCount * sizeof(Value));
+    HeapValue *tmpslots = (HeapValue*) cx->malloc_(allocCount * sizeof(HeapValue));
     if (!tmpslots)
         return false;  /* Leave slots at inline buffer. */
     slots = tmpslots;
     capacity = newcap;
 
     if (isDenseArray()) {
         /* Copy over anything from the inline buffer. */
-        memcpy(slots, fixedSlots(), getDenseArrayInitializedLength() * sizeof(Value));
+        memcpy(slots, fixedSlots(), getDenseArrayInitializedLength() * sizeof(HeapValue));
         if (!cx->typeInferenceEnabled())
             backfillDenseArrayHoles(cx);
     } else {
         /* Clear out the new slots without copying. */
-        ClearValueRange(slots, allocCount, false);
+        InitValueRange(slots, allocCount, false);
     }
 
     Probes::resizeObject(cx, this, oldSize, slotsAndStructSize());
 
     return true;
 }
 
 bool
@@ -4587,31 +4604,31 @@ JSObject::growSlots(JSContext *cx, size_
 
     /* If nothing was allocated yet, treat it as initial allocation. */
     if (!hasSlotsArray())
         return allocSlots(cx, actualCapacity);
 
     uint32 oldAllocCount = numDynamicSlots(oldcap);
     uint32 allocCount = numDynamicSlots(actualCapacity);
 
-    Value *tmpslots = (Value*) cx->realloc_(slots, oldAllocCount * sizeof(Value),
-                                            allocCount * sizeof(Value));
+    HeapValue *tmpslots = (HeapValue*) cx->realloc_(slots, oldAllocCount * sizeof(HeapValue),
+                                                    allocCount * sizeof(HeapValue));
     if (!tmpslots)
         return false;    /* Leave dslots as its old size. */
 
     bool changed = slots != tmpslots;
     slots = tmpslots;
     capacity = actualCapacity;
 
     if (isDenseArray()) {
         if (!cx->typeInferenceEnabled())
             backfillDenseArrayHoles(cx);
     } else {
         /* Clear the new slots we added. */
-        ClearValueRange(slots + oldAllocCount, allocCount - oldAllocCount, false);
+        InitValueRange(slots + oldAllocCount, allocCount - oldAllocCount, false);
     }
 
     if (changed && isGlobal())
         types::MarkObjectStateChange(cx, this);
 
     Probes::resizeObject(cx, this, oldSize, slotsAndStructSize());
 
     return true;
@@ -4624,16 +4641,18 @@ JSObject::shrinkSlots(JSContext *cx, siz
      * Refuse to shrink slots for call objects. This only happens in a very
      * obscure situation (deleting names introduced by a direct 'eval') and
      * allowing the slots pointer to change may require updating pointers in
      * the function's active args/vars information.
      */
     if (isCall())
         return;
 
+    JS_ASSERT_IF(isDenseArray(), initializedLength() <= newcap);
+
     uint32 oldcap = numSlots();
     JS_ASSERT(newcap <= oldcap);
     JS_ASSERT(newcap >= slotSpan());
 
     size_t oldSize = slotsAndStructSize();
 
     if (oldcap <= SLOT_CAPACITY_MIN || !hasSlotsArray()) {
         /*
@@ -4645,17 +4664,17 @@ JSObject::shrinkSlots(JSContext *cx, siz
             clearSlotRange(newcap, oldcap - newcap);
         return;
     }
 
     uint32 fill = newcap;
     newcap = Max(newcap, size_t(SLOT_CAPACITY_MIN));
     newcap = Max(newcap, numFixedSlots());
 
-    Value *tmpslots = (Value*) cx->realloc_(slots, newcap * sizeof(Value));
+    HeapValue *tmpslots = (HeapValue*) cx->realloc_(slots, newcap * sizeof(HeapValue));
     if (!tmpslots)
         return;  /* Leave slots at its old size. */
 
     bool changed = slots != tmpslots;
     slots = tmpslots;
     capacity = newcap;
 
     if (fill < newcap) {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -54,16 +54,17 @@
 #include "jsfriendapi.h"
 #include "jsinfer.h"
 #include "jshash.h"
 #include "jspubtd.h"
 #include "jsprvtd.h"
 #include "jslock.h"
 #include "jscell.h"
 
+#include "gc/Barrier.h"
 #include "vm/String.h"
 
 namespace nanojit { class ValidateWriter; }
 
 namespace js {
 
 class AutoPropDescArrayRooter;
 class ProxyHandler;
@@ -422,17 +423,17 @@ struct JSObject : js::gc::Cell {
      */
     friend class js::TraceRecorder;
     friend class nanojit::ValidateWriter;
 
     /*
      * Private pointer to the last added property and methods to manipulate the
      * list it links among properties in this scope.
      */
-    js::Shape           *lastProp;
+    js::HeapPtrShape    lastProp;
 
   private:
     js::Class           *clasp;
 
   protected:
     inline void setLastProperty(const js::Shape *shape);
 
   private:
@@ -483,66 +484,64 @@ struct JSObject : js::gc::Cell {
      * Impose a sane upper bound, originally checked only for dense arrays, on
      * number of slots in an object.
      */
     enum {
         NSLOTS_BITS     = 29,
         NSLOTS_LIMIT    = JS_BIT(NSLOTS_BITS)
     };
 
-    uint32      flags;                      /* flags */
-    uint32      objShape;                   /* copy of lastProp->shape, or override if different */
+    uint32            flags;                /* flags */
+    uint32            objShape;             /* copy of lastProp->shape, or override if different */
 
-    union {
-        /* If prototype, type of values using this as their prototype. */
-        js::types::TypeObject *newType;
+    /*
+     * If prototype, type of values using this as their prototype. If a dense
+     * array, this holds the initialized length (see jsarray.cpp).
+     */
+    js::HeapPtr<js::types::TypeObject, jsuword> newType;
 
-        /* If dense array, the initialized length (see jsarray.cpp). */
-        jsuword initializedLength;
-    };
+    jsuword &initializedLength() { return *newType.unsafeGetUnioned(); }
 
     JS_FRIEND_API(size_t) sizeOfSlotsArray(JSUsableSizeFun usf);
 
-    JSObject    *parent;                    /* object's parent */
-    void        *privateData;               /* private data */
-    jsuword     capacity;                   /* total number of available slots */
+    js::HeapPtrObject parent;               /* object's parent */
+    void              *privateData;         /* private data */
+    jsuword           capacity;             /* total number of available slots */
 
   private:
-    js::Value   *slots;                     /* dynamically allocated slots,
+    js::HeapValue     *slots;               /* dynamically allocated slots,
                                                or pointer to fixedSlots() for
                                                dense arrays. */
 
     /*
      * The object's type and prototype. For objects with the LAZY_TYPE flag
      * set, this is the prototype's default 'new' type and can only be used
      * to get that prototype.
      */
-    js::types::TypeObject *type_;
+    js::HeapPtr<js::types::TypeObject> type_;
 
     /* Make the type object to use for LAZY_TYPE objects. */
     void makeLazyType(JSContext *cx);
 
   public:
-
     inline bool isNative() const;
     inline bool isNewborn() const;
 
     void setClass(js::Class *c) { clasp = c; }
     js::Class *getClass() const { return clasp; }
     JSClass *getJSClass() const { return Jsvalify(clasp); }
 
     bool hasClass(const js::Class *c) const {
         return c == clasp;
     }
 
     const js::ObjectOps *getOps() const {
         return &getClass()->ops;
     }
 
-    inline void trace(JSTracer *trc);
     inline void scanSlots(js::GCMarker *gcmarker);
 
     uint32 shape() const {
         JS_ASSERT(objShape != INVALID_SHAPE);
         return objShape;
     }
 
     bool isDelegate() const     { return !!(flags & DELEGATE); }
@@ -612,16 +611,17 @@ struct JSObject : js::gc::Cell {
     inline void setOwnShape(uint32 s);
     inline void clearOwnShape();
 
   public:
     inline bool nativeEmpty() const;
 
     bool hasOwnShape() const    { return !!(flags & OWN_SHAPE); }
 
+    inline void initMap(js::Shape *amap);
     inline void setMap(js::Shape *amap);
 
     inline void setSharedNonNativeMap();
 
     /* Functions for setting up scope chain object maps and shapes. */
     void initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent);
     void initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *priv);
     void setBlockOwnShape(JSContext *cx);
@@ -725,40 +725,41 @@ struct JSObject : js::gc::Cell {
     inline size_t structSize() const;
     inline size_t slotsAndStructSize() const;
 
     /* Slot accessors for JITs. */
 
     static inline size_t getFixedSlotOffset(size_t slot);
     static inline size_t offsetOfCapacity() { return offsetof(JSObject, capacity); }
     static inline size_t offsetOfSlots() { return offsetof(JSObject, slots); }
+    static inline size_t offsetOfInitializedLength() { return offsetof(JSObject, newType); }
 
     /*
      * Get a raw pointer to the object's slots, or a slot of the object given
      * a previous value for its since-reallocated dynamic slots.
      */
-    inline const js::Value *getRawSlots();
-    inline const js::Value *getRawSlot(size_t slot, const js::Value *slots);
+    inline const js::HeapValue *getRawSlots();
+    inline const js::HeapValue *getRawSlot(size_t slot, const js::HeapValue *slots);
 
     /* Whether a slot is at a fixed offset from this object. */
     inline bool isFixedSlot(size_t slot);
 
     /* Index into the dynamic slots array to use for a dynamic slot. */
     inline size_t dynamicSlotIndex(size_t slot);
 
     inline size_t numFixedSlots() const;
 
     /* Whether this object has any dynamic slots at all. */
     inline bool hasSlotsArray() const;
 
     /* Get the number of dynamic slots required for a given capacity. */
     inline size_t numDynamicSlots(size_t capacity) const;
 
   private:
-    inline js::Value* fixedSlots() const;
+    inline js::HeapValue *fixedSlots() const;
 
   protected:
     inline bool hasContiguousSlots(size_t start, size_t count) const;
 
   public:
     /* Minimum size for dynamically allocated slots. */
     static const uint32 SLOT_CAPACITY_MIN = 8;
 
@@ -768,26 +769,34 @@ struct JSObject : js::gc::Cell {
 
     bool ensureSlots(JSContext *cx, size_t nslots) {
         if (numSlots() < nslots)
             return growSlots(cx, nslots);
         return true;
     }
 
     /*
+     * Trigger the write barrier on a range of slots that will no longer be
+     * reachable.
+     */
+    inline void prepareSlotRangeForOverwrite(size_t start, size_t end);
+
+    /*
      * Fill a range of slots with holes or undefined, depending on whether this
      * is a dense array.
      */
     void clearSlotRange(size_t start, size_t length);
 
     /*
      * Copy a flat array of slots to this object at a start slot. Caller must
-     * ensure there are enough slots in this object.
+     * ensure there are enough slots in this object. If |valid|, then the slots
+     * being overwritten hold valid data and must be invalidated for the write
+     * barrier.
      */
-    void copySlotRange(size_t start, const js::Value *vector, size_t length);
+    void copySlotRange(size_t start, const js::Value *vector, size_t length, bool valid);
 
     /*
      * Ensure that the object has at least JSCLASS_RESERVED_SLOTS(clasp) +
      * nreserved slots.
      *
      * This method may be called only for native objects freshly created using
      * NewObject or one of its variant where the new object will both (a) never
      * escape to script and (b) never be extended with ad-hoc properties that
@@ -812,75 +821,74 @@ struct JSObject : js::gc::Cell {
     inline bool ensureClassReservedSlots(JSContext *cx);
 
     inline uint32 slotSpan() const;
 
     inline bool containsSlot(uint32 slot) const;
 
     void rollbackProperties(JSContext *cx, uint32 slotSpan);
 
-    js::Value *getSlotAddress(uintN slot) {
+    js::HeapValue *getSlotAddress(uintN slot) {
         /*
          * This can be used to get the address of the end of the slots for the
          * object, which may be necessary when fetching zero-length arrays of
          * slots (e.g. for callObjVarArray).
          */
+        JS_ASSERT(!isDenseArray());
         JS_ASSERT(slot <= capacity);
         size_t fixed = numFixedSlots();
         if (slot < fixed)
             return fixedSlots() + slot;
         return slots + (slot - fixed);
     }
 
-    js::Value &getSlotRef(uintN slot) {
+    js::HeapValue &getSlotRef(uintN slot) {
         JS_ASSERT(slot < capacity);
         return *getSlotAddress(slot);
     }
 
-    inline js::Value &nativeGetSlotRef(uintN slot);
+    inline js::HeapValue &nativeGetSlotRef(uintN slot);
 
     const js::Value &getSlot(uintN slot) const {
         JS_ASSERT(slot < capacity);
         size_t fixed = numFixedSlots();
         if (slot < fixed)
             return fixedSlots()[slot];
         return slots[slot - fixed];
     }
 
     inline const js::Value &nativeGetSlot(uintN slot) const;
 
-    void setSlot(uintN slot, const js::Value &value) {
-        JS_ASSERT(slot < capacity);
-        getSlotRef(slot) = value;
-    }
+    inline void setSlot(uintN slot, const js::Value &value);
+    inline void initSlot(uintN slot, const js::Value &value);
+    inline void initSlotUnchecked(uintN slot, const js::Value &value);
 
     inline void nativeSetSlot(uintN slot, const js::Value &value);
     inline void nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js::Value &value);
 
     inline js::Value getReservedSlot(uintN index) const;
+    inline js::HeapValue &getReservedSlotRef(uintN index);
 
     /* Call this only after the appropriate ensure{Class,Instance}ReservedSlots call. */
     inline void setReservedSlot(uintN index, const js::Value &v);
 
     /* For slots which are known to always be fixed, due to the way they are allocated. */
 
-    js::Value &getFixedSlotRef(uintN slot) {
+    js::HeapValue &getFixedSlotRef(uintN slot) {
         JS_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
 
     const js::Value &getFixedSlot(uintN slot) const {
         JS_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
 
-    void setFixedSlot(uintN slot, const js::Value &value) {
-        JS_ASSERT(slot < numFixedSlots());
-        fixedSlots()[slot] = value;
-    }
+    inline void setFixedSlot(uintN slot, const js::Value &value);
+    inline void initFixedSlot(uintN slot, const js::Value &value);
 
     /* Defined in jsscopeinlines.h to avoid including implementation dependencies here. */
     inline void updateShape(JSContext *cx);
     inline void updateFlags(const js::Shape *shape, bool isDefinitelyAtom = false);
 
     /* Extend this object to have shape as its last-added property. */
     inline void extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom = false);
 
@@ -907,32 +915,33 @@ struct JSObject : js::gc::Cell {
 
     inline js::types::TypeObject *getType(JSContext *cx);
 
     js::types::TypeObject *type() const {
         JS_ASSERT(!hasLazyType());
         return type_;
     }
 
-    js::types::TypeObject *typeFromGC() const {
+    const js::HeapPtr<js::types::TypeObject> &typeFromGC() const {
         /* Direct field access for use by GC. */
         return type_;
     }
 
     static inline size_t offsetOfType() { return offsetof(JSObject, type_); }
 
     inline void clearType();
     inline void setType(js::types::TypeObject *newType);
+    inline void initType(js::types::TypeObject *newType);
 
     inline js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL,
                                              bool markUnknown = false);
   private:
     void makeNewType(JSContext *cx, JSFunction *fun, bool markUnknown);
+
   public:
-
     /* Set a new prototype for an object with a singleton type. */
     bool splicePrototype(JSContext *cx, JSObject *proto);
 
     /*
      * For bootstrapping, whether to splice a prototype for Function.prototype
      * or the global object.
      */
     bool shouldSplicePrototype(JSContext *cx);
@@ -940,46 +949,35 @@ struct JSObject : js::gc::Cell {
     JSObject * getProto() const {
         return type_->proto;
     }
 
     JSObject *getParent() const {
         return parent;
     }
 
-    void clearParent() {
-        parent = NULL;
-    }
-
-    void setParent(JSObject *newParent) {
-#ifdef DEBUG
-        for (JSObject *obj = newParent; obj; obj = obj->getParent())
-            JS_ASSERT(obj != this);
-#endif
-        setDelegateNullSafe(newParent);
-        parent = newParent;
-    }
+    inline void clearParent();
+    inline void setParent(JSObject *newParent);
+    inline void initParent(JSObject *newParent);
 
     JS_FRIEND_API(js::GlobalObject *) getGlobal() const;
 
     bool isGlobal() const {
         return !!(getClass()->flags & JSCLASS_IS_GLOBAL);
     }
 
     inline js::GlobalObject *asGlobal();
 
     void *getPrivate() const {
         JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
         return privateData;
     }
 
-    void setPrivate(void *data) {
-        JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
-        privateData = data;
-    }
+    inline void initPrivate(void *data);
+    inline void setPrivate(void *data);
 
     /* N.B. Infallible: NULL means 'no principal', not an error. */
     inline JSPrincipals *principals(JSContext *cx);
 
     /*
      * ES5 meta-object properties and operations.
      */
 
@@ -1038,21 +1036,24 @@ struct JSObject : js::gc::Cell {
     inline void setArrayLength(JSContext *cx, uint32 length);
 
     inline uint32 getDenseArrayCapacity();
     inline uint32 getDenseArrayInitializedLength();
     inline void setDenseArrayLength(uint32 length);
     inline void setDenseArrayInitializedLength(uint32 length);
     inline void ensureDenseArrayInitializedLength(JSContext *cx, uintN index, uintN extra);
     inline void backfillDenseArrayHoles(JSContext *cx);
-    inline const js::Value* getDenseArrayElements();
+    inline js::HeapValueArray getDenseArrayElements();
     inline const js::Value &getDenseArrayElement(uintN idx);
     inline void setDenseArrayElement(uintN idx, const js::Value &val);
+    inline void initDenseArrayElement(uintN idx, const js::Value &val);
     inline void setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val);
+    inline void initDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val);
     inline void copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
+    inline void initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
     inline void moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count);
     inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
     inline bool denseArrayHasInlineSlots() const;
 
     /* Packed information for this array. */
     inline bool isPackedDenseArray();
     inline void markDenseArrayNotPacked(JSContext *cx);
 
@@ -1151,21 +1152,21 @@ struct JSObject : js::gc::Cell {
     static const uint32 FUN_CLASS_RESERVED_SLOTS = 2;
 
     static size_t getFlatClosureUpvarsOffset() {
         return getFixedSlotOffset(JSSLOT_FLAT_CLOSURE_UPVARS);
     }
 
     inline JSFunction *getFunctionPrivate() const;
 
-    inline js::Value *getFlatClosureUpvars() const;
+    inline js::FlatClosureData *getFlatClosureData() const;
     inline js::Value getFlatClosureUpvar(uint32 i) const;
     inline const js::Value &getFlatClosureUpvar(uint32 i);
     inline void setFlatClosureUpvar(uint32 i, const js::Value &v);
-    inline void setFlatClosureUpvars(js::Value *upvars);
+    inline void setFlatClosureData(js::FlatClosureData *data);
 
     /* See comments in fun_finalize. */
     inline void finalizeUpvarsIfFlatClosure();
 
     inline bool hasMethodObj(const JSObject& obj) const;
     inline void setMethodObj(JSObject& obj);
 
     inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
@@ -1235,22 +1236,17 @@ struct JSObject : js::gc::Cell {
     inline void setWithThis(JSObject *thisp);
 
     /*
      * Back to generic stuff.
      */
     inline bool isCallable();
 
     /* Do initialization required immediately after allocation. */
-    void earlyInit(jsuword capacity) {
-        this->capacity = capacity;
-
-        /* Stops obj from being scanned until initializated. */
-        lastProp = NULL;
-    }
+    inline void earlyInit(jsuword capacity);
 
     /* The map field is not initialized here and should be set separately. */
     void init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type,
               JSObject *parent, void *priv, bool denseArray);
 
     inline void finish(JSContext *cx);
     JS_ALWAYS_INLINE void finalize(JSContext *cx);
 
@@ -1498,16 +1494,21 @@ struct JSObject : js::gc::Cell {
         JS_STATIC_ASSERT(offsetof(JSObject, type_) == offsetof(js::shadow::Object, type));
         JS_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object));
         JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Object::FIXED_SLOTS_SHIFT);
     }
 
     /*** For jit compiler: ***/
 
     static size_t offsetOfClassPointer() { return offsetof(JSObject, clasp); }
+
+    static inline void writeBarrierPre(JSObject *obj);
+    static inline void writeBarrierPost(JSObject *obj, void *addr);
+    inline void privateWriteBarrierPre(void **oldval);
+    inline void privateWriteBarrierPost(void **oldval);
 };
 
 /*
  * The only sensible way to compare JSObject with == is by identity. We use
  * const& instead of * as a syntactic way to assert non-null. This leads to an
  * abundance of address-of operators to identity. Hence this overload.
  */
 static JS_ALWAYS_INLINE bool
@@ -1517,19 +1518,20 @@ operator==(const JSObject &lhs, const JS
 }
 
 static JS_ALWAYS_INLINE bool
 operator!=(const JSObject &lhs, const JSObject &rhs)
 {
     return &lhs != &rhs;
 }
 
-inline js::Value*
-JSObject::fixedSlots() const {
-    return (js::Value*) (jsuword(this) + sizeof(JSObject));
+inline js::HeapValue*
+JSObject::fixedSlots() const
+{
+    return (js::HeapValue *) (jsuword(this) + sizeof(JSObject));
 }
 
 inline size_t
 JSObject::numFixedSlots() const
 {
     return flags >> FIXED_SLOTS_SHIFT;
 }
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  *
  * ***** 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
@@ -37,19 +37,21 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsobjinlines_h___
 #define jsobjinlines_h___
 
 #include <new>
+
 #include "jsarray.h"
 #include "jsdate.h"
 #include "jsfun.h"
+#include "jsgcmark.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsobj.h"
 #include "jsprobes.h"
 #include "jspropertytree.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jstypedarray.h"
@@ -60,23 +62,28 @@
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsnum.h"
 #include "jsinferinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsstr.h"
 
+#include "gc/Barrier.h"
+#include "js/TemplateLib.h"
 #include "vm/GlobalObject.h"
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsgcinlines.h"
 #include "jsscopeinlines.h"
 
+#include "gc/Barrier-inl.h"
+#include "vm/String-inl.h"
+
 inline bool
 JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props)
 {
     JS_ASSERT(isExtensible());
 
     if (js::FixOp fix = getOps()->fix) {
         bool success;
         if (!fix(cx, this, &success, props))
@@ -272,17 +279,17 @@ JSObject::finalize(JSContext *cx)
 /* 
  * Initializer for Call objects for functions and eval frames. Set class,
  * parent, map, and shape, and allocate slots.
  */
 inline void
 JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent)
 {
     init(cx, &js::CallClass, &js::types::emptyTypeObject, parent, NULL, false);
-    lastProp = bindings.lastShape();
+    lastProp.init(bindings.lastShape());
 
     /*
      * If |bindings| is for a function that has extensible parents, that means
      * its Call should have its own shape; see js::Bindings::extensibleParents.
      */
     if (bindings.extensibleParents())
         setOwnShape(js_GenerateShape(cx));
     else
@@ -312,17 +319,18 @@ JSObject::initClonedBlock(JSContext *cx,
         objShape = lastProp->shapeid;
 }
 
 /* 
  * Mark a compile-time block as OWN_SHAPE, indicating that its run-time clones
  * also need unique shapes. See js::Bindings::extensibleParents.
  */
 inline void
-JSObject::setBlockOwnShape(JSContext *cx) {
+JSObject::setBlockOwnShape(JSContext *cx)
+{
     JS_ASSERT(isStaticBlock());
     setOwnShape(js_GenerateShape(cx));
 }
 
 /*
  * Property read barrier for deferred cloning of compiler-created function
  * objects optimized as typically non-escaping, ad-hoc methods in obj.
  */
@@ -392,25 +400,25 @@ JSObject::methodWriteBarrier(JSContext *
         const js::Value &prev = nativeGetSlot(slot);
 
         if (ChangesMethodValue(prev, v))
             return methodShapeChange(cx, slot);
     }
     return true;
 }
 
-inline const js::Value *
+inline const js::HeapValue *
 JSObject::getRawSlots()
 {
     JS_ASSERT(isGlobal());
     return slots;
 }
 
-inline const js::Value *
-JSObject::getRawSlot(size_t slot, const js::Value *slots)
+inline const js::HeapValue *
+JSObject::getRawSlot(size_t slot, const js::HeapValue *slots)
 {
     JS_ASSERT(isGlobal());
     size_t fixed = numFixedSlots();
     if (slot < fixed)
         return fixedSlots() + slot;
     return slots + slot - fixed;
 }
 
@@ -442,16 +450,23 @@ JSObject::ensureClassReservedSlots(JSCon
 }
 
 inline js::Value
 JSObject::getReservedSlot(uintN index) const
 {
     return (index < numSlots()) ? getSlot(index) : js::UndefinedValue();
 }
 
+inline js::HeapValue &
+JSObject::getReservedSlotRef(uintN index)
+{
+    JS_ASSERT(index < numSlots());
+    return getSlotRef(index);
+}
+
 inline void
 JSObject::setReservedSlot(uintN index, const js::Value &v)
 {
     JS_ASSERT(index < JSSLOT_FREE(getClass()));
     setSlot(index, v);
 }
 
 inline bool
@@ -488,16 +503,29 @@ JSObject::hasContiguousSlots(size_t star
     /*
      * Check that the range [start, start+count) is either all inline or all
      * out of line.
      */
     JS_ASSERT(start + count <= numSlots());
     return (start + count <= numFixedSlots()) || (start >= numFixedSlots());
 }
 
+inline void
+JSObject::prepareSlotRangeForOverwrite(size_t start, size_t end)
+{
+    if (isDenseArray()) {
+        JS_ASSERT(end <= initializedLength());
+        for (size_t i = start; i < end; i++)
+            slots[i].js::HeapValue::~HeapValue();
+    } else {
+        for (size_t i = start; i < end; i++)
+            getSlotRef(i).js::HeapValue::~HeapValue();
+    }
+}
+
 inline size_t
 JSObject::structSize() const
 {
     return (isFunction() && !getPrivate())
            ? sizeof(JSFunction)
            : (sizeof(JSObject) + sizeof(js::Value) * numFixedSlots());
 }
 
@@ -536,40 +564,40 @@ JSObject::setArrayLength(JSContext *cx, 
         js::types::MarkTypeObjectFlags(cx, this,
                                        js::types::OBJECT_FLAG_NON_PACKED_ARRAY |
                                        js::types::OBJECT_FLAG_NON_DENSE_ARRAY);
         jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
         js::types::AddTypePropertyId(cx, this, lengthId,
                                      js::types::Type::DoubleType());
     }
 
-    setPrivate((void*)(uintptr_t) length);
+    privateData = (void*)(uintptr_t) length;
 }
 
 inline void
 JSObject::setDenseArrayLength(uint32 length)
 {
     /* Variant of setArrayLength for use on dense arrays where the length cannot overflow int32. */
     JS_ASSERT(isDenseArray());
     JS_ASSERT(length <= INT32_MAX);
-    setPrivate((void*)(uintptr_t) length);
+    privateData = (void*)(uintptr_t) length;
 }
 
 inline uint32
 JSObject::getDenseArrayCapacity()
 {
     JS_ASSERT(isDenseArray());
     return numSlots();
 }
 
-inline const js::Value *
+inline js::HeapValueArray
 JSObject::getDenseArrayElements()
 {
     JS_ASSERT(isDenseArray());
-    return slots;
+    return js::HeapValueArray(slots);
 }
 
 inline const js::Value &
 JSObject::getDenseArrayElement(uintN idx)
 {
     JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
     return slots[idx];
 }
@@ -577,36 +605,74 @@ JSObject::getDenseArrayElement(uintN idx
 inline void
 JSObject::setDenseArrayElement(uintN idx, const js::Value &val)
 {
     JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
     slots[idx] = val;
 }
 
 inline void
+JSObject::initDenseArrayElement(uintN idx, const js::Value &val)
+{
+    JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
+    slots[idx].init(val);
+}
+
+inline void
 JSObject::setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val)
 {
     js::types::AddTypePropertyId(cx, this, JSID_VOID, val);
     setDenseArrayElement(idx, val);
 }
 
 inline void
+JSObject::initDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val)
+{
+    js::types::AddTypePropertyId(cx, this, JSID_VOID, val);
+    initDenseArrayElement(idx, val);
+}
+
+inline void
 JSObject::copyDenseAr