Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Tue, 03 Jan 2012 11:44:34 -0800
changeset 105548 c612b1c32a84b4b491fc375f4ebc34c91bac3a76
parent 105547 284cc80e914b403210955573d1bd9c5b6bb63ee1 (current diff)
parent 83739 a737cc816eeccdb145f4d73043d02a2d4f79c5aa (diff)
child 105550 aa47a35d6b7fc1f97a27c9f6e64c995a74104021
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
browser/devtools/styleinspector/CssHtmlTree.jsm
content/base/test/Makefile.in
content/html/content/src/nsFormSubmission.cpp
dom/base/nsStructuredCloneContainer.cpp
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBEvents.cpp
dom/indexedDB/IDBKeyRange.cpp
dom/locales/en-US/chrome/layout/HtmlForm.properties
dom/workers/WorkerPrivate.cpp
intl/uconv/tests/unit/test_decode_geostd8.js
intl/uconv/tests/unit/test_encode_geostd8.js
intl/uconv/ucvlatin/geostd8.uf
intl/uconv/ucvlatin/geostd8.ut
intl/uconv/ucvlatin/nsGEOSTD8ToUnicode.cpp
intl/uconv/ucvlatin/nsGEOSTD8ToUnicode.h
intl/uconv/ucvlatin/nsUnicodeToGEOSTD8.cpp
intl/uconv/ucvlatin/nsUnicodeToGEOSTD8.h
js/src/Makefile.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfuninlines.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jspropertycache.cpp
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jsprvtd.h
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscriptinlines.h
js/src/jsstack.js
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsweakmap.cpp
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/CallObject-inl.h
js/src/vm/CallObject.cpp
js/src/vm/CallObject.h
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/RegExpObject-inl.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSSubScriptLoader.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/Makefile.in
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCDebug.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCMaps.h
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCQuickStubs.h
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeInfo.cpp
js/xpconnect/src/qsgen.py
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/XrayWrapper.cpp
modules/libpref/src/init/all.js
parser/html/nsHtml5TreeBuilder.cpp
parser/html/nsHtml5TreeBuilder.h
startupcache/StartupCache.cpp
startupcache/test/TestStartupCache.cpp
xpcom/ds/nsExpirationTracker.h
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -35,16 +35,17 @@
  * 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 ***** */
 
+const Ci = Components.interfaces;
 const Cu = Components.utils;
 const FILTER_CHANGED_TIMEOUT = 300;
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
@@ -284,17 +285,18 @@ CssHtmlTree.prototype = {
       let fragment = this.doc.createDocumentFragment();
       this._refreshProcess = new UpdateProcess(this.win, CssHtmlTree.propertyNames, {
         onItem: function(aPropertyName) {
           // Per-item callback.
           if (this.viewedElement != aElement || !this.styleInspector.isOpen()) {
             return false;
           }
           let propView = new PropertyView(this, aPropertyName);
-          fragment.appendChild(propView.build());
+          fragment.appendChild(propView.buildMain());
+          fragment.appendChild(propView.buildSelectorContainer());
           if (propView.visible) {
             this.numVisibleProperties++;
           }
           propView.refreshAllSelectors();
           this.propertyViews.push(propView);
         }.bind(this),
         onDone: function() {
           // Completed callback.
@@ -512,16 +514,19 @@ function PropertyView(aTree, aName)
 
 PropertyView.prototype = {
   // The parent element which contains the open attribute
   element: null,
 
   // Property header node
   propertyHeader: null,
 
+  // Destination for property names
+  nameNode: null,
+
   // Destination for property values
   valueNode: null,
 
   // Are matched rules expanded?
   matchedExpanded: false,
 
   // Are unmatched rules expanded?
   unmatchedExpanded: false,
@@ -606,109 +611,146 @@ PropertyView.prototype = {
     return true;
   },
 
   /**
    * Returns the className that should be assigned to the propertyView.
    *
    * @return string
    */
-  get className()
+  get propertyHeaderClassName()
   {
     if (this.visible) {
       this.tree._darkStripe = !this.tree._darkStripe;
       let darkValue = this.tree._darkStripe ?
                       "property-view darkrow" : "property-view";
       return darkValue;
     }
     return "property-view-hidden";
   },
 
-  build: function PropertyView_build()
+  /**
+   * Returns the className that should be assigned to the propertyView content
+   * container.
+   * @return string
+   */
+  get propertyContentClassName()
+  {
+    if (this.visible) {
+      let darkValue = this.tree._darkStripe ?
+                      "property-content darkrow" : "property-content";
+      return darkValue;
+    }
+    return "property-content-hidden";
+  },
+
+  buildMain: function PropertyView_buildMain()
   {
     let doc = this.tree.doc;
-    this.element = doc.createElementNS(HTML_NS, "div");
-    this.element.setAttribute("class", this.className);
+    this.element = doc.createElementNS(HTML_NS, "tr");
+    this.element.setAttribute("class", this.propertyHeaderClassName);
+    this.element.addEventListener("click", this.propertyRowClick.bind(this), false);
 
-    this.propertyHeader = doc.createElementNS(XUL_NS, "hbox");
+    this.propertyHeader = doc.createElementNS(HTML_NS, "td");
     this.element.appendChild(this.propertyHeader);
     this.propertyHeader.setAttribute("class", "property-header");
-    this.propertyHeader.addEventListener("click", this.propertyHeaderClick.bind(this), false);
 
     this.matchedExpander = doc.createElementNS(HTML_NS, "div");
     this.propertyHeader.appendChild(this.matchedExpander);
     this.matchedExpander.setAttribute("class", "match expander");
 
-    let name = doc.createElementNS(HTML_NS, "div");
-    this.propertyHeader.appendChild(name);
-    name.setAttribute("class", "property-name");
-    name.textContent = this.name;
+    this.nameNode = doc.createElementNS(HTML_NS, "div");
+    this.propertyHeader.appendChild(this.nameNode);
+    this.nameNode.setAttribute("tabindex", "0");
+    this.nameNode.addEventListener("keydown", function(aEvent) {
+      let keyEvent = Ci.nsIDOMKeyEvent;
+      if (aEvent.keyCode == keyEvent.DOM_VK_F1) {
+        this.mdnLinkClick();
+      }
+      if (aEvent.keyCode == keyEvent.DOM_VK_RETURN ||
+          aEvent.keyCode == keyEvent.DOM_VK_SPACE) {
+        this.propertyRowClick(aEvent);
+      }
+    }.bind(this), false);
 
-    let helpcontainer = doc.createElementNS(HTML_NS, "div");
-    this.propertyHeader.appendChild(helpcontainer);
+    this.nameNode.setAttribute("class", "property-name");
+    this.nameNode.textContent = this.name;
+
+    let helpcontainer = doc.createElementNS(HTML_NS, "td");
+    this.element.appendChild(helpcontainer);
     helpcontainer.setAttribute("class", "helplink-container");
 
     let helplink = doc.createElementNS(HTML_NS, "a");
     helpcontainer.appendChild(helplink);
     helplink.setAttribute("class", "helplink");
     helplink.setAttribute("title", CssHtmlTree.HELP_LINK_TITLE);
     helplink.textContent = CssHtmlTree.HELP_LINK_TITLE;
     helplink.addEventListener("click", this.mdnLinkClick.bind(this), false);
 
-    this.valueNode = doc.createElementNS(HTML_NS, "div");
-    this.propertyHeader.appendChild(this.valueNode);
+    this.valueNode = doc.createElementNS(HTML_NS, "td");
+    this.element.appendChild(this.valueNode);
     this.valueNode.setAttribute("class", "property-value");
     this.valueNode.setAttribute("dir", "ltr");
     this.valueNode.textContent = this.value;
 
-    this.matchedSelectorsContainer = doc.createElementNS(HTML_NS, "div");
-    this.element.appendChild(this.matchedSelectorsContainer);
+    return this.element;
+  },
+
+  buildSelectorContainer: function PropertyView_buildSelectorContainer()
+  {
+    let doc = this.tree.doc;
+    let element = doc.createElementNS(HTML_NS, "tr");
+    element.setAttribute("class", this.propertyContentClassName);
+    this.matchedSelectorsContainer = doc.createElementNS(HTML_NS, "td");
+    this.matchedSelectorsContainer.setAttribute("colspan", "0");
     this.matchedSelectorsContainer.setAttribute("class", "rulelink");
+    element.appendChild(this.matchedSelectorsContainer);
 
-    return this.element;
+    return element;
   },
 
   /**
    * Refresh the panel's CSS property value.
    */
   refresh: function PropertyView_refresh()
   {
-    this.element.className = this.className;
+    this.element.className = this.propertyHeaderClassName;
+    this.element.nextElementSibling.className = this.propertyContentClassName;
 
     if (this.prevViewedElement != this.tree.viewedElement) {
       this._matchedSelectorViews = null;
       this._unmatchedSelectorViews = null;
       this.prevViewedElement = this.tree.viewedElement;
     }
 
     if (!this.tree.viewedElement || !this.visible) {
       this.valueNode.innerHTML = "";
-      this.matchedSelectorsContainer.hidden = true;
+      this.matchedSelectorsContainer.parentNode.hidden = true;
       this.matchedSelectorsContainer.innerHTML = "";
       this.matchedExpander.removeAttribute("open");
       return;
     }
 
     this.tree.numVisibleProperties++;
     this.valueNode.innerHTML = this.propertyInfo.value;
     this.refreshAllSelectors();
   },
 
   /**
    * Refresh the panel matched rules.
    */
   refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors()
   {
     let hasMatchedSelectors = this.hasMatchedSelectors;
-    this.matchedSelectorsContainer.hidden = !hasMatchedSelectors;
+    this.matchedSelectorsContainer.parentNode.hidden = !hasMatchedSelectors;
 
     if (hasMatchedSelectors) {
-      this.propertyHeader.classList.add("expandable");
+      this.propertyHeader.parentNode.classList.add("expandable");
     } else {
-      this.propertyHeader.classList.remove("expandable");
+      this.propertyHeader.parentNode.classList.remove("expandable");
     }
 
     if (this.matchedExpanded && hasMatchedSelectors) {
       CssHtmlTree.processTemplate(this.templateMatchedSelectors,
         this.matchedSelectorsContainer, this);
       this.matchedExpander.setAttribute("open", "");
     } else {
       this.matchedSelectorsContainer.innerHTML = "";
@@ -797,21 +839,22 @@ PropertyView.prototype = {
 
   /**
    * The action when a user expands matched selectors.
    *
    * @param {Event} aEvent Used to determine the class name of the targets click
    * event. If the class name is "helplink" then the event is allowed to bubble
    * to the mdn link icon.
    */
-  propertyHeaderClick: function PropertyView_propertyHeaderClick(aEvent)
+  propertyRowClick: function PropertyView_propertyRowClick(aEvent)
   {
     if (aEvent.target.className != "helplink") {
       this.matchedExpanded = !this.matchedExpanded;
       this.refreshAllSelectors();
+      this.nameNode.focus();
       aEvent.preventDefault();
     }
   },
 
   /**
    * The action when a user expands unmatched selectors.
    */
   unmatchedSelectorsClick: function PropertyView_unmatchedSelectorsClick(aEvent)
--- a/browser/devtools/styleinspector/csshtmltree.xul
+++ b/browser/devtools/styleinspector/csshtmltree.xul
@@ -64,18 +64,18 @@
 <div id="root"></div>
 
 <!-- When no properties are found the following block is displayed. -->
 <div id="noResults" hidden="">
   &noPropertiesFound;
 </div>
 
 <!-- The output from #templateProperty (below) is appended here. -->
-<div id="propertyContainer">
-</div>
+<table id="propertyContainer">
+</table>
 
 <xul:hbox id="footer">
   <xul:label class="legendKey bestmatch">&bestMatch;</xul:label>
   <xul:label class="legendKey matched">&matched;</xul:label>
   <xul:label class="legendKey parentmatch">&parentMatch;</xul:label>
 </xul:hbox>
 <!--
 To visually debug the templates without running firefox, alter the display:none
--- a/browser/devtools/styleinspector/test/Makefile.in
+++ b/browser/devtools/styleinspector/test/Makefile.in
@@ -45,16 +45,17 @@ relativesrcdir  = browser/devtools/style
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
   browser_styleinspector.js \
   browser_bug683672.js \
   browser_styleinspector_bug_672746_default_styles.js \
   browser_styleinspector_bug_672744_search_filter.js \
+  browser_bug589375_keybindings.js \
   browser_styleinspector_bug_689759_no_results_placeholder.js \
   browser_bug_692400_element_style.js \
   browser_csslogic_inherited.js \
   browser_ruleview_editor.js \
   browser_ruleview_inherit.js \
   browser_ruleview_manipulation.js \
   browser_ruleview_override.js \
   browser_ruleview_ui.js \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_bug589375_keybindings.js
@@ -0,0 +1,149 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the key bindings work properly.
+
+let doc;
+let stylePanel;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<style type="text/css"> ' +
+    '.matches {color: #F00;}</style>' +
+    '<span class="matches">Some styled text</span>' +
+    '</div>';
+  doc.title = "Style Inspector key binding test";
+  ok(window.StyleInspector, "StyleInspector exists");
+  stylePanel = new StyleInspector(window);
+  Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+  stylePanel.createPanel(false, function() {
+    stylePanel.open(doc.body);
+  });
+}
+
+function runStyleInspectorTests()
+{
+  Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+
+  ok(stylePanel.isOpen(), "style inspector is open");
+
+  Services.obs.addObserver(SI_test, "StyleInspector-populated", false);
+  SI_inspectNode();
+}
+
+function SI_inspectNode()
+{
+  var span = doc.querySelector(".matches");
+  ok(span, "captain, we have the matches span");
+
+  let htmlTree = stylePanel.cssHtmlTree;
+  stylePanel.selectNode(span);
+
+  is(span, htmlTree.viewedElement,
+    "style inspector node matches the selected node");
+  is(htmlTree.viewedElement, stylePanel.cssLogic.viewedElement,
+     "cssLogic node matches the cssHtmlTree node");
+}
+
+function SI_test()
+{
+  Services.obs.removeObserver(SI_test, "StyleInspector-populated", false);
+
+  info("checking keybindings");
+
+  let iframe = stylePanel.iframe;
+  let searchbar = stylePanel.cssHtmlTree.searchField;
+  let propView = getFirstVisiblePropertyView();
+  let rulesTable = propView.matchedSelectorsContainer;
+  let nameNode = propView.nameNode;
+
+  info("Adding focus event handler to property name node");
+  nameNode.addEventListener("focus", function nameFocused() {
+    this.removeEventListener("focus", nameFocused);
+    info("property name is focused");
+    info("checking expand / collapse");
+    testKey(iframe.contentWindow, "VK_SPACE", rulesTable);
+    testKey(iframe.contentWindow, "VK_RETURN", rulesTable);
+
+    checkHelpLinkKeybinding();
+    Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
+    stylePanel.close();
+  });
+
+  info("Adding focus event handler to search filter");
+  searchbar.addEventListener("focus", function searchbarFocused() {
+    this.removeEventListener("focus", searchbarFocused);
+    info("search filter is focused");
+    info("tabbing to property name node");
+    EventUtils.synthesizeKey("VK_TAB", {}, iframe.contentWindow);
+  });
+
+  info("Making sure that the style inspector panel is focused");
+  SimpleTest.waitForFocus(function windowFocused() {
+    info("window is focused");
+    info("focusing search filter");
+    searchbar.focus();
+  }, stylePanel.iframe.contentWindow);
+}
+
+function getFirstVisiblePropertyView()
+{
+  let propView = null;
+  stylePanel.cssHtmlTree.propertyViews.some(function(aPropView) {
+    if (aPropView.visible) {
+      propView = aPropView;
+      return true;
+    }
+  });
+
+  return propView;
+}
+
+function testKey(aContext, aVirtKey, aRulesTable)
+{
+  info("testing " + aVirtKey + " key");
+  info("expanding rules table");
+  EventUtils.synthesizeKey(aVirtKey, {}, aContext);
+  isnot(aRulesTable.innerHTML, "", "rules Table is populated");
+  info("collapsing rules table");
+  EventUtils.synthesizeKey(aVirtKey, {}, aContext);
+  is(aRulesTable.innerHTML, "", "rules Table is not populated");
+}
+
+function checkHelpLinkKeybinding()
+{
+  info("checking help link keybinding");
+  let iframe = stylePanel.iframe;
+  let propView = getFirstVisiblePropertyView();
+
+  info("check that MDN link is opened on \"F1\"");
+  let linkClicked = false;
+  propView.mdnLinkClick = function(aEvent) {
+    linkClicked = true;
+  };
+  EventUtils.synthesizeKey("VK_F1", {}, iframe.contentWindow);
+  is(linkClicked, true, "MDN link will be shown");
+}
+
+function finishUp()
+{
+  Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
+  ok(!stylePanel.isOpen(), "style inspector is closed");
+  doc = stylePanel = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html,default styles test";
+}
--- a/browser/devtools/tilt/TiltGL.jsm
+++ b/browser/devtools/tilt/TiltGL.jsm
@@ -509,17 +509,17 @@ TiltGL.Renderer.prototype = {
    *                 the x amount of scaling
    * @param {Number} y
    *                 the y amount of scaling
    * @param {Number} z
    *                 optional, the z amount of scaling
    */
   scale: function TGLR_scale(x, y, z)
   {
-    mat4.scale(this.mvMatrix, [x, y, z || 0]);
+    mat4.scale(this.mvMatrix, [x, y, z || 1]);
   },
 
   /**
    * Performs a custom interpolation between two matrices.
    * The result is saved in the first operand.
    *
    * @param {Array} aMat
    *                the first matrix
--- a/browser/devtools/tilt/TiltUtils.jsm
+++ b/browser/devtools/tilt/TiltUtils.jsm
@@ -646,21 +646,34 @@ TiltUtils.getWindowId = function TU_getW
   }
 
   return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                 .getInterface(Ci.nsIDOMWindowUtils)
                 .currentInnerWindowID;
 };
 
 /**
+ * Gets the markup document viewer zoom for the currently selected browser.
+ *
+ * @return {Number} the zoom ammount
+ */
+TiltUtils.getDocumentZoom = function TU_getDocumentZoom() {
+  let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
+    .getService(Ci.nsIWindowMediator)
+    .getMostRecentWindow("navigator:browser");
+
+  return browserWindow.gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
+};
+
+/**
  * Performs a garbage collection.
  */
 TiltUtils.gc = function TU_gc()
 {
-  var browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
+  let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
     .getService(Ci.nsIWindowMediator)
     .getMostRecentWindow("navigator:browser");
 
   browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIDOMWindowUtils)
                .garbageCollect();
 };
 
--- a/browser/devtools/tilt/TiltVisualizer.jsm
+++ b/browser/devtools/tilt/TiltVisualizer.jsm
@@ -216,16 +216,17 @@ TiltVisualizer.Presenter = function TV_P
     v3: vec3.create()
   };
 
   /**
    * Scene transformations, exposing offset, translation and rotation.
    * Modified by events in the controller through delegate functions.
    */
   this.transforms = {
+    zoom: TiltUtils.getDocumentZoom(),
     offset: vec3.create(),      // mesh offset, aligned to the viewport center
     translation: vec3.create(), // scene translation, on the [x, y, z] axis
     rotation: quat4.create()    // scene rotation, expressed as a quaternion
   };
 
   /**
    * Variables holding information about the initial and current node selected.
    */
@@ -333,16 +334,18 @@ TiltVisualizer.Presenter.prototype = {
                        transforms.translation[2]);
 
     renderer.transform(quat4.toMat4(transforms.rotation));
 
     // offset the visualization mesh to center
     renderer.translate(transforms.offset[0],
                        transforms.offset[1] + transforms.translation[1], 0);
 
+    renderer.scale(transforms.zoom, transforms.zoom);
+
     // draw the visualization mesh
     renderer.strokeWeight(2);
     renderer.depthTest(true);
     this.drawMeshStacks();
     this.drawMeshWireframe();
     this.drawHighlight();
 
     // make sure the initial transition is drawn until finished
@@ -487,22 +490,23 @@ TiltVisualizer.Presenter.prototype = {
     };
 
     // if there's no initial selection made, highlight the required node
     if (!this._initialSelection) {
       this._initialSelection = true;
       this.highlightNode(this.inspectorUI.selection);
     }
 
-    let width = renderer.width;
-    let height = renderer.height;
+    let zoom = TiltUtils.getDocumentZoom();
+    let width = Math.min(aData.meshWidth * zoom, renderer.width);
+    let height = Math.min(aData.meshHeight * zoom, renderer.height);
 
     // set the necessary mesh offsets
-    this.transforms.offset[0] = -Math.min(aData.meshWidth, width) * 0.5;
-    this.transforms.offset[1] = -Math.min(aData.meshHeight, height) * 0.5;
+    this.transforms.offset[0] = -width * 0.5;
+    this.transforms.offset[1] = -height * 0.5;
 
     // make sure the canvas is opaque now that the initialization is finished
     this.canvas.style.background = TiltVisualizerStyle.canvas.background;
 
     this.drawVisualization();
     this.redraw = true;
   },
 
@@ -554,18 +558,19 @@ TiltVisualizer.Presenter.prototype = {
     this.contentWindow.addEventListener("resize", this.onResize, false);
   },
 
   /**
    * Called when the content window of the current browser is resized.
    */
   onResize: function TVP_onResize(e)
   {
-    let width = e.target.innerWidth;
-    let height = e.target.innerHeight;
+    let zoom = TiltUtils.getDocumentZoom();
+    let width = e.target.innerWidth * zoom;
+    let height = e.target.innerHeight * zoom;
 
     // handle aspect ratio changes to update the projection matrix
     this.renderer.width = width;
     this.renderer.height = height;
 
     this.redraw = true;
   },
 
@@ -698,19 +703,22 @@ TiltVisualizer.Presenter.prototype = {
         }
       } else {
         if ("function" === typeof aProperties.onfail) {
           aProperties.onfail();
         }
       }
     }, false);
 
-    let width = this.renderer.width;
-    let height = this.renderer.height;
+    let zoom = TiltUtils.getDocumentZoom();
+    let width = this.renderer.width * zoom;
+    let height = this.renderer.height * zoom;
     let mesh = this.meshStacks;
+    x *= zoom;
+    y *= zoom;
 
     // create a ray following the mouse direction from the near clipping plane
     // to the far clipping plane, to check for intersections with the mesh,
     // and do all the heavy lifting in a separate thread
     worker.postMessage({
       thickness: STACK_THICKNESS,
       vertices: mesh.vertices.components,
 
@@ -983,17 +991,21 @@ TiltVisualizer.Controller.prototype = {
   onKeyDown: function TVC_onKeyDown(e)
   {
     let code = e.keyCode || e.which;
 
     if (code >= e.DOM_VK_LEFT && code <= e.DOM_VK_DOWN) {
       e.preventDefault();
       e.stopPropagation();
     }
-    this.arcball.keyDown(code);
+    if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
+      this.arcball.cancelKeyEvents();
+    } else {
+      this.arcball.keyDown(code);
+    }
   },
 
   /**
    * Called when a key is released.
    */
   onKeyUp: function TVC_onKeyUp(e)
   {
     let code = e.keyCode || e.which;
@@ -1008,26 +1020,27 @@ TiltVisualizer.Controller.prototype = {
     }
     this.arcball.keyUp(code);
   },
 
   /**
    * Called when the canvas looses focus.
    */
   onBlur: function TVC_onBlur(e) {
-    this.arcball._keyCode = {};
+    this.arcball.cancelKeyEvents();
   },
 
   /**
    * Called when the content window of the current browser is resized.
    */
   onResize: function TVC_onResize(e)
   {
-    let width = e.target.innerWidth;
-    let height = e.target.innerHeight;
+    let zoom = TiltUtils.getDocumentZoom();
+    let width = e.target.innerWidth * zoom;
+    let height = e.target.innerHeight * zoom;
 
     this.arcball.resize(width, height);
   },
 
   /**
    * Checks if this object was initialized properly.
    *
    * @return {Boolean} true if the object was initialized properly
@@ -1464,16 +1477,23 @@ TiltVisualizer.Arcball.prototype = {
       // set the vector to a point mapped inside the sphere
       aSphereVec[0] = x;
       aSphereVec[1] = y;
       aSphereVec[2] = Math.sqrt(1 - sqlength);
     }
   },
 
   /**
+   * Cancels all pending transformations caused by key events.
+   */
+  cancelKeyEvents: function TVA_cancelKeyEvents() {
+    this._keyCode = {};
+  },
+
+  /**
    * Resize this implementation to use different bounds.
    * This function is automatically called when the arcball is created.
    *
    * @param {Number} newWidth
    *                 the new width of canvas
    * @param {Number} newHeight
    *                 the new  height of canvas
    * @param {Number} newRadius
--- a/browser/devtools/tilt/test/Makefile.in
+++ b/browser/devtools/tilt/test/Makefile.in
@@ -71,12 +71,13 @@ include $(topsrcdir)/config/rules.mk
 	browser_tilt_math07.js \
 	browser_tilt_utils01.js \
 	browser_tilt_utils02.js \
 	browser_tilt_utils03.js \
 	browser_tilt_utils04.js \
 	browser_tilt_utils05.js \
 	browser_tilt_utils06.js \
 	browser_tilt_visualizer.js \
+	browser_tilt_zoom.js \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/devtools/tilt/test/browser_tilt_controller.js
+++ b/browser/devtools/tilt/test/browser_tilt_controller.js
@@ -40,46 +40,65 @@ function test() {
         }
 
         ok(isEqualVec(tran(), prev_tran),
           "At init, the translation should be zero.");
         ok(isEqualVec(rot(), prev_rot),
           "At init, the rotation should be zero.");
 
 
-        EventUtils.synthesizeKey("VK_A", { type: "keydown" });
-        EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
-        instance.controller.update();
+        function testEventCancel(cancellingEvent) {
+          EventUtils.synthesizeKey("VK_A", { type: "keydown" });
+          EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
+          instance.controller.update();
+
+          ok(!isEqualVec(tran(), prev_tran),
+            "After a translation key is pressed, the vector should change.");
+          ok(!isEqualVec(rot(), prev_rot),
+            "After a rotation key is pressed, the quaternion should change.");
 
-        ok(!isEqualVec(tran(), prev_tran),
-          "After a translation key is pressed, the vector should change.");
-        ok(!isEqualVec(rot(), prev_rot),
-          "After a rotation key is pressed, the quaternion should change.");
+          save();
+
+
+          cancellingEvent();
+          instance.controller.update();
 
-        save();
+          ok(!isEqualVec(tran(), prev_tran),
+            "Even if the canvas lost focus, the vector has some inertia.");
+          ok(!isEqualVec(rot(), prev_rot),
+            "Even if the canvas lost focus, the quaternion has some inertia.");
+
+          save();
 
 
-        gBrowser.selectedBrowser.contentWindow.focus();
-        instance.controller.update();
+          while (!isEqualVec(tran(), prev_tran) ||
+                 !isEqualVec(rot(), prev_rot)) {
+            instance.controller.update();
+            save();
+          }
 
-        ok(!isEqualVec(tran(), prev_tran),
-          "Even if the canvas lost focus, the vector has some inertia.");
-        ok(!isEqualVec(rot(), prev_rot),
-          "Even if the canvas lost focus, the quaternion has some inertia.");
-
-        save();
-
-
-        while (!isEqualVec(tran(), prev_tran) || !isEqualVec(rot(), prev_rot)) {
-          instance.controller.update();
-          save();
+          ok(isEqualVec(tran(), prev_tran) && isEqualVec(rot(), prev_rot),
+            "After focus lost, the transforms inertia eventually stops.");
         }
 
-        ok(isEqualVec(tran(), prev_tran) && isEqualVec(rot(), prev_rot),
-          "After the focus is lost, the transforms inertia eventually stops.");
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("T", { type: "keydown", altKey: 1 });
+        });
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("I", { type: "keydown", ctrlKey: 1 });
+        });
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("L", { type: "keydown", metaKey: 1 });
+        });
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("T", { type: "keydown", shiftKey: 1 });
+        });
+        testEventCancel(function() {
+          gBrowser.selectedBrowser.contentWindow.focus();
+        });
       },
       onEnd: function()
       {
         gBrowser.removeCurrentTab();
         finish();
       }
     }, true);
   });
--- a/browser/devtools/tilt/test/browser_tilt_gl04.js
+++ b/browser/devtools/tilt/test/browser_tilt_gl04.js
@@ -108,9 +108,19 @@ function test() {
     -0.6889029145240784, 0.6511549949645996, 1.7610820531845093, 0,
     1.5683804750442505, -0.8317608833312988, 0.9210627675056458, 0, 1, 1, 1, 1
   ]), "The identity matrix transformation wasn't applied correctly.");
 
   renderer.origin(1, 1, 1);
   ok(isApproxVec(renderer.mvMatrix, [
     1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
   ]), "The origin wasn't reset to identity correctly.");
+
+  renderer.translate(1, 2);
+  ok(isApproxVec(renderer.mvMatrix, [
+    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 0, 1
+  ]), "The second translation transformation wasn't applied correctly.");
+
+  renderer.scale(3, 4);
+  ok(isApproxVec(renderer.mvMatrix, [
+    3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 0, 1, 2, 0, 1
+  ]), "The second scale transformation wasn't applied correctly.");
 }
--- a/browser/devtools/tilt/test/browser_tilt_visualizer.js
+++ b/browser/devtools/tilt/test/browser_tilt_visualizer.js
@@ -94,16 +94,18 @@ function testPresenter(presenter) {
   ok(isApproxVec(presenter.highlight.v1, [0, 0, 0]),
     "The presenter highlight second vertex should be initially zeroed.");
   ok(isApproxVec(presenter.highlight.v2, [0, 0, 0]),
     "The presenter highlight third vertex should be initially zeroed.");
   ok(isApproxVec(presenter.highlight.v3, [0, 0, 0]),
     "The presenter highlight fourth vertex should be initially zeroed.");
   ok(presenter.transforms,
     "The presenter transforms wasn't initialized properly.");
+  ok(isApproxVec(presenter.transforms.zoom, 1),
+    "The presenter transforms zoom should be initially 1.");
   ok(isApproxVec(presenter.transforms.offset, [0, 0, 0]),
     "The presenter transforms offset should be initially zeroed.");
   ok(isApproxVec(presenter.transforms.translation, [0, 0, 0]),
     "The presenter transforms translation should be initially zeroed.");
   ok(isApproxVec(presenter.transforms.rotation, [0, 0, 0, 1]),
     "The presenter transforms rotation should be initially set to identity.");
 
   presenter.setTranslation([1, 2, 3]);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_zoom.js
@@ -0,0 +1,98 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, waitForExplicitFinish, finish, executeSoon, gBrowser */
+/*global isApprox, isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, EventUtils, TiltUtils, InspectorUI, TILT_DESTROYED */
+"use strict";
+
+const ZOOM = 2;
+const RESIZE = 50;
+
+function setZoom(value) {
+  gBrowser.selectedBrowser.markupDocumentViewer.fullZoom = value;
+}
+
+function getZoom() {
+  return gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
+}
+
+function test() {
+  setZoom(Math.random());
+  is(getZoom(), TiltUtils.getDocumentZoom(),
+    "The getDocumentZoom utility function didn't return the expected results.");
+
+  if (!isTiltEnabled()) {
+    info("Skipping controller test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping controller test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  createTab(function() {
+    createTilt({
+      onInspectorOpen: function()
+      {
+        setZoom(ZOOM);
+      },
+      onTiltOpen: function(instance)
+      {
+        ok(isApprox(instance.presenter.transforms.zoom, ZOOM),
+          "The presenter transforms zoom wasn't initially set correctly.");
+
+        let contentWindow = gBrowser.selectedBrowser.contentWindow;
+        let initialWidth = contentWindow.innerWidth;
+        let initialHeight = contentWindow.innerHeight;
+
+        let renderer = instance.presenter.renderer;
+        let arcball = instance.controller.arcball;
+
+        ok(isApprox(contentWindow.innerWidth * ZOOM, renderer.width, 1),
+          "The renderer width wasn't set correctly.");
+        ok(isApprox(contentWindow.innerHeight * ZOOM, renderer.height, 1),
+          "The renderer height wasn't set correctly.");
+
+        ok(isApprox(contentWindow.innerWidth * ZOOM, arcball.width, 1),
+          "The arcball width wasn't set correctly.");
+        ok(isApprox(contentWindow.innerHeight * ZOOM, arcball.height, 1),
+          "The arcball height wasn't set correctly.");
+
+
+        window.resizeBy(-RESIZE * ZOOM, -RESIZE * ZOOM);
+
+        executeSoon(function() {
+          ok(isApprox(contentWindow.innerWidth + RESIZE, initialWidth, 1),
+            "The content window width wasn't set correctly.");
+          ok(isApprox(contentWindow.innerHeight + RESIZE, initialHeight, 1),
+            "The content window height wasn't set correctly.");
+
+          ok(isApprox(contentWindow.innerWidth * ZOOM, renderer.width, 1),
+            "The renderer width wasn't set correctly.");
+          ok(isApprox(contentWindow.innerHeight * ZOOM, renderer.height, 1),
+            "The renderer height wasn't set correctly.");
+
+          ok(isApprox(contentWindow.innerWidth * ZOOM, arcball.width, 1),
+            "The arcball width wasn't set correctly.");
+          ok(isApprox(contentWindow.innerHeight * ZOOM, arcball.height, 1),
+            "The arcball height wasn't set correctly.");
+
+
+          window.resizeBy(RESIZE * ZOOM, RESIZE * ZOOM);
+
+          Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+          InspectorUI.closeInspectorUI();
+        });
+      },
+    });
+  });
+}
+
+function cleanup() {
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
--- a/browser/devtools/tilt/test/head.js
+++ b/browser/devtools/tilt/test/head.js
@@ -1,12 +1,12 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/*global Services, Components, gBrowser, executeSoon */
+/*global Services, Components, gBrowser, executeSoon, info */
 /*global InspectorUI, Tilt, TiltGL, EPSILON */
 "use strict";
 
 Components.utils.import("resource:///modules/devtools/TiltGL.jsm");
 Components.utils.import("resource:///modules/devtools/TiltMath.jsm");
 Components.utils.import("resource:///modules/devtools/TiltUtils.jsm");
 Components.utils.import("resource:///modules/devtools/TiltVisualizer.jsm");
 
@@ -48,38 +48,50 @@ const INSP_ENABLED = Services.prefs.getB
 function isTiltEnabled() {
   return TILT_ENABLED && INSP_ENABLED;
 }
 
 function isWebGLSupported() {
   return TiltGL.isWebGLSupported() && TiltGL.create3DContext(createCanvas());
 }
 
-function isApprox(num1, num2) {
-  return Math.abs(num1 - num2) < EPSILON;
+function isApprox(num1, num2, delta) {
+  if (Math.abs(num1 - num2) > (delta || EPSILON)) {
+    info("isApprox expected " + num1 + ", got " + num2 + " instead.");
+    return false;
+  }
+  return true;
 }
 
-function isApproxVec(vec1, vec2) {
+function isApproxVec(vec1, vec2, delta) {
+  vec1 = Array.prototype.slice.call(vec1);
+  vec2 = Array.prototype.slice.call(vec2);
+
   if (vec1.length !== vec2.length) {
     return false;
   }
   for (let i = 0, len = vec1.length; i < len; i++) {
-    if (!isApprox(vec1[i], vec2[i])) {
+    if (!isApprox(vec1[i], vec2[i], delta)) {
+      info("isApproxVec expected [" + vec1 + "], got [" + vec2 + "] instead.");
       return false;
     }
   }
   return true;
 }
 
 function isEqualVec(vec1, vec2) {
+  vec1 = Array.prototype.slice.call(vec1);
+  vec2 = Array.prototype.slice.call(vec2);
+
   if (vec1.length !== vec2.length) {
     return false;
   }
   for (let i = 0, len = vec1.length; i < len; i++) {
     if (vec1[i] !== vec2[i]) {
+      info("isEqualVec expected [" + vec1 + "], got [" + vec2 + "] instead.");
       return false;
     }
   }
   return true;
 }
 
 function createCanvas() {
   return document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -2117,16 +2117,17 @@ panel[dimmed="true"] {
      This negative margin compensate the extra row of pixels created
      by the shadow.*/
   margin-bottom: -1px;
 }
 
 .inspector-breadcrumbs-button {
   -moz-appearance: none;
   background-color: transparent;
+  border-style: solid;
   border-width: 1px 13px 2px 13px;
   color: hsl(210,30%,85%);
   max-width: 85px;
   /* The content of the button can be larger than the button */
   overflow: hidden;
   min-height: 25px;
 
   margin: 0 -11px 0 0;
@@ -2148,120 +2149,120 @@ panel[dimmed="true"] {
 
 /* Highlighter toolbar - breadcrumbs - LTR */
 
 .inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type {
   margin-left: 0;
 }
 
 .inspector-breadcrumbs-button {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:not([checked]),
 .inspector-breadcrumbs-button:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked][siblings-menu-open],
 .inspector-breadcrumbs-button[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]),
 .inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked],
 .inspector-breadcrumbs-button:first-of-type[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]),
 .inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked],
 .inspector-breadcrumbs-button:last-of-type[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 /* Highlighter toolbar - breadcrumbs - RTL */
 
 .inspector-breadcrumbs-button:-moz-locale-dir(rtl):first-of-type {
   margin-right: 0;
 }
 
 .inspector-breadcrumbs-button:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked][siblings-menu-open]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:first-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 fill stretch;
 }
--- a/browser/themes/gnomestripe/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/devtools/csshtmltree.css
@@ -46,170 +46,147 @@
 }
 
 #root {
   display: -moz-box;
 }
 
 
 .property-header {
-  padding: 4px;
-  -moz-padding-start: 0;
-  -moz-padding-end: 5px;
-}
-
-.rule-unmatched {
-  cursor: pointer;
-  padding: 2px;
-  -moz-padding-start: 4px;
-  -moz-padding-end: 0;
+  padding: 5px 0;
   white-space: nowrap;
+  vertical-align: text-top;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
 .link,
 .link:visited {
   color: #0091ff;
 }
 .link,
 .helplink,
 .link:visited,
 .helplink:visited {
   text-decoration: none;
 }
 
-.helplink-container {
-  position: relative;
-  top: 2px;
-}
-
 .helplink {
   display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
   -moz-margin-end: 2px;
+  cursor: pointer;
 }
 
-.property-header:not(:hover) > .helplink-container {
+.property-view:not(:hover) > .helplink-container {
   visibility: hidden;
 }
 
-.unmatchedSelectorTable {
-  -moz-margin-start: 15px;
-}
-
 .rulelink {
   color: -moz-dialogtext;
-  -moz-margin-start: 12px;
+  padding: 0;
 }
 
 .expander {
   -moz-appearance: treetwisty;
-  -moz-margin-start: 10px;
+  padding-top: 12px;
+  -moz-margin-start: 5px;
   -moz-margin-end: 5px;
+  display: inline-block;
+  vertical-align: middle;
 }
 
 .expander[open] {
   -moz-appearance: treetwistyopen;
 }
 
 .expandable {
   cursor: pointer;
 }
 
 .match {
   visibility: hidden;
 }
 
-.expandable > .match {
+.expandable > .property-header > .match {
   visibility: visible;
 }
 
-.only-unmatched {
-  -moz-margin-start: 0;
-}
-
 .property-name {
   font-size: 12px;
   color: -moz-FieldText;
-  width: 220px;
+  display: inline-block;
 }
 .property-value {
+  padding: 0;
   font-size: 10px;
   color: grey;
+  vertical-align: text-top;
+  width: 100%;
 }
 
-.property-view-hidden {
+.property-view-hidden,
+.property-content-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
-  -moz-padding-start: 15px;
+  padding: 0;
+  -moz-padding-start: 20px;
 }
 
 .bestmatch {
   color: black;
 }
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
-.unmatched {
-  color: brown;
-}
 
 #propertyContainer {
   display: -moz-box;
   -moz-box-orient: vertical;
   -moz-box-flex: 1;
   overflow-y: auto;
+  border-collapse: collapse;
 }
 
 .darkrow {
   background-color: rgba(0,0,0,.022);
 }
 
 #noResults {
   font-size: 18px;
   margin-top: 5px;
   text-align: center;
 }
 
 .headerControls {
   color: -moz-dialogtext;
   background-color: -moz-dialog;
-  padding-top: 5px;
 }
 
 .onlyuserstyles {
   cursor: pointer;
   font-size: 11px;
 }
 
-.searchfield {
-  -moz-margin-start: 10px;
-}
-
-.styleinspector-legend {
-  -moz-margin-start: 12px;
-}
-
 #footer {
   border-top: 1px solid -moz-dialog;
 }
 
 .legendKey {
   margin: 0 5px;
 }
 
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -2853,16 +2853,17 @@ panel[dimmed="true"] {
      inspector-breadcrumbs-buttons, to match toolbar-buttons style.
      This negative margin compensate the extra row of pixels created
      by the shadow.*/
   margin-bottom: -1px;
 }
 
 .inspector-breadcrumbs-button {
   -moz-appearance: none;
+  border-style: solid;
   border-width: 1px 13px 2px 13px;
   color: hsl(210,30%,85%);
   max-width: 85px;
   /* The content of the button can be larger than the button */
   overflow: hidden;
   min-height: 25px;
 
   margin: 0 -11px 0 0;
@@ -2884,120 +2885,120 @@ panel[dimmed="true"] {
 
 /* Highlighter toolbar - breadcrumbs - LTR */
 
 .inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type {
   margin-left: 0;
 }
 
 .inspector-breadcrumbs-button {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:not([checked]),
 .inspector-breadcrumbs-button:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked][siblings-menu-open],
 .inspector-breadcrumbs-button[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]),
 .inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked],
 .inspector-breadcrumbs-button:first-of-type[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]),
 .inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked],
 .inspector-breadcrumbs-button:last-of-type[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 /* Highlighter toolbar - breadcrumbs - RTL */
 
 .inspector-breadcrumbs-button:-moz-locale-dir(rtl):first-of-type {
   margin-right: 0;
 }
 
 .inspector-breadcrumbs-button:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked][siblings-menu-open]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:first-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 1 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 1 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 stretch;
-}
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 fill stretch;
+}
--- a/browser/themes/pinstripe/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/devtools/csshtmltree.css
@@ -46,172 +46,149 @@
 }
 
 #root {
   display: -moz-box;
 }
 
 
 .property-header {
-  padding: 4px;
-  -moz-padding-start: 0;
-  -moz-padding-end: 5px;
-}
-
-.rule-unmatched {
-  cursor: pointer;
-  padding: 2px;
-  -moz-padding-start: 4px;
-  -moz-padding-end: 0;
+  padding: 5px 0;
   white-space: nowrap;
+  vertical-align: text-top;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
 .link,
 .link:visited {
   color: #0091ff;
 }
 .link,
 .helplink,
 .link:visited,
 .helplink:visited {
   text-decoration: none;
 }
 
-.helplink-container {
-  position: relative;
-  top: 2px;
-}
-
 .helplink {
   display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
   -moz-margin-end: 2px;
+  cursor: pointer;
 }
 
-.property-header:not(:hover) > .helplink-container {
+.property-view:not(:hover) > .helplink-container {
   visibility: hidden;
 }
 
-.unmatchedSelectorTable {
-  -moz-margin-start: 15px;
-}
-
 .rulelink {
   color: -moz-dialogtext;
-  -moz-margin-start: 12px;
+  padding: 0;
 }
 
 .expander {
   -moz-appearance: treetwisty;
   width: 12px;
   height: 12px;
+  padding-top: 12px;
   -moz-margin-start: 5px;
   -moz-margin-end: 5px;
+  display: inline-block;
+  vertical-align: middle;
 }
 
 .expander[open] {
   -moz-appearance: treetwistyopen;
 }
 
 .expandable {
   cursor: pointer;
 }
 
 .match {
   visibility: hidden;
 }
 
-.expandable > .match {
+.expandable > .property-header > .match {
   visibility: visible;
 }
 
-.only-unmatched {
-  -moz-margin-start: 0;
-}
-
 .property-name {
   font-size: 12px;
   color: -moz-FieldText;
-  width: 220px;
+  display: inline-block;
 }
 .property-value {
+  padding: 0;
   font-size: 10px;
   color: grey;
+  vertical-align: text-top;
+  width: 100%;
 }
 
-.property-view-hidden {
+.property-view-hidden,
+.property-content-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
-  -moz-padding-start: 15px;
+  padding: 0;
+  -moz-padding-start: 20px;
 }
 
 .bestmatch {
   color: black;
 }
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
-.unmatched {
-  color: brown;
-}
 
 #propertyContainer {
   display: -moz-box;
   -moz-box-orient: vertical;
   -moz-box-flex: 1;
   overflow-y: auto;
+  border-collapse: collapse;
 }
 
 .darkrow {
   background-color: rgba(0,0,0,.022);
 }
 
 #noResults {
   font-size: 18px;
   margin-top: 5px;
   text-align: center;
 }
 
 .headerControls {
   color: -moz-dialogtext;
   background-color: -moz-dialog;
-  padding-top: 5px;
 }
 
 .onlyuserstyles {
   cursor: pointer;
   font-size: 11px;
 }
 
-.searchfield {
-  -moz-margin-start: 10px;
-}
-
-.styleinspector-legend {
-  -moz-margin-start: 12px;
-}
-
 #footer {
   border-top: 1px solid -moz-dialog;
 }
 
 .legendKey {
   margin: 0 5px;
 }
 
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -2797,16 +2797,17 @@ panel[dimmed="true"] {
      This negative margin compensate the extra row of pixels created
      by the shadow.*/
   margin: -1px 0;
 }
 
 .inspector-breadcrumbs-button {
   -moz-appearance: none;
   background-color: transparent;
+  border-style: solid;
   border-width: 2px 13px;
   outline: none;
   color: hsl(210,30%,85%);
   max-width: 85px;
   /* The content of the button can be larger than the button */
   overflow: hidden;
   min-height: 25px;
   margin: 0 -11px 0 0;
@@ -2828,120 +2829,120 @@ panel[dimmed="true"] {
 
 /* Highlighter toolbar - breadcrumbs - LTR */
 
 .inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type {
   margin-left: 0;
 }
 
 .inspector-breadcrumbs-button {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:not([checked]),
 .inspector-breadcrumbs-button:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked][siblings-menu-open],
 .inspector-breadcrumbs-button[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-middle-selected-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]),
 .inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked],
 .inspector-breadcrumbs-button:first-of-type[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-start-selected-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]),
 .inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type[checked] {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked],
 .inspector-breadcrumbs-button:last-of-type[checked]:hover:active {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/ltr-end-selected-pressed.png") 2 13 2 13 fill stretch;
 }
 
 /* Highlighter toolbar - breadcrumbs - RTL */
 
 .inspector-breadcrumbs-button:-moz-locale-dir(rtl):first-of-type {
   margin-right: 0;
 }
 
 .inspector-breadcrumbs-button:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[checked][siblings-menu-open]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-middle-selected-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:first-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:first-of-type[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:first-of-type[checked]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:first-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-start-selected-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type:not([checked]):-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:last-of-type:not([checked]):hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-pressed.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button:last-of-type[checked]:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 2 13 2 13 stretch;
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected.png") 2 13 2 13 fill stretch;
 }
 
 .inspector-breadcrumbs-button[siblings-menu-open]:last-of-type[checked]:-moz-locale-dir(rtl),
 .inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 2 13 2 13 stretch;
-}
+  -moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 2 13 2 13 fill stretch;
+}
--- a/browser/themes/winstripe/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/devtools/csshtmltree.css
@@ -45,172 +45,148 @@
   color: -moz-FieldText;
 }
 
 #root {
   display: -moz-box;
 }
 
 .property-header {
-  padding: 4px;
-  -moz-padding-start: 0;
-  -moz-padding-end: 5px;
-}
-
-.rule-unmatched {
-  cursor: pointer;
-  padding: 2px;
-  -moz-padding-start: 4px;
-  -moz-padding-end: 0;
+  padding: 5px 0;
   white-space: nowrap;
+  vertical-align: text-top;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
 .link,
 .link:visited {
   color: #0091ff;
 }
 .link,
 .helplink,
 .link:visited,
 .helplink:visited {
   text-decoration: none;
 }
 
-.helplink-container {
-  position: relative;
-  top: 2px;
-}
-
 .helplink {
   display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
   -moz-margin-end: 2px;
+  cursor: pointer;
 }
 
-.property-header:not(:hover) > .helplink-container {
+.property-view:not(:hover) > .helplink-container {
   visibility: hidden;
 }
 
-.unmatchedSelectorTable {
-  -moz-margin-start: 15px;
-}
-
 .rulelink {
   color: -moz-dialogtext;
-  -moz-margin-start: 12px;
+  padding: 0;
 }
 
 .expander {
   width: 9px;
   height: 9px;
   -moz-margin-start: 5px;
   -moz-margin-end: 5px;
   background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
+  display: inline-block;
+  vertical-align: middle;
 }
 
 .expander[open] {
   background-image: url("chrome://global/skin/tree/twisty-open.png");
 }
 
 .expandable {
   cursor: pointer;
 }
 
 .match {
   visibility: hidden;
 }
 
-.expandable > .match {
+.expandable > .property-header > .match {
   visibility: visible;
 }
 
-.only-unmatched {
-  -moz-margin-start: 0;
-}
-
 .property-name {
   font-size: 12px;
   color: -moz-FieldText;
-  width: 220px;
+  display: inline-block;
 }
 .property-value {
+  padding: 0;
   font-size: 10px;
   color: grey;
+  vertical-align: text-top;
+  width: 100%;
 }
 
-.property-view-hidden {
+.property-view-hidden,
+.property-content-hidden {
   display: none;
 }
 
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
-  -moz-padding-start: 15px;
+  padding: 0;
+  -moz-padding-start: 20px;
 }
 
 .bestmatch {
   color: black;
 }
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
-.unmatched {
-  color: brown;
-}
 
 #propertyContainer {
   display: -moz-box;
   -moz-box-orient: vertical;
   -moz-box-flex: 1;
   overflow-y: auto;
+  border-collapse: collapse;
 }
 
 .darkrow {
   background-color: rgba(0,0,0,.022);
 }
 
 #noResults {
   font-size: 18px;
   margin-top: 5px;
   text-align: center;
 }
 
 .headerControls {
   color: -moz-dialogtext;
   background-color: -moz-dialog;
-  padding-top: 5px;
 }
 
 .onlyuserstyles {
   cursor: pointer;
   font-size: 11px;
 }
 
-.searchfield {
-  -moz-margin-start: 10px;
-}
-
-.styleinspector-legend {
-  -moz-margin-start: 12px;
-}
-
 #footer {
   border-top: 1px solid -moz-dialog;
 }
 
 .legendKey {
   margin: 0 5px;
 }
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -535,16 +535,19 @@ include $(topsrcdir)/config/rules.mk
 		test_bug702439.html \
 		test_bug702439.html^headers^ \
 		file_bug702439.html \
 		test_bug707142.html \
 		file_bug707142_baseline.json \
 		file_bug707142_bom.json \
 		file_bug707142_utf-16.json \
 		test_reentrant_flush.html \
+		test_bug708620.html \
+		file_bug708620.html \
+		file_bug708620-2.html \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug708620-2.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Non-UTF form target</title>
+<body onload="parent.finish();">
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug708620.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset=windows-1252>
+<title>Non-UTF form</title>
+<body onload="document.forms[0].submit();">
+<form action="file_bug708620-2.html">
+<input name=foo value=bar>
+</form>
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug708620.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=708620
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 708620</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="start();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=708620">Mozilla Bug 708620</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <iframe></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 708620 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+  "file_bug708620.html"
+];
+
+var expectedErrors = [
+  '[JavaScript Warning: "A form was submitted in the windows-1252 encoding which cannot encode all Unicode characters, so user input may get corrupted. To avoid this problem, the page should be changed so that the form is submitted in the UTF-8 encoding either by changing the encoding of the page itself to UTF-8 or by specifying accept-charset=utf-8 on the form element."]'
+];
+
+function consoleError(msg) {
+  var expected = expectedErrors.shift();
+  is(msg, expected, "Not the right error message");
+}
+
+SpecialPowers.addErrorConsoleListener(consoleError);
+
+function start() {
+  var url = tests.shift();
+  document.getElementsByTagName("iframe")[0].src = url;
+}
+
+function finish() {
+    is(expectedErrors.length, 0, "The error supply was not exhausted");
+    SpecialPowers.removeErrorConsoleListener(consoleError);
+    SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -719,16 +719,27 @@ nsEncodingFormSubmission::nsEncodingForm
   }
 
   // use UTF-8 for UTF-16* (per WHATWG and existing practice of
   // MS IE/Opera). 
   if (StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-16"))) {
     charset.AssignLiteral("UTF-8");
   }
 
+  if (!(charset.EqualsLiteral("UTF-8") || charset.EqualsLiteral("gb18030"))) {
+    nsAutoString charsetUtf16;
+    CopyUTF8toUTF16(charset, charsetUtf16);
+    const PRUnichar* charsetPtr = charsetUtf16.get();
+    SendJSWarning(aOriginatingElement ? aOriginatingElement->GetOwnerDocument()
+                                      : nsnull,
+                  "CannotEncodeAllUnicode",
+                  &charsetPtr,
+                  1);
+  }
+
   mEncoder = do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
   if (mEncoder) {
     nsresult rv =
       mEncoder->Init(charset.get(),
                      (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
                       nsISaveAsCharset::attr_FallbackDecimalNCR),
                      0);
     if (NS_FAILED(rv)) {
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -91,17 +91,17 @@ nsStructuredCloneContainer::InitFromVari
 
   uint64_t* jsBytes = nsnull;
   bool success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize,
                                            nsnull, nsnull);
   NS_ENSURE_STATE(success);
   NS_ENSURE_STATE(jsBytes);
 
   // Copy jsBytes into our own buffer.
-  mData = (PRUint64*) malloc(mSize);
+  mData = (uint64_t*) malloc(mSize);
   if (!mData) {
     mSize = 0;
     mVersion = 0;
 
     // FIXME This should really be js::Foreground::Free, but that's not public.
     JS_free(aCx, jsBytes);
 
     return NS_ERROR_FAILURE;
@@ -126,17 +126,17 @@ nsStructuredCloneContainer::InitFromBase
 
   NS_ConvertUTF16toUTF8 data(aData);
 
   nsCAutoString binaryData;
   nsresult rv = Base64Decode(data, binaryData);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Copy the string's data into our own buffer.
-  mData = (PRUint64*) malloc(binaryData.Length());
+  mData = (uint64_t*) malloc(binaryData.Length());
   NS_ENSURE_STATE(mData);
   memcpy(mData, binaryData.get(), binaryData.Length());
 
   mSize = binaryData.Length();
   mVersion = aFormatVersion;
   return NS_OK;
 }
 
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -34,17 +34,16 @@
  * 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 "IDBCursor.h"
 
-#include "jscntxt.h"
 #include "mozilla/storage.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -34,17 +34,16 @@
  * 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 "IDBDatabase.h"
 
-#include "jscntxt.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/storage.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMLists.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
--- a/dom/indexedDB/IDBEvents.cpp
+++ b/dom/indexedDB/IDBEvents.cpp
@@ -37,17 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBEvents.h"
 
 #include "nsIIDBDatabaseException.h"
 #include "nsIPrivateDOMEvent.h"
 
-#include "jscntxt.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMException.h"
 #include "nsJSON.h"
 #include "nsThreadUtils.h"
 
 #include "IDBRequest.h"
 #include "IDBTransaction.h"
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -36,17 +36,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBKeyRange.h"
 
 #include "nsIXPConnect.h"
 
-#include "jscntxt.h"
 #include "nsDOMClassInfo.h"
 #include "nsJSUtils.h"
 #include "nsThreadUtils.h"
 #include "nsContentUtils.h"
 
 #include "Key.h"
 
 USING_INDEXEDDB_NAMESPACE
--- a/dom/locales/en-US/chrome/charsetTitles.properties
+++ b/dom/locales/en-US/chrome/charsetTitles.properties
@@ -91,17 +91,16 @@ koi8-r.title = Cyrillic (KOI8-R)
 koi8-u.title = Cyrillic/Ukrainian (KOI8-U)
 iso-8859-7.title = Greek (ISO-8859-7)
 windows-1253.title = Greek (Windows-1253)
 x-mac-greek.title = Greek (MacGreek)
 windows-1258.title = Vietnamese (Windows-1258)
 x-viet-tcvn5712.title = Vietnamese (TCVN)
 viscii.title = Vietnamese (VISCII)
 x-viet-vps.title = Vietnamese (VPS)
-geostd8.title = Georgian (GEOSTD8)
 tis-620.title = Thai (TIS-620)
 iso-8859-11.title = Thai (ISO-8859-11)
 windows-874.title = Thai (Windows-874)
 ibm874.title = Thai (IBM-874)
 armscii-8.title = Armenian (ARMSCII-8)
 iso-8859-6.title = Arabic (ISO-8859-6)
 iso-8859-6-i.title = Arabic (ISO-8859-6-I)
 iso-8859-6-e.title = Arabic (ISO-8859-6-E)
--- a/dom/locales/en-US/chrome/layout/HtmlForm.properties
+++ b/dom/locales/en-US/chrome/layout/HtmlForm.properties
@@ -43,8 +43,9 @@ MediaUpload=Media Upload
 # should be a space (U+0020) in most locales. The prompt is followed by an 
 # input field. The space needs be escaped in the property file to avoid 
 # trimming.
 IsIndexPromptWithSpace=This is a searchable index. Enter search keywords:\u0020
 ForgotPostWarning=Form contains enctype=%S, but does not contain method=post.  Submitting normally with method=GET and no enctype instead.
 ForgotFileEnctypeWarning=Form contains a file input, but is missing method=POST and enctype=multipart/form-data on the form.  The file will not be sent.
 # LOCALIZATION NOTE (DefaultFormSubject): %S will be replaced with brandShortName
 DefaultFormSubject=Form Post from %S
+CannotEncodeAllUnicode=A form was submitted in the %S encoding which cannot encode all Unicode characters, so user input may get corrupted. To avoid this problem, the page should be changed so that the form is submitted in the UTF-8 encoding either by changing the encoding of the page itself to UTF-8 or by specifying accept-charset=utf-8 on the form element.
--- a/dom/workers/ChromeWorkerScope.cpp
+++ b/dom/workers/ChromeWorkerScope.cpp
@@ -34,17 +34,16 @@
  * 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 "ChromeWorkerScope.h"
 
 #include "jsapi.h"
-#include "jscntxt.h"
 
 #include "nsXPCOM.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsStringGlue.h"
 
 #include "WorkerPrivate.h"
 
 #define CTYPES_STR "ctypes"
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -825,17 +825,17 @@ public:
     }
 
     aWorkerPrivate->CloseHandlerFinished();
   }
 };
 
 class MessageEventRunnable : public WorkerRunnable
 {
-  uint64* mData;
+  uint64_t* mData;
   size_t mDataByteCount;
   nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
 
 public:
   MessageEventRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget,
                        JSAutoStructuredCloneBuffer& aData,
                        nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects)
   : WorkerRunnable(aWorkerPrivate, aTarget, aTarget == WorkerThread ?
--- a/editor/libeditor/base/nsEditorController.cpp
+++ b/editor/libeditor/base/nsEditorController.cpp
@@ -105,18 +105,16 @@ nsresult nsEditorController::RegisterEdi
 
   return NS_OK;
 }
 
 
 // static
 nsresult nsEditorController::RegisterEditorCommands(nsIControllerCommandTable *inCommandTable)
 {
-  nsresult rv;
-
   // These are commands that will be used in text widgets only.
 
   NS_REGISTER_FIRST_COMMAND(nsSelectionMoveCommands, "cmd_scrollTop");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_scrollBottom");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_moveTop");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_moveBottom");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_selectTop");
   NS_REGISTER_NEXT_COMMAND(nsSelectionMoveCommands, "cmd_selectBottom");
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -181,11 +181,13 @@ unicode-printing.patch: Print as unicode
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
 pixman-export.patch: use cairo_public for PIXMAN_EXPORT to make sure pixman symbols are not exported in libxul
 
+bad-memset.patch: Fix third argument in memcmp call in pixman-image.c
+
 ==== disable printing patch ====
 
 disable-printing.patch:  allows us to use NS_PRINTING to disable printing.
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/bad-memset.patch
@@ -0,0 +1,28 @@
+# HG changeset patch
+# Parent a968f1430c74282c673c01a2c0a4417e238f2de7
+# User Thomas Prip Vestergaard <thomas@prip.nu>
+Bug 710992 - Fix third argument in memcmp call in pixman-image.c
+
+
+diff --git a/gfx/cairo/libpixman/src/pixman-image.c b/gfx/cairo/libpixman/src/pixman-image.c
+--- a/gfx/cairo/libpixman/src/pixman-image.c
++++ b/gfx/cairo/libpixman/src/pixman-image.c
+@@ -512,17 +512,17 @@ pixman_image_set_transform (pixman_image
+ 	free (common->transform);
+ 	common->transform = NULL;
+ 	result = TRUE;
+ 
+ 	goto out;
+     }
+ 
+     if (common->transform &&
+-	memcmp (common->transform, transform, sizeof (pixman_transform_t) == 0))
++	memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0)
+     {
+ 	return TRUE;
+     }
+ 
+     if (common->transform == NULL)
+ 	common->transform = malloc (sizeof (pixman_transform_t));
+ 
+     if (common->transform == NULL)
--- a/gfx/cairo/libpixman/src/pixman-image.c
+++ b/gfx/cairo/libpixman/src/pixman-image.c
@@ -512,17 +512,17 @@ pixman_image_set_transform (pixman_image
 	free (common->transform);
 	common->transform = NULL;
 	result = TRUE;
 
 	goto out;
     }
 
     if (common->transform &&
-	memcmp (common->transform, transform, sizeof (pixman_transform_t) == 0))
+	memcmp (common->transform, transform, sizeof (pixman_transform_t)) == 0)
     {
 	return TRUE;
     }
 
     if (common->transform == NULL)
 	common->transform = malloc (sizeof (pixman_transform_t));
 
     if (common->transform == NULL)
--- a/intl/locale/src/charsetalias.properties
+++ b/intl/locale/src/charsetalias.properties
@@ -136,17 +136,16 @@ x-mac-romanian=x-mac-romanian
 x-mac-cyrillic=x-mac-cyrillic
 x-mac-ukrainian=x-mac-cyrillic
 x-mac-hebrew=x-mac-hebrew
 x-mac-arabic=x-mac-arabic
 x-mac-farsi=x-mac-farsi
 x-mac-devanagari=x-mac-devanagari
 x-mac-gujarati=x-mac-gujarati
 x-mac-gurmukhi=x-mac-gurmukhi
-geostd8=GEOSTD8
 armscii-8=armscii-8
 x-viet-tcvn5712=x-viet-tcvn5712
 x-viet-vps=x-viet-vps
 iso-10646-ucs-2=UTF-16BE
 x-iso-10646-ucs-2-be=UTF-16BE
 x-iso-10646-ucs-2-le=UTF-16LE
 x-user-defined=x-user-defined
 x-johab=x-johab
--- a/intl/uconv/directory.txt
+++ b/intl/uconv/directory.txt
@@ -12,17 +12,17 @@ util       - utility functions used by t
 
 The following directories contain different charset converters:
 
 ucvcn    - Simplified Chinese charsets - GB2312, HZ, ISO-2022-CN, GBK, GB18030
 ucvibm   - IBM charsets - CP850, 852, 855, 857, 862, 864, 869, 1125, 1131
 ucvja    - Japanese charsets - Shift-JIS, ISO-2022-JP, EUC-JP
 ucvko    - Korean charsets - ISO-2022-KR, EUC-KR, CP949
 ucvlatin - Latin charsets and others - ISO-8859-x, CP1250-1258
-                            CP866, 874, GEOSTD8, ARMSCII, ISO-IR-111, KOI8,
+                            CP866, 874, ARMSCII, ISO-IR-111, KOI8,
                             Mac charsets, T61, TIS620, TCVN, VISCII, VPS
                             UTF7, UTF16
 ucvtw    - Traditional Chinese charsets Set 1 - Big5
 ucvtw2   - Traditional Chinese charsets Set 2 - EUC-TW
 
 Within the directories containing charset converters:
 
 *.ut - tables used to convert to Unicode from a charset
--- a/intl/uconv/src/charsetData.properties
+++ b/intl/uconv/src/charsetData.properties
@@ -132,17 +132,16 @@ big5.LangGroup                     = zh-
 x-x-big5.LangGroup                 = zh-TW
 big5-hkscs.LangGroup               = zh-HK
 euc-jp.LangGroup                   = ja
 euc-kr.LangGroup                   = ko
 gb2312.LangGroup                   = zh-CN
 gb18030.LangGroup                  = zh-CN
 gb18030.2000-0.LangGroup           = zh-CN
 gb18030.2000-1.LangGroup           = zh-CN
-geostd8.LangGroup                  = x-geor
 hkscs-1.LangGroup                  = zh-HK
 hz-gb-2312.LangGroup               = zh-CN
 ibm850.LangGroup                   = x-western
 ibm852.LangGroup                   = x-central-euro
 ibm855.LangGroup                   = x-cyrillic
 ibm857.LangGroup                   = tr
 ibm862.LangGroup                   = he
 ibm864.LangGroup                   = ar
--- a/intl/uconv/src/nsUConvModule.cpp
+++ b/intl/uconv/src/nsUConvModule.cpp
@@ -110,17 +110,16 @@
 #include "nsKOI8UToUnicode.h"
 #include "nsMacCEToUnicode.h"
 #include "nsMacGreekToUnicode.h"
 #include "nsMacTurkishToUnicode.h"
 #include "nsMacCroatianToUnicode.h"
 #include "nsMacRomanianToUnicode.h"
 #include "nsMacCyrillicToUnicode.h"
 #include "nsMacIcelandicToUnicode.h"
-#include "nsGEOSTD8ToUnicode.h"
 #include "nsARMSCII8ToUnicode.h"
 #include "nsTCVN5712ToUnicode.h"
 #include "nsVISCIIToUnicode.h"
 #include "nsVPSToUnicode.h"
 #include "nsUTF7ToUnicode.h"
 #include "nsMUTF7ToUnicode.h"
 #include "nsUCS2BEToUnicode.h"
 #include "nsT61ToUnicode.h"
@@ -160,17 +159,16 @@
 #include "nsUnicodeToKOI8U.h"
 #include "nsUnicodeToMacCE.h"
 #include "nsUnicodeToMacGreek.h"
 #include "nsUnicodeToMacTurkish.h"
 #include "nsUnicodeToMacCroatian.h"
 #include "nsUnicodeToMacRomanian.h"
 #include "nsUnicodeToMacCyrillic.h"
 #include "nsUnicodeToMacIcelandic.h"
-#include "nsUnicodeToGEOSTD8.h"
 #include "nsUnicodeToARMSCII8.h"
 #include "nsUnicodeToTCVN5712.h"
 #include "nsUnicodeToVISCII.h"
 #include "nsUnicodeToVPS.h"
 #include "nsUnicodeToUTF7.h"
 #include "nsUnicodeToMUTF7.h"
 #include "nsUnicodeToUCS2BE.h"
 #include "nsUnicodeToT61.h"
@@ -311,17 +309,16 @@ NS_UCONV_REG_UNREG("KOI8-R", NS_KOI8RTOU
 NS_UCONV_REG_UNREG("KOI8-U", NS_KOI8UTOUNICODE_CID, NS_UNICODETOKOI8U_CID)
 NS_UCONV_REG_UNREG("x-mac-ce", NS_MACCETOUNICODE_CID, NS_UNICODETOMACCE_CID)
 NS_UCONV_REG_UNREG("x-mac-greek", NS_MACGREEKTOUNICODE_CID, NS_UNICODETOMACGREEK_CID)
 NS_UCONV_REG_UNREG("x-mac-turkish", NS_MACTURKISHTOUNICODE_CID, NS_UNICODETOMACTURKISH_CID)
 NS_UCONV_REG_UNREG("x-mac-croatian", NS_MACCROATIANTOUNICODE_CID, NS_UNICODETOMACCROATIAN_CID)
 NS_UCONV_REG_UNREG("x-mac-romanian", NS_MACROMANIANTOUNICODE_CID, NS_UNICODETOMACROMANIAN_CID)
 NS_UCONV_REG_UNREG("x-mac-cyrillic", NS_MACCYRILLICTOUNICODE_CID, NS_UNICODETOMACCYRILLIC_CID)
 NS_UCONV_REG_UNREG("x-mac-icelandic", NS_MACICELANDICTOUNICODE_CID, NS_UNICODETOMACICELANDIC_CID)
-NS_UCONV_REG_UNREG("GEOSTD8", NS_GEOSTD8TOUNICODE_CID, NS_UNICODETOGEOSTD8_CID)
 NS_UCONV_REG_UNREG("armscii-8", NS_ARMSCII8TOUNICODE_CID, NS_UNICODETOARMSCII8_CID)
 NS_UCONV_REG_UNREG("x-viet-tcvn5712", NS_TCVN5712TOUNICODE_CID, NS_UNICODETOTCVN5712_CID)
 NS_UCONV_REG_UNREG("VISCII", NS_VISCIITOUNICODE_CID, NS_UNICODETOVISCII_CID)
 NS_UCONV_REG_UNREG("x-viet-vps", NS_VPSTOUNICODE_CID, NS_UNICODETOVPS_CID)
 NS_UCONV_REG_UNREG("UTF-7", NS_UTF7TOUNICODE_CID, NS_UNICODETOUTF7_CID)
 NS_UCONV_REG_UNREG("x-imap4-modified-utf7", NS_MUTF7TOUNICODE_CID, NS_UNICODETOMUTF7_CID)
 NS_UCONV_REG_UNREG("UTF-16", NS_UTF16TOUNICODE_CID, NS_UNICODETOUTF16_CID)
 NS_UCONV_REG_UNREG("UTF-16BE", NS_UTF16BETOUNICODE_CID, NS_UNICODETOUTF16BE_CID)
@@ -611,17 +608,16 @@ NS_DEFINE_NAMED_CID(NS_KOI8RTOUNICODE_CI
 NS_DEFINE_NAMED_CID(NS_KOI8UTOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MACCETOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MACGREEKTOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MACTURKISHTOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MACCROATIANTOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MACROMANIANTOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MACCYRILLICTOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MACICELANDICTOUNICODE_CID);
-NS_DEFINE_NAMED_CID(NS_GEOSTD8TOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_ARMSCII8TOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_TCVN5712TOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_VISCIITOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_VPSTOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_UTF7TOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_MUTF7TOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_UTF16TOUNICODE_CID);
 NS_DEFINE_NAMED_CID(NS_UTF16BETOUNICODE_CID);
@@ -669,17 +665,16 @@ NS_DEFINE_NAMED_CID(NS_UNICODETOKOI8R_CI
 NS_DEFINE_NAMED_CID(NS_UNICODETOKOI8U_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMACCE_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMACGREEK_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMACTURKISH_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMACCROATIAN_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMACROMANIAN_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMACCYRILLIC_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMACICELANDIC_CID);
-NS_DEFINE_NAMED_CID(NS_UNICODETOGEOSTD8_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOARMSCII8_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOTCVN5712_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOVISCII_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOVPS_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOUTF7_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOMUTF7_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOUTF16BE_CID);
 NS_DEFINE_NAMED_CID(NS_UNICODETOUTF16LE_CID);
@@ -802,17 +797,16 @@ static const mozilla::Module::CIDEntry k
   { &kNS_KOI8UTOUNICODE_CID, false, NULL, nsKOI8UToUnicodeConstructor },
   { &kNS_MACCETOUNICODE_CID, false, NULL, nsMacCEToUnicodeConstructor },
   { &kNS_MACGREEKTOUNICODE_CID, false, NULL, nsMacGreekToUnicodeConstructor },
   { &kNS_MACTURKISHTOUNICODE_CID, false, NULL, nsMacTurkishToUnicodeConstructor },
   { &kNS_MACCROATIANTOUNICODE_CID, false, NULL, nsMacCroatianToUnicodeConstructor },
   { &kNS_MACROMANIANTOUNICODE_CID, false, NULL, nsMacRomanianToUnicodeConstructor },
   { &kNS_MACCYRILLICTOUNICODE_CID, false, NULL, nsMacCyrillicToUnicodeConstructor },
   { &kNS_MACICELANDICTOUNICODE_CID, false, NULL, nsMacIcelandicToUnicodeConstructor },
-  { &kNS_GEOSTD8TOUNICODE_CID, false, NULL, nsGEOSTD8ToUnicodeConstructor },
   { &kNS_ARMSCII8TOUNICODE_CID, false, NULL, nsARMSCII8ToUnicodeConstructor },
   { &kNS_TCVN5712TOUNICODE_CID, false, NULL, nsTCVN5712ToUnicodeConstructor },
   { &kNS_VISCIITOUNICODE_CID, false, NULL, nsVISCIIToUnicodeConstructor },
   { &kNS_VPSTOUNICODE_CID, false, NULL, nsVPSToUnicodeConstructor },
   { &kNS_UTF7TOUNICODE_CID, false, NULL, nsUTF7ToUnicodeConstructor },
   { &kNS_MUTF7TOUNICODE_CID, false, NULL, nsMUTF7ToUnicodeConstructor },
   { &kNS_UTF16TOUNICODE_CID, false, NULL, nsUTF16ToUnicodeConstructor },
   { &kNS_UTF16BETOUNICODE_CID, false, NULL, nsUTF16BEToUnicodeConstructor },
@@ -860,17 +854,16 @@ static const mozilla::Module::CIDEntry k
   { &kNS_UNICODETOKOI8U_CID, false, NULL, nsUnicodeToKOI8UConstructor },
   { &kNS_UNICODETOMACCE_CID, false, NULL, nsUnicodeToMacCEConstructor },
   { &kNS_UNICODETOMACGREEK_CID, false, NULL, nsUnicodeToMacGreekConstructor },
   { &kNS_UNICODETOMACTURKISH_CID, false, NULL, nsUnicodeToMacTurkishConstructor },
   { &kNS_UNICODETOMACCROATIAN_CID, false, NULL, nsUnicodeToMacCroatianConstructor },
   { &kNS_UNICODETOMACROMANIAN_CID, false, NULL, nsUnicodeToMacRomanianConstructor },
   { &kNS_UNICODETOMACCYRILLIC_CID, false, NULL, nsUnicodeToMacCyrillicConstructor },
   { &kNS_UNICODETOMACICELANDIC_CID, false, NULL, nsUnicodeToMacIcelandicConstructor },
-  { &kNS_UNICODETOGEOSTD8_CID, false, NULL, nsUnicodeToGEOSTD8Constructor },
   { &kNS_UNICODETOARMSCII8_CID, false, NULL, nsUnicodeToARMSCII8Constructor },
   { &kNS_UNICODETOTCVN5712_CID, false, NULL, nsUnicodeToTCVN5712Constructor },
   { &kNS_UNICODETOVISCII_CID, false, NULL, nsUnicodeToVISCIIConstructor },
   { &kNS_UNICODETOVPS_CID, false, NULL, nsUnicodeToVPSConstructor },
   { &kNS_UNICODETOUTF7_CID, false, NULL, nsUnicodeToUTF7Constructor },
   { &kNS_UNICODETOMUTF7_CID, false, NULL, nsUnicodeToMUTF7Constructor },
   { &kNS_UNICODETOUTF16BE_CID, false, NULL, nsUnicodeToUTF16BEConstructor },
   { &kNS_UNICODETOUTF16LE_CID, false, NULL, nsUnicodeToUTF16LEConstructor },
@@ -995,17 +988,16 @@ static const mozilla::Module::ContractID
   { NS_UNICODEDECODER_CONTRACTID_BASE "KOI8-U", &kNS_KOI8UTOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-mac-ce", &kNS_MACCETOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-mac-greek", &kNS_MACGREEKTOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-mac-turkish", &kNS_MACTURKISHTOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-mac-croatian", &kNS_MACCROATIANTOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-mac-romanian", &kNS_MACROMANIANTOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-mac-cyrillic", &kNS_MACCYRILLICTOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-mac-icelandic", &kNS_MACICELANDICTOUNICODE_CID },
-  { NS_UNICODEDECODER_CONTRACTID_BASE "GEOSTD8", &kNS_GEOSTD8TOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "armscii-8", &kNS_ARMSCII8TOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-viet-tcvn5712", &kNS_TCVN5712TOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "VISCII", &kNS_VISCIITOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-viet-vps", &kNS_VPSTOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "UTF-7", &kNS_UTF7TOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "x-imap4-modified-utf7", &kNS_MUTF7TOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "UTF-16", &kNS_UTF16TOUNICODE_CID },
   { NS_UNICODEDECODER_CONTRACTID_BASE "UTF-16BE", &kNS_UTF16BETOUNICODE_CID },
@@ -1053,17 +1045,16 @@ static const mozilla::Module::ContractID
   { NS_UNICODEENCODER_CONTRACTID_BASE "KOI8-U", &kNS_UNICODETOKOI8U_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-mac-ce", &kNS_UNICODETOMACCE_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-mac-greek", &kNS_UNICODETOMACGREEK_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-mac-turkish", &kNS_UNICODETOMACTURKISH_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-mac-croatian", &kNS_UNICODETOMACCROATIAN_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-mac-romanian", &kNS_UNICODETOMACROMANIAN_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-mac-cyrillic", &kNS_UNICODETOMACCYRILLIC_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-mac-icelandic", &kNS_UNICODETOMACICELANDIC_CID },
-  { NS_UNICODEENCODER_CONTRACTID_BASE "GEOSTD8", &kNS_UNICODETOGEOSTD8_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "armscii-8", &kNS_UNICODETOARMSCII8_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-viet-tcvn5712", &kNS_UNICODETOTCVN5712_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "VISCII", &kNS_UNICODETOVISCII_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-viet-vps", &kNS_UNICODETOVPS_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "UTF-7", &kNS_UNICODETOUTF7_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "x-imap4-modified-utf7", &kNS_UNICODETOMUTF7_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "UTF-16BE", &kNS_UNICODETOUTF16BE_CID },
   { NS_UNICODEENCODER_CONTRACTID_BASE "UTF-16LE", &kNS_UNICODETOUTF16LE_CID },
deleted file mode 100644
--- a/intl/uconv/tests/unit/test_decode_geostd8.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Tests conversion from geostd8 to Unicode
-	
-load('CharsetConversionTests.js');
-	
-const inString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x82\x84\x85\x86\x87\x89\x8b\x91\x92\x93\x94\x95\x96\x97\x9b\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xfd";
-    
-const expectedString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u20ac\u201a\u201e\u2026\u2020\u2021\u2030\u2039\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u203a\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u10d0\u10d1\u10d2\u10d3\u10d4\u10d5\u10d6\u10f1\u10d7\u10d8\u10d9\u10da\u10db\u10dc\u10f2\u10dd\u10de\u10df\u10e0\u10e1\u10e2\u10f3\u10e3\u10e4\u10e5\u10e6\u10e7\u10e8\u10e9\u10ea\u10eb\u10ec\u10ed\u10ee\u10f4\u10ef\u10f0\u10f5\u2116";
-
-const aliases = ["GEOSTD8"];
-
-function run_test() {
-  testDecodeAliases();
-}
deleted file mode 100644
--- a/intl/uconv/tests/unit/test_encode_geostd8.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Tests conversion from Unicode to geostd8
-	
-load('CharsetConversionTests.js');
-	
-const inString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u20ac\u201a\u201e\u2026\u2020\u2021\u2030\u2039\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u203a\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u10d0\u10d1\u10d2\u10d3\u10d4\u10d5\u10d6\u10f1\u10d7\u10d8\u10d9\u10da\u10db\u10dc\u10f2\u10dd\u10de\u10df\u10e0\u10e1\u10e2\u10f3\u10e3\u10e4\u10e5\u10e6\u10e7\u10e8\u10e9\u10ea\u10eb\u10ec\u10ed\u10ee\u10f4\u10ef\u10f0\u10f5\u2116";
-    
-const expectedString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x82\x84\x85\x86\x87\x89\x8b\x91\x92\x93\x94\x95\x96\x97\x9b\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xfd";
-
-const aliases = ["GEOSTD8"];
-
-function run_test() {
-  testEncodeAliases();
-}
--- a/intl/uconv/tests/unit/xpcshell.ini
+++ b/intl/uconv/tests/unit/xpcshell.ini
@@ -55,17 +55,16 @@ tail =
 [test_decode_CP850.js]
 [test_decode_CP852.js]
 [test_decode_CP855.js]
 [test_decode_CP857.js]
 [test_decode_CP862.js]
 [test_decode_CP864.js]
 [test_decode_CP874.js]
 [test_decode_armscii.js]
-[test_decode_geostd8.js]
 [test_decode_gbk.js]
 [test_decode_tcvn5712.js]
 [test_decode_utf-7_internal.js]
 [test_decode_utf-7.js]
 [test_decode_viscii.js]
 [test_decode_vps.js]
 [test_decode_x_mac_arabic.js]
 [test_decode_x_mac_arabic_internal.js]
@@ -111,17 +110,16 @@ tail =
 [test_encode_CP850.js]
 [test_encode_CP852.js]
 [test_encode_CP855.js]
 [test_encode_CP857.js]
 [test_encode_CP862.js]
 [test_encode_CP864.js]
 [test_encode_CP874.js]
 [test_encode_armscii.js]
-[test_encode_geostd8.js]
 [test_encode_gbk.js]
 [test_encode_tcvn5712.js]
 [test_encode_utf-7_internal.js]
 [test_encode_utf-7.js]
 [test_encode_viscii.js]
 [test_encode_vps.js]
 [test_encode_x_mac_arabic.js]
 [test_encode_x_mac_arabic_internal.js]
--- a/intl/uconv/ucvlatin/Makefile.in
+++ b/intl/uconv/ucvlatin/Makefile.in
@@ -90,17 +90,16 @@ CPPSRCS		= \
 		nsMacCyrillicToUnicode.cpp \
 		nsMacIcelandicToUnicode.cpp \
 		nsMacHebrewToUnicode.cpp \
 		nsMacArabicToUnicode.cpp \
 		nsMacDevanagariToUnicode.cpp \
 		nsMacFarsiToUnicode.cpp \
 		nsMacGujaratiToUnicode.cpp \
 		nsMacGurmukhiToUnicode.cpp \
-		nsGEOSTD8ToUnicode.cpp \
 		nsARMSCII8ToUnicode.cpp \
 		nsTCVN5712ToUnicode.cpp \
 		nsVISCIIToUnicode.cpp \
 		nsVPSToUnicode.cpp \
 		nsUTF7ToUnicode.cpp \
 		nsMUTF7ToUnicode.cpp \
 		nsUCS2BEToUnicode.cpp \
 		nsT61ToUnicode.cpp \
@@ -146,17 +145,16 @@ CPPSRCS		= \
 		nsUnicodeToMacCyrillic.cpp \
 		nsUnicodeToMacIcelandic.cpp \
 		nsUnicodeToMacHebrew.cpp \
 		nsUnicodeToMacArabic.cpp \
 		nsUnicodeToMacDevanagari.cpp \
 		nsUnicodeToMacFarsi.cpp \
 		nsUnicodeToMacGujarati.cpp \
 		nsUnicodeToMacGurmukhi.cpp \
-		nsUnicodeToGEOSTD8.cpp \
 		nsUnicodeToARMSCII8.cpp \
 		nsUnicodeToTCVN5712.cpp \
 		nsUnicodeToVISCII.cpp \
 		nsUnicodeToVPS.cpp \
 		nsUnicodeToUTF7.cpp \
 		nsUnicodeToMUTF7.cpp \
 		nsUnicodeToUCS2BE.cpp \
 		nsUnicodeToT61.cpp \
deleted file mode 100644
--- a/intl/uconv/ucvlatin/geostd8.uf
+++ /dev/null
@@ -1,139 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): Gia Shervashidze
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either 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 ***** */
-/*========================================================
-  This is a Generated file. Please don't edit it.
-
-  The tool which used to generate this file is called fromu.
-  If you have any problem of this file. Please contact 
-  Netscape Client International Team or 
-  ftang@netscape <Frank Tang> 
-
-              Table in Debug form 
-Begin of Item 0000
- Format 0
-  srcBegin = 0000
-  srcEnd = 007F
-  destBegin = 0000
-End of Item 0000 
-
-Begin of Item 0001
- Format 0
-  srcBegin = 00A0
-  srcEnd = 00BF
-  destBegin = 00A0
-End of Item 0001 
-
-Begin of Item 0002
- Format 1
-  srcBegin = 10D0
-  srcEnd = 10F5
-  mappingOffset = 0000
- Mapping  = 
-  00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C8
-  00C9 00CA 00CB 00CC 00CD 00CF 00D0 00D1
-  00D2 00D3 00D4 00D6 00D7 00D8 00D9 00DA
-  00DB 00DC 00DD 00DE 00DF 00E0 00E1 00E3
-  00E4 00C7 00CE 00D5 00E2 00E5
-End of Item 0002 
-
-Begin of Item 0003
- Format 1
-  srcBegin = 2013
-  srcEnd = 203A
-  mappingOffset = 0026
- Mapping  = 
-  0096 0097 FFFD FFFD FFFD 0091 0092 0082 
-  FFFD 0093 0094 0084 FFFD 0086 0087 0095 
-  FFFD FFFD FFFD 0085 FFFD FFFD FFFD FFFD 
-  FFFD FFFD FFFD FFFD FFFD 0089 FFFD FFFD 
-  FFFD FFFD FFFD FFFD FFFD FFFD 008B 009B 
-End of Item 0003 
-
-Begin of Item 0004
- Format 2
-  srcBegin = 20AC
-  destBegin = 0080
-End of Item 0004 
-
-Begin of Item 0005
- Format 2
-  srcBegin = 2116
-  destBegin = 00FD
-End of Item 0005 
-
-========================================================*/
-/* Offset=0x0000  ItemOfList */
-  0x0006,
-/*-------------------------------------------------------*/
-/* Offset=0x0001  offsetToFormatArray */
-  0x0004,
-/*-------------------------------------------------------*/
-/* Offset=0x0002  offsetToMapCellArray */ 
-  0x0006,
-/*-------------------------------------------------------*/
-/* Offset=0x0003  offsetToMappingTable */ 
-  0x0018,
-/*-------------------------------------------------------*/
-/*       Offset=0x0004   Start of Format Array */ 
-/*      Total of Format 0 : 0x0002                       */
-/*      Total of Format 1 : 0x0002                       */
-/*      Total of Format 2 : 0x0002                       */
-/*      Total of Format 3 : 0x0000                       */
-
-0x1100, 0x0022, 
-/*-------------------------------------------------------*/
-/*       Offset=0x0006   Start of MapCell Array */ 
-/* 0000 */    0x0000, 0x007F, 0x0000, 
-/* 0001 */    0x00A0, 0x00BF, 0x00A0, 
-/* 0002 */    0x10D0, 0x10F5, 0x0000, 
-/* 0003 */    0x2013, 0x203A, 0x0026, 
-/* 0004 */    0x20AC, 0x0000, 0x0080, 
-/* 0005 */    0x2116, 0x0000, 0x00FD, 
-/*-------------------------------------------------------*/
-/*       Offset=0x0018   Start of MappingTable */ 
-
-/* 0000 */    0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C8, 
-/* 0008 */    0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CF, 0x00D0, 0x00D1, 
-/* 0010 */    0x00D2, 0x00D3, 0x00D4, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 
-/* 0018 */    0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E3, 
-/* 0020 */    0x00E4, 0x00C7, 0x00CE, 0x00D5, 0x00E2, 0x00E5, 0x0096, 0x0097, 
-/* 0028 */    0xFFFD, 0xFFFD, 0xFFFD, 0x0091, 0x0092, 0x0082, 0xFFFD, 0x0093, 
-/* 0030 */    0x0094, 0x0084, 0xFFFD, 0x0086, 0x0087, 0x0095, 0xFFFD, 0xFFFD, 
-/* 0038 */    0xFFFD, 0x0085, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 
-/* 0040 */    0xFFFD, 0xFFFD, 0xFFFD, 0x0089, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 
-/* 0048 */    0xFFFD, 0x0085, 0xFFFD, 0xFFFD, 0x008B, 0x009B, 
-/*      End of table Total Length = 0x0066 * 2 */
deleted file mode 100644
--- a/intl/uconv/ucvlatin/geostd8.ut
+++ /dev/null
@@ -1,168 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Gia Shervashidze
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either 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 ***** */
-/*========================================================
-  This is a Generated file. Please don't edit it.
-
-  The tool which used to generate this file is called umaptable.
-  You can find this tool under mozilla/intl/uconv/tools/umaptable.c.
-  If you have any problem of this file. Please contact 
-  Netscape Client International Team or 
-  ftang@netscape <Frank Tang> 
-
-              Table in Debug form 
-Begin of Item 0000
- Format 0
-  srcBegin = 0000
-  srcEnd = 007F
-  destBegin = 0000
-End of Item 0000 
-
-Begin of Item 0001
- Format 0
-  srcBegin = 00A0
-  srcEnd = 00BF
-  destBegin = 00A0
-End of Item 0001 
-
-Begin of Item 0002
- Format 0
-  srcBegin = 00C0
-  srcEnd = 00C6
-  destBegin = 10D0
-End of Item 0002 
-
-Begin of Item 0003
- Format 0
-  srcBegin = 00C8
-  srcEnd = 00CD
-  destBegin = 10D7
-End of Item 0003 
-
-Begin of Item 0004
- Format 0
-  srcBegin = 00CF
-  srcEnd = 00D4
-  destBegin = 10DD
-End of Item 0004 
-
-Begin of Item 0005
- Format 0
-  srcBegin = 00D6
-  srcEnd = 00E1
-  destBegin = 10E3
-End of Item 0005 
-
-Begin of Item 0006
- Format 1
-  srcBegin = 0080
-  srcEnd = 009B
-  mappingOffset = 0000
- Mapping  = 
-  20AC FFFD 201A FFFD 201E 2026 2020 2021 
-  FFFD 2030 FFFD 2039 FFFD FFFD FFFD FFFD 
-  FFFD 2018 2019 201C 201D 2022 2013 2014 
-  FFFD FFFD FFFD 203A 
-End of Item 0006 
-
-Begin of Item 0007
- Format 1
-  srcBegin = 00C7
-  srcEnd = 00D5
-  mappingOffset = 001C
- Mapping  = 
-  10F1 FFFD FFFD FFFD FFFD FFFD FFFD 10F2 
-  FFFD FFFD FFFD FFFD FFFD FFFD 10F3 
-End of Item 0007 
-
-Begin of Item 0008
- Format 1
-  srcBegin = 00E2
-  srcEnd = 00E5
-  mappingOffset = 002B
- Mapping  = 
-  10F4 10EF 10F0 10F5 
-End of Item 0008 
-
-Begin of Item 0009
- Format 2
-  srcBegin = 00FD
-  destBegin = 2116
-End of Item 0009 
-
-========================================================*/
-/* Offset=0x0000  ItemOfList */
-  0x000A,
-/*-------------------------------------------------------*/
-/* Offset=0x0001  offsetToFormatArray */
-  0x0004,
-/*-------------------------------------------------------*/
-/* Offset=0x0002  offsetToMapCellArray */ 
-  0x0007,
-/*-------------------------------------------------------*/
-/* Offset=0x0003  offsetToMappingTable */ 
-  0x0025,
-/*-------------------------------------------------------*/
-/*       Offset=0x0004   Start of Format Array */ 
-/*	Total of Format 0 : 0x0006			 */
-/*	Total of Format 1 : 0x0003			 */
-/*	Total of Format 2 : 0x0001			 */
-/*	Total of Format 3 : 0x0000			 */
-
-0x0000, 0x1100, 0x0021, 
-/*-------------------------------------------------------*/
-/*       Offset=0x0007   Start of MapCell Array */ 
-/* 0000 */    0x0000, 0x007F, 0x0000, 
-/* 0001 */    0x00A0, 0x00BF, 0x00A0, 
-/* 0002 */    0x00C0, 0x00C6, 0x10D0, 
-/* 0003 */    0x00C8, 0x00CD, 0x10D7, 
-/* 0004 */    0x00CF, 0x00D4, 0x10DD, 
-/* 0005 */    0x00D6, 0x00E1, 0x10E3, 
-/* 0006 */    0x0080, 0x009B, 0x0000, 
-/* 0007 */    0x00C7, 0x00D5, 0x001C, 
-/* 0008 */    0x00E2, 0x00E5, 0x002B, 
-/* 0009 */    0x00FD, 0x0000, 0x2116, 
-/*-------------------------------------------------------*/
-/*       Offset=0x0025   Start of MappingTable */ 
-
-/* 0000 */    0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, 
-/* 0008 */    0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 
-/* 0010 */    0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 
-/* 0018 */    0xFFFD, 0xFFFD, 0xFFFD, 0x203A, 0x10F1, 0xFFFD, 0xFFFD, 0xFFFD, 
-/* 0020 */    0xFFFD, 0xFFFD, 0xFFFD, 0x10F2, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 
-/* 0028 */    0xFFFD, 0xFFFD, 0x10F3, 0x10F4, 0x10EF, 0x10F0, 0x10F5, 
-/*	End of table Total Length = 0x0054 * 2 */
deleted file mode 100644
--- a/intl/uconv/ucvlatin/nsGEOSTD8ToUnicode.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** 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.
- *
- * 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 ***** */
-
-#include "nsUCConstructors.h"
-#include "nsGEOSTD8ToUnicode.h"
-
-//----------------------------------------------------------------------
-// Global functions and data [declaration]
-
-static const PRUint16 g_utMappingTable[] = {
-#include "geostd8.ut"
-};
-
-nsresult
-nsGEOSTD8ToUnicodeConstructor(nsISupports *aOuter, REFNSIID aIID,
-                              void **aResult) 
-{
-  return CreateOneByteDecoder((uMappingTable*) &g_utMappingTable,
-                              aOuter, aIID, aResult);
-}
-
deleted file mode 100644
--- a/intl/uconv/ucvlatin/nsGEOSTD8ToUnicode.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** 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.
- *
- * 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 nsGEOSTD8ToUnicode_h___
-#define nsGEOSTD8ToUnicode_h___
-
-#include "nsISupports.h"
-
-/**
- * A character set converter from GEOSTD8 to Unicode.
- *
- */
-nsresult
-nsGEOSTD8ToUnicodeConstructor(nsISupports *aOuter, REFNSIID aIID,
-                            void **aResult);
-
-#endif /* nsGEOSTD8ToUnicode_h___ */
--- a/intl/uconv/ucvlatin/nsUCvLatinCID.h
+++ b/intl/uconv/ucvlatin/nsUCvLatinCID.h
@@ -196,21 +196,16 @@
 #define NS_MACCYRILLICTOUNICODE_CID \
   { 0x6394eea9, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
 
 // Class ID for our MacIcelandicToUnicode charset converter
 // {6394EEAB-FC3D-11d2-B3B8-00805F8A6670}
 #define NS_MACICELANDICTOUNICODE_CID \
   { 0x6394eeab, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
 
-// Class ID for our GEOSTD8ToUnicode charset converter
-// {6394EEAF-FC3D-11d2-B3B8-00805F8A6670}
-#define NS_GEOSTD8TOUNICODE_CID \
-  { 0x6394eeaf, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
-
 // Class ID for our ARMSCII8ToUnicode charset converter
 // {6394EEAC-FC3D-11d2-B3B8-00805F8A6670}
 #define NS_ARMSCII8TOUNICODE_CID \
   { 0x6394eeac, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
 
 // Class ID for our TCVN5712ToUnicode charset converter
 // {6394EEAD-FC3D-11d2-B3B8-00805F8A6670}
 #define NS_TCVN5712TOUNICODE_CID \
@@ -392,21 +387,16 @@
 #define NS_UNICODETOMACCYRILLIC_CID \
   { 0x6394eeb9, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
 
 // Class ID for our UnicodeToMacIcelandic charset converter
 // {6394EEBB-FC3D-11d2-B3B8-00805F8A6670}
 #define NS_UNICODETOMACICELANDIC_CID \
   { 0x6394eebb, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
 
-// Class ID for our UnicodeToGEOSTD8 charset converter
-// {6394EEBE-FC3D-11d2-B3B8-00805F8A6670}
-#define NS_UNICODETOGEOSTD8_CID \
-  { 0x6394eebe, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
-
 // Class ID for our UnicodeToARMSCII8 charset converter
 // {6394EEBC-FC3D-11d2-B3B8-00805F8A6670}
 #define NS_UNICODETOARMSCII8_CID \
   { 0x6394eebc, 0xfc3d, 0x11d2, {0xb3, 0xb8, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70}}
 
 // Class ID for our UnicodeToTCVN5712 charset converter
 // {6394EEBD-FC3D-11d2-B3B8-00805F8A6670}
 #define NS_UNICODETOTCVN5712_CID \
deleted file mode 100644
--- a/intl/uconv/ucvlatin/nsUnicodeToGEOSTD8.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** 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.
- *
- * 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 ***** */
-
-#include "nsUCConstructors.h"
-#include "nsUnicodeToGEOSTD8.h"
-
-//----------------------------------------------------------------------
-// Global functions and data [declaration]
-
-static const PRUint16 g_ufMappingTable[] = {
-#include "geostd8.uf"
-};
-
-nsresult
-nsUnicodeToGEOSTD8Constructor(nsISupports *aOuter, REFNSIID aIID,
-                              void **aResult) 
-{
-  return CreateTableEncoder(u1ByteCharset,
-                            (uMappingTable*) &g_ufMappingTable, 1,
-                            aOuter, aIID, aResult);
-}
deleted file mode 100644
--- a/intl/uconv/ucvlatin/nsUnicodeToGEOSTD8.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** 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.
- *
- * 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 nsUnicodeToGEOSTD8_h___
-#define nsUnicodeToGEOSTD8_h___
-
-#include "nsISupports.h"
-
-/**
- * A character set converter from Unicode to GEOSTD8.
- *
- */
-nsresult
-nsUnicodeToGEOSTD8Constructor(nsISupports *aOuter, REFNSIID aIID,
-                              void **aResult);
-
-#endif /* nsUnicodeToGEOSTD8_h___ */
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -43,16 +43,18 @@
 #ifndef jshashtable_h_
 #define jshashtable_h_
 
 #include "TemplateLib.h"
 #include "Utility.h"
 
 namespace js {
 
+class TempAllocPolicy;
+
 /* Integral types for all hash functions. */
 typedef uint32_t HashNumber;
 
 /*****************************************************************************/
 
 namespace detail {
 
 template <class T, class HashPolicy, class AllocPolicy>
@@ -953,17 +955,20 @@ struct IsPodType<HashMapEntry<K, V> >
  *  - see "Hash policy" above (default js::DefaultHasher<Key>)
  * AllocPolicy:
  *  - see "Allocation policies" in jsalloc.h
  *
  * N.B: HashMap is not reentrant: Key/Value/HashPolicy/AllocPolicy members
  *      called by HashMap must not call back into the same HashMap object.
  * N.B: Due to the lack of exception handling, the user must call |init()|.
  */
-template <class Key, class Value, class HashPolicy, class AllocPolicy>
+template <class Key,
+          class Value,
+          class HashPolicy = DefaultHasher<Key>,
+          class AllocPolicy = TempAllocPolicy>
 class HashMap
 {
   public:
     typedef typename HashPolicy::Lookup Lookup;
 
     typedef HashMapEntry<Key, Value> Entry;
 
   private:
@@ -1195,17 +1200,17 @@ class HashMap
  *  - see "Hash policy" above (default js::DefaultHasher<Key>)
  * AllocPolicy:
  *  - see "Allocation policies" in jsalloc.h
  *
  * N.B: HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by
  *      HashSet must not call back into the same HashSet object.
  * N.B: Due to the lack of exception handling, the user must call |init()|.
  */
-template <class T, class HashPolicy, class AllocPolicy>
+template <class T, class HashPolicy = DefaultHasher<T>, class AllocPolicy = TempAllocPolicy>
 class HashSet
 {
     typedef typename HashPolicy::Lookup Lookup;
 
     /* Implement HashSet in terms of HashTable. */
     struct SetOps : HashPolicy {
         typedef T KeyType;
         static const KeyType &getKey(const T &t) { return t; }
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -69,17 +69,17 @@ JS_BEGIN_EXTERN_C
 
 /*
  * Pattern used to overwrite freed memory. If you are accessing an object with
  * this pattern, you probably have a dangling pointer.
  */
 #define JS_FREE_PATTERN 0xDA
 
 #define JS_ASSERT(expr)           MOZ_ASSERT(expr)
-#define JS_ASSERT_IF(cond, expr)  MOZ_ASSERT_IF((cond), (expr))
+#define JS_ASSERT_IF(cond, expr)  MOZ_ASSERT_IF(cond, expr)
 #define JS_NOT_REACHED(reason)    MOZ_NOT_REACHED(reason)
 #define JS_ALWAYS_TRUE(expr)      MOZ_ALWAYS_TRUE(expr)
 #define JS_ALWAYS_FALSE(expr)     MOZ_ALWAYS_FALSE(expr)
 
 #ifdef DEBUG
 # ifdef JS_THREADSAFE
 #  define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr)
 # else
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -49,17 +49,21 @@
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
 namespace js {
 
-template <class T, size_t N, class AllocPolicy>
+class TempAllocPolicy;
+
+template <class T,
+          size_t MinInlineCapacity = 0,
+          class AllocPolicy = TempAllocPolicy>
 class Vector;
 
 /*
  * This template class provides a default implementation for vector operations
  * when the element type is not known to be a POD, as judged by IsPodType.
  */
 template <class T, size_t N, class AP, bool IsPod>
 struct VectorImpl
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -152,17 +152,17 @@ CPPSRCS		= \
 		jsutil.cpp \
 		jswatchpoint.cpp \
 		jsweakmap.cpp \
 		jswrapper.cpp \
 		jsxdrapi.cpp \
 		jsxml.cpp \
 		prmjtime.cpp \
 		sharkctl.cpp \
-		CallObject.cpp \
+		ScopeObject.cpp \
 		Debugger.cpp \
 		GlobalObject.cpp \
 		Stack.cpp \
 		String.cpp \
 		BytecodeCompiler.cpp \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
 		ParseMaps.cpp \
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -239,17 +239,17 @@ CompileRegExpObject(JSContext *cx, RegEx
          * Note: the regexp static flags are not taken into consideration here.
          */
         JSObject &sourceObj = sourceValue.toObject();
         if (argc >= 2 && !argv[1].isUndefined()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
             return false;
         }
 
-        RegExpObject *reobj = builder.build(sourceObj.asRegExp());
+        RegExpObject *reobj = builder.build(&sourceObj.asRegExp());
         if (!reobj)
             return false;
         *rval = ObjectValue(*reobj);
         return true;
     }
 
     JSLinearString *sourceStr;
     if (sourceValue.isUndefined()) {
@@ -295,17 +295,17 @@ regexp_compile(JSContext *cx, uintN argc
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, regexp_compile, &RegExpClass, &ok);
     if (!obj)
         return ok;
 
-    RegExpObjectBuilder builder(cx, obj->asRegExp());
+    RegExpObjectBuilder builder(cx, &obj->asRegExp());
     return CompileRegExpObject(cx, builder, args.length(), args.array(), &args.rval());
 }
 
 static JSBool
 regexp_construct(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = JS_ARGV(cx, vp);
 
@@ -334,17 +334,17 @@ regexp_toString(JSContext *cx, uintN arg
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, regexp_toString, &RegExpClass, &ok);
     if (!obj)
         return ok;
 
-    JSString *str = obj->asRegExp()->toString(cx);
+    JSString *str = obj->asRegExp().toString(cx);
     if (!str)
         return false;
 
     *vp = StringValue(str);
     return true;
 }
 
 static JSFunctionSpec regexp_methods[] = {
@@ -448,24 +448,24 @@ static JSPropertySpec regexp_static_prop
     {0,0,0,0,0}
 };
 
 JSObject *
 js_InitRegExpClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    GlobalObject *global = obj->asGlobal();
+    GlobalObject *global = &obj->asGlobal();
 
     JSObject *proto = global->createBlankPrototype(cx, &RegExpClass);
     if (!proto)
         return NULL;
     proto->setPrivate(NULL);
 
-    RegExpObject *reproto = proto->asRegExp();
+    RegExpObject *reproto = &proto->asRegExp();
     RegExpObjectBuilder builder(cx, reproto);
     if (!builder.build(cx->runtime->emptyString, RegExpFlag(0)))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, regexp_methods))
         return NULL;
 
     JSFunction *ctor = global->createConstructor(cx, regexp_construct, &RegExpClass,
@@ -509,17 +509,17 @@ ExecuteRegExp(JSContext *cx, Native nati
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     bool ok;
     JSObject *obj = NonGenericMethodGuard(cx, args, native, &RegExpClass, &ok);
     if (!obj)
         return ok;
 
-    RegExpObject *reobj = obj->asRegExp();
+    RegExpObject *reobj = &obj->asRegExp();
 
     RegExpMatcher matcher(cx);
     if (reobj->startsWithAtomizedGreedyStar()) {
         if (!matcher.resetWithTestOptimized(reobj))
             return false;
     } else {
         if (!matcher.reset(reobj))
             return false;
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -187,19 +187,19 @@ frontend::CompileScript(JSContext *cx, J
     BytecodeEmitter bce(&parser, tokenStream.getLineno());
     if (!bce.init(cx, TreeContext::USED_AS_TREE_CONTEXT))
         return NULL;
 
     Probes::compileScriptBegin(cx, filename, lineno);
     MUST_FLOW_THROUGH("out");
 
     // We can specialize a bit for the given scope chain if that scope chain is the global object.
-    JSObject *globalObj = scopeChain && scopeChain == scopeChain->getGlobal()
-                        ? scopeChain->getGlobal()
-                        : NULL;
+    JSObject *globalObj = scopeChain && scopeChain == &scopeChain->global()
+                          ? &scopeChain->global()
+                          : NULL;
 
     JS_ASSERT_IF(globalObj, globalObj->isNative());
     JS_ASSERT_IF(globalObj, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalObj->getClass()));
 
     /* Null script early in case of error, to reduce our code footprint. */
     script = NULL;
 
     GlobalScope globalScope(cx, globalObj, &bce);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -185,22 +185,22 @@ EmitCheck(JSContext *cx, BytecodeEmitter
         JS_ASSERT(newlength >= size_t(offset + delta));
         bce->current->base = newbase;
         bce->current->limit = newbase + newlength;
         bce->current->next = newbase + offset;
     }
     return offset;
 }
 
-static JSObject *
+static StaticBlockObject &
 CurrentBlock(BytecodeEmitter *bce)
 {
     JS_ASSERT(bce->topStmt->type == STMT_BLOCK || bce->topStmt->type == STMT_SWITCH);
     JS_ASSERT(bce->topStmt->blockObj->isStaticBlock());
-    return bce->topStmt->blockObj;
+    return *bce->topStmt->blockObj;
 }
 
 static void
 UpdateDepth(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t target)
 {
     jsbytecode *pc = bce->code(target);
     JSOp op = (JSOp) *pc;
     const JSCodeSpec *cs = &js_CodeSpec[op];
@@ -220,21 +220,21 @@ UpdateDepth(JSContext *cx, BytecodeEmitt
     /*
      * Specially handle any case that would call js_GetIndexFromBytecode since
      * it requires a well-formed script. This allows us to safely pass NULL as
      * the 'script' parameter.
      */
     intN nuses, ndefs;
     if (op == JSOP_ENTERBLOCK) {
         nuses = 0;
-        ndefs = OBJ_BLOCK_COUNT(cx, CurrentBlock(bce));
+        ndefs = CurrentBlock(bce).slotCount();
     } else if (op == JSOP_ENTERLET0) {
-        nuses = ndefs = OBJ_BLOCK_COUNT(cx, CurrentBlock(bce));
+        nuses = ndefs = CurrentBlock(bce).slotCount();
     } else if (op == JSOP_ENTERLET1) {
-        nuses = ndefs = OBJ_BLOCK_COUNT(cx, CurrentBlock(bce)) + 1;
+        nuses = ndefs = CurrentBlock(bce).slotCount() + 1;
     } else {
         nuses = StackUses(NULL, pc);
         ndefs = StackDefs(NULL, pc);
     }
 
     bce->stackDepth -= nuses;
     JS_ASSERT(bce->stackDepth >= 0);
     bce->stackDepth += ndefs;
@@ -1351,25 +1351,25 @@ frontend::PushStatement(TreeContext *tc,
         stmt->downScope = tc->topScopeStmt;
         tc->topScopeStmt = stmt;
     } else {
         stmt->downScope = NULL;
     }
 }
 
 void
-frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, JSObject *blockObj, ptrdiff_t top)
+frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, StaticBlockObject &blockObj, ptrdiff_t top)
 {
     PushStatement(tc, stmt, STMT_BLOCK, top);
     stmt->flags |= SIF_SCOPE;
-    blockObj->setStaticBlockScopeChain(tc->blockChain);
+    blockObj.setEnclosingBlock(tc->blockChain);
     stmt->downScope = tc->topScopeStmt;
     tc->topScopeStmt = stmt;
-    tc->blockChain = blockObj;
-    stmt->blockObj = blockObj;
+    tc->blockChain = &blockObj;
+    stmt->blockObj = &blockObj;
 }
 
 /*
  * Emit a backpatch op with offset pointing to the previous jump of this type,
  * so that we can walk back up the chain fixing up the op and jump offset.
  */
 static ptrdiff_t
 EmitBackPatchOp(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t *lastp)
@@ -1555,17 +1555,17 @@ EmitNonLocalJumpFixup(JSContext *cx, Byt
             npops += 2;
             break;
 
           default:;
         }
 
         if (stmt->flags & SIF_SCOPE) {
             FLUSH_POPS();
-            uintN blockObjCount = OBJ_BLOCK_COUNT(cx, stmt->blockObj);
+            uintN blockObjCount = stmt->blockObj->slotCount();
             if (stmt->flags & SIF_FOR_BLOCK) {
                 /*
                  * For a for-let-in statement, pushing/popping the block is
                  * interleaved with JSOP_(END)ITER. Just handle both together
                  * here and skip over the enclosing STMT_FOR_IN_LOOP.
                  */
                 JS_ASSERT(stmt->down->type == STMT_FOR_IN_LOOP);
                 stmt = stmt->down;
@@ -1644,17 +1644,17 @@ BackPatch(JSContext *cx, BytecodeEmitter
 void
 frontend::PopStatementTC(TreeContext *tc)
 {
     StmtInfo *stmt = tc->topStmt;
     tc->topStmt = stmt->down;
     if (STMT_LINKS_SCOPE(stmt)) {
         tc->topScopeStmt = stmt->downScope;
         if (stmt->flags & SIF_SCOPE)
-            tc->blockChain = stmt->blockObj->staticBlockScopeChain();
+            tc->blockChain = stmt->blockObj->enclosingBlock();
     }
 }
 
 JSBool
 frontend::PopStatementBCE(JSContext *cx, BytecodeEmitter *bce)
 {
     StmtInfo *stmt = bce->topStmt;
     if (!STMT_IS_TRYING(stmt) &&
@@ -1686,27 +1686,23 @@ frontend::LexicalLookup(TreeContext *tc,
     for (; stmt; stmt = stmt->downScope) {
         if (stmt->type == STMT_WITH)
             break;
 
         /* Skip "maybe scope" statements that don't contain let bindings. */
         if (!(stmt->flags & SIF_SCOPE))
             continue;
 
-        JSObject *obj = stmt->blockObj;
-        JS_ASSERT(obj->isStaticBlock());
-
-        const Shape *shape = obj->nativeLookup(tc->parser->context, ATOM_TO_JSID(atom));
+        StaticBlockObject &blockObj = *stmt->blockObj;
+        const Shape *shape = blockObj.nativeLookup(tc->parser->context, ATOM_TO_JSID(atom));
         if (shape) {
             JS_ASSERT(shape->hasShortID());
 
-            if (slotp) {
-                JS_ASSERT(obj->getSlot(JSSLOT_BLOCK_DEPTH).isInt32());
-                *slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid();
-            }
+            if (slotp)
+                *slotp = blockObj.stackDepth() + shape->shortid();
             return stmt;
         }
     }
 
     if (slotp)
         *slotp = -1;
     return stmt;
 }
@@ -1958,70 +1954,61 @@ AdjustBlockSlot(JSContext *cx, BytecodeE
 
 static bool
 EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
 {
     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
     if (!EmitObjectOp(cx, pn->pn_objbox, op, bce))
         return false;
 
-    JSObject *blockObj = pn->pn_objbox->object;
-    JS_ASSERT(blockObj->isStaticBlock());
-    JS_ASSERT(blockObj->getSlot(JSSLOT_BLOCK_DEPTH).isUndefined());
+    StaticBlockObject &blockObj = pn->pn_objbox->object->asStaticBlock();
 
     int depth = bce->stackDepth -
-                (OBJ_BLOCK_COUNT(cx, blockObj) + ((op == JSOP_ENTERLET1) ? 1 : 0));
+                (blockObj.slotCount() + ((op == JSOP_ENTERLET1) ? 1 : 0));
     JS_ASSERT(depth >= 0);
-    OBJ_SET_BLOCK_DEPTH(cx, blockObj, depth);
+
+    blockObj.setStackDepth(depth);
+
     int depthPlusFixed = AdjustBlockSlot(cx, bce, depth);
     if (depthPlusFixed < 0)
         return false;
 
-    uintN base = JSSLOT_FREE(&BlockClass);
-    for (uintN slot = base, limit = base + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) {
-        const Value &v = blockObj->getSlot(slot);
+    for (unsigned i = 0; i < blockObj.slotCount(); i++) {
+        Definition *dn = blockObj.maybeDefinitionParseNode(i);
+        blockObj.poisonDefinitionParseNode(i);
 
         /* Beware the empty destructuring dummy. */
-        if (v.isUndefined()) {
-            JS_ASSERT(slot + 1 <= limit);
+        if (!dn) {
+            JS_ASSERT(i + 1 <= blockObj.slotCount());
             continue;
         }
 
-        Definition *dn = (Definition *) v.toPrivate();
         JS_ASSERT(dn->isDefn());
         JS_ASSERT(uintN(dn->frameSlot() + depthPlusFixed) < JS_BIT(16));
         dn->pn_cookie.set(dn->pn_cookie.level(), uint16_t(dn->frameSlot() + depthPlusFixed));
 #ifdef DEBUG
         for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
             JS_ASSERT(pnu->pn_lexdef == dn);
             JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
             JS_ASSERT(pnu->pn_cookie.isFree());
         }
 #endif
-
-        /*
-         * If this variable is closed over, and |eval| is not present, then
-         * then set a bit in dslots so the Method JIT can deoptimize this
-         * slot.
-         */
-        bool isClosed = bce->shouldNoteClosedName(dn);
-        blockObj->setSlot(slot, BooleanValue(isClosed));
     }
 
     /*
      * If clones of this block will have any extensible parents, then the
      * clones must get unique shapes; see the comments for
      * js::Bindings::extensibleParents.
      */
     if ((bce->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
         bce->bindings.extensibleParents()) {
-        Shape *newShape = Shape::setExtensibleParents(cx, blockObj->lastProperty());
+        Shape *newShape = Shape::setExtensibleParents(cx, blockObj.lastProperty());
         if (!newShape)
             return false;
-        blockObj->setLastPropertyInfallible(newShape);
+        blockObj.setLastPropertyInfallible(newShape);
     }
 
     return true;
 }
 
 /*
  * Try to convert a *NAME op to a *GNAME op, which optimizes access to
  * undeclared globals. Return true if a conversion was made.
@@ -3222,33 +3209,33 @@ EmitSwitch(JSContext *cx, BytecodeEmitte
     defaultOffset = -1;
 
     pn2 = pn->pn_right;
 #if JS_HAS_BLOCK_SCOPE
     /*
      * If there are hoisted let declarations, their stack slots go under the
      * discriminant's value so push their slots now and enter the block later.
      */
-    uint32_t blockCount = 0;
+    uint32_t blockObjCount = 0;
     if (pn2->isKind(PNK_LEXICALSCOPE)) {
-        blockCount = OBJ_BLOCK_COUNT(cx, pn2->pn_objbox->object);
-        for (uint32_t i = 0; i < blockCount; ++i) {
+        blockObjCount = pn2->pn_objbox->object->asStaticBlock().slotCount();
+        for (uint32_t i = 0; i < blockObjCount; ++i) {
             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
                 return JS_FALSE;
         }
     }
 #endif
 
     /* Push the discriminant. */
     if (!EmitTree(cx, bce, pn->pn_left))
         return JS_FALSE;
 
 #if JS_HAS_BLOCK_SCOPE
     if (pn2->isKind(PNK_LEXICALSCOPE)) {
-        PushBlockScope(bce, &stmtInfo, pn2->pn_objbox->object, -1);
+        PushBlockScope(bce, &stmtInfo, pn2->pn_objbox->object->asStaticBlock(), -1);
         stmtInfo.type = STMT_SWITCH;
         if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
             return JS_FALSE;
     }
 #endif
 
     /* Switch bytecodes run from here till end of final case. */
     top = bce->offset();
@@ -3705,17 +3692,17 @@ EmitSwitch(JSContext *cx, BytecodeEmitte
 out:
     if (table)
         cx->free_(table);
     if (ok) {
         ok = PopStatementBCE(cx, bce);
 
 #if JS_HAS_BLOCK_SCOPE
         if (ok && pn->pn_right->isKind(PNK_LEXICALSCOPE))
-            EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockCount);
+            EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
 #endif
     }
     return ok;
 
 bad:
     ok = JS_FALSE;
     goto out;
 }
@@ -5119,17 +5106,17 @@ EmitTry(JSContext *cx, BytecodeEmitter *
             CATCHNOTE(stmtInfo) = catchNote;
 
             /*
              * Emit the lexical scope and catch body.  Save the catch's
              * block object population via count, for use when targeting
              * guardJump at the next catch (the guard mismatch case).
              */
             JS_ASSERT(pn3->isKind(PNK_LEXICALSCOPE));
-            count = OBJ_BLOCK_COUNT(cx, pn3->pn_objbox->object);
+            count = pn3->pn_objbox->object->asStaticBlock().slotCount();
             if (!EmitTree(cx, bce, pn3))
                 return false;
 
             /* gosub <finally>, if required */
             if (pn->pn_kid3) {
                 if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &GOSUBS(stmtInfo)) < 0)
                     return false;
                 JS_ASSERT(bce->stackDepth == depth);
@@ -5358,29 +5345,28 @@ EmitIf(JSContext *cx, BytecodeEmitter *b
 static bool
 EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
 {
     JS_ASSERT(pnLet->isArity(PN_BINARY));
     ParseNode *varList = pnLet->pn_left;
     JS_ASSERT(varList->isArity(PN_LIST));
     ParseNode *letBody = pnLet->pn_right;
     JS_ASSERT(letBody->isLet() && letBody->isKind(PNK_LEXICALSCOPE));
-    JSObject *blockObj = letBody->pn_objbox->object;
-    JS_ASSERT(blockObj->isStaticBlock());
+    StaticBlockObject &blockObj = letBody->pn_objbox->object->asStaticBlock();
 
     ptrdiff_t letHeadOffset = bce->offset();
     intN letHeadDepth = bce->stackDepth;
 
     LetNotes letNotes(cx);
     if (!EmitVariables(cx, bce, varList, PushInitialValues, &letNotes))
         return false;
 
     /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */
     uint32_t alreadyPushed = uintN(bce->stackDepth - letHeadDepth);
-    uint32_t blockObjCount = OBJ_BLOCK_COUNT(cx, blockObj);
+    uint32_t blockObjCount = blockObj.slotCount();
     for (uint32_t i = alreadyPushed; i < blockObjCount; ++i) {
         /* Tell the decompiler not to print the decl in the let head. */
         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
             return false;
         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
             return false;
     }
 
@@ -5403,17 +5389,17 @@ EmitLet(JSContext *cx, BytecodeEmitter *
 
     JSOp leaveOp = letBody->getOp();
     if (leaveOp == JSOP_LEAVEBLOCKEXPR) {
         if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - letHeadOffset) < 0)
             return false;
     }
 
     JS_ASSERT(leaveOp == JSOP_LEAVEBLOCK || leaveOp == JSOP_LEAVEBLOCKEXPR);
-    EMIT_UINT16_IMM_OP(leaveOp, OBJ_BLOCK_COUNT(cx, blockObj));
+    EMIT_UINT16_IMM_OP(leaveOp, blockObj.slotCount());
 
     ptrdiff_t bodyEnd = bce->offset();
     JS_ASSERT(bodyEnd > bodyBegin);
 
     if (!PopStatementBCE(cx, bce))
         return false;
 
     ptrdiff_t o = PackLetData((bodyEnd - bodyBegin) -
@@ -5501,18 +5487,17 @@ EmitXMLProcessingInstruction(JSContext *
 static bool
 EmitLexicalScope(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
     JS_ASSERT(pn->getOp() == JSOP_LEAVEBLOCK);
 
     StmtInfo stmtInfo;
     ObjectBox *objbox = pn->pn_objbox;
-    JSObject *blockObj = objbox->object;
-    JS_ASSERT(blockObj->isStaticBlock());
+    StaticBlockObject &blockObj = objbox->object->asStaticBlock();
     PushBlockScope(bce, &stmtInfo, blockObj, bce->offset());
 
     /*
      * For compound statements (i.e. { stmt-list }), the decompiler does not
      * emit curlies by default. However, if this stmt-list contains a let
      * declaration, this is semantically invalid so we need to add a srcnote to
      * enterblock to tell the decompiler to add curlies. This condition
      * shouldn't be so complicated; try to find a simpler condition.
@@ -5541,17 +5526,17 @@ EmitLexicalScope(JSContext *cx, Bytecode
     if (!EmitTree(cx, bce, pn->pn_expr))
         return false;
 
     if (noteIndex >= 0) {
         if (!SetSrcNoteOffset(cx, bce, (uintN)noteIndex, 0, bce->offset() - bodyBegin))
             return false;
     }
 
-    EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, OBJ_BLOCK_COUNT(cx, blockObj));
+    EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObj.slotCount());
 
     return PopStatementBCE(cx, bce);
 }
 
 static bool
 EmitWith(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     StmtInfo stmtInfo;
@@ -5613,18 +5598,18 @@ EmitForIn(JSContext *cx, BytecodeEmitter
 
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
     ParseNode *pn1 = forHead->pn_kid1;
     bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
     JS_ASSERT_IF(letDecl, pn1->isLet());
 
-    JSObject *blockObj = letDecl ? pn1->pn_objbox->object : NULL;
-    uint32_t blockObjCount = blockObj ? OBJ_BLOCK_COUNT(cx, blockObj) : 0;
+    StaticBlockObject *blockObj = letDecl ? &pn1->pn_objbox->object->asStaticBlock() : NULL;
+    uint32_t blockObjCount = blockObj ? blockObj->slotCount() : 0;
 
     if (letDecl) {
         /*
          * The let's slot(s) will be under the iterator, but the block must not
          * be entered (i.e. fp->blockChain set) until after evaluating the rhs.
          * Thus, push to reserve space and enterblock after. The same argument
          * applies when leaving the loop. Thus, a for-let-in loop looks like:
          *
@@ -5671,17 +5656,17 @@ EmitForIn(JSContext *cx, BytecodeEmitter
      */
     JS_ASSERT(pn->isOp(JSOP_ITER));
     if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
         return false;
 
     /* Enter the block before the loop body, after evaluating the obj. */
     StmtInfo letStmt;
     if (letDecl) {
-        PushBlockScope(bce, &letStmt, blockObj, bce->offset());
+        PushBlockScope(bce, &letStmt, *blockObj, bce->offset());
         letStmt.flags |= SIF_FOR_BLOCK;
         if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
             return false;
     }
 
     /* Annotate so the decompiler can find the loop-closing jump. */
     intN noteIndex = NewSrcNote(cx, bce, SRC_FOR_IN);
     if (noteIndex < 0)
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -133,17 +133,17 @@ struct StmtInfo {
     uint16_t        type;           /* statement type */
     uint16_t        flags;          /* flags, see below */
     uint32_t        blockid;        /* for simplified dominance computation */
     ptrdiff_t       update;         /* loop update offset (top if none) */
     ptrdiff_t       breaks;         /* offset of last break in loop */
     ptrdiff_t       continues;      /* offset of last continue in loop */
     union {
         JSAtom      *label;         /* name of LABEL */
-        JSObject    *blockObj;      /* block scope object */
+        StaticBlockObject *blockObj;/* block scope object */
     };
     StmtInfo        *down;          /* info for enclosing statement */
     StmtInfo        *downScope;     /* next enclosing lexical scope */
 };
 
 #define SIF_SCOPE        0x0001     /* statement has its own lexical scope */
 #define SIF_BODY_BLOCK   0x0002     /* STMT_BLOCK type is a function body */
 #define SIF_FOR_BLOCK    0x0004     /* for (let ...) induced block scope */
@@ -294,17 +294,17 @@ struct TreeContext {                /* t
     uint32_t        parenDepth;     /* nesting depth of parens that might turn out
                                        to be generator expressions */
     uint32_t        yieldCount;     /* number of |yield| tokens encountered at
                                        non-zero depth in current paren tree */
     uint32_t        argumentsCount; /* number of |arguments| references encountered
                                        at non-zero depth in current paren tree */
     StmtInfo        *topStmt;       /* top of statement info stack */
     StmtInfo        *topScopeStmt;  /* top lexical scope statement */
-    JSObject        *blockChain;    /* compile time block scope chain (NB: one
+    StaticBlockObject *blockChain;  /* compile block scope chain (NB: one
                                        deeper than the topScopeStmt/downScope
                                        chain when in head of let block/expr) */
     ParseNode       *blockNode;     /* parse node for a block with let declarations
                                        (block with its own lexical scope)  */
     AtomDecls       decls;          /* function, const, and var declarations */
     Parser          *parser;        /* ptr to common parsing and lexing data */
     ParseNode       *yieldNode;     /* parse node for a yield expression that might
                                        be an error if we turn out to be inside a
@@ -829,17 +829,17 @@ void
 PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top);
 
 /*
  * Push a block scope statement and link blockObj into tc->blockChain. To pop
  * this statement info record, use PopStatementTC as usual, or if appropriate
  * (if generating code), PopStatementBCE.
  */
 void
-PushBlockScope(TreeContext *tc, StmtInfo *stmt, JSObject *blockObj, ptrdiff_t top);
+PushBlockScope(TreeContext *tc, StmtInfo *stmt, StaticBlockObject &blockObj, ptrdiff_t top);
 
 /*
  * Pop tc->topStmt. If the top StmtInfo struct is not stack-allocated, it
  * is up to the caller to free it.
  */
 void
 PopStatementTC(TreeContext *tc);
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -174,18 +174,16 @@ Parser::setPrincipals(JSPrincipals *prin
     originPrincipals = originPrin;
     if (originPrincipals)
         JSPRINCIPALS_HOLD(context, originPrincipals);
 }
 
 ObjectBox *
 Parser::newObjectBox(JSObject *obj)
 {
-    JS_ASSERT(obj);
-
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
      * function.
      */
     ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>();
@@ -848,28 +846,28 @@ struct BindData {
 
     ParseNode       *pn;        /* name node for definition processing and
                                    error source coordinates */
     JSOp            op;         /* prolog bytecode or nop */
     Binder          binder;     /* binder, discriminates u */
     union {
         struct {
             VarContext varContext;
-            JSObject *blockObj;
+            StaticBlockObject *blockObj;
             uintN   overflow;
         } let;
     };
     bool fresh;
 
-    void initLet(VarContext varContext, JSObject *blockObj, uintN overflow) {
+    void initLet(VarContext varContext, StaticBlockObject &blockObj, uintN overflow) {
         this->pn = NULL;
         this->op = JSOP_NOP;
         this->binder = BindLet;
         this->let.varContext = varContext;
-        this->let.blockObj = blockObj;
+        this->let.blockObj = &blockObj;
         this->let.overflow = overflow;
     }
 
     void initVarOrConst(JSOp op) {
         this->op = op;
         this->binder = BindVarOrConst;
     }
 };
@@ -1925,18 +1923,18 @@ ReportRedeclaration(JSContext *cx, TreeC
  */
 static JSBool
 BindLet(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
 {
     ParseNode *pn = data->pn;
     if (!CheckStrictBinding(cx, tc, atom->asPropertyName(), pn))
         return false;
 
-    JSObject *blockObj = data->let.blockObj;
-    uintN blockCount = OBJ_BLOCK_COUNT(cx, blockObj);
+    StaticBlockObject &blockObj = *data->let.blockObj;
+    uintN blockCount = blockObj.slotCount();
     if (blockCount == JS_BIT(16)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
                                  JSREPORT_ERROR, data->let.overflow);
         return false;
     }
 
     /*
      * For bindings that are hoisted to the beginning of the block/function,
@@ -1963,62 +1961,59 @@ BindLet(JSContext *cx, BindData *data, J
     pn->pn_dflags |= PND_LET | PND_BOUND;
 
     /*
      * Define the let binding's property before storing pn in the the binding's
      * slot indexed by blockCount off the class-reserved slot base.
      */
     bool redeclared;
     jsid id = ATOM_TO_JSID(atom);
-    const Shape *shape = blockObj->defineBlockVariable(cx, id, blockCount, &redeclared);
+    const Shape *shape = blockObj.addVar(cx, id, blockCount, &redeclared);
     if (!shape) {
         if (redeclared)
             ReportRedeclaration(cx, tc, pn, false, atom);
         return false;
     }
 
-    /*
-     * Store pn temporarily in the shape-mapped slots in the static block
-     * object. This value is clobbered in EmitEnterBlock.
-     */
-    blockObj->setSlot(shape->slot(), PrivateValue(pn));
+    /* Store pn in the static block object. */
+    blockObj.setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
     return true;
 }
 
 template <class Op>
 static inline bool
-ForEachLetDef(TreeContext *tc, JSObject *blockObj, Op op)
+ForEachLetDef(TreeContext *tc, StaticBlockObject &blockObj, Op op)
 {
-    for (Shape::Range r = blockObj->lastProperty()->all(); !r.empty(); r.popFront()) {
+    for (Shape::Range r = blockObj.lastProperty()->all(); !r.empty(); r.popFront()) {
         const Shape &shape = r.front();
 
         /* Beware the destructuring dummy slots. */
         if (JSID_IS_INT(shape.propid()))
             continue;
 
         if (!op(tc, blockObj, shape, JSID_TO_ATOM(shape.propid())))
             return false;
     }
     return true;
 }
 
 struct RemoveDecl {
-    bool operator()(TreeContext *tc, JSObject *, const Shape &, JSAtom *atom) {
+    bool operator()(TreeContext *tc, StaticBlockObject &, const Shape &, JSAtom *atom) {
         tc->decls.remove(atom);
         return true;
     }
 };
 
 static void
 PopStatement(TreeContext *tc)
 {
     if (tc->topStmt->flags & SIF_SCOPE) {
-        JSObject *obj = tc->topStmt->blockObj;
-        JS_ASSERT(!obj->inDictionaryMode());
-        ForEachLetDef(tc, obj, RemoveDecl());
+        StaticBlockObject &blockObj = *tc->topStmt->blockObj;
+        JS_ASSERT(!blockObj.inDictionaryMode());
+        ForEachLetDef(tc, blockObj, RemoveDecl());
     }
     PopStatementTC(tc);
 }
 
 static inline bool
 OuterLet(TreeContext *tc, StmtInfo *stmt, JSAtom *atom)
 {
     while (stmt->downScope) {
@@ -2582,18 +2577,18 @@ CheckDestructuring(JSContext *cx, BindDa
     bool ok;
 
     if (left->isKind(PNK_ARRAYCOMP)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), left, JSREPORT_ERROR,
                                  JSMSG_ARRAY_COMP_LEFTSIDE);
         return false;
     }
 
-    JSObject *blockObj = data && data->binder == BindLet ? data->let.blockObj : NULL;
-    uint32_t blockCountBefore = blockObj ? OBJ_BLOCK_COUNT(cx, blockObj) : 0;
+    StaticBlockObject *blockObj = data && data->binder == BindLet ? data->let.blockObj : NULL;
+    uint32_t blockCountBefore = blockObj ? blockObj->slotCount() : 0;
 
     if (left->isKind(PNK_RB)) {
         for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
             /* Nullary comma is an elision; binary comma is an expression.*/
             if (!pn->isArrayHole()) {
                 if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC)) {
                     ok = CheckDestructuring(cx, data, pn, tc, false);
                 } else {
@@ -2653,25 +2648,25 @@ CheckDestructuring(JSContext *cx, BindDa
      *   let (x = 1, [[]] = b, y = 3, {a:[]} = c) { ... }
      *
      * four slots are needed.
      *
      * To satisfy both constraints, we push a dummy slot (and add a
      * corresponding dummy property to the block object) for each initializer
      * that doesn't introduce at least one binding.
      */
-    if (toplevel && blockObj && blockCountBefore == OBJ_BLOCK_COUNT(cx, blockObj)) {
+    if (toplevel && blockObj && blockCountBefore == blockObj->slotCount()) {
         if (!DefineNativeProperty(cx, blockObj,
                                   INT_TO_JSID(blockCountBefore),
                                   UndefinedValue(), NULL, NULL,
                                   JSPROP_ENUMERATE | JSPROP_PERMANENT,
                                   Shape::HAS_SHORTID, blockCountBefore)) {
             return false;
         }
-        JS_ASSERT(OBJ_BLOCK_COUNT(cx, blockObj) == blockCountBefore + 1);
+        JS_ASSERT(blockObj->slotCount() == blockCountBefore + 1);
     }
 
     return true;
 }
 
 /*
  * Extend the pn_pos.end source coordinate of each name in a destructuring
  * binding such as
@@ -2806,23 +2801,23 @@ Parser::returnOrYield(bool useAssignExpr
                          JSMSG_ANON_NO_RETURN_VALUE)) {
         return NULL;
     }
 
     return pn;
 }
 
 static ParseNode *
-PushLexicalScope(JSContext *cx, TreeContext *tc, JSObject *obj, StmtInfo *stmt)
+PushLexicalScope(JSContext *cx, TreeContext *tc, StaticBlockObject &obj, StmtInfo *stmt)
 {
     ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, tc);
     if (!pn)
         return NULL;
 
-    ObjectBox *blockbox = tc->parser->newObjectBox(obj);
+    ObjectBox *blockbox = tc->parser->newObjectBox(&obj);
     if (!blockbox)
         return NULL;
 
     PushBlockScope(tc, stmt, obj, -1);
     pn->setOp(JSOP_LEAVEBLOCK);
     pn->pn_objbox = blockbox;
     pn->pn_cookie.makeFree();
     pn->pn_dflags = 0;
@@ -2830,41 +2825,41 @@ PushLexicalScope(JSContext *cx, TreeCont
         return NULL;
     pn->pn_blockid = stmt->blockid;
     return pn;
 }
 
 static ParseNode *
 PushLexicalScope(JSContext *cx, TreeContext *tc, StmtInfo *stmt)
 {
-    JSObject *obj = js_NewBlockObject(cx);
-    if (!obj)
+    StaticBlockObject *blockObj = StaticBlockObject::create(cx);
+    if (!blockObj)
         return NULL;
 
-    return PushLexicalScope(cx, tc, obj, stmt);
+    return PushLexicalScope(cx, tc, *blockObj, stmt);
 }
 
 #if JS_HAS_BLOCK_SCOPE
 
 struct AddDecl
 {
     uint32_t blockid;
 
     AddDecl(uint32_t blockid) : blockid(blockid) {}
 
-    bool operator()(TreeContext *tc, JSObject *blockObj, const Shape &shape, JSAtom *atom)
+    bool operator()(TreeContext *tc, StaticBlockObject &blockObj, const Shape &shape, JSAtom *atom)
     {
-        ParseNode *def = (ParseNode *) blockObj->getSlot(shape.slot()).toPrivate();
+        ParseNode *def = (ParseNode *) blockObj.getSlot(shape.slot()).toPrivate();
         def->pn_blockid = blockid;
         return Define(def, atom, tc, true);
     }
 };
 
 static ParseNode *
-PushLetScope(JSContext *cx, TreeContext *tc, JSObject *blockObj, StmtInfo *stmt)
+PushLetScope(JSContext *cx, TreeContext *tc, StaticBlockObject &blockObj, StmtInfo *stmt)
 {
     ParseNode *pn = PushLexicalScope(cx, tc, blockObj, stmt);
     if (!pn)
         return NULL;
 
     /* Tell codegen to emit JSOP_ENTERLETx (not JSOP_ENTERBLOCK). */
     pn->pn_dflags |= PND_LET;
 
@@ -2884,30 +2879,30 @@ ParseNode *
 Parser::letBlock(LetContext letContext)
 {
     JS_ASSERT(tokenStream.currentToken().type == TOK_LET);
 
     ParseNode *pnlet = BinaryNode::create(PNK_LET, tc);
     if (!pnlet)
         return NULL;
 
-    JSObject *blockObj = js_NewBlockObject(context);
+    StaticBlockObject *blockObj = StaticBlockObject::create(context);
     if (!blockObj)
         return NULL;
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET);
 
     ParseNode *vars = variables(PNK_LET, blockObj, DontHoistVars);
     if (!vars)
         return NULL;
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET);
 
     StmtInfo stmtInfo;
-    ParseNode *block = PushLetScope(context, tc, blockObj, &stmtInfo);
+    ParseNode *block = PushLetScope(context, tc, *blockObj, &stmtInfo);
     if (!block)
         return NULL;
 
     pnlet->pn_left = vars;
     pnlet->pn_right = block;
 
     ParseNode *ret;
     if (letContext == LetStatement && !tokenStream.matchToken(TOK_LC, TSF_OPERAND)) {
@@ -2964,17 +2959,17 @@ Parser::letBlock(LetContext letContext)
 static bool
 PushBlocklikeStatement(StmtInfo *stmt, StmtType type, TreeContext *tc)
 {
     PushStatement(tc, stmt, type, -1);
     return GenerateBlockId(tc, stmt->blockid);
 }
 
 static ParseNode *
-NewBindingNode(JSAtom *atom, TreeContext *tc, JSObject *blockObj = NULL,
+NewBindingNode(JSAtom *atom, TreeContext *tc, StaticBlockObject *blockObj = NULL,
                VarContext varContext = HoistVars)
 {
     /*
      * If this name is being injected into an existing block/function, see if
      * it has already been declared or if it resolves an outstanding lexdep.
      * Otherwise, this is a let block/expr that introduces a new scope and thus
      * shadows existing decls and doesn't resolve existing lexdeps. Duplicate
      * names are caught by BindLet.
@@ -3164,17 +3159,17 @@ Parser::forStatement()
 
     /*
      * True if we have 'for (var/let/const ...)', except in the oddball case
      * where 'let' begins a let-expression in 'for (let (...) ...)'.
      */
     bool forDecl = false;
 
     /* Non-null when forDecl is true for a 'for (let ...)' statement. */
-    JSObject *blockObj = NULL;
+    StaticBlockObject *blockObj = NULL;
 
     /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
     ParseNode *pn1;
 
     {
         TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
         if (tt == TOK_SEMI) {
             if (pn->pn_iflags & JSITER_FOREACH) {
@@ -3205,17 +3200,17 @@ Parser::forStatement()
             }
 #if JS_HAS_BLOCK_SCOPE
             else if (tt == TOK_LET) {
                 (void) tokenStream.getToken();
                 if (tokenStream.peekToken() == TOK_LP) {
                     pn1 = letBlock(LetExpresion);
                 } else {
                     forDecl = true;
-                    blockObj = js_NewBlockObject(context);
+                    blockObj = StaticBlockObject::create(context);
                     if (!blockObj)
                         return NULL;
                     pn1 = variables(PNK_LET, blockObj, DontHoistVars);
                 }
             }
 #endif
             else {
                 pn1 = expr();
@@ -3366,17 +3361,17 @@ Parser::forStatement()
 
         if (blockObj) {
             /*
              * Now that the pn3 has been parsed, push the let scope. To hold
              * the blockObj for the emitter, wrap the TOK_LEXICALSCOPE node
              * created by PushLetScope around the for's initializer. This also
              * serves to indicate the let-decl to the emitter.
              */
-            ParseNode *block = PushLetScope(context, tc, blockObj, &letStmt);
+            ParseNode *block = PushLetScope(context, tc, *blockObj, &letStmt);
             if (!block)
                 return NULL;
             letStmt.flags |= SIF_FOR_BLOCK;
             block->pn_expr = pn1;
             pn1 = block;
         }
 
         if (forDecl) {
@@ -3423,17 +3418,17 @@ Parser::forStatement()
         if (!forHead)
             return NULL;
     } else {
         if (blockObj) {
             /*
              * Desugar 'for (let A; B; C) D' into 'let (A) { for (; B; C) D }'
              * to induce the correct scoping for A.
              */
-            ParseNode *block = PushLetScope(context, tc, blockObj, &letStmt);
+            ParseNode *block = PushLetScope(context, tc, *blockObj, &letStmt);
             if (!block)
                 return NULL;
             letStmt.flags |= SIF_FOR_BLOCK;
 
             ParseNode *let = new_<BinaryNode>(PNK_LET, JSOP_NOP, pos, pn1, block);
             if (!let)
                 return NULL;
 
@@ -3583,17 +3578,17 @@ Parser::tryStatement()
             pnblock->pn_expr = pn2;
             MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
 
             /*
              * Contrary to ECMA Ed. 3, the catch variable is lexically
              * scoped, not a property of a new Object instance.  This is
              * an intentional change that anticipates ECMA Ed. 4.
              */
-            data.initLet(HoistVars, tc->blockChain, JSMSG_TOO_MANY_CATCH_VARS);
+            data.initLet(HoistVars, *tc->blockChain, JSMSG_TOO_MANY_CATCH_VARS);
             JS_ASSERT(data.let.blockObj && data.let.blockObj == pnblock->pn_objbox->object);
 
             tt = tokenStream.getToken();
             ParseNode *pn3;
             switch (tt) {
 #if JS_HAS_DESTRUCTURING
               case TOK_LB:
               case TOK_LC:
@@ -3787,37 +3782,37 @@ Parser::letStatement()
             JS_ASSERT(stmt != tc->topScopeStmt);
             JS_ASSERT(stmt->type == STMT_BLOCK ||
                       stmt->type == STMT_SWITCH ||
                       stmt->type == STMT_TRY ||
                       stmt->type == STMT_FINALLY);
             JS_ASSERT(!stmt->downScope);
 
             /* Convert the block statement into a scope statement. */
-            JSObject *obj = js_NewBlockObject(tc->parser->context);
-            if (!obj)
+            StaticBlockObject *blockObj = StaticBlockObject::create(tc->parser->context);
+            if (!blockObj)
                 return NULL;
 
-            ObjectBox *blockbox = tc->parser->newObjectBox(obj);
+            ObjectBox *blockbox = tc->parser->newObjectBox(blockObj);
             if (!blockbox)
                 return NULL;
 
             /*
              * Insert stmt on the tc->topScopeStmt/stmtInfo.downScope linked
              * list stack, if it isn't already there.  If it is there, but it
              * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
              * block.
              */
             stmt->flags |= SIF_SCOPE;
             stmt->downScope = tc->topScopeStmt;
             tc->topScopeStmt = stmt;
 
-            obj->setStaticBlockScopeChain(tc->blockChain);
-            tc->blockChain = obj;
-            stmt->blockObj = obj;
+            blockObj->setEnclosingBlock(tc->blockChain);
+            tc->blockChain = blockObj;
+            stmt->blockObj = blockObj;
 
 #ifdef DEBUG
             ParseNode *tmp = tc->blockNode;
             JS_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
 #endif
 
             /* Create a new lexical scope node for these statements. */
             ParseNode *pn1 = LexicalScopeNode::create(PNK_LEXICALSCOPE, tc);
@@ -4278,17 +4273,17 @@ Parser::statement()
 }
 
 /*
  * The 'blockObj' parameter is non-null when parsing the 'vars' in a let
  * expression, block statement, non-top-level let declaration in statement
  * context, and the let-initializer of a for-statement.
  */
 ParseNode *
-Parser::variables(ParseNodeKind kind, JSObject *blockObj, VarContext varContext)
+Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext varContext)
 {
     /*
      * The four options here are:
      * - PNK_VAR:   We're parsing var declarations.
      * - PNK_CONST: We're parsing const declarations.
      * - PNK_LET:   We are parsing a let declaration.
      * - PNK_LP:    We are parsing the head of a let block.
      */
@@ -4303,17 +4298,17 @@ Parser::variables(ParseNodeKind kind, JS
 
     /*
      * SpiderMonkey const is really "write once per initialization evaluation"
      * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
      * this code will change soon.
      */
     BindData data;
     if (blockObj)
-        data.initLet(varContext, blockObj, JSMSG_TOO_MANY_LOCALS);
+        data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS);
     else
         data.initVarOrConst(pn->getOp());
 
     ParseNode *pn2;
     do {
         TokenKind tt = tokenStream.getToken();
 #if JS_HAS_DESTRUCTURING
         if (tt == TOK_LB || tt == TOK_LC) {
@@ -5364,17 +5359,17 @@ Parser::comprehensionTail(ParseNode *kid
     }
 
     pnp = &pn->pn_expr;
 
     CompExprTransplanter transplanter(kid, tc, kind == PNK_SEMI, adjust);
     transplanter.transplant(kid);
 
     JS_ASSERT(tc->blockChain && tc->blockChain == pn->pn_objbox->object);
-    data.initLet(HoistVars, tc->blockChain, JSMSG_ARRAY_INIT_TOO_BIG);
+    data.initLet(HoistVars, *tc->blockChain, JSMSG_ARRAY_INIT_TOO_BIG);
 
     do {
         /*
          * FOR node is binary, left is loop control and right is body.  Use
          * index to count each block-local let-variable on the left-hand side
          * of the IN.
          */
         pn2 = BinaryNode::create(PNK_FOR, tc);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -55,16 +55,18 @@
 #include "frontend/ParseNode.h"
 
 #define NUM_TEMP_FREELISTS      6U      /* 32 to 2048 byte size classes (32 bit) */
 
 typedef struct BindData BindData;
 
 namespace js {
 
+class StaticBlockObject;
+
 enum FunctionSyntaxKind { Expression, Statement };
 enum LetContext { LetExpresion, LetStatement };
 enum VarContext { HoistVars, DontHoistVars };
 
 struct Parser : private AutoGCRooter
 {
     JSContext           *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
     void                *tempFreeList[NUM_TEMP_FREELISTS];
@@ -193,17 +195,18 @@ struct Parser : private AutoGCRooter
     ParseNode *switchStatement();
     ParseNode *forStatement();
     ParseNode *tryStatement();
     ParseNode *withStatement();
 #if JS_HAS_BLOCK_SCOPE
     ParseNode *letStatement();
 #endif
     ParseNode *expressionStatement();
-    ParseNode *variables(ParseNodeKind kind, JSObject *blockObj = NULL, VarContext varContext = HoistVars);
+    ParseNode *variables(ParseNodeKind kind, StaticBlockObject *blockObj = NULL,
+                         VarContext varContext = HoistVars);
     ParseNode *expr();
     ParseNode *assignExpr();
     ParseNode *condExpr1();
     ParseNode *orExpr1();
     ParseNode *andExpr1i();
     ParseNode *andExpr1n();
     ParseNode *bitOrExpr1i();
     ParseNode *bitOrExpr1n();
--- a/js/src/jit-test/tests/basic/bug680217.js
+++ b/js/src/jit-test/tests/basic/bug680217.js
@@ -1,12 +1,13 @@
 try {
-for (var BUGNUMBER = 0, sz = Math.pow(2, 21); i < sz; i++)
-  str += '0,';
+    for (var BUGNUMBER = 0, sz = Math.pow(2, 12); i < sz; i++)
+        str += '0,';
 } catch (exc1) {}
 var str = '[';
 for (var i = 0, BUGNUMBER; i < sz; i++)
-  str += '0,'; 
-  var obj = {
+    str += '0,';
+var obj = {
     p: { __proto__: null },
-  };
-for (var i = 0, sz = Math.pow(2, 21); i < sz; i++)
-  str += '0,';
+};
+for (var i = 0; i < sz; i++)
+    str += '0,';
+gc();
--- a/js/src/jsapi-tests/testArgumentsObject.cpp
+++ b/js/src/jsapi-tests/testArgumentsObject.cpp
@@ -81,24 +81,24 @@ BEGIN_TEST(testArgumentsObject)
 
 template<size_t ArgCount> bool
 ExhaustiveTest(const char funcode[])
 {
     jsval v;
     EVAL(funcode, &v);
 
     EVAL(CALL_CODES[ArgCount], &v);
-    ArgumentsObject *argsobj = JSVAL_TO_OBJECT(v)->asArguments();
+    ArgumentsObject &argsobj = JSVAL_TO_OBJECT(v)->asArguments();
 
     Value elems[MAX_ELEMS];
 
     for (size_t i = 0; i <= ArgCount; i++) {
         for (size_t j = 0; j <= ArgCount - i; j++) {
             ClearElements(elems);
-            CHECK(argsobj->getElements(i, j, elems));
+            CHECK(argsobj.getElements(i, j, elems));
             for (size_t k = 0; k < j; k++)
                 CHECK_SAME(elems[k], INT_TO_JSVAL(i + k));
             for (size_t k = j; k < MAX_ELEMS - 1; k++)
                 CHECK_SAME(elems[k], JSVAL_NULL);
             CHECK_SAME(elems[MAX_ELEMS - 1], INT_TO_JSVAL(42));
         }
     }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1407,17 +1407,17 @@ JS_EnterCrossCompartmentCallScript(JSCon
 }
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallStackFrame(JSContext *cx, JSStackFrame *target)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
 
-    return JS_EnterCrossCompartmentCall(cx, Valueify(target)->scopeChain().getGlobal());
+    return JS_EnterCrossCompartmentCall(cx, &Valueify(target)->scopeChain().global());
 }
 
 JS_PUBLIC_API(void)
 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
 {
     AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
     AssertNoGC(realcall->context);
     CHECK_REQUEST(realcall->context);
@@ -1747,17 +1747,17 @@ JS_InitStandardClasses(JSContext *cx, JS
      * it before assertSameCompartment. (The API contract is that *after* this,
      * cx and obj must be in the same compartment.)
      */
     if (!cx->globalObject)
         JS_SetGlobalObject(cx, obj);
 
     assertSameCompartment(cx, obj);
 
-    return obj->asGlobal()->initStandardClasses(cx);
+    return obj->global().initStandardClasses(cx);
 }
 
 #define CLASP(name)                 (&name##Class)
 #define TYPED_ARRAY_CLASP(type)     (&TypedArray::fastClasses[TypedArray::type])
 #define EAGER_ATOM(name)            ATOM_OFFSET(name), NULL
 #define EAGER_CLASS_ATOM(name)      CLASS_ATOM_OFFSET(name), NULL
 #define EAGER_ATOM_AND_CLASP(name)  EAGER_CLASS_ATOM(name), CLASP(name)
 #define LAZY_ATOM(name)             ATOM_OFFSET(lazy.name), js_##name##_str
@@ -2172,17 +2172,17 @@ JS_GetClassObject(JSContext *cx, JSObjec
     return js_GetClassObject(cx, obj, key, objp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
 {
     AssertNoGC(cx);
     assertSameCompartment(cx, obj);
-    return obj->getGlobal();
+    return &obj->global();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForScopeChain(JSContext *cx)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     return GetGlobalForScopeChain(cx);
@@ -3232,27 +3232,27 @@ JS_SetPrototype(JSContext *cx, JSObject 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, proto);
     return SetProto(cx, obj, proto, JS_FALSE);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetParent(JSContext *cx, JSObject *obj)
 {
-    JS_ASSERT(!obj->isInternalScope());
+    JS_ASSERT(!obj->isScope());
     assertSameCompartment(cx, obj);
     return obj->getParent();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
-    JS_ASSERT(!obj->isInternalScope());
+    JS_ASSERT(!obj->isScope());
     JS_ASSERT(parent || !obj->getParent());
     assertSameCompartment(cx, obj, parent);
     return obj->setParent(cx, parent);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetConstructor(JSContext *cx, JSObject *proto)
 {
@@ -3736,24 +3736,24 @@ DefineProperty(JSContext *cx, JSObject *
     }
 
     if (attrs & JSPROP_NATIVE_ACCESSORS) {
         RootId idRoot(cx, &id);
 
         JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
         attrs &= ~JSPROP_NATIVE_ACCESSORS;
         if (getter) {
-            JSObject *getobj = JS_NewFunction(cx, (Native) getter, 0, 0, obj->getGlobal(), NULL);
+            JSObject *getobj = JS_NewFunction(cx, (Native) getter, 0, 0, &obj->global(), NULL);
             if (!getobj)
                 return false;
             getter = JS_DATA_TO_FUNC_PTR(PropertyOp, getobj);
             attrs |= JSPROP_GETTER;
         }
         if (setter) {
-            JSObject *setobj = JS_NewFunction(cx, (Native) setter, 1, 0, obj->getGlobal(), NULL);
+            JSObject *setobj = JS_NewFunction(cx, (Native) setter, 1, 0, &obj->global(), NULL);
             if (!setobj)
                 return false;
             setter = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setobj);
             attrs |= JSPROP_SETTER;
         }
     }
 
     return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
@@ -4223,17 +4223,17 @@ JS_ClearScope(JSContext *cx, JSObject *o
     if (clearOp)
         clearOp(cx, obj);
 
     if (obj->isNative())
         js_ClearNative(cx, obj);
 
     /* Clear cached class objects on the global object. */
     if (obj->isGlobal())
-        obj->asGlobal()->clear(cx);
+        obj->asGlobal().clear(cx);
 
     js_InitRandom(cx);
 }
 
 JS_PUBLIC_API(JSIdArray *)
 JS_Enumerate(JSContext *cx, JSObject *obj)
 {
     AssertNoGC(cx);
@@ -4612,17 +4612,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
         JSObject *obj = parent;
         int skip = uva->vector[i].level();
         while (--skip > 0) {
             if (!obj) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
                 return NULL;
             }
-            obj = obj->scopeChain();
+            obj = obj->enclosingScope();
         }
 
         Value v;
         if (!obj->getGeneric(cx, r.front().propid(), &v))
             return NULL;
         clone->toFunction()->setFlatClosureUpvar(i, v);
     }
 
@@ -6298,60 +6298,60 @@ JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     jschar *chars = InflateString(cx, bytes, &length);
     if (!chars)
         return NULL;
 
-    RegExpStatics *res = obj->asGlobal()->getRegExpStatics();
+    RegExpStatics *res = obj->asGlobal().getRegExpStatics();
     RegExpObject *reobj = RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
     cx->free_(chars);
     return reobj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
-    RegExpStatics *res = obj->asGlobal()->getRegExpStatics();
+    RegExpStatics *res = obj->asGlobal().getRegExpStatics();
     return RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
 }
 
 JS_PUBLIC_API(void)
 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, input);
 
-    obj->asGlobal()->getRegExpStatics()->reset(cx, input, !!multiline);
+    obj->asGlobal().getRegExpStatics()->reset(cx, input, !!multiline);
 }
 
 JS_PUBLIC_API(void)
 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     JS_ASSERT(obj);
 
-    obj->asGlobal()->getRegExpStatics()->clear();
+    obj->asGlobal().getRegExpStatics()->clear();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
                  size_t *indexp, JSBool test, jsval *rval)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
 
-    RegExpStatics *res = obj->asGlobal()->getRegExpStatics();
-    return ExecuteRegExp(cx, res, reobj->asRegExp(), NULL, chars, length,
+    RegExpStatics *res = obj->asGlobal().getRegExpStatics();
+    return ExecuteRegExp(cx, res, &reobj->asRegExp(), NULL, chars, length,
                          indexp, test ? RegExpTest : RegExpExec, rval);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
@@ -6373,17 +6373,17 @@ JS_NewUCRegExpObjectNoStatics(JSContext 
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
                           size_t *indexp, JSBool test, jsval *rval)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
 
-    return ExecuteRegExp(cx, NULL, obj->asRegExp(), NULL, chars, length, indexp,
+    return ExecuteRegExp(cx, NULL, &obj->asRegExp(), NULL, chars, length, indexp,
                          test ? RegExpTest : RegExpExec, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsRegExp(JSContext *cx, JSObject *obj)
 {
     AssertNoGC(cx);
     JS_ASSERT(obj);
@@ -6391,26 +6391,26 @@ JS_ObjectIsRegExp(JSContext *cx, JSObjec
 }
 
 JS_PUBLIC_API(uintN)
 JS_GetRegExpFlags(JSContext *cx, JSObject *obj)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
 
-    return obj->asRegExp()->getFlags();
+    return obj->asRegExp().getFlags();
 }
 
 JS_PUBLIC_API(JSString *)
 JS_GetRegExpSource(JSContext *cx, JSObject *obj)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
 
-    return obj->asRegExp()->getSource();
+    return obj->asRegExp().getSource();
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
 {
     AssertNoGC(cx);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -151,19 +151,19 @@ JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     if (obj->isArray()) {
         *lengthp = obj->getArrayLength();
         return true;
     }
 
     if (obj->isArguments()) {
-        ArgumentsObject *argsobj = obj->asArguments();
-        if (!argsobj->hasOverriddenLength()) {
-            *lengthp = argsobj->initialLength();
+        ArgumentsObject &argsobj = obj->asArguments();
+        if (!argsobj.hasOverriddenLength()) {
+            *lengthp = argsobj.initialLength();
             return true;
         }
     }
 
     AutoValueRooter tvr(cx);
     if (!obj->getProperty(cx, cx->runtime->atomState.lengthAtom, tvr.addr()))
         return false;
 
@@ -410,17 +410,17 @@ GetElement(JSContext *cx, JSObject *obj,
 {
     JS_ASSERT(index >= 0);
     if (obj->isDenseArray() && index < obj->getDenseArrayInitializedLength() &&
         !(*vp = obj->getDenseArrayElement(uint32_t(index))).isMagic(JS_ARRAY_HOLE)) {
         *hole = JS_FALSE;
         return JS_TRUE;
     }
     if (obj->isArguments()) {
-        if (obj->asArguments()->getElement(uint32_t(index), vp)) {
+        if (obj->asArguments().getElement(uint32_t(index), vp)) {
             *hole = JS_FALSE;
             return true;
         }
     }
 
     return DoGetElement(cx, obj, index, hole, vp);
 }
 
@@ -447,19 +447,19 @@ GetElements(JSContext *cx, JSObject *aob
         const Value *srcend = srcbeg + length;
         const Value *src = srcbeg;
         for (Value *dst = vp; src < srcend; ++dst, ++src)
             *dst = src->isMagic(JS_ARRAY_HOLE) ? UndefinedValue() : *src;
         return true;
     }
 
     if (aobj->isArguments()) {
-        ArgumentsObject *argsobj = aobj->asArguments();
-        if (!argsobj->hasOverriddenLength()) {
-            if (argsobj->getElements(0, length, vp))
+        ArgumentsObject &argsobj = aobj->asArguments();
+        if (!argsobj.hasOverriddenLength()) {
+            if (argsobj.getElements(0, length, vp))
                 return true;
         }
     }
 
     return GetElementsSlow(cx, aobj, length, vp);
 }
 
 }
@@ -2010,17 +2010,17 @@ struct SortComparatorStringValuePairs {
 struct SortComparatorFunction {
     JSContext          *const cx;
     const Value        &fval;
     InvokeArgsGuard    &ag;
 
     SortComparatorFunction(JSContext *cx, const Value &fval, InvokeArgsGuard &ag)
       : cx(cx), fval(fval), ag(ag) { }
 
-    bool JS_REQUIRES_STACK operator()(const Value &a, const Value &b, bool *lessOrEqualp);
+    bool operator()(const Value &a, const Value &b, bool *lessOrEqualp);
 };
 
 bool
 SortComparatorFunction::operator()(const Value &a, const Value &b, bool *lessOrEqualp)
 {
     /*
      * array_sort deals with holes and undefs on its own and they should not
      * come here.
@@ -3581,17 +3581,17 @@ js_Array(JSContext *cx, uintN argc, Valu
 }
 
 JSObject *
 js_InitArrayClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     RootedVar<GlobalObject*> global(cx);
-    global = obj->asGlobal();
+    global = &obj->asGlobal();
 
     RootedVarObject arrayProto(cx);
     arrayProto = global->createBlankPrototype(cx, &SlowArrayClass);
     if (!arrayProto || !AddLengthProperty(cx, arrayProto))
         return NULL;
     arrayProto->setArrayLength(cx, 0);
 
     RootedVarFunction ctor(cx);
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -148,17 +148,17 @@ Boolean(JSContext *cx, uintN argc, Value
     return true;
 }
 
 JSObject *
 js_InitBooleanClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    GlobalObject *global = obj->asGlobal();
+    GlobalObject *global = &obj->asGlobal();
 
     JSObject *booleanProto = global->createBlankPrototype(cx, &BooleanClass);
     if (!booleanProto)
         return NULL;
     booleanProto->setPrimitiveThis(BooleanValue(false));
 
     JSFunction *ctor = global->createConstructor(cx, Boolean, &BooleanClass,
                                                  CLASS_ATOM(cx, Boolean), 1);
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -518,19 +518,19 @@ JSStructuredCloneWriter::startWrite(cons
         return out.writePair(SCTAG_BOOLEAN, v.toBoolean());
     } else if (v.isNull()) {
         return out.writePair(SCTAG_NULL, 0);
     } else if (v.isUndefined()) {
         return out.writePair(SCTAG_UNDEFINED, 0);
     } else if (v.isObject()) {
         JSObject *obj = &v.toObject();
         if (obj->isRegExp()) {
-            RegExpObject *reobj = obj->asRegExp();
-            return out.writePair(SCTAG_REGEXP_OBJECT, reobj->getFlags()) &&
-                   writeString(SCTAG_STRING, reobj->getSource());
+            RegExpObject &reobj = obj->asRegExp();
+            return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) &&
+                   writeString(SCTAG_STRING, reobj.getSource());
         } else if (obj->isDate()) {
             jsdouble d = js_DateGetMsecSinceEpoch(context(), obj);
             return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d);
         } else if (obj->isObject() || obj->isArray()) {
             return startObject(obj);
         } else if (js_IsTypedArray(obj)) {
             return writeTypedArray(obj);
         } else if (js_IsArrayBuffer(obj)) {
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1601,39 +1601,39 @@ typedef Root<jsid>               RootId;
 typedef Root<Value>              RootValue;
 
 /* Mark a stack location as a root for a rooting analysis. */
 class CheckRoot
 {
 #if defined(DEBUG) && defined(JSGC_ROOT_ANALYSIS)
 
     CheckRoot **stack, *prev;
-    const uint8 *ptr;
+    const uint8_t *ptr;
 
   public:
     template <typename T>
     CheckRoot(JSContext *cx, const T *ptr
               JS_GUARD_OBJECT_NOTIFIER_PARAM)
     {
         this->stack = &cx->checkGCRooters;
         this->prev = *stack;
         *stack = this;
-        this->ptr = (const uint8 *) ptr;
+        this->ptr = static_cast<const uint8_t*>(ptr);
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     ~CheckRoot()
     {
         JS_ASSERT(*stack == this);
         *stack = prev;
     }
 
     CheckRoot *previous() { return prev; }
 
-    bool contains(const uint8 *v, size_t len) {
+    bool contains(const uint8_t *v, size_t len) {
         return ptr >= v && ptr < v + len;
     }
 
 #else /* DEBUG && JSGC_ROOT_ANALYSIS */
 
   public:
     template <typename T>
     CheckRoot(JSContext *cx, const T *ptr
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -71,22 +71,22 @@ struct PreserveRegsGuard
     JSContext *cx;
     FrameRegs &regs_;
 };
 
 static inline GlobalObject *
 GetGlobalForScopeChain(JSContext *cx)
 {
     if (cx->hasfp())
-        return cx->fp()->scopeChain().getGlobal();
+        return &cx->fp()->scopeChain().global();
 
     JSObject *scope = JS_ObjectToInnerObject(cx, cx->globalObject);
     if (!scope)
         return NULL;
-    return scope->asGlobal();
+    return &scope->asGlobal();
 }
 
 inline GSNCache *
 GetGSNCache(JSContext *cx)
 {
     return &JS_THREAD_DATA(cx)->gsnCache;
 }
 
@@ -497,21 +497,18 @@ inline bool
 JSContext::ensureParseMapPool()
 {
     if (parseMapPool_)
         return true;
     parseMapPool_ = js::OffTheBooks::new_<js::ParseMapPool>(this);
     return parseMapPool_;
 }
 
-/*
- * Get the current frame, first lazily instantiating stack frames if needed.
- * (Do not access cx->fp() directly except in JS_REQUIRES_STACK code.)
- */
-static JS_FORCES_STACK JS_INLINE js::StackFrame *
+/* Get the current frame, first lazily instantiating stack frames if needed. */
+static inline js::StackFrame *
 js_GetTopStackFrame(JSContext *cx, FrameExpandKind expand)
 {
 #ifdef JS_METHODJIT
     if (expand)
         js::mjit::ExpandInlineFrames(cx->compartment);
 #endif
 
     return cx->maybefp();
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -225,17 +225,17 @@ JSCompartment::wrap(JSContext *cx, Value
      * Wrappers should really be parented to the wrapped parent of the wrapped
      * object, but in that case a wrapped global object would have a NULL
      * parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead,
      * we parent all wrappers to the global object in their home compartment.
      * This loses us some transparency, and is generally very cheesy.
      */
     JSObject *global;
     if (cx->hasfp()) {
-        global = cx->fp()->scopeChain().getGlobal();
+        global = &cx->fp()->scopeChain().global();
     } else {
         global = JS_ObjectToInnerObject(cx, cx->globalObject);
         if (!global)
             return false;
     }
 
     /* Unwrap incoming objects. */
     if (vp->isObject()) {
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2642,17 +2642,17 @@ js_Date(JSContext *cx, uintN argc, Value
 JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     /* Set the static LocalTZA. */
     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
 
-    GlobalObject *global = obj->asGlobal();
+    GlobalObject *global = &obj->asGlobal();
 
     JSObject *dateProto = global->createBlankPrototype(cx, &DateClass);
     if (!dateProto)
         return NULL;
     SetDateToNaN(cx, dateProto);
 
     JSFunction *ctor = global->createConstructor(cx, js_Date, &DateClass,
                                                  CLASS_ATOM(cx, Date), MAXARGS);
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -642,17 +642,17 @@ JS_PUBLIC_API(JSFunction *)
 JS_GetScriptFunction(JSContext *cx, JSScript *script)
 {
     return script->function();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetParentOrScopeChain(JSContext *cx, JSObject *obj)
 {
-    return obj->scopeChain();
+    return obj->enclosingScope();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
 {
     return Valueify(fp)->isConstructing();
 }
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -1025,17 +1025,17 @@ InitErrorClass(JSContext *cx, GlobalObje
 }
 
 JSObject *
 js_InitExceptionClasses(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isGlobal());
     JS_ASSERT(obj->isNative());
 
-    GlobalObject *global = obj->asGlobal();
+    GlobalObject *global = &obj->asGlobal();
 
     JSObject *objectProto;
     if (!js_GetClassPrototype(cx, global, JSProto_Object, &objectProto))
         return NULL;
 
     /* Initialize the base Error class first. */
     JSObject *errorProto = InitErrorClass(cx, global, JSEXN_ERR, *objectProto);
     if (!errorProto)
@@ -1328,15 +1328,15 @@ js_CopyErrorObject(JSContext *cx, JSObje
         return NULL;
     JS::Anchor<JSString *> filenameAnchor(copy->filename);
     copy->lineno = priv->lineno;
     copy->stackDepth = 0;
     copy->exnType = priv->exnType;
 
     // Create the Error object.
     JSObject *proto;
-    if (!js_GetClassPrototype(cx, scope->getGlobal(), GetExceptionProtoKey(copy->exnType), &proto))
+    if (!js_GetClassPrototype(cx, &scope->global(), GetExceptionProtoKey(copy->exnType), &proto))
         return NULL;
     JSObject *copyobj = NewObjectWithGivenProto(cx, &ErrorClass, proto, NULL);
     SetExnPrivate(cx, copyobj, copy);
     autoFree.p = NULL;
     return copyobj;
 }
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -87,17 +87,17 @@ JS_GetObjectFunction(JSObject *obj)
     if (obj->isFunction())
         return obj->toFunction();
     return NULL;
 }
 
 JS_FRIEND_API(JSObject *)
 JS_GetGlobalForFrame(JSStackFrame *fp)
 {
-    return Valueify(fp)->scopeChain().getGlobal();
+    return &Valueify(fp)->scopeChain().global();
 }
 
 JS_FRIEND_API(JSBool)
 JS_SplicePrototype(JSContext *cx, JSObject *obj, JSObject *proto)
 {
     /*
      * Change the prototype of an object which hasn't been used anywhere
      * and does not share its type with another object. Unlike JS_SetPrototype,
@@ -192,35 +192,35 @@ AutoSwitchCompartment::~AutoSwitchCompar
 
 JS_FRIEND_API(bool)
 js::IsSystemCompartment(const JSCompartment *c)
 {
     return c->isSystemCompartment;
 }
 
 JS_FRIEND_API(bool)
-js::IsScopeObject(const JSObject *obj)
+js::IsScopeObject(JSObject *obj)
 {
-    return obj->isInternalScope();
+    return obj->isScope();
 }
 
 JS_FRIEND_API(JSObject *)
-js::GetObjectParentMaybeScope(const JSObject *obj)
+js::GetObjectParentMaybeScope(JSObject *obj)
 {
-    return obj->scopeChain();
+    return obj->enclosingScope();
 }
 
 JS_FRIEND_API(JSObject *)
 js::GetGlobalForObjectCrossCompartment(JSObject *obj)
 {
-    return obj->getGlobal();
+    return &obj->global();
 }
 
 JS_FRIEND_API(uint32_t)
-js::GetObjectSlotSpan(const JSObject *obj)
+js::GetObjectSlotSpan(JSObject *obj)
 {
     return obj->slotSpan();
 }
 
 JS_FRIEND_API(bool)
 js::IsObjectInContextCompartment(const JSObject *obj, const JSContext *cx)
 {
     return obj->compartment() == cx->compartment;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -280,44 +280,43 @@ extern JS_FRIEND_DATA(js::Class) Attribu
 extern JS_FRIEND_DATA(js::Class) CallClass;
 extern JS_FRIEND_DATA(js::Class) DeclEnvClass;
 extern JS_FRIEND_DATA(js::Class) FunctionClass;
 extern JS_FRIEND_DATA(js::Class) FunctionProxyClass;
 extern JS_FRIEND_DATA(js::Class) NamespaceClass;
 extern JS_FRIEND_DATA(js::Class) OuterWindowProxyClass;
 extern JS_FRIEND_DATA(js::Class) ObjectProxyClass;
 extern JS_FRIEND_DATA(js::Class) QNameClass;
-extern JS_FRIEND_DATA(js::Class) ScriptClass;
 extern JS_FRIEND_DATA(js::Class) XMLClass;
 extern JS_FRIEND_DATA(js::Class) ObjectClass;
 
 inline js::Class *
 GetObjectClass(const JSObject *obj)
 {
     return reinterpret_cast<const shadow::Object*>(obj)->shape->base->clasp;
 }
 
 inline JSClass *
 GetObjectJSClass(const JSObject *obj)
 {
     return js::Jsvalify(GetObjectClass(obj));
 }
 
 JS_FRIEND_API(bool)
-IsScopeObject(const JSObject *obj);
+IsScopeObject(JSObject *obj);
 
 inline JSObject *
-GetObjectParent(const JSObject *obj)
+GetObjectParent(JSObject *obj)
 {
     JS_ASSERT(!IsScopeObject(obj));
-    return reinterpret_cast<const shadow::Object*>(obj)->shape->base->parent;
+    return reinterpret_cast<shadow::Object*>(obj)->shape->base->parent;
 }
 
 JS_FRIEND_API(JSObject *)
-GetObjectParentMaybeScope(const JSObject *obj);
+GetObjectParentMaybeScope(JSObject *obj);
 
 JS_FRIEND_API(JSObject *)
 GetGlobalForObjectCrossCompartment(JSObject *obj);
 
 JS_FRIEND_API(bool)
 IsOriginalScriptFunction(JSFunction *fun);
 
 JS_FRIEND_API(JSFunction *)
@@ -340,23 +339,23 @@ InitClassWithReserved(JSContext *cx, JSO
 
 JS_FRIEND_API(const Value &)
 GetFunctionNativeReserved(JSObject *fun, size_t which);
 
 JS_FRIEND_API(void)
 SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val);
 
 inline JSObject *
-GetObjectProto(const JSObject *obj)
+GetObjectProto(JSObject *obj)
 {
     return reinterpret_cast<const shadow::Object*>(obj)->type->proto;
 }
 
 inline void *
-GetObjectPrivate(const JSObject *obj)
+GetObjectPrivate(JSObject *obj)
 {
     const shadow::Object *nobj = reinterpret_cast<const shadow::Object*>(obj);
     void **addr = reinterpret_cast<void**>(&nobj->fixedSlots()[nobj->numFixedSlots()]);
     return *addr;
 }
 
 /*
  * Get a slot that is both reserved for object's clasp *and* is fixed (fits
@@ -372,27 +371,27 @@ GetReservedSlot(const JSObject *obj, siz
 inline void
 SetReservedSlot(JSObject *obj, size_t slot, const Value &value)
 {
     JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
     reinterpret_cast<shadow::Object *>(obj)->slotRef(slot) = value;
 }
 
 JS_FRIEND_API(uint32_t)
-GetObjectSlotSpan(const JSObject *obj);
+GetObjectSlotSpan(JSObject *obj);
 
 inline const Value &
-GetObjectSlot(const JSObject *obj, size_t slot)
+GetObjectSlot(JSObject *obj, size_t slot)
 {
     JS_ASSERT(slot < GetObjectSlotSpan(obj));
     return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot);
 }
 
 inline Shape *
-GetObjectShape(const JSObject *obj)
+GetObjectShape(JSObject *obj)
 {
     shadow::Shape *shape = reinterpret_cast<const shadow::Object*>(obj)->shape;
     return reinterpret_cast<Shape *>(shape);
 }
 
 static inline js::PropertyOp
 CastAsJSPropertyOp(JSObject *object)
 {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -67,17 +67,17 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsexn.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/TokenStream.h"
-#include "vm/CallObject.h"
+#include "vm/ScopeObject.h"
 #include "vm/Debugger.h"
 
 #if JS_HAS_GENERATORS
 # include "jsiter.h"
 #endif
 
 #if JS_HAS_XDR
 # include "jsxdrapi.h"
@@ -87,29 +87,29 @@
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
-#include "vm/CallObject-inl.h"
+#include "vm/ScopeObject-inl.h"
 #include "vm/ArgumentsObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 inline JSObject *
 JSObject::getThrowTypeError() const
 {
-    return getGlobal()->getThrowTypeError();
+    return global().getThrowTypeError();
 }
 
 JSBool
 js_GetArgsValue(JSContext *cx, StackFrame *fp, Value *vp)
 {
     JSObject *argsobj;
     if (fp->hasOverriddenArgs()) {
         JS_ASSERT(fp->hasCallObj());
@@ -122,17 +122,17 @@ js_GetArgsValue(JSContext *cx, StackFram
     return JS_TRUE;
 }
 
 js::ArgumentsObject *
 ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee, StackFrame *fp)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
-    JSObject *proto = callee.getGlobal()->getOrCreateObjectPrototype(cx);
+    JSObject *proto = callee.global().getOrCreateObjectPrototype(cx);
     if (!proto)
         return NULL;
 
     RootedVarTypeObject type(cx);
 
     type = proto->getNewType(cx);
     if (!type)
         return NULL;
@@ -156,27 +156,27 @@ ArgumentsObject::create(JSContext *cx, u
     data->callee.init(ObjectValue(callee));
     InitValueRange(data->slots, argc, false);
 
     /* We have everything needed to fill in the object, so make the object. */
     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
     if (!obj)
         return NULL;
 
-    ArgumentsObject *argsobj = obj->asArguments();
+    ArgumentsObject &argsobj = obj->asArguments();
 
     JS_ASSERT(UINT32_MAX > (uint64_t(argc) << PACKED_BITS_COUNT));
-    argsobj->initInitialLength(argc);
-    argsobj->initData(data);
-    argsobj->setStackFrame(strict ? NULL : fp);
+    argsobj.initInitialLength(argc);
+    argsobj.initData(data);
+    argsobj.setStackFrame(strict ? NULL : fp);
 
-    JS_ASSERT(argsobj->numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
-    JS_ASSERT(argsobj->numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
+    JS_ASSERT(argsobj.numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
+    JS_ASSERT(argsobj.numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
 
-    return argsobj;
+    return &argsobj;
 }
 
 struct STATIC_SKIP_INFERENCE PutArg
 {
     PutArg(JSCompartment *comp, HeapValue *dst) : dst(dst), compartment(comp) {}
     HeapValue *dst;
     JSCompartment *compartment;
     bool operator()(uintN, Value *src) {
@@ -246,73 +246,73 @@ js_PutArgsObject(StackFrame *fp)
     } else {
         JS_ASSERT(!argsobj.maybeStackFrame());
     }
 }
 
 static JSBool
 args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    ArgumentsObject *argsobj = obj->asArguments();
+    ArgumentsObject &argsobj = obj->asArguments();
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < argsobj->initialLength())
-            argsobj->setElement(arg, MagicValue(JS_ARGS_HOLE));
+        if (arg < argsobj.initialLength())
+            argsobj.setElement(arg, MagicValue(JS_ARGS_HOLE));
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-        argsobj->markLengthOverridden();
+        argsobj.markLengthOverridden();
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
-        argsobj->asNormalArguments()->clearCallee();
+        argsobj.asNormalArguments().clearCallee();
     }
     return true;
 }
 
 static JSBool
 ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     if (!obj->isNormalArguments())
         return true;
 
-    NormalArgumentsObject *argsobj = obj->asNormalArguments();
+    NormalArgumentsObject &argsobj = obj->asNormalArguments();
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < argsobj->initialLength()) {
-            JS_ASSERT(!argsobj->element(arg).isMagic(JS_ARGS_HOLE));
-            if (StackFrame *fp = argsobj->maybeStackFrame())
+        if (arg < argsobj.initialLength()) {
+            JS_ASSERT(!argsobj.element(arg).isMagic(JS_ARGS_HOLE));
+            if (StackFrame *fp = argsobj.maybeStackFrame())
                 *vp = fp->canonicalActualArg(arg);
             else
-                *vp = argsobj->element(arg);
+                *vp = argsobj.element(arg);
         }
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-        if (!argsobj->hasOverriddenLength())
-            vp->setInt32(argsobj->initialLength());
+        if (!argsobj.hasOverriddenLength())
+            vp->setInt32(argsobj.initialLength());
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
-        const Value &v = argsobj->callee();
+        const Value &v = argsobj.callee();
         if (!v.isMagic(JS_ARGS_HOLE))
             *vp = v;
     }
     return true;
 }
 
 static JSBool
 ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     if (!obj->isNormalArguments())
         return true;
 
-    NormalArgumentsObject *argsobj = obj->asNormalArguments();
+    NormalArgumentsObject &argsobj = obj->asNormalArguments();
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < argsobj->initialLength()) {
-            if (StackFrame *fp = argsobj->maybeStackFrame()) {
+        if (arg < argsobj.initialLength()) {
+            if (StackFrame *fp = argsobj.maybeStackFrame()) {
                 JSScript *script = fp->functionScript();
                 if (script->usesArguments) {
                     if (arg < fp->numFormalArgs())
                         TypeScript::SetArgument(cx, script, arg, *vp);
                     fp->canonicalActualArg(arg) = *vp;
                 }
                 return true;
             }
@@ -326,178 +326,178 @@ ArgSetter(JSContext *cx, JSObject *obj, 
      * For simplicity we use delete/define to replace the property with one
      * backed by the default Object getter and setter. Note that we rely on
      * args_delProperty to clear the corresponding reserved slot so the GC can
      * collect its value. Note also that we must define the property instead
      * of setting it in case the user has changed the prototype to an object
      * that has a setter for this id.
      */
     AutoValueRooter tvr(cx);
-    return js_DeleteProperty(cx, argsobj, id, tvr.addr(), false) &&
-           js_DefineProperty(cx, argsobj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
+    return js_DeleteProperty(cx, &argsobj, id, tvr.addr(), false) &&
+           js_DefineProperty(cx, &argsobj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
 }
 
 static JSBool
 args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
              JSObject **objp)
 {
     *objp = NULL;
 
-    NormalArgumentsObject *argsobj = obj->asNormalArguments();
+    NormalArgumentsObject &argsobj = obj->asNormalArguments();
 
     uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
-        if (arg >= argsobj->initialLength() || argsobj->element(arg).isMagic(JS_ARGS_HOLE))
+        if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-        if (argsobj->hasOverriddenLength())
+        if (argsobj.hasOverriddenLength())
             return true;
     } else {
         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
             return true;
 
-        if (argsobj->callee().isMagic(JS_ARGS_HOLE))
+        if (argsobj.callee().isMagic(JS_ARGS_HOLE))
             return true;
     }
 
     Value undef = UndefinedValue();
-    if (!js_DefineProperty(cx, argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
+    if (!js_DefineProperty(cx, &argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
         return JS_FALSE;
 
-    *objp = argsobj;
+    *objp = &argsobj;
     return true;
 }
 
 static JSBool
 args_enumerate(JSContext *cx, JSObject *obj)
 {
-    NormalArgumentsObject *argsobj = obj->asNormalArguments();
+    NormalArgumentsObject &argsobj = obj->asNormalArguments();
 
     /*
      * Trigger reflection in args_resolve using a series of js_LookupProperty
      * calls.
      */
-    int argc = int(argsobj->initialLength());
+    int argc = int(argsobj.initialLength());
     for (int i = -2; i != argc; i++) {
         jsid id = (i == -2)
                   ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
                   : (i == -1)
                   ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)
                   : INT_TO_JSID(i);
 
         JSObject *pobj;
         JSProperty *prop;
-        if (!js_LookupProperty(cx, argsobj, id, &pobj, &prop))
+        if (!js_LookupProperty(cx, &argsobj, id, &pobj, &prop))
             return false;
     }
     return true;
 }
 
 static JSBool
 StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     if (!obj->isStrictArguments())
         return true;
 
-    StrictArgumentsObject *argsobj = obj->asStrictArguments();
+    StrictArgumentsObject &argsobj = obj->asStrictArguments();
 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < argsobj->initialLength()) {
-            const Value &v = argsobj->element(arg);
+        if (arg < argsobj.initialLength()) {
+            const Value &v = argsobj.element(arg);
             if (!v.isMagic(JS_ARGS_HOLE))
                 *vp = v;
         }
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
-        if (!argsobj->hasOverriddenLength())
-            vp->setInt32(argsobj->initialLength());
+        if (!argsobj.hasOverriddenLength())
+            vp->setInt32(argsobj.initialLength());
     }
     return true;
 }
 
 static JSBool
 StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     if (!obj->isStrictArguments())
         return true;
 
-    StrictArgumentsObject *argsobj = obj->asStrictArguments();
+    StrictArgumentsObject &argsobj = obj->asStrictArguments();
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
-        if (arg < argsobj->initialLength()) {
-            argsobj->setElement(arg, *vp);
+        if (arg < argsobj.initialLength()) {
+            argsobj.setElement(arg, *vp);
             return true;
         }
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
     }
 
     /*
      * For simplicity we use delete/set to replace the property with one
      * backed by the default Object getter and setter. Note that we rely on
      * args_delProperty to clear the corresponding reserved slot so the GC can
      * collect its value.
      */
     AutoValueRooter tvr(cx);
-    return js_DeleteProperty(cx, argsobj, id, tvr.addr(), strict) &&
-           js_SetPropertyHelper(cx, argsobj, id, 0, vp, strict);
+    return js_DeleteProperty(cx, &argsobj, id, tvr.addr(), strict) &&
+           js_SetPropertyHelper(cx, &argsobj, id, 0, vp, strict);
 }
 
 static JSBool
 strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
 {
     *objp = NULL;
 
-    StrictArgumentsObject *argsobj = obj->asStrictArguments();
+    StrictArgumentsObject &argsobj = obj->asStrictArguments();
 
     uintN attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     PropertyOp getter = StrictArgGetter;
     StrictPropertyOp setter = StrictArgSetter;
 
     if (JSID_IS_INT(id)) {
         uint32_t arg = uint32_t(JSID_TO_INT(id));
-        if (arg >= argsobj->initialLength() || argsobj->element(arg).isMagic(JS_ARGS_HOLE))
+        if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
             return true;
 
         attrs |= JSPROP_ENUMERATE;
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-        if (argsobj->hasOverriddenLength())
+        if (argsobj.hasOverriddenLength())
             return true;
     } else {
         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
             !JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
             return true;
         }
 
         attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
-        getter = CastAsPropertyOp(argsobj->getThrowTypeError());
-        setter = CastAsStrictPropertyOp(argsobj->getThrowTypeError());
+        getter = CastAsPropertyOp(argsobj.getThrowTypeError());
+        setter = CastAsStrictPropertyOp(argsobj.getThrowTypeError());
     }
 
     Value undef = UndefinedValue();
-    if (!js_DefineProperty(cx, argsobj, id, &undef, getter, setter, attrs))
+    if (!js_DefineProperty(cx, &argsobj, id, &undef, getter, setter, attrs))
         return false;
 
-    *objp = argsobj;
+    *objp = &argsobj;
     return true;
 }
 
 static JSBool
 strictargs_enumerate(JSContext *cx, JSObject *obj)
 {
-    StrictArgumentsObject *argsobj = obj->asStrictArguments();
+    StrictArgumentsObject *argsobj = &obj->asStrictArguments();
 
     /*
      * Trigger reflection in strictargs_resolve using a series of
      * js_LookupProperty calls.
      */
     JSObject *pobj;
     JSProperty *prop;
 
@@ -519,38 +519,38 @@ strictargs_enumerate(JSContext *cx, JSOb
     }
 
     return true;
 }
 
 static void
 args_finalize(JSContext *cx, JSObject *obj)
 {
-    cx->free_(reinterpret_cast<void *>(obj->asArguments()->data()));
+    cx->free_(reinterpret_cast<void *>(obj->asArguments().data()));
 }
 
 static void
 args_trace(JSTracer *trc, JSObject *obj)
 {
-    ArgumentsObject *argsobj = obj->asArguments();
-    ArgumentsData *data = argsobj->data();
+    ArgumentsObject &argsobj = obj->asArguments();
+    ArgumentsData *data = argsobj.data();
     MarkValue(trc, data->callee, js_callee_str);
-    MarkValueRange(trc, argsobj->initialLength(), data->slots, js_arguments_str);
+    MarkValueRange(trc, argsobj.initialLength(), data->slots, js_arguments_str);
 
     /*
      * If a generator's arguments or call object escapes, and the generator
      * frame is not executing, the generator object needs to be marked because
      * it is not otherwise reachable. An executing generator is rooted by its
      * invocation.  To distinguish the two cases (which imply different access
      * paths to the generator object), we use the JSFRAME_FLOATING_GENERATOR
      * flag, which is only set on the StackFrame kept in the generator object's
      * JSGenerator.
      */
 #if JS_HAS_GENERATORS
-    StackFrame *fp = argsobj->maybeStackFrame();
+    StackFrame *fp = argsobj.maybeStackFrame();
     if (fp && fp->isFloatingGenerator())
         MarkObject(trc, js_FloatingFrameToGenerator(fp)->obj, "generator object");
 #endif
 }
 
 /*
  * The classes below collaborate to lazily reflect and synchronize actual
  * argument values, argument count, and callee function object stored in a
@@ -601,63 +601,16 @@ Class js::StrictArgumentsObjectClass = {
     NULL,                    /* checkAccess */
     NULL,                    /* call        */
     NULL,                    /* construct   */
     NULL,                    /* xdrObject   */
     NULL,                    /* hasInstance */
     args_trace
 };
 
-/*
- * A Declarative Environment object stores its active StackFrame pointer in
- * its private slot, just as Call and Arguments objects do.
- */
-Class js::DeclEnvClass = {
-    js_Object_str,
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(CallObject::DECL_ENV_RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    JS_PropertyStub,         /* addProperty */
-    JS_PropertyStub,         /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
-};
-
-static inline JSObject *
-NewDeclEnvObject(JSContext *cx, StackFrame *fp)
-{
-    RootedVarTypeObject type(cx);
-    type = cx->compartment->getEmptyType(cx);
-    if (!type)
-        return NULL;
-
-    JSObject *parent = fp->scopeChain().getGlobal();
-
-    RootedVarShape emptyDeclEnvShape(cx);
-    emptyDeclEnvShape =
-        EmptyShape::getInitialShape(cx, &DeclEnvClass, NULL,
-                                    parent, CallObject::DECL_ENV_FINALIZE_KIND);
-    if (!emptyDeclEnvShape)
-        return NULL;
-
-    JSObject *envobj = JSObject::create(cx, CallObject::DECL_ENV_FINALIZE_KIND,
-                                        emptyDeclEnvShape, type, NULL);
-    if (!envobj)
-        return NULL;
-    envobj->setPrivate(fp);
-
-    if (!envobj->setInternalScopeChain(cx, &fp->scopeChain()))
-        return NULL;
-
-    return envobj;
-}
-
 namespace js {
 
 CallObject *
 CreateFunCallObject(JSContext *cx, StackFrame *fp)
 {
     JS_ASSERT(fp->isNonEvalFunctionFrame());
     JS_ASSERT(!fp->hasCallObj());
 
@@ -665,17 +618,17 @@ CreateFunCallObject(JSContext *cx, Stack
     JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(),
                  scopeChain->getPrivate() != fp);
 
     /*
      * For a named function expression Call's parent points to an environment
      * object holding function's name.
      */
     if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) {
-        scopeChain = NewDeclEnvObject(cx, fp);
+        scopeChain = DeclEnvObject::create(cx, fp);
         if (!scopeChain)
             return NULL;
 
         if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
                                   ObjectValue(fp->callee()), NULL, NULL,
                                   JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
             return NULL;
         }
@@ -784,21 +737,19 @@ js_PutCallObject(StackFrame *fp)
             if (nesting && script->isOuterFunction) {
                 nesting->argArray = callobj.argArray();
                 nesting->varArray = callobj.varArray();
             }
         }
 
         /* Clear private pointers to fp, which is about to go away. */
         if (js_IsNamedLambda(fun)) {
-            JSObject *env = callobj.internalScopeChain();
-
-            JS_ASSERT(env->isDeclEnv());
-            JS_ASSERT(env->getPrivate() == fp);
-            env->setPrivate(NULL);
+            JSObject &env = callobj.enclosingScope();
+            JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp);
+            env.setPrivate(NULL);
         }
     }
 
     callobj.setStackFrame(NULL);
 }
 
 namespace js {
 
@@ -1950,17 +1901,17 @@ JSFunctionSpec function_methods[] = {
 
 JSBool
 Function(JSContext *cx, uintN argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Block this call if security callbacks forbid it. */
     RootedVar<GlobalObject*> global(cx);
-    global = args.callee().getGlobal();
+    global = &args.callee().global();
     if (!global->isRuntimeCodeGenEnabled(cx)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
         return false;
     }
 
     Bindings bindings(cx);
 
     const char *filename;
@@ -2245,17 +2196,17 @@ js_CloneFunctionObject(JSContext *cx, JS
             JS_ASSERT(script->compartment() == fun->compartment());
             JS_ASSERT(script->compartment() != cx->compartment);
 
             clone->script().init(NULL);
             JSScript *cscript = js_CloneScript(cx, script);
             if (!cscript)
                 return NULL;
 
-            cscript->globalObject = clone->getGlobal();
+            cscript->globalObject = &clone->global();
             clone->setScript(cscript);
             if (!cscript->typeSetFunction(cx, clone))
                 return NULL;
 
             js_CallNewScriptHook(cx, clone->script(), clone);
             Debugger::onNewScript(cx, clone->script(), NULL);
         }
     }
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -40,16 +40,18 @@
 #ifndef jsfuninlines_h___
 #define jsfuninlines_h___
 
 #include "jsfun.h"
 #include "jsscript.h"
 
 #include "vm/GlobalObject.h"
 
+#include "vm/ScopeObject-inl.h"
+
 inline bool
 JSFunction::inStrictMode() const
 {
     return script()->strictModeCode;
 }
 
 inline JSObject *
 JSFunction::environment() const
@@ -346,27 +348,27 @@ IsBuiltinFunctionConstructor(JSFunction 
 const Shape *
 LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj);
 
 static inline JSObject *
 SkipScopeParent(JSObject *parent)
 {
     if (!parent)
         return NULL;
-    while (parent->isInternalScope())
-        parent = parent->scopeChain();
+    while (parent->isScope())
+        parent = &parent->asScope().enclosingScope();
     return parent;
 }
 
 inline JSFunction *
 CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
                     gc::AllocKind kind = JSFunction::FinalizeKind)
 {
     JS_ASSERT(parent);
-    JSObject *proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx);
+    JSObject *proto = parent->global().getOrCreateFunctionPrototype(cx);
     if (!proto)
         return NULL;
 
     return js_CloneFunctionObject(cx, fun, parent, proto, kind);
 }
 
 inline JSFunction *
 CloneFunctionObjectIfNotSingleton(JSContext *cx, JSFunction *fun, JSObject *parent)
@@ -390,17 +392,17 @@ CloneFunctionObjectIfNotSingleton(JSCont
 
 inline JSFunction *
 CloneFunctionObject(JSContext *cx, JSFunction *fun)
 {
     /*
      * Variant which makes an exact clone of fun, preserving parent and proto.
      * Calling the above version CloneFunctionObject(cx, fun, fun->getParent())
      * is not equivalent: API clients, including XPConnect, can reparent
-     * objects so that fun->getGlobal() != fun->getProto()->getGlobal().
+     * objects so that fun->global() != fun->getProto()->global().
      * See ReparentWrapperIfFound.
      */
     JS_ASSERT(fun->getParent() && fun->getProto());
 
     if (fun->hasSingletonType())
         return fun;
 
     return js_CloneFunctionObject(cx, fun, fun->environment(), fun->getProto(),
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -95,17 +95,17 @@
 #ifdef JS_ION
 # include "ion/IonMacroAssembler.h"
 #endif
 #include "ion/IonFrameIterator.h"
 
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 
-#include "vm/CallObject-inl.h"
+#include "vm/ScopeObject-inl.h"
 #include "vm/String-inl.h"
 
 #ifdef MOZ_VALGRIND
 # define JS_VALGRIND
 #endif
 #ifdef JS_VALGRIND
 # include <valgrind/memcheck.h>
 #endif
@@ -2127,17 +2127,17 @@ MarkWeakReferences(GCMarker *gcmarker)
     while (WatchpointMap::markAllIteratively(gcmarker) ||
            WeakMapBase::markAllIteratively(gcmarker) ||
            Debugger::markAllIteratively(gcmarker)) {
         gcmarker->drainMarkStack();
     }
     JS_ASSERT(gcmarker->isMarkStackEmpty());
 }
 
-JS_REQUIRES_STACK void
+void
 MarkRuntime(JSTracer *trc)
 {
     JSRuntime *rt = trc->runtime;
 
     if (rt->state != JSRTS_LANDING)
         MarkConservativeStackRoots(trc);
 
     for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront())
@@ -3475,17 +3475,17 @@ CheckStackRoot(JSTracer *trc, jsuword *w
                 while (rooter) {
                     if (rooter->address() == (Cell **) w)
                         matched = true;
                     rooter = rooter->previous();
                 }
             }
             CheckRoot *check = acx->checkGCRooters;
             while (check) {
-                if (check->contains((uint8 *) w, sizeof(w)))
+                if (check->contains(static_cast<uint8_t*>(w), sizeof(w)))
                     matched = true;
                 check = check->previous();
             }
         }
         if (!matched) {
             /*
              * Only poison the last byte in the word. It is easy to get
              * accidental collisions when a value that does not occupy a full
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1369,23 +1369,23 @@ js_GCThingIsMarked(void *thing, uintN co
 extern void
 js_TraceStackFrame(JSTracer *trc, js::StackFrame *fp);
 
 extern bool
 js_IsAddressableGCThing(JSRuntime *rt, jsuword w, js::gc::AllocKind *thingKind, void **thing);
 
 namespace js {
 
-extern JS_REQUIRES_STACK void
+extern void
 MarkRuntime(JSTracer *trc);
 
 extern void
 TraceRuntime(JSTracer *trc);
 
-extern JS_REQUIRES_STACK JS_FRIEND_API(void)
+extern JS_FRIEND_API(void)
 MarkContext(JSTracer *trc, JSContext *acx);
 
 /* Must be called with GC lock taken. */
 extern void
 TriggerGC(JSRuntime *rt, js::gcstats::Reason reason);
 
 /* Must be called with GC lock taken. */
 extern void
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1886,17 +1886,17 @@ TypeSet::getSingleton(JSContext *cx, boo
 
 static inline bool
 TypeHasGlobal(Type type, JSObject *global)
 {
     if (type.isUnknown() || type.isAnyObject())
         return false;
 
     if (type.isSingleObject())
-        return type.singleObject()->getGlobal() == global;
+        return &type.singleObject()->global() == global;
 
     if (type.isTypeObject())
         return type.typeObject()->getGlobal() == global;
 
     JS_ASSERT(type.isPrimitive());
     return true;
 }
 
@@ -5206,18 +5206,18 @@ TypeScript::SetScope(JSContext *cx, JSSc
     JS_ASSERT_IF(scope && scope->isCall() && !scope->asCall().isForEval(),
                  scope->asCall().getCalleeFunction() != fun);
 
     if (!script->compileAndGo) {
         script->types->global = NULL;
         return true;
     }
 
-    JS_ASSERT_IF(fun && scope, fun->getGlobal() == scope->getGlobal());
-    script->types->global = fun ? fun->getGlobal() : scope->getGlobal();
+    JS_ASSERT_IF(fun && scope, fun->global() == scope->global());
+    script->types->global = fun ? &fun->global() : &scope->global();
 
     /*
      * Update the parent in the script's bindings. The bindings are created
      * with a NULL parent, and fixing the parent now avoids the need to reshape
      * every time a call object is created from the bindings.
      */
     if (!script->bindings.setParent(cx, script->types->global))
         return false;
@@ -5238,17 +5238,17 @@ TypeScript::SetScope(JSContext *cx, JSSc
         return true;
     }
 
     /*
      * Walk the scope chain to the next call object, which will be the function
      * the script is nested inside.
      */
     while (!scope->isCall())
-        scope = scope->internalScopeChain();
+        scope = &scope->asScope().enclosingScope();
 
     CallObject &call = scope->asCall();
 
     /* The isInnerFunction test ensures there is no intervening strict eval call object. */
     JS_ASSERT(!call.isForEval());
 
     /* Don't track non-heavyweight parents, NAME ops won't reach into them. */
     JSFunction *parentFun = call.getCalleeFunction();
@@ -5271,19 +5271,19 @@ TypeScript::SetScope(JSContext *cx, JSSc
      * compartment and there may be inner function objects parented to an
      * activation of the outer function sticking around. In such cases, treat
      * the parent's call object as the most recent one, so that it is not
      * marked as reentrant.
      */
     if (!parent->ensureHasTypes(cx))
         return false;
     if (!parent->types->hasScope()) {
-        if (!SetScope(cx, parent, scope->internalScopeChain()))
+        if (!SetScope(cx, parent, &call.enclosingScope()))
             return false;
-        parent->nesting()->activeCall = scope;
+        parent->nesting()->activeCall = &call;
         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. */
 
@@ -5366,32 +5366,32 @@ ClearActiveNesting(JSScript *start)
 static void
 CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
 {
   restart:
     JSScript *parent = script->nesting()->parent;
     JS_ASSERT(parent);
 
     while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent)
-        scope = scope->internalScopeChain();
+        scope = &scope->asScope().enclosingScope();
 
     if (scope != parent->nesting()->activeCall) {
         parent->reentrantOuterFunction = true;
         MarkTypeObjectFlags(cx, parent->function(), OBJECT_FLAG_REENTRANT_FUNCTION);
 
         /*
          * Continue checking parents to see if this is reentrant for them too.
          * We don't need to check this in for non-reentrant calls on the outer
          * function: when we entered any outer function to the immediate parent
          * we cleared the active call for its transitive children, so a
          * non-reentrant call on a child is also a non-reentrant call on the
          * parent.
          */
         if (parent->nesting()->parent) {
-            scope = scope->internalScopeChain();
+            scope = &scope->asScope().enclosingScope();
             script = parent;
             goto restart;
         }
     }
 }
 
 void
 NestingPrologue(JSContext *cx, StackFrame *fp)
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1245,19 +1245,19 @@ TypeObject::setFlagsFromKey(JSContext *c
     if (!hasAllFlags(flags))
         setFlags(cx, flags);
 }
 
 inline JSObject *
 TypeObject::getGlobal()
 {
     if (singleton)
-        return singleton->getGlobal();
+        return &singleton->global();
     if (interpretedFunction && interpretedFunction->script()->compileAndGo)
-        return interpretedFunction->getGlobal();
+        return &interpretedFunction->global();
     return NULL;
 }
 
 inline void
 TypeObject::writeBarrierPre(TypeObject *type)
 {
 #ifdef JSGC_INCREMENTAL
     if (!type)
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -135,17 +135,17 @@ using namespace js::types;
  * place a mutable clone of it on scopeChain.
  *
  * This lazy cloning is implemented in GetScopeChain, which is also used in
  * some other cases --- entering 'with' blocks, for example.
  */
 JSObject *
 js::GetScopeChain(JSContext *cx, StackFrame *fp)
 {
-    JSObject *sharedBlock = fp->maybeBlockChain();
+    StaticBlockObject *sharedBlock = fp->maybeBlockChain();
 
     if (!sharedBlock) {
         /*
          * Don't force a call object for a lightweight function call, but do
          * insist that there is a call object for a heavyweight function call.
          */
         JS_ASSERT_IF(fp->isNonEvalFunctionFrame() && fp->fun()->isHeavyweight(),
                      fp->hasCallObj());
@@ -171,17 +171,17 @@ js::GetScopeChain(JSContext *cx, StackFr
         /*
          * scopeChain includes all blocks whose static scope we're within that
          * have already been cloned.  Find the innermost such block.  Its
          * prototype should appear on blockChain; we'll clone blockChain up
          * to, but not including, that prototype.
          */
         limitClone = &fp->scopeChain();
         while (limitClone->isWith())
-            limitClone = limitClone->internalScopeChain();
+            limitClone = &limitClone->asWith().enclosingScope();
         JS_ASSERT(limitClone);
 
         /*
          * It may seem like we don't know enough about limitClone to be able
          * to just grab its prototype as we do here, but it's actually okay.
          *
          * If limitClone is a block object belonging to this frame, then its
          * prototype is the innermost entry in blockChain that we have already
@@ -203,55 +203,54 @@ js::GetScopeChain(JSContext *cx, StackFr
         if (limitBlock == sharedBlock)
             return &fp->scopeChain();
     }
 
     /*
      * Special-case cloning the innermost block; this doesn't have enough in
      * common with subsequent steps to include in the loop.
      *
-     * js_CloneBlockObject leaves the clone's parent slot uninitialized. We
-     * populate it below.
+     * create() leaves the clone's enclosingScope unset. We set it below.
      */
-    JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp);
+    ClonedBlockObject *innermostNewChild = ClonedBlockObject::create(cx, *sharedBlock, fp);
     if (!innermostNewChild)
         return NULL;
 
     /*
      * Clone our way towards outer scopes until we reach the innermost
      * enclosing function, or the innermost block we've already cloned.
      */
-    JSObject *newChild = innermostNewChild;
+    ClonedBlockObject *newChild = innermostNewChild;
     for (;;) {
         JS_ASSERT(newChild->getProto() == sharedBlock);
-        sharedBlock = sharedBlock->staticBlockScopeChain();
+        sharedBlock = sharedBlock->enclosingBlock();
 
         /* Sometimes limitBlock will be NULL, so check that first.  */
         if (sharedBlock == limitBlock || !sharedBlock)
             break;
 
         /* As in the call above, we don't know the real parent yet.  */
-        JSObject *clone = js_CloneBlockObject(cx, sharedBlock, fp);
+        ClonedBlockObject *clone = ClonedBlockObject::create(cx, *sharedBlock, fp);
         if (!clone)
             return NULL;
 
-        if (!newChild->setInternalScopeChain(cx, clone))
+        if (!newChild->setEnclosingScope(cx, *clone))
             return NULL;
         newChild = clone;
     }
-    if (!newChild->setInternalScopeChain(cx, &fp->scopeChain()))
+    if (!newChild->setEnclosingScope(cx, fp->scopeChain()))
         return NULL;
 
 
     /*
      * If we found a limit block belonging to this frame, then we should have
      * found it in blockChain.
      */
     JS_ASSERT_IF(limitBlock &&
-                 limitBlock->isBlock() &&
+                 limitBlock->isClonedBlock() &&
                  limitClone->getPrivate() == js_FloatingFrameIfGenerator(cx, fp),
                  sharedBlock);
 
     /* Place our newly cloned blocks at the head of the scope chain.  */
     fp->setScopeChainNoCallObj(*innermostNewChild);
     return innermostNewChild;
 }
 
@@ -323,17 +322,17 @@ js::BoxNonStrictThis(JSContext *cx, cons
     JS_ASSERT(!thisv.isMagic());
 
 #ifdef DEBUG
     JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
     JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
 #endif
 
     if (thisv.isNullOrUndefined()) {
-        JSObject *thisp = call.callee().getGlobal()->thisObject(cx);
+        JSObject *thisp = call.callee().global().thisObject(cx);
         if (!thisp)
             return false;
         call.thisv().setObject(*thisp);
         return true;
     }
 
     if (!thisv.isObject())
         return !!js_PrimitiveToObject(cx, &thisv);
@@ -417,17 +416,17 @@ js::OnUnknownMethod(JSContext *cx, Value
 
         obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value());
         obj->setSlot(JSSLOT_SAVED_ID, vp[0]);
         vp[0].setObject(*obj);
     }
     return true;
 }
 
-static JS_REQUIRES_STACK JSBool
+static JSBool
 NoSuchMethod(JSContext *cx, uintN argc, Value *vp)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, 2, &args))
         return JS_FALSE;
 
     JS_ASSERT(vp[0].isObject());
     JS_ASSERT(vp[1].isObject());
@@ -443,29 +442,29 @@ NoSuchMethod(JSContext *cx, uintN argc, 
     args[1].setObject(*argsobj);
     JSBool ok = Invoke(cx, args);
     vp[0] = args.rval();
     return ok;
 }
 
 #endif /* JS_HAS_NO_SUCH_METHOD */
 
-JS_REQUIRES_STACK bool
+bool
 js::RunScript(JSContext *cx, JSScript *script, StackFrame *fp)
 {
     JS_ASSERT(script);
     JS_ASSERT(fp == cx->fp());
     JS_ASSERT(fp->script() == script);
 #ifdef JS_METHODJIT_SPEW
     JMCheckLogging();
 #endif
 
     /* FIXME: Once bug 470510 is fixed, make this an assert. */
     if (script->compileAndGo) {
-        if (fp->scopeChain().getGlobal()->isCleared()) {
+        if (fp->scopeChain().global().isCleared()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CLEARED_SCOPE);
             return false;
         }
     }
 
 #ifdef JS_ION
     if (ion::IsEnabled()) {
         ion::MethodStatus status = ion::Compile(cx, script, fp, NULL);
@@ -1092,80 +1091,67 @@ EnterWith(JSContext *cx, jsint stackInde
     JSObject *parent = GetScopeChain(cx, fp);
     if (!parent)
         return JS_FALSE;
 
     OBJ_TO_INNER_OBJECT(cx, obj);
     if (!obj)
         return JS_FALSE;
 
-    JSObject *withobj = js_NewWithObject(cx, obj, parent,
-                                         sp + stackIndex - fp->base());
+    JSObject *withobj = WithObject::create(cx, fp, *obj, *parent,
+                                           sp + stackIndex - fp->base());
     if (!withobj)
         return JS_FALSE;
 
     fp->setScopeChainNoCallObj(*withobj);
     return JS_TRUE;
 }
 
 static void
 LeaveWith(JSContext *cx)
 {
-    JSObject *withobj;
-
-    withobj = &cx->fp()->scopeChain();
-    JS_ASSERT(withobj->getClass() == &WithClass);
-    JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
-    JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
-    withobj->setPrivate(NULL);
-    cx->fp()->setScopeChainNoCallObj(*withobj->internalScopeChain());
+    WithObject &withobj = cx->fp()->scopeChain().asWith();
+    JS_ASSERT(withobj.maybeStackFrame() == js_FloatingFrameIfGenerator(cx, cx->fp()));
+    JS_ASSERT(withobj.stackDepth() >= 0);
+    withobj.setStackFrame(NULL);
+    cx->fp()->setScopeChainNoCallObj(withobj.enclosingScope());
 }
 
 bool
-js::IsActiveWithOrBlock(JSContext *cx, JSObject &obj, int stackDepth)
+js::IsActiveWithOrBlock(JSContext *cx, JSObject &obj, uint32_t stackDepth)
 {
     return (obj.isWith() || obj.isBlock()) &&
            obj.getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()) &&
-           OBJ_BLOCK_DEPTH(cx, &obj) >= stackDepth;
+           obj.asNestedScope().stackDepth() >= stackDepth;
 }
 
-/*
- * Unwind block and scope chains to match the given depth. The function sets
- * fp->sp on return to stackDepth.
- */
-bool
-js::UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind)
+/* Unwind block and scope chains to match the given depth. */
+void
+js::UnwindScope(JSContext *cx, uint32_t stackDepth)
 {
-    JS_ASSERT(stackDepth >= 0);
     JS_ASSERT(cx->fp()->base() + stackDepth <= cx->regs().sp);
 
     StackFrame *fp = cx->fp();
-    JSObject *obj = fp->maybeBlockChain();
-    while (obj) {
-        JS_ASSERT(obj->isStaticBlock());
-        if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth)
+    StaticBlockObject *block = fp->maybeBlockChain();
+    while (block) {
+        if (block->stackDepth() < stackDepth)
             break;
-        obj = obj->staticBlockScopeChain();
+        block = block->enclosingBlock();
     }
-    fp->setBlockChain(obj);
+    fp->setBlockChain(block);
 
     for (;;) {
         JSObject &scopeChain = fp->scopeChain();
         if (!IsActiveWithOrBlock(cx, scopeChain, stackDepth))
             break;
-        if (scopeChain.isBlock()) {
-            /* Don't fail until after we've updated all stacks. */
-            normalUnwind &= js_PutBlockObject(cx, normalUnwind);
-        } else {
+        if (scopeChain.isClonedBlock())
+            scopeChain.asClonedBlock().put(cx);
+        else
             LeaveWith(cx);
-        }
     }
-
-    cx->regs().sp = fp->base() + stackDepth;
-    return normalUnwind;
 }
 
 /*
  * Find the results of incrementing or decrementing *vp. For pre-increments,
  * both *vp and *vp2 will contain the result on return. For post-increments,
  * vp will contain the original value converted to a number and vp2 will get
  * the result. Both vp and vp2 must be roots.
  */
@@ -1945,27 +1931,27 @@ BEGIN_CASE(JSOP_POP)
     regs.sp--;
 END_CASE(JSOP_POP)
 
 BEGIN_CASE(JSOP_POPN)
 {
     regs.sp -= GET_UINT16(regs.pc);
 #ifdef DEBUG
     JS_ASSERT(regs.fp()->base() <= regs.sp);
-    JSObject *obj = regs.fp()->maybeBlockChain();
-    JS_ASSERT_IF(obj,
-                 OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
+    StaticBlockObject *block = regs.fp()->maybeBlockChain();
+    JS_ASSERT_IF(block,
+                 block->stackDepth() + block->slotCount()
                  <= (size_t) (regs.sp - regs.fp()->base()));
-    for (obj = &regs.fp()->scopeChain(); obj; obj = obj->scopeChain()) {
+    for (JSObject *obj = &regs.fp()->scopeChain(); obj; obj = obj->enclosingScope()) {
         if (!obj->isBlock() || !obj->isWith())
             continue;
         if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp()))
             break;
-        JS_ASSERT(regs.fp()->base() + OBJ_BLOCK_DEPTH(cx, obj)
-                  + (obj->isBlock() ? OBJ_BLOCK_COUNT(cx, obj) : 1)
+        JS_ASSERT(regs.fp()->base() + obj->asBlock().stackDepth()
+                  + (obj->isBlock() ? obj->asBlock().slotCount() : 1)
                   <= regs.sp);
     }
 #endif
 }
 END_CASE(JSOP_POPN)
 
 BEGIN_CASE(JSOP_SETRVAL)
 BEGIN_CASE(JSOP_POPV)
@@ -2368,17 +2354,17 @@ BEGIN_CASE(JSOP_ENUMCONSTELEM)
         goto error;
     }
     regs.sp -= 3;
 }
 END_CASE(JSOP_ENUMCONSTELEM)
 #endif
 
 BEGIN_CASE(JSOP_BINDGNAME)
-    PUSH_OBJECT(*regs.fp()->scopeChain().getGlobal());
+    PUSH_OBJECT(regs.fp()->scopeChain().global());
 END_CASE(JSOP_BINDGNAME)
 
 BEGIN_CASE(JSOP_BINDNAME)
 {
     JSObject *obj;
     do {
         /*
          * We can skip the property lookup for the global object. If the
@@ -2997,19 +2983,19 @@ BEGIN_CASE(JSOP_LENGTH)
                 JSObject *obj = &vp->toObject();
                 if (obj->isArray()) {
                     jsuint length = obj->getArrayLength();
                     rval = NumberValue(length);
                     break;
                 }
 
                 if (obj->isArguments()) {
-                    ArgumentsObject *argsobj = obj->asArguments();
-                    if (!argsobj->hasOverriddenLength()) {
-                        uint32_t length = argsobj->initialLength();
+                    ArgumentsObject &argsobj = obj->asArguments();
+                    if (!argsobj.hasOverriddenLength()) {
+                        uint32_t length = argsobj.initialLength();
                         JS_ASSERT(length < INT32_MAX);
                         rval = Int32Value(int32_t(length));
                         break;
                     }
                 }
 
                 if (js_IsTypedArray(obj)) {
                     JSObject *tarray = TypedArray::getTypedArray(obj);
@@ -3056,24 +3042,24 @@ END_CASE(JSOP_GETPROP)
 BEGIN_CASE(JSOP_CALLPROP)
 {
     Value lval = regs.sp[-1];
 
     Value objv;
     if (lval.isObject()) {
         objv = lval;
     } else {
-        GlobalObject *global = regs.fp()->scopeChain().getGlobal();
+        GlobalObject &global = regs.fp()->scopeChain().global();
         JSObject *pobj;
         if (lval.isString()) {
-            pobj = global->getOrCreateStringPrototype(cx);
+            pobj = global.getOrCreateStringPrototype(cx);
         } else if (lval.isNumber()) {
-            pobj = global->getOrCreateNumberPrototype(cx);
+            pobj = global.getOrCreateNumberPrototype(cx);
         } else if (lval.isBoolean()) {
-            pobj = global->getOrCreateBooleanPrototype(cx);
+            pobj = global.getOrCreateBooleanPrototype(cx);
         } else {
             JS_ASSERT(lval.isNull() || lval.isUndefined());
             js_ReportIsNullOrUndefined(cx, -1, lval, NULL);
             goto error;
         }
         if (!pobj)
             goto error;
         objv.setObject(*pobj);
@@ -3143,17 +3129,17 @@ BEGIN_CASE(JSOP_SETMETHOD)
 {
     Value rval = regs.sp[-1];
     JS_ASSERT_IF(op == JSOP_SETMETHOD, IsFunctionObject(rval));
     Value &lref = regs.sp[-2];
     JS_ASSERT_IF(op == JSOP_SETNAME, lref.isObject());
     JSObject *obj;
     VALUE_TO_OBJECT(cx, &lref, obj);
 
-    JS_ASSERT_IF(op == JSOP_SETGNAME, obj == regs.fp()->scopeChain().getGlobal());
+    JS_ASSERT_IF(op == JSOP_SETGNAME, obj == &regs.fp()->scopeChain().global());
 
     do {
         PropertyCache *cache = &JS_PROPERTY_CACHE(cx);
 
         /*
          * Probe the property cache, specializing for two important
          * set-property cases. First:
          *
@@ -3276,17 +3262,17 @@ BEGIN_CASE(JSOP_GETELEM)
     if (IsDefinitelyIndex(rref, &index)) {
         if (obj->isDenseArray()) {
             if (index < obj->getDenseArrayInitializedLength()) {
                 rval = obj->getDenseArrayElement(index);
                 if (!rval.isMagic())
                     goto end_getelem;
             }
         } else if (obj->isArguments()) {
-            if (obj->asArguments()->getElement(index, &rval))
+            if (obj->asArguments().getElement(index, &rval))
                 goto end_getelem;
         }
 
         if (!obj->getElement(cx, index, &rval))
             goto error;
     } else {
         if (script->hasAnalysis())
             script->analysis()->getCode(regs.pc).getStringElement = true;
@@ -3535,17 +3521,17 @@ BEGIN_CASE(JSOP_GETGNAME)
 BEGIN_CASE(JSOP_CALLGNAME)
 BEGIN_CASE(JSOP_NAME)
 BEGIN_CASE(JSOP_CALLNAME)
 {
     JSObject *obj = &regs.fp()->scopeChain();
 
     bool global = js_CodeSpec[op].format & JOF_GNAME;
     if (global)
-        obj = obj->getGlobal();
+        obj = &obj->global();
 
     Value rval;
 
     PropertyCacheEntry *entry;
     JSObject *obj2;
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
     if (!atom) {
@@ -3581,18 +3567,18 @@ BEGIN_CASE(JSOP_CALLNAME)
 
     /* Take the slow path if prop was not found in a native object. */
     if (!obj->isNative() || !obj2->isNative()) {
         if (!obj->getGeneric(cx, id, &rval))
             goto error;
     } else {
         Shape *shape = (Shape *)prop;
         JSObject *normalized = obj;
-        if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
-            normalized = js_UnwrapWithObject(cx, normalized);
+        if (normalized->isWith() && !shape->hasDefaultGetter())
+            normalized = &normalized->asWith().object();
         NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval);
     }
 
     PUSH_COPY(rval);
     TypeScript::Monitor(cx, script, regs.pc, rval);
 
     /* obj must be on the scope chain, thus not a function. */
     if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
@@ -3661,17 +3647,17 @@ END_CASE(JSOP_OBJECT)
 
 BEGIN_CASE(JSOP_REGEXP)
 {
     /*
      * Push a regexp object cloned from the regexp literal object mapped by the
      * bytecode at pc.
      */
     jsatomid index = GET_FULL_INDEX(0);
-    JSObject *proto = regs.fp()->scopeChain().getGlobal()->getOrCreateRegExpPrototype(cx);
+    JSObject *proto = regs.fp()->scopeChain().global().getOrCreateRegExpPrototype(cx);
     if (!proto)
         goto error;
     JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto);
     if (!obj)
         goto error;
     PUSH_OBJECT(*obj);
 }
 END_CASE(JSOP_REGEXP)
@@ -5131,106 +5117,101 @@ BEGIN_CASE(JSOP_XMLPI)
 }
 END_CASE(JSOP_XMLPI)
 
 BEGIN_CASE(JSOP_GETFUNNS)
 {
     JS_ASSERT(!script->strictModeCode);
 
     Value rval;
-    if (!cx->fp()->scopeChain().getGlobal()->getFunctionNamespace(cx, &rval))
+    if (!cx->fp()->scopeChain().global().getFunctionNamespace(cx, &rval))
         goto error;
     PUSH_COPY(rval);
 }
 END_CASE(JSOP_GETFUNNS)
 #endif /* JS_HAS_XML_SUPPORT */
 
 BEGIN_CASE(JSOP_ENTERBLOCK)
 BEGIN_CASE(JSOP_ENTERLET0)
 BEGIN_CASE(JSOP_ENTERLET1)
 {
     JSObject *obj;
     LOAD_OBJECT(0, obj);
-    JS_ASSERT(obj->isStaticBlock());
-    JS_ASSERT(regs.fp()->maybeBlockChain() == obj->staticBlockScopeChain());
+    StaticBlockObject &blockObj = obj->asStaticBlock();
+    JS_ASSERT(regs.fp()->maybeBlockChain() == blockObj.enclosingBlock());
 
     if (op == JSOP_ENTERBLOCK) {
-        JS_ASSERT(regs.fp()->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
-        Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
+        JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp);
+        Value *vp = regs.sp + blockObj.slotCount();
         JS_ASSERT(regs.sp < vp);
         JS_ASSERT(vp <= regs.fp()->slots() + script->nslots);
         SetValueRangeToUndefined(regs.sp, vp);
         regs.sp = vp;
     } else if (op == JSOP_ENTERLET0) {
-        JS_ASSERT(regs.fp()->base() + OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
+        JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount()
                   == regs.sp);
     } else if (op == JSOP_ENTERLET1) {
-        JS_ASSERT(regs.fp()->base() + OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
+        JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() + blockObj.slotCount()
                   == regs.sp - 1);
     }
 
 #ifdef DEBUG
-    JS_ASSERT(regs.fp()->maybeBlockChain() == obj->staticBlockScopeChain());
+    JS_ASSERT(regs.fp()->maybeBlockChain() == blockObj.enclosingBlock());
 
     /*
      * The young end of fp->scopeChain may omit blocks if we haven't closed
      * over them, but if there are any closure blocks on fp->scopeChain, they'd
      * better be (clones of) ancestors of the block we're entering now;
      * anything else we should have popped off fp->scopeChain when we left its
      * static scope.
      */
     JSObject *obj2 = &regs.fp()->scopeChain();
     while (obj2->isWith())
-        obj2 = obj2->internalScopeChain();
+        obj2 = &obj2->asWith().enclosingScope();
     if (obj2->isBlock() &&
         obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp()))
     {
-        JSObject *youngestProto = obj2->getProto();
-        JS_ASSERT(youngestProto->isStaticBlock());
-        JSObject *parent = obj;
-        while ((parent = parent->scopeChain()) != youngestProto)
+        StaticBlockObject &youngestProto = obj2->asClonedBlock().staticBlock();
+        StaticBlockObject *parent = &blockObj;
+        while ((parent = parent->enclosingBlock()) != &youngestProto)
             JS_ASSERT(parent);
     }
 #endif
 
-    regs.fp()->setBlockChain(obj);
+    regs.fp()->setBlockChain(&blockObj);
 }
 END_CASE(JSOP_ENTERBLOCK)
 
 BEGIN_CASE(JSOP_LEAVEBLOCK)
 BEGIN_CASE(JSOP_LEAVEFORLETIN)
 BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
 {
-    JS_ASSERT(regs.fp()->blockChain().isStaticBlock());
-    DebugOnly<uintN> blockDepth = OBJ_BLOCK_DEPTH(cx, &regs.fp()->blockChain());
-    JS_ASSERT(blockDepth <= StackDepth(script));
+    StaticBlockObject &blockObj = regs.fp()->blockChain();
+    JS_ASSERT(blockObj.stackDepth() <= StackDepth(script));
 
     /*
      * If we're about to leave the dynamic scope of a block that has been
      * cloned onto fp->scopeChain, clear its private data, move its locals from
      * the stack into the clone, and pop it off the chain.
      */
-    JSObject &obj = regs.fp()->scopeChain();
-    if (obj.getProto() == &regs.fp()->blockChain()) {
-        JS_ASSERT(obj.isClonedBlock());
-        if (!js_PutBlockObject(cx, JS_TRUE))
-            goto error;
-    }
-
-    regs.fp()->setBlockChain(regs.fp()->blockChain().staticBlockScopeChain());
+    JSObject &scope = regs.fp()->scopeChain();
+    if (scope.getProto() == &blockObj)
+        scope.asClonedBlock().put(cx);
+
+    regs.fp()->setBlockChain(blockObj.enclosingBlock());
 
     if (op == JSOP_LEAVEBLOCK) {
         /* Pop the block's slots. */
         regs.sp -= GET_UINT16(regs.pc);
-        JS_ASSERT(regs.fp()->base() + blockDepth == regs.sp);
+        JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp);
     } else if (op == JSOP_LEAVEBLOCKEXPR) {
         /* Pop the block's slots maintaining the topmost expr. */
         Value *vp = &regs.sp[-1];
         regs.sp -= GET_UINT16(regs.pc);
-        JS_ASSERT(regs.fp()->base() + blockDepth == regs.sp - 1);
+        JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp - 1);
         regs.sp[-1] = *vp;
     } else {
         /* Another op will pop; nothing to do here. */
         len = JSOP_LEAVEFORLETIN_LENGTH;
         DO_NEXT_OP(len);
     }
 }
 END_CASE(JSOP_LEAVEBLOCK)
@@ -5424,25 +5405,18 @@ END_CASE(JSOP_ARRAYPUSH)
 
             /*
              * Set pc to the first bytecode after the the try note to point
              * to the beginning of catch or finally or to [enditer] closing
              * the for-in loop.
              */
             regs.pc = (script)->main() + tn->start + tn->length;
 
-            JSBool ok = UnwindScope(cx, tn->stackDepth, JS_TRUE);
-            JS_ASSERT(regs.sp == regs.fp()->base() + tn->stackDepth);
-            if (!ok) {
-                /*
-                 * Restart the handler search with updated pc and stack depth
-                 * to properly notify the debugger.
-                 */
-                goto error;
-            }
+            UnwindScope(cx, tn->stackDepth);
+            regs.sp = regs.fp()->base() + tn->stackDepth;
 
             switch (tn->kind) {
               case JSTRY_CATCH:
                   JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK);
 
 #if JS_HAS_GENERATORS
                 /* Catch cannot intercept the closing of a generator. */
                   if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
@@ -5468,17 +5442,17 @@ END_CASE(JSOP_ARRAYPUSH)
                 len = 0;
                 DO_NEXT_OP(len);
 
               case JSTRY_ITER: {
                 /* This is similar to JSOP_ENDITER in the interpreter loop. */
                 JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER);
                 Value v = cx->getPendingException();
                 cx->clearPendingException();
-                ok = js_CloseIterator(cx, &regs.sp[-1].toObject());
+                bool ok = js_CloseIterator(cx, &regs.sp[-1].toObject());
                 regs.sp -= 1;
                 if (!ok)
                     goto error;
                 cx->setPendingException(v);
               }
            }
         } while (++tn != tnlimit);
 
@@ -5494,25 +5468,18 @@ END_CASE(JSOP_ARRAYPUSH)
             cx->clearPendingException();
             interpReturnOK = JS_TRUE;
             regs.fp()->clearReturnValue();
         }
 #endif
     }
 
   forced_return:
-    /*
-     * Unwind the scope making sure that interpReturnOK stays false even when
-     * UnwindScope returns true.
-     *
-     * When a trap handler returns JSTRAP_RETURN, we jump here with
-     * interpReturnOK set to true bypassing any finally blocks.
-     */
-    interpReturnOK &= (JSBool)UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending());
-    JS_ASSERT(regs.sp == regs.fp()->base());
+    UnwindScope(cx, 0);
+    regs.sp = regs.fp()->base();
 
     if (entryFrame != regs.fp())
         goto inline_return;
 
   exit:
     if (cx->compartment->debugMode())
         interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
     interpReturnOK = ScriptEpilogueOrGeneratorYield(cx, regs.fp(), interpReturnOK);
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -175,17 +175,17 @@ Invoke(JSContext *cx, const Value &thisv
 extern bool
 InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, uintN argc, Value *argv,
                      Value *rval);
 
 /*
  * InvokeConstructor* implement a function call from a constructor context
  * (e.g. 'new') handling the the creation of the new 'this' object.
  */
-extern JS_REQUIRES_STACK bool
+extern bool
 InvokeConstructorKernel(JSContext *cx, const CallArgs &args);
 
 /* See the InvokeArgsGuard overload of Invoke. */
 inline bool
 InvokeConstructor(JSContext *cx, InvokeArgsGuard &args)
 {
     args.setActive();
     bool ok = InvokeConstructorKernel(cx, ImplicitCast<CallArgs>(args));
@@ -196,17 +196,17 @@ InvokeConstructor(JSContext *cx, InvokeA
 /* See the fval overload of Invoke. */
 extern bool
 InvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, Value *rval);
 
 /*
  * InvokeConstructorWithGivenThis directly calls the constructor with the given
  * 'this'; the caller must choose the semantically correct 'this'.
  */
-extern JS_REQUIRES_STACK bool
+extern bool
 InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval,
                                uintN argc, Value *argv, Value *rval);
 
 /*
  * Executes a script with the given scopeChain/this. The 'type' indicates
  * whether this is eval code or global code. To support debugging, the
  * evalFrame parameter can point to an arbitrary frame in the context's call
  * stack to simulate executing an eval in that frame.
@@ -229,20 +229,20 @@ enum InterpMode
     JSINTERP_SKIP_TRAP = 4, /* as REJOIN, but skip trap at first opcode */
     JSINTERP_BAILOUT   = 5  /* interpreter is running from an Ion bailout */
 };
 
 /*
  * Execute the caller-initialized frame for a user-defined script or function
  * pointed to by cx->fp until completion or error.
  */
-extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
+extern JS_NEVER_INLINE bool
 Interpret(JSContext *cx, StackFrame *stopFp, InterpMode mode = JSINTERP_NORMAL);
 
-extern JS_REQUIRES_STACK bool
+extern bool
 RunScript(JSContext *cx, JSScript *script, StackFrame *fp);
 
 extern bool
 CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs);
 
 extern bool
 StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *equal);
 
@@ -319,24 +319,24 @@ class InterpreterFrames {
     FrameRegs *regs;
     const InterruptEnablerBase &enabler;
 };
 
 /*
  * Unwind block and scope chains to match the given depth. The function sets
  * fp->sp on return to stackDepth.
  */
-extern bool
-UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind);
+extern void
+UnwindScope(JSContext *cx, uint32_t stackDepth);
 
 extern bool
 OnUnknownMethod(JSContext *cx, js::Value *vp);
 
 extern bool
-IsActiveWithOrBlock(JSContext *cx, JSObject &obj, int stackDepth);
+IsActiveWithOrBlock(JSContext *cx, JSObject &obj, uint32_t stackDepth);
 
 /************************************************************************/
 
 /*
  * To really poison a set of values, using 'magic' or 'undefined' isn't good
  * enough since often these will just be ignored by buggy code (see bug 629974)
  * in debug builds and crash in release builds. Instead, we use a safe-for-crash
  * pointer.
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -861,17 +861,17 @@ js_ValueToIterator(JSContext *cx, uintN 
                 return false;
         }
     }
 
     return GetIterator(cx, obj, flags, vp);
 }
 
 #if JS_HAS_GENERATORS
-static JS_REQUIRES_STACK JSBool
+static JSBool
 CloseGenerator(JSContext *cx, JSObject *genobj);
 #endif
 
 JS_FRIEND_API(JSBool)
 js_CloseIterator(JSContext *cx, JSObject *obj)
 {
     cx->iterValue.setMagic(JS_NO_ITER_VALUE);
 
@@ -1265,25 +1265,25 @@ Class js::GeneratorClass = {
 /*
  * Called from the JSOP_GENERATOR case in the interpreter, with fp referring
  * to the frame by which the generator function was activated.  Create a new
  * JSGenerator object, which contains its own StackFrame that we populate
  * from *fp.  We know that upon return, the JSOP_GENERATOR opcode will return
  * from the activation in fp, so we can steal away fp->callobj and fp->argsobj
  * if they are non-null.
  */
-JS_REQUIRES_STACK JSObject *
+JSObject *
 js_NewGenerator(JSContext *cx)
 {
     FrameRegs &stackRegs = cx->regs();
     StackFrame *stackfp = stackRegs.fp();
     JS_ASSERT(stackfp->base() == cx->regs().sp);
     JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
 
-    GlobalObject *global = stackfp->scopeChain().getGlobal();
+    GlobalObject *global = &stackfp->scopeChain().global();
     JSObject *proto = global->getOrCreateGeneratorPrototype(cx);
     if (!proto)
         return NULL;
     JSObject *obj = NewObjectWithGivenProto(cx, &GeneratorClass, proto, global);
     if (!obj)
         return NULL;
 
     /* Load and compute stack slot counts. */
@@ -1335,17 +1335,17 @@ typedef enum JSGeneratorOp {
     JSGENOP_THROW,
     JSGENOP_CLOSE
 } JSGeneratorOp;
 
 /*
  * Start newborn or restart yielding generator and perform the requested
  * operation inside its frame.
  */
-static JS_REQUIRES_STACK JSBool
+static JSBool
 SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
                 JSGenerator *gen, const Value &arg)
 {
     if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) {
         js_ReportValueError(cx, JSMSG_NESTING_GENERATOR,
                             JSDVG_SEARCH_STACK, ObjectOrNullValue(obj),
                             JS_GetFunctionId(gen->floatingFrame()->fun()));
         return JS_FALSE;
@@ -1441,17 +1441,17 @@ SendToGenerator(JSContext *cx, JSGenerat
 
     /*
      * An error, silent termination by operation callback or an exception.
      * Propagate the condition to the caller.
      */
     return JS_FALSE;
 }
 
-static JS_REQUIRES_STACK JSBool
+static JSBool
 CloseGenerator(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isGenerator());
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* Generator prototype object. */
         return JS_TRUE;
@@ -1617,17 +1617,17 @@ InitStopIterationClass(JSContext *cx, Gl
     return proto;
 }
 
 JSObject *
 js_InitIteratorClasses(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
-    GlobalObject *global = obj->asGlobal();
+    GlobalObject *global = &obj->asGlobal();
 
     /*
      * Bail if Iterator has already been initialized.  We test for Iterator
      * rather than for StopIteration because if js_InitIteratorClasses recurs,
      * as happens when the StopIteration object is frozen, initializing the
      * Iterator class a second time will assert.
      */
     JSObject *iter;
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1007,22 +1007,22 @@ FinishRuntimeNumberState(JSRuntime *rt)
 JSObject *
 js_InitNumberClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     /* XXX must do at least once per new thread, so do it per JSContext... */
     FIX_FPU();
 
-    GlobalObject *global = obj->asGlobal();
+    GlobalObject *global = &obj->asGlobal();
 
     JSObject *numberProto = global->createBlankPrototype(cx, &NumberClass);
     if (!numberProto)
         return NULL;
-    numberProto->asNumber()->setPrimitiveValue(0);
+    numberProto->asNumber().setPrimitiveValue(0);
 
     JSFunction *ctor = global->createConstructor(cx, Number, &NumberClass,
                                                  CLASS_ATOM(cx, Number), 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, numberProto))
         return NULL;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -943,17 +943,17 @@ obj_valueOf(JSContext *cx, uintN argc, V
     return true;
 }
 
 /* We should be able to assert this for *any* fp->scopeChain(). */
 static void
 AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
 {
 #ifdef DEBUG
-    for (JSObject *o = &scopeobj; o; o = o->scopeChain()) {
+    for (JSObject *o = &scopeobj; o; o = o->enclosingScope()) {
         if (JSObjectOp op = o->getClass()->ext.innerObject)
             JS_ASSERT(op(cx, o) == o);
     }
 #endif
 }
 
 #ifndef EVAL_CACHE_CHAIN_LIMIT
 # define EVAL_CACHE_CHAIN_LIMIT 4
@@ -1128,17 +1128,17 @@ enum EvalType { DIRECT_EVAL = EXECUTE_DI
  */
 static bool
 EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *caller,
            JSObject &scopeobj)
 {
     JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
     AssertInnerizedScopeChain(cx, scopeobj);
 
-    if (!scopeobj.getGlobal()->isRuntimeCodeGenEnabled(cx)) {
+    if (!scopeobj.global().isRuntimeCodeGenEnabled(cx)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_EVAL);
         return false;
     }
 
     /* ES5 15.1.2.1 step 1. */
     if (args.length() < 1) {
         args.rval().setUndefined();
         return true;
@@ -1170,17 +1170,17 @@ EvalKernel(JSContext *cx, const CallArgs
             return false;
         thisv = caller->thisValue();
 
 #ifdef DEBUG
         jsbytecode *callerPC = caller->pcQuadratic(cx);
         JS_ASSERT(callerPC && JSOp(*callerPC) == JSOP_EVAL);
 #endif
     } else {
-        JS_ASSERT(args.callee().getGlobal() == &scopeobj);
+        JS_ASSERT(args.callee().global() == scopeobj);
         staticLevel = 0;
 
         /* Use the global as 'this', modulo outerization. */
         JSObject *thisobj = scopeobj.thisObject(cx);
         if (!thisobj)
             return false;
         thisv = ObjectValue(*thisobj);
     }
@@ -1300,17 +1300,17 @@ namespace js {
  *
  * NB: This method handles only indirect eval.
  */
 JSBool
 eval(JSContext *cx, uintN argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return WarnOnTooManyArgs(cx, args) &&
-           EvalKernel(cx, args, INDIRECT_EVAL, NULL, *args.callee().getGlobal());
+           EvalKernel(cx, args, INDIRECT_EVAL, NULL, args.callee().global());
 }
 
 bool
 DirectEval(JSContext *cx, const CallArgs &args)
 {
     /* Direct eval can assume it was called from an interpreted frame. */
     StackFrame *caller = cx->fp();
     JS_ASSERT(caller->isScriptFrame());
@@ -1327,17 +1327,17 @@ DirectEval(JSContext *cx, const CallArgs
         return false;
 
     return EvalKernel(cx, args, DIRECT_EVAL, caller, *scopeChain);
 }
 
 bool
 IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v)
 {
-    return scopeChain->getGlobal()->getOriginalEval() == v;
+    return scopeChain->global().getOriginalEval() == v;
 }
 
 bool
 IsAnyBuiltinEval(JSFunction *fun)
 {
     return fun->maybeNative() == eval;
 }
 
@@ -2607,17 +2607,17 @@ obj_create(JSContext *cx, uintN argc, Va
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
         return false;
     }
 
     /*
      * Use the callee's global as the parent of the new object to avoid dynamic
      * scoping (i.e., using the caller's global).
      */
-    JSObject *obj = NewObjectWithGivenProto(cx, &ObjectClass, proto, vp->toObject().getGlobal());
+    JSObject *obj = NewObjectWithGivenProto(cx, &ObjectClass, proto, &vp->toObject().global());
     if (!obj)
         return JS_FALSE;
     vp->setObject(*obj); /* Root and prepare for eventual return. */
 
     /* Don't track types or array-ness for objects created here. */
     MarkTypeObjectUnknownProperties(cx, obj->type());
 
     /* 15.2.3.5 step 4. */
@@ -2998,17 +2998,17 @@ js::NewObjectWithClassProto(JSContext *c
      * will flush the new object cache).
      */
     JSProtoKey protoKey = GetClassProtoKey(clasp);
 
     NewObjectCache &cache = cx->compartment->newObjectCache;
 
     NewObjectCache::EntryIndex entry = -1;
     if (parent->isGlobal() && protoKey != JSProto_Null) {
-        if (cache.lookupGlobal(clasp, parent->asGlobal(), kind, &entry))
+        if (cache.lookupGlobal(clasp, &parent->asGlobal(), kind, &entry))
             return cache.newObjectFromHit(cx, entry);
     }
 
     RootObject parentRoot(cx, &parent);
 
     if (!FindProto(cx, clasp, parentRoot, &proto))
         return NULL;
 
@@ -3016,17 +3016,17 @@ js::NewObjectWithClassProto(JSContext *c
     if (!type)
         return NULL;
 
     JSObject *obj = NewObject(cx, clasp, type, parent, kind);
     if (!obj)
         return NULL;
 
     if (entry != -1 && !obj->hasDynamicSlots())
-        cache.fillGlobal(entry, clasp, parent->asGlobal(), kind, obj);
+        cache.fillGlobal(entry, clasp, &parent->asGlobal(), kind, obj);
 
     return obj;
 }
 
 JSObject *
 js::NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind)
 {
     JS_ASSERT(type->proto->hasNewType(type));
@@ -3180,17 +3180,17 @@ js_CreateThisForFunction(JSContext *cx, 
     return obj;
 }
 
 /*
  * Given pc pointing after a property accessing bytecode, return true if the
  * access is "object-detecting" in the sense used by web scripts, e.g., when
  * checking whether document.all is defined.
  */
-JS_REQUIRES_STACK JSBool
+JSBool
 Detecting(JSContext *cx, jsbytecode *pc)
 {
     jsbytecode *endpc;
     JSOp op;
     JSAtom *atom;
 
     JSScript *script = cx->stack.currentScript();
     endpc = script->code + script->length;
@@ -3271,467 +3271,16 @@ js_InferFlags(JSContext *cx, uintN defau
         if (pc < script->code + script->length && Detecting(cx, pc))
             flags |= JSRESOLVE_DETECTING;
     }
     if (format & JOF_DECLARING)
         flags |= JSRESOLVE_DECLARING;
     return flags;
 }
 
-/*
- * ObjectOps and Class for with-statement stack objects.
- */
-static JSBool
-with_LookupGeneric(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, JSProperty **propp)
-{
-    /* Fixes bug 463997 */
-    uintN flags = cx->resolveFlags;
-    if (flags == RESOLVE_INFER)
-        flags = js_InferFlags(cx, flags);
-    flags |= JSRESOLVE_WITH;
-    JSAutoResolveFlags rf(cx, flags);
-    return obj->getProto()->lookupGeneric(cx, id, objp, propp);
-}
-
-static JSBool
-with_LookupProperty(JSContext *cx, JSObject *obj, PropertyName *name, JSObject **objp, JSProperty **propp)
-{
-    return with_LookupGeneric(cx, obj, ATOM_TO_JSID(name), objp, propp);
-}
-
-static JSBool
-with_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, JSObject **objp,
-                   JSProperty **propp)
-{
-    jsid id;
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return with_LookupGeneric(cx, obj, id, objp, propp);
-}
-
-static JSBool
-with_LookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp, JSProperty **propp)
-{
-    return with_LookupGeneric(cx, obj, SPECIALID_TO_JSID(sid), objp, propp);
-}
-
-static JSBool
-with_GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
-{
-    return obj->getProto()->getGeneric(cx, id, vp);
-}
-
-static JSBool
-with_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name, Value *vp)
-{
-    return with_GetGeneric(cx, obj, receiver, ATOM_TO_JSID(name), vp);
-}
-
-static JSBool
-with_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
-{
-    jsid id;
-    if (!IndexToId(cx, index, &id))
-        return false;
-    return with_GetGeneric(cx, obj, receiver, id, vp);
-}
-
-static JSBool
-with_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
-{
-    return with_GetGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
-}
-
-static JSBool
-with_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
-{
-    return obj->getProto()->setGeneric(cx, id, vp, strict);
-}
-
-static JSBool
-with_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
-{
-    return obj->getProto()->setProperty(cx, name, vp, strict);
-}
-
-static JSBool
-with_SetElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
-{
-    return obj->getProto()->setElement(cx, index, vp, strict);
-}
-
-static JSBool
-with_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
-{
-    return obj->getProto()->setSpecial(cx, sid, vp, strict);
-}
-
-static JSBool
-with_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
-{
-    return obj->getProto()->getGenericAttributes(cx, id, attrsp);
-}
-
-static JSBool
-with_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
-{
-    return obj->getProto()->getPropertyAttributes(cx, name, attrsp);
-}
-
-static JSBool
-with_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, uintN *attrsp)
-{
-    return obj->getProto()->getElementAttributes(cx, index, attrsp);
-}
-
-static JSBool
-with_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
-{
-    return obj->getProto()->getSpecialAttributes(cx, sid, attrsp);
-}
-
-static JSBool
-with_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
-{
-    return obj->getProto()->setGenericAttributes(cx, id, attrsp);
-}
-
-static JSBool
-with_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, uintN *attrsp)
-{
-    return obj->getProto()->setPropertyAttributes(cx, name, attrsp);
-}
-
-static JSBool
-with_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, uintN *attrsp)
-{
-    return obj->getProto()->setElementAttributes(cx, index, attrsp);
-}
-
-static JSBool
-with_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, uintN *attrsp)
-{
-    return obj->getProto()->setSpecialAttributes(cx, sid, attrsp);
-}
-
-static JSBool
-with_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
-{
-    return obj->getProto()->deleteGeneric(cx, id, rval, strict);
-}
-
-static JSBool
-with_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
-{
-    return obj->getProto()->deleteProperty(cx, name, rval, strict);
-}
-
-static JSBool
-with_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
-{
-    return obj->getProto()->deleteElement(cx, index, rval, strict);
-}
-
-static JSBool
-with_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
-{
-    return obj->getProto()->deleteSpecial(cx, sid, rval, strict);
-}
-
-static JSBool
-with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
-               Value *statep, jsid *idp)
-{
-    return obj->getProto()->enumerate(cx, enum_op, statep, idp);
-}
-
-static JSType
-with_TypeOf(JSContext *cx, JSObject *obj)
-{
-    return JSTYPE_OBJECT;
-}
-
-static JSObject *
-with_ThisObject(JSContext *cx, JSObject *obj)
-{
-    return obj->getWithThis();
-}
-
-Class js::WithClass = {
-    "With",
-    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(3) | JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_PropertyStub,         /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    NULL,                    /* finalize */
-    NULL,                    /* reserved    */
-    NULL,                    /* checkAccess */
-    NULL,                    /* call        */
-    NULL,                    /* construct   */
-    NULL,                    /* xdrObject   */
-    NULL,                    /* hasInstance */
-    NULL,                    /* trace       */
-    JS_NULL_CLASS_EXT,
-    {
-        with_LookupGeneric,
-        with_LookupProperty,
-        with_LookupElement,
-        with_LookupSpecial,
-        NULL,             /* defineGeneric */
-        NULL,             /* defineProperty */
-        NULL,             /* defineElement */
-        NULL,             /* defineSpecial */
-        with_GetGeneric,
-        with_GetProperty,
-        with_GetElement,
-        NULL,             /* getElementIfPresent */
-        with_GetSpecial,
-        with_SetGeneric,
-        with_SetProperty,
-        with_SetElement,
-        with_SetSpecial,
-        with_GetGenericAttributes,
-        with_GetPropertyAttributes,
-        with_GetElementAttributes,
-        with_GetSpecialAttributes,
-        with_SetGenericAttributes,
-        with_SetPropertyAttributes,
-        with_SetElementAttributes,
-        with_SetSpecialAttributes,
-        with_DeleteGeneric,
-        with_DeleteProperty,
-        with_DeleteElement,
-        with_DeleteSpecial,
-        with_Enumerate,
-        with_TypeOf,
-        NULL,             /* fix   */
-        with_ThisObject,
-        NULL,             /* clear */
-    }
-};
-
-static const gc::AllocKind WITH_FINALIZE_KIND = gc::FINALIZE_OBJECT4;
-
-JS_REQUIRES_STACK JSObject *
-js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
-{
-    JSObject *obj;
-
-    RootedVarTypeObject type(cx);
-    type = proto->getNewType(cx);
-    if (!type)
-        return NULL;
-
-    StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
-
-    RootedVarShape emptyWithShape(cx);
-    emptyWithShape = EmptyShape::getInitialShape(cx, &WithClass, proto,
-                                                 parent->getGlobal(),
-                                                 WITH_FINALIZE_KIND);
-    if (!emptyWithShape)
-        return NULL;
-
-    obj = JSObject::create(cx, WITH_FINALIZE_KIND, emptyWithShape, type, NULL);
-    if (!obj)
-        return NULL;
-    OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
-
-    if (!obj->setInternalScopeChain(cx, parent))
-        return NULL;
-    obj->setPrivate(priv);
-
-    JSObject *thisp = proto->thisObject(cx);
-    if (!thisp)
-        return NULL;
-
-    assertSameCompartment(cx, obj, thisp);
-
-    obj->setWithThis(thisp);
-    return obj;
-}
-
-static const uint32_t BLOCK_RESERVED_SLOTS = 2;
-static const gc::AllocKind BLOCK_FINALIZE_KIND = gc::FINALIZE_OBJECT4;
-
-JSObject *
-js_NewBlockObject(JSContext *cx)
-{
-    RootedVarTypeObject type(cx);
-    type = cx->compartment->getEmptyType(cx);
-    if (!type)
-        return NULL;
-
-    RootedVarShape emptyBlockShape(cx);
-    emptyBlockShape = EmptyShape::getInitialShape(cx, &BlockClass, NULL, NULL,
-                                                  BLOCK_FINALIZE_KIND);
-    if (!emptyBlockShape)
-        return NULL;
-
-    return JSObject::create(cx, FINALIZE_OBJECT4, emptyBlockShape, type, NULL);
-}
-
-JSObject *
-js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
-{
-    JS_ASSERT(proto->isStaticBlock());
-
-    RootedVarTypeObject type(cx);
-    type = proto->getNewType(cx);
-    if (!type)
-        return NULL;
-
-    HeapValue *slots;
-    if (!PreallocateObjectDynamicSlots(cx, proto->lastProperty(), &slots))
-        return NULL;
-
-    RootedVarShape shape(cx);
-    shape = proto->lastProperty();
-
-    JSObject *clone = JSObject::create(cx, BLOCK_FINALIZE_KIND,
-                                       shape, type, slots);
-    if (!clone)
-        return NULL;
-
-    /* Set the parent if necessary, as for call objects. */
-    JSObject *global = fp->scopeChain().getGlobal();
-    if (global != clone->getParent()) {
-        JS_ASSERT(clone->getParent() == NULL);
-        if (!clone->setParent(cx, global))
-            return NULL;
-    }
-
-    JS_ASSERT(!clone->inDictionaryMode());
-    JS_ASSERT(clone->isClonedBlock());
-    JS_ASSERT(clone->slotSpan() >= OBJ_BLOCK_COUNT(cx, proto) + BLOCK_RESERVED_SLOTS);
-
-    clone->setPrivate(js_FloatingFrameIfGenerator(cx, fp));
-    clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH));
-
-    if (clone->lastProperty()->extensibleParents() && !clone->generateOwnShape(cx))
-        return NULL;
-
-    return clone;
-}
-
-JS_REQUIRES_STACK JSBool
-js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
-{
-    StackFrame *const fp = cx->fp();
-    JSObject *obj = &fp->scopeChain();
-    JS_ASSERT(obj->isClonedBlock());
-    JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
-
-    /* Block objects should have all reserved slots allocated early. */
-    uintN count = OBJ_BLOCK_COUNT(cx, obj);
-    JS_ASSERT(obj->slotSpan() >= JSSLOT_BLOCK_DEPTH + 1 + count);
-
-    /* The block and its locals must be on the current stack for GC safety. */
-    uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
-    JS_ASSERT(depth <= size_t(cx->regs().sp - fp->base()));
-    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);
-    }
-
-    /* We must clear the private slot even with errors. */
-    obj->setPrivate(NULL);
-    fp->setScopeChainNoCallObj(*obj->internalScopeChain());
-    return normalUnwind;
-}
-
-static JSBool
-block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
-{
-    /*
-     * Block objects are never exposed to script, and the engine handles them
-     * with care. So unlike other getters, this one can assert (rather than
-     * check) certain invariants about obj.
-     */
-    JS_ASSERT(obj->isClonedBlock());
-    uintN index = (uintN) JSID_TO_INT(id);
-    JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj));
-
-    StackFrame *fp = (StackFrame *) obj->getPrivate();
-    if (fp) {
-        fp = js_LiveFrameIfGenerator(fp);
-        index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
-        JS_ASSERT(index < fp->numSlots());
-        *vp = fp->slots()[index];
-        return true;
-    }
-
-    /* Values are in slots immediately following the class-reserved ones. */
-    JS_ASSERT(obj->getSlot(JSSLOT_FREE(&BlockClass) + index) == *vp);
-    return true;
-}
-
-static JSBool
-block_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
-{
-    JS_ASSERT(obj->isClonedBlock());
-    uintN index = (uintN) JSID_TO_INT(id);
-    JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj));
-
-    StackFrame *fp = (StackFrame *) obj->getPrivate();
-    if (fp) {
-        fp = js_LiveFrameIfGenerator(fp);
-        index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
-        JS_ASSERT(index < fp->numSlots());
-        fp->slots()[index] = *vp;
-        return true;
-    }
-
-    /*
-     * The value in *vp will be written back to the slot in obj that was
-     * allocated when this let binding was defined.
-     */
-    return true;
-}
-
-const Shape *
-JSObject::defineBlockVariable(JSContext *cx, jsid id, intN index, bool *redeclared)
-{
-    JS_ASSERT(isStaticBlock());
-
-    *redeclared = false;
-
-    RootedVarObject self(cx, this);
-
-    /* Inline JSObject::addProperty in order to trap the redefinition case. */
-    Shape **spp;
-    Shape *shape = Shape::search(cx, lastProperty(), id, &spp, true);
-    if (shape) {
-        *redeclared = true;
-        return NULL;
-    }
-
-    /*
-     * Don't convert this object to dictionary mode so that we can clone the
-     * block's shape later.
-     */
-    uint32_t slot = JSSLOT_FREE(&BlockClass) + index;
-    shape = self->addPropertyInternal(cx, id, block_getProperty, block_setProperty,
-                                      slot, JSPROP_ENUMERATE | JSPROP_PERMANENT,
-                                      Shape::HAS_SHORTID, index, spp,
-                                      /* allowDictionary = */ false);
-    if (!shape)
-        return NULL;
-    return shape;
-}
-
 JSBool
 JSObject::nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict)
 {
     if (JS_UNLIKELY(watched())) {
         id = js_CheckForStringIndex(id);
         WatchpointMap *wpmap = cx->compartment->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, this, id, vp))
             return false;
@@ -4123,163 +3672,16 @@ JSObject::swap(JSContext *cx, JSObject *
     }
 
     TradeGuts(cx, this, otherClone, reservedThis);
     TradeGuts(cx, other, thisClone, reservedOther);
 
     return true;
 }
 
-#if JS_HAS_XDR
-
-#define NO_PARENT_INDEX UINT32_MAX
-
-uint32_t
-FindObjectIndex(JSObjectArray *array, JSObject *obj)
-{
-    size_t i;
-
-    if (array) {
-        i = array->length;
-        do {
-
-            if (array->vector[--i] == obj)
-                return i;
-        } while (i != 0);
-    }
-
-    return NO_PARENT_INDEX;
-}
-
-JSBool
-js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
-{
-    JSContext *cx;
-    uint32_t parentId;
-    JSObject *obj, *parent;
-    uintN depth, count;
-    uint32_t depthAndCount;
-    const Shape *shape;
-
-    cx = xdr->cx;
-#ifdef __GNUC__
-    obj = NULL;         /* quell GCC overwarning */
-#endif
-
-    if (xdr->mode == JSXDR_ENCODE) {
-        obj = *objp;
-        parent = obj->staticBlockScopeChain();
-        parentId = JSScript::isValidOffset(xdr->script->objectsOffset)
-                   ? FindObjectIndex(xdr->script->objects(), parent)
-                   : NO_PARENT_INDEX;
-        depth = uint16_t(OBJ_BLOCK_DEPTH(cx, obj));
-        count = uint16_t(OBJ_BLOCK_COUNT(cx, obj));
-        depthAndCount = uint32_t(depth << 16) | count;
-    }
-#ifdef __GNUC__ /* suppress bogus gcc warnings */
-    else count = 0;
-#endif
-
-    /* First, XDR the parent atomid. */
-    if (!JS_XDRUint32(xdr, &parentId))
-        return JS_FALSE;
-
-    if (xdr->mode == JSXDR_DECODE) {
-        obj = js_NewBlockObject(cx);
-        if (!obj)
-            return JS_FALSE;
-        *objp = obj;
-
-        /*
-         * If there's a parent id, then get the parent out of our script's
-         * object array. We know that we XDR block object in outer-to-inner
-         * order, which means that getting the parent now will work.
-         */
-        if (parentId == NO_PARENT_INDEX)
-            parent = NULL;
-        else
-            parent = xdr->script->getObject(parentId);
-        obj->setStaticBlockScopeChain(parent);
-    }
-
-    if (!JS_XDRUint32(xdr, &depthAndCount))
-        return false;
-
-    if (xdr->mode == JSXDR_DECODE) {
-        depth = uint16_t(depthAndCount >> 16);
-        count = uint16_t(depthAndCount);
-        obj->setSlot(JSSLOT_BLOCK_DEPTH, Value(Int32Value(depth)));
-
-        /*
-         * XDR the block object's properties. We know that there are 'count'
-         * properties to XDR, stored as id/shortid pairs.
-         */
-        for (uintN i = 0; i < count; i++) {
-            JSAtom *atom;
-
-            /* XDR the real id. */
-            if (!js_XDRAtom(xdr, &atom))
-                return false;
-
-            bool redeclared;
-            if (!obj->defineBlockVariable(cx, ATOM_TO_JSID(atom), i, &redeclared)) {
-                JS_ASSERT(!redeclared);
-                return false;
-            }
-        }
-    } else {
-        AutoShapeVector shapes(cx);
-        shapes.growBy(count);
-
-        for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
-            shape = &r.front();
-            shapes[shape->shortid()] = shape;
-        }
-
-        /*
-         * XDR the block object's properties. We know that there are 'count'
-         * properties to XDR, stored as id/shortid pairs.
-         */
-        for (uintN i = 0; i < count; i++) {
-            shape = shapes[i];
-            JS_ASSERT(shape->getter() == block_getProperty);
-
-            jsid propid = shape->propid();
-            JS_ASSERT(JSID_IS_ATOM(propid));
-            JSAtom *atom = JSID_TO_ATOM(propid);
-
-#ifdef DEBUG
-            uint16_t shortid = uint16_t(shape->shortid());
-            JS_ASSERT(shortid == i);
-#endif
-
-            /* XDR the real id. */
-            if (!js_XDRAtom(xdr, &atom))
-                return false;
-        }
-    }
-    return true;
-}
-
-#endif
-
-Class js::BlockClass = {
-    "Block",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(BLOCK_RESERVED_SLOTS) |
-    JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_PropertyStub,         /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
-};
-
 static bool
 DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
                    const Value &v, uint32_t attrs, bool &named)
 {
     jsid id = ATOM_TO_JSID(atom);
 
     if (key != JSProto_Null) {
         /*
@@ -5025,17 +4427,17 @@ SetProto(JSContext *cx, JSObject *obj, J
 }
 
 JSBool
 js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
                   JSObject **objp)
 {
     RootObject objRoot(cx, &obj);
 
-    obj = obj->getGlobal();
+    obj = &obj->global();
     if (!obj->isGlobal()) {
         *objp = NULL;
         return true;
     }
 
     Value v = obj->getReservedSlot(key);
     if (v.isObject()) {
         *objp = &v.toObject();
@@ -5069,17 +4471,17 @@ js_FindClassObject(JSContext *cx, JSObje
     JSObject *cobj, *pobj;
     jsid id;
     JSProperty *prop;
     const Shape *shape;
 
     RootedVarObject obj(cx);
 
     if (start) {
-        obj = start->getGlobal();
+        obj = &start->global();
         OBJ_TO_INNER_OBJECT(cx, *obj.address());
     } else {
         obj = GetGlobalForScopeChain(cx);
     }
     if (!obj)
         return false;
 
     if (protoKey != JSProto_Null) {
@@ -5281,17 +4683,17 @@ js_PurgeScopeChainHelper(JSContext *cx, 
 
     /*
      * We must purge the scope chain only for Call objects as they are the only
      * kind of cacheable non-global object that can gain properties after outer
      * properties with the same names have been cached or traced. Call objects
      * may gain such properties via eval introducing new vars; see bug 490364.
      */
     if (obj->isCall()) {
-        while ((obj = obj->scopeChain()) != NULL) {
+        while ((obj = obj->enclosingScope()) != NULL) {
             if (!PurgeProtoChain(cx, obj, id))
                 return false;
         }
     }
 
     return true;
 }
 
@@ -5719,23 +5121,23 @@ js_FindPropertyHelper(JSContext *cx, jsi
          * Skip along the scope chain to the enclosing global object. This is
          * used for GNAME opcodes where the bytecode emitter has determined a
          * name access must be on the global. It also insulates us from bugs
          * in the emitter: type inference will assume that GNAME opcodes are
          * accessing the global object, and the inferred behavior should match
          * the actual behavior even if the id could be found on the scope chain
          * before the global object.
          */
-        scopeChain = scopeChain->getGlobal();
+        scopeChain = &scopeChain->global();
     }
 
     /* Scan entries on the scope chain that we can cache across. */
     entry = JS_NO_PROP_CACHE_FILL;
     obj = scopeChain;
-    parent = obj->scopeChain();
+    parent = obj->enclosingScope();
     for (scopeIndex = 0;
          parent
          ? IsCacheableNonGlobalScope(obj)
          : !obj->getOps()->lookupProperty;
          ++scopeIndex) {
         if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
             return NULL;
 
@@ -5771,32 +5173,32 @@ js_FindPropertyHelper(JSContext *cx, jsi
             goto out;
         }
 
         if (!parent) {
             pobj = NULL;
             goto out;
         }
         obj = parent;
-        parent = obj->scopeChain();
+        parent = obj->enclosingScope();
     }
 
     for (;;) {
         if (!obj->lookupGeneric(cx, id, &pobj, &prop))
             return NULL;
         if (prop) {
             PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
             goto out;
         }
 
         /*
          * We conservatively assume that a resolve hook could mutate the scope
          * chain during JSObject::lookupGeneric. So we read parent here again.
          */
-        parent = obj->scopeChain();
+        parent = obj->enclosingScope();
         if (!parent) {
             pobj = NULL;
             break;
         }
         obj = parent;
     }
 
   out:
@@ -5820,17 +5222,17 @@ js_FindProperty(JSContext *cx, jsid id, 
 
 JSObject *
 js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
 {
     /*
      * This function should not be called for a global object or from the
      * trace and should have a valid cache entry for native scopeChain.
      */
-    JS_ASSERT(scopeChain->scopeChain() != NULL);
+    JS_ASSERT(scopeChain->enclosingScope() != NULL);
 
     JSObject *obj = scopeChain;
 
     /*
      * Loop over cacheable objects on the scope chain until we find a
      * property. We also stop when we reach the global object skipping any
      * farther checks or lookups. For details see the JSOP_BINDNAME case of
      * js_Interpret.
@@ -5845,24 +5247,24 @@ js_FindIdentifierBase(JSContext *cx, JSO
         JSProperty *prop;
         if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
             return NULL;
         if (prop) {
             if (!pobj->isNative()) {
                 JS_ASSERT(obj->isGlobal());
                 return obj;
             }
-            JS_ASSERT_IF(obj->isInternalScope(), pobj->getClass() == obj->getClass());
+            JS_ASSERT_IF(obj->isScope(), pobj->getClass() == obj->getClass());
             DebugOnly<PropertyCacheEntry*> entry =
                 JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop);
             JS_ASSERT(entry);
             return obj;
         }
 
-        JSObject *parent = obj->scopeChain();
+        JSObject *parent = obj->enclosingScope();
         if (!parent)
             return obj;
         obj = parent;
     }
 
     /* Loop until we find a property or reach the global object. */
     do {
         JSObject *pobj;
@@ -5872,17 +5274,17 @@ js_FindIdentifierBase(JSContext *cx, JSO
         if (prop)
             break;
 
         /*
          * We conservatively assume that a resolve hook could mutate the scope
          * chain during JSObject::lookupGeneric. So we must check if parent is
          * not null here even if it wasn't before the lookup.
          */
-        JSObject *parent = obj->scopeChain();
+        JSObject *parent = obj->enclosingScope();
         if (!parent)
             break;
         obj = parent;
     } while (!obj->isGlobal());
     return obj;
 }
 
 static JS_ALWAYS_INLINE JSBool
@@ -6858,17 +6260,17 @@ js_GetClassPrototype(JSContext *cx, JSOb
                      JSObject **protop, Class *clasp)
 {
     JS_ASSERT(JSProto_Null <= protoKey);
     JS_ASSERT(protoKey < JSProto_LIMIT);
 
     if (protoKey != JSProto_Null) {
         GlobalObject *global;
         if (scopeobj) {
-            global = scopeobj->getGlobal();
+            global = &scopeobj->global();
         } else {
             global = GetCurrentGlobal(cx);
             if (!global) {
                 *protop = NULL;
                 return true;
             }
         }
         const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -338,23 +338,30 @@ extern Class SlowArrayClass;
 extern Class StopIterationClass;
 extern Class StringClass;
 extern Class StrictArgumentsObjectClass;
 extern Class WeakMapClass;
 extern Class WithClass;
 extern Class XMLFilterClass;
 
 class ArgumentsObject;
+class BlockObject;
 class BooleanObject;
+class ClonedBlockObject;
+class DeclEnvObject;
 class GlobalObject;
+class NestedScopeObject;
 class NormalArgumentsObject;
 class NumberObject;
+class ScopeObject;
+class StaticBlockObject;
 class StrictArgumentsObject;
 class StringObject;
 class RegExpObject;
+class WithObject;
 
 /*
  * Header structure for object element arrays. This structure is immediately
  * followed by an array of elements, with the elements member in an object
  * pointing to the beginning of that array (the end of this structure).
  * See below for usage of this structure.
  */
 class ObjectElements
@@ -770,20 +777,18 @@ struct JSObject : js::gc::Cell
 
     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 const 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::HeapValue &getFixedSlotRef(uintN slot) {
         JS_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
@@ -868,60 +873,44 @@ struct JSObject : js::gc::Cell
      *
      * All script-accessible objects with a NULL parent are global objects,
      * and all global objects have a NULL parent. Some builtin objects which
      * are not script-accessible also have a NULL parent, such as parser
      * created functions for non-compileAndGo scripts.
      *
      * Except for the non-script-accessible builtins, the global with which an
      * object is associated can be reached by following parent links to that
-     * global (see getGlobal()).
+     * global (see global()).
      *
      * The scope chain of an object is the link in the search path when a
      * script does a name lookup on a scope object. For JS internal scope
-     * objects --- Call, Block, DeclEnv and With --- the chain is stored in
+     * objects --- Call, DeclEnv and block --- the chain is stored in
      * the first fixed slot of the object, and the object's parent is the
      * associated global. For other scope objects, the chain is stored in the
      * object's parent.
      *
      * In compileAndGo code, scope chains can contain only internal scope
      * objects with a global object at the root as the scope of the outermost
      * non-function script. In non-compileAndGo code, the scope of the
      * outermost non-function script might not be a global object, and can have
      * a mix of other objects above it before the global object is reached.
      */
 
     /* Access the parent link of an object. */
     inline JSObject *getParent() const;
     bool setParent(JSContext *cx, JSObject *newParent);
 
-    /* Get the scope chain of an arbitrary scope object. */
-    inline JSObject *scopeChain() const;
-
-    inline bool isGlobal() const;
-    inline js::GlobalObject *asGlobal();
-    inline js::GlobalObject *getGlobal() const;
-
-    inline bool isInternalScope() const;
+    /*
+     * Get the enclosing scope of an object. When called on non-scope object,
+     * this will just be the global (the name "enclosing scope" still applies
+     * in this situation because non-scope objects can be on the scope chain).
+     */
+    inline JSObject *enclosingScope();
 
-    /* Access the scope chain of an internal scope object. */
-    inline JSObject *internalScopeChain() const;
-    inline bool setInternalScopeChain(JSContext *cx, JSObject *obj);
-    static inline size_t offsetOfInternalScopeChain();
-
-    /*
-     * Access the scope chain of a static block object. These do not appear
-     * on scope chains but mirror their structure, and can have a NULL
-     * scope chain.
-     */
-    inline JSObject *staticBlockScopeChain() const;
-    inline void setStaticBlockScopeChain(JSObject *obj);
-
-    /* Common fixed slot for the scope chain of internal scope objects. */
-    static const uint32_t SCOPE_CHAIN_SLOT = 0;
+    inline js::GlobalObject &global() const;
 
     /* Private data accessors. */
 
     inline bool hasPrivate() const;
     inline void *getPrivate() const;
     inline void setPrivate(void *data);
 
     /* Access private data for an object with a known number of fixed slots. */
@@ -976,22 +965,16 @@ struct JSObject : js::gc::Cell
     inline const js::Value &getPrimitiveThis() const;
     inline void setPrimitiveThis(const js::Value &pthis);
 
     static size_t getPrimitiveThisOffset() {
         /* All primitive objects have their value in a fixed slot. */
         return getFixedSlotOffset(JSSLOT_PRIMITIVE_THIS);
     }
 
-  public:
-    inline js::BooleanObject *asBoolean();
-    inline js::NumberObject *asNumber();
-    inline js::StringObject *asString();
-    inline js::RegExpObject *asRegExp();
-
     /* Accessors for elements. */
 
     js::ObjectElements *getElementsHeader() const {
         return js::ObjectElements::fromElements(elements);
     }
 
     inline bool ensureElements(JSContext *cx, uintN cap);
     bool growElements(JSContext *cx, uintN cap);
@@ -1075,24 +1058,16 @@ struct JSObject : js::gc::Cell
     bool arrayGetOwnDataElement(JSContext *cx, size_t i, js::Value *vp);
 
   public:
     bool allocateArrayBufferSlots(JSContext *cx, uint32_t size);
     inline uint32_t arrayBufferByteLength();
     inline uint8_t * arrayBufferDataOffset();
 
   public:
-    inline js::ArgumentsObject *asArguments();
-    inline js::NormalArgumentsObject *asNormalArguments();
-    inline js::StrictArgumentsObject *asStrictArguments();
-
-  public:
-    inline js::CallObject &asCall();
-
-  public:
     /*
      * Date-specific getters and setters.
      */
 
     static const uint32_t JSSLOT_DATE_UTC_TIME = 0;
 
     /*
      * Cached slots holding local properties of the date.
@@ -1174,22 +1149,16 @@ struct JSObject : js::gc::Cell
     inline void setQNameLocalName(JSAtom *name);
 
     /*
      * Proxy-specific getters and setters.
      */
     inline js::Wrapper *getWrapperHandler() const;
 
     /*
-     * With object-specific getters and setters.
-     */
-    inline JSObject *getWithThis() const;
-    inline void setWithThis(JSObject *thisp);
-
-    /*
      * Back to generic stuff.
      */
     inline bool isCallable();
 
     inline void finish(JSContext *cx);
     JS_ALWAYS_INLINE void finalize(JSContext *cx, bool background);
 
     inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0);
@@ -1215,29 +1184,31 @@ struct JSObject : js::gc::Cell
      * callable a TypeError will be thrown. On success the value returned by
      * the call is stored in *vp.
      */
     bool callMethod(JSContext *cx, jsid id, uintN argc, js::Value *argv, js::Value *vp);
 
   private:
     js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::StackShape &child);
 
+  protected:
     /*
      * Internal helper that adds a shape not yet mapped by this object.
      *
      * Notes:
      * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
      * 2. !isExtensible() checking must be done by callers.
      */
     js::Shape *addPropertyInternal(JSContext *cx, jsid id,
                                    JSPropertyOp getter, JSStrictPropertyOp setter,
                                    uint32_t slot, uintN attrs,
                                    uintN flags, intN shortid, js::Shape **spp,
                                    bool allowDictionary);
 
+  private:
     bool toDictionaryMode(JSContext *cx);
 
     struct TradeGutsReserved;
     static bool ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
                                     TradeGutsReserved &reserved);
 
     static void TradeGuts(JSContext *cx, JSObject *a, JSObject *b,
                           TradeGutsReserved &reserved);
@@ -1340,63 +1311,116 @@ struct JSObject : js::gc::Cell
     inline JSObject *thisObject(JSContext *cx);
 
     static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
 
     inline JSObject *getThrowTypeError() const;
 
     bool swap(JSContext *cx, JSObject *other);
 
-    const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index, bool *redeclared);
-
-    inline bool isArguments() const;
-    inline bool isArrayBuffer() const;
-    inline bool isNormalArguments() const;
-    inline bool isStrictArguments() const;
-    inline bool isArray() const;
-    inline bool isDenseArray() const;
-    inline bool isSlowArray() const;
-    inline bool isNumber() const;
-    inline bool isBoolean() const;
-    inline bool isString() const;
-    inline bool isPrimitive() const;
-    inline bool isDate() const;
-    inline bool isFunction() const;
-    inline bool isObject() const;
-    inline bool isWith() const;
-    inline bool isBlock() const;
-    inline bool isStaticBlock() const;
-    inline bool isClonedBlock() const;
-    inline bool isCall() const;
-    inline bool isDeclEnv() const;
-    inline bool isRegExp() const;
-    inline bool isScript() const;
-    inline bool isGenerator() const;
-    inline bool isIterator() const;
-    inline bool isStopIteration() const;
-    inline bool isError() const;
-    inline bool isXML() const;
-    inline bool isNamespace() const;
-    inline bool isWeakMap() const;
-    inline bool isFunctionProxy() const;
-    inline bool isProxy() const;
-
-    inline bool isXMLId() const;
-    inline bool isQName() const;
-
-    inline bool isWrapper() const;
-    inline bool isCrossCompartmentWrapper() const;
-
     inline void initArrayClass();
 
     static inline void writeBarrierPre(JSObject *obj);
     static inline void writeBarrierPost(JSObject *obj, void *addr);
     inline void privateWriteBarrierPre(void **oldval);
     inline void privateWriteBarrierPost(void **oldval);
 
+    /*
+     * In addition to the generic object interface provided by JSObject,
+     * specific types of objects may provide additional operations. To access,
+     * these addition operations, callers should use the pattern:
+     *
+     *   if (obj.isX()) {
+     *     XObject &x = obj.asX();
+     *     x.foo();
+     *   }
+     *
+     * These XObject classes form a hierarchy. For example, for a cloned block
+     * object, the following predicates are true: isClonedBlock, isBlock,
+     * isNestedScope and isScope. Each of these has a respective class that
+     * derives and adds operations.
+     *
+     * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file
+     * triplet (along with any class YObject that derives XObject).
+     *
+     * Note that X represents a low-level representation and does not query the
+     * [[Class]] property of object defined by the spec (for this, see
+     * js::ObjectClassIs).
+     *
+     * SpiderMonkey has not been completely switched to the isX/asX/XObject
+     * pattern so in some cases there is no XObject class and the engine
+     * instead pokes directly at reserved slots and getPrivate. In such cases,
+     * consider adding the missing XObject class.
+     */
+
+    /* Direct subtypes of JSObject: */
+    inline bool isArguments() const;
+    inline bool isArrayBuffer() const;
+    inline bool isArray() const;
+    inline bool isDate() const;
+    inline bool isDenseArray() const;
+    inline bool isError() const;
+    inline bool isFunction() const;
+    inline bool isGenerator() const;
+    inline bool isGlobal() const;
+    inline bool isIterator() const;
+    inline bool isNamespace() const;
+    inline bool isObject() const;
+    inline bool isQName() const;
+    inline bool isPrimitive() const;
+    inline bool isProxy() const;
+    inline bool isRegExp() const;
+    inline bool isScope() const;
+    inline bool isScript() const;
+    inline bool isSlowArray() const;
+    inline bool isStopIteration() const;
+    inline bool isWeakMap() const;
+    inline bool isXML() const;
+    inline bool isXMLId() const;
+
+    /* Subtypes of ScopeObject. */
+    inline bool isBlock() const;
+    inline bool isCall() const;
+    inline bool isDeclEnv() const;
+    inline bool isNestedScope() const;
+    inline bool isWith() const;
+    inline bool isClonedBlock() const;
+    inline bool isStaticBlock() const;
+
+    /* Subtypes of PrimitiveObject. */
+    inline bool isBoolean() const;
+    inline bool isNumber() const;
+    inline bool isString() const;
+
+    /* Subtypes of ArgumentsObject. */
+    inline bool isNormalArguments() const;
+    inline bool isStrictArguments() const;
+
+    /* Subtypes of Proxy. */
+    inline bool isWrapper() const;
+    inline bool isFunctionProxy() const;
+    inline bool isCrossCompartmentWrapper() const;
+
+    inline js::ArgumentsObject &asArguments();
+    inline js::BlockObject &asBlock();
+    inline js::BooleanObject &asBoolean();
+    inline js::CallObject &asCall();
+    inline js::ClonedBlockObject &asClonedBlock();
+    inline js::DeclEnvObject &asDeclEnv();
+    inline js::GlobalObject &asGlobal();
+    inline js::NestedScopeObject &asNestedScope();
+    inline js::NormalArgumentsObject &asNormalArguments();
+    inline js::NumberObject &asNumber();
+    inline js::RegExpObject &asRegExp();
+    inline js::ScopeObject &asScope();
+    inline js::StrictArgumentsObject &asStrictArguments();
+    inline js::StaticBlockObject &asStaticBlock();
+    inline js::StringObject &asString();
+    inline js::WithObject &asWith();
+
     static inline js::ThingRootKind rootKind() { return js::THING_ROOT_OBJECT; }
 
   private:
     static void staticAsserts() {
         /* Check alignment for any fixed slots allocated after the object. */
         JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0);
 
         JS_STATIC_ASSERT(offsetof(JSObject, shape_) == offsetof(js::shadow::Object, shape));
@@ -1479,76 +1503,16 @@ class JSValueArray {
 class ValueArray {
   public:
     js::Value *array;
     size_t length;
 
     ValueArray(js::Value *v, size_t c) : array(v), length(c) {}
 };
 
-/*
- * Block scope object macros.  The slots reserved by BlockClass are:
- *
- *   private              StackFrame *      active frame pointer or null
- *   JSSLOT_SCOPE_CHAIN   JSObject *        scope chain, as for other scopes
- *   JSSLOT_BLOCK_DEPTH   int               depth of block slots in frame
- *
- * After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals.
- *
- * A With object is like a Block object, in that both have a reserved slot
- * telling the stack depth of the relevant slots (the slot whose value is the
- * object named in the with statement, the slots containing the block's local
- * variables); and both have a private slot referring to the StackFrame in
- * whose activation they were created (or null if the with or block object
- * outlives the frame).
- */
-static const uint32_t JSSLOT_BLOCK_DEPTH = 1;
-static const uint32_t JSSLOT_BLOCK_FIRST_FREE_SLOT = JSSLOT_BLOCK_DEPTH + 1;
-
-static const uint32_t JSSLOT_WITH_THIS = 2;
-
-#define OBJ_BLOCK_COUNT(cx,obj)                                               \
-    (obj)->propertyCount()
-#define OBJ_BLOCK_DEPTH(cx,obj)                                               \
-    (obj)->getFixedSlot(JSSLOT_BLOCK_DEPTH).toInt32()
-#define OBJ_SET_BLOCK_DEPTH(cx,obj,depth)                                     \
-    (obj)->setFixedSlot(JSSLOT_BLOCK_DEPTH, Value(Int32Value(depth)))
-
-/*
- * To make sure this slot is well-defined, always call js_NewWithObject to
- * create a With object, don't call js_NewObject directly.  When creating a
- * With object that does not correspond to a stack slot, pass -1 for depth.
- *
- * When popping the stack across this object's "with" statement, client code
- * must call withobj->setPrivate(NULL).
- */
-extern JS_REQUIRES_STACK JSObject *
-js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth);
-
-inline JSObject *
-js_UnwrapWithObject(JSContext *cx, JSObject *withobj);
-
-/*
- * Create a new block scope object not linked to any proto or parent object.
- * Blocks are created by the compiler to reify let blocks and comprehensions.
- * Only when dynamic scope is captured do they need to be cloned and spliced
- * into an active scope chain.
- */
-extern JSObject *
-js_NewBlockObject(JSContext *cx);
-
-extern JSObject *
-js_CloneBlockObject(JSContext *cx, JSObject *proto, js::StackFrame *fp);
-
-extern JS_REQUIRES_STACK JSBool
-js_PutBlockObject(JSContext *cx, JSBool normalUnwind);
-
-JSBool
-js_XDRBlockObject(JSXDRState *xdr, JSObject **objp);
-
 /* For manipulating JSContext::sharpObjectMap. */
 #define SHARP_BIT       ((jsatomid) 1)
 #define BUSY_BIT        ((jsatomid) 2)
 #define SHARP_ID_SHIFT  2
 #define IS_SHARP(he)    (uintptr_t((he)->value) & SHARP_BIT)
 #define MAKE_SHARP(he)  ((he)->value = (void *) (uintptr_t((he)->value)|SHARP_BIT))
 #define IS_BUSY(he)     (uintptr_t((he)->value) & BUSY_BIT)
 #define MAKE_BUSY(he)   ((he)->value = (void *) (uintptr_t((he)->value)|BUSY_BIT))
@@ -1820,17 +1784,17 @@ js_FindPropertyHelper(JSContext *cx, jsi
 /*
  * Search for id either on the current scope chain or on the scope chain's
  * global object, per the global parameter.
  */
 extern JS_FRIEND_API(JSBool)
 js_FindProperty(JSContext *cx, jsid id, bool global,
                 JSObject **objp, JSObject **pobjp, JSProperty **propp);
 
-extern JS_REQUIRES_STACK JSObject *
+extern JSObject *
 js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id);
 
 extern JSObject *
 js_FindVariableScope(JSContext *cx, JSFunction **funp);
 
 /*
  * JSGET_CACHE_RESULT is the analogue of JSDNP_CACHE_RESULT for js_GetMethod.
  *
@@ -1983,17 +1947,17 @@ obj_toStringHelper(JSContext *cx, JSObje
 extern JSBool
 eval(JSContext *cx, uintN argc, Value *vp);
 
 /*
  * Performs a direct eval for the given arguments, which must correspond to the
  * currently-executing stack frame, which must be a script frame. On completion
  * the result is returned in args.rval.
  */
-extern JS_REQUIRES_STACK bool
+extern bool
 DirectEval(JSContext *cx, const CallArgs &args);
 
 /*
  * True iff |v| is the built-in eval function for the global object that
  * corresponds to |scopeChain|.
  */
 extern bool
 IsBuiltinEvalForScope(JSObject *scopeChain, const js::Value &v);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -39,47 +39,44 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsobjinlines_h___
 #define jsobjinlines_h___
 
 #include <new>
 
 #include "jsarray.h"
+#include "jsbool.h"
+#include "jscntxt.h"
 #include "jsdate.h"
 #include "jsfun.h"
 #include "jsgcmark.h"
 #include "jsiter.h"
 #include "jslock.h"
+#include "jsnum.h"
 #include "jsobj.h"
 #include "jsprobes.h"
 #include "jspropertytree.h"
 #include "jsproxy.h"
 #include "jsscope.h"
+#include "jsstr.h"
 #include "jstypedarray.h"
 #include "jsxml.h"
 #include "jswrapper.h"
 
-/* Headers included for inline implementations used by this header. */
-#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 "jsinferinlines.h"
 #include "jsscopeinlines.h"
+#include "jsscriptinlines.h"
 
 #include "gc/Barrier-inl.h"
 #include "vm/String-inl.h"
 
 inline bool
 JSObject::hasPrivate() const
 {
     return getClass()->hasPrivate();
@@ -283,63 +280,20 @@ JSObject::finalize(JSContext *cx, bool b
 }
 
 inline JSObject *
 JSObject::getParent() const
 {
     return lastProperty()->getObjectParent();
 }
 
-inline bool
-JSObject::isInternalScope() const
-{
-    return isCall() || isDeclEnv() || isBlock() || isWith();
-}
-
 inline JSObject *
-JSObject::internalScopeChain() const
-{
-    JS_ASSERT(isInternalScope());
-    return &getFixedSlot(SCOPE_CHAIN_SLOT).toObject();
-}
-
-inline bool
-JSObject::setInternalScopeChain(JSContext *cx, JSObject *obj)
+JSObject::enclosingScope()
 {
-    JS_ASSERT(isInternalScope());
-    if (!obj->setDelegate(cx))
-        return false;
-    setFixedSlot(SCOPE_CHAIN_SLOT, JS::ObjectValue(*obj));
-    return true;
-}
-
-/*static*/ inline size_t
-JSObject::offsetOfInternalScopeChain()
-{
-    return getFixedSlotOffset(SCOPE_CHAIN_SLOT);
-}
-
-inline JSObject *
-JSObject::scopeChain() const
-{
-    return isInternalScope() ? internalScopeChain() : getParent();
-}
-
-inline JSObject *
-JSObject::staticBlockScopeChain() const
-{
-    JS_ASSERT(isStaticBlock());
-    return getFixedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
-}
-
-inline void
-JSObject::setStaticBlockScopeChain(JSObject *obj)
-{
-    JS_ASSERT(isStaticBlock());
-    setFixedSlot(SCOPE_CHAIN_SLOT, JS::ObjectOrNullValue(obj));
+    return isScope() ? &asScope().enclosingScope() : getParent();
 }
 
 /*
  * Property read barrier for deferred cloning of compiler-created function
  * objects optimized as typically non-escaping, ad-hoc methods in obj.
  */
 inline js::Shape *
 JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp)
@@ -453,17 +407,17 @@ JSObject::canRemoveLastProperty()
 
 inline const js::HeapValue *
 JSObject::getRawSlots()
 {
     JS_ASSERT(isGlobal());
     return slots;
 }
 
-inline js::Value
+inline const js::Value &
 JSObject::getReservedSlot(uintN index) const
 {
     JS_ASSERT(index < JSSLOT_FREE(getClass()));
     return getSlot(index);
 }
 
 inline js::HeapValue &
 JSObject::getReservedSlotRef(uintN index)
@@ -800,28 +754,16 @@ JSObject::getQNameLocalNameVal() const
 
 inline void
 JSObject::setQNameLocalName(JSAtom *name)
 {
     JS_ASSERT(isQName());
     setSlot(JSSLOT_QNAME_LOCAL_NAME, name ? js::StringValue(name) : js::UndefinedValue());
 }
 
-inline JSObject *
-JSObject::getWithThis() const
-{
-    return &getFixedSlot(JSSLOT_WITH_THIS).toObject();
-}
-
-inline void
-JSObject::setWithThis(JSObject *thisp)
-{
-    setFixedSlot(JSSLOT_WITH_THIS, js::ObjectValue(*thisp));
-}
-
 inline bool
 JSObject::setSingletonType(JSContext *cx)
 {
     if (!cx->typeInferenceEnabled())
         return true;
 
     JS_ASSERT(!lastProperty()->previous());
     JS_ASSERT(!hasLazyType());
@@ -942,41 +884,42 @@ inline bool JSObject::watched() const
 
 inline bool JSObject::hasSpecialEquality() const
 {
     return !!getClass()->ext.equality;
 }
 
 inline bool JSObject::isArguments() const { return isNormalArguments() || isStrictArguments(); }
 inline bool JSObject::isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); }
-inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
-inline bool JSObject::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
-inline bool JSObject::isNumber() const { return hasClass(&js::NumberClass); }
+inline bool JSObject::isBlock() const { return hasClass(&js::BlockClass); }
 inline bool JSObject::isBoolean() const { return hasClass(&js::BooleanClass); }
-inline bool JSObject::isString() const { return hasClass(&js::StringClass); }
-inline bool JSObject::isPrimitive() const { return isNumber() || isString() || isBoolean(); }
+inline bool JSObject::isCall() const { return hasClass(&js::CallClass); }
+inline bool JSObject::isClonedBlock() const { return isBlock() && !!getProto(); }
 inline bool JSObject::isDate() const { return hasClass(&js::DateClass); }
+inline bool JSObject::isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
+inline bool JSObject::isError() const { return hasClass(&js::ErrorClass); }
 inline bool JSObject::isFunction() const { return hasClass(&js::FunctionClass); }
-inline bool JSObject::isObject() const { return hasClass(&js::ObjectClass); }
-inline bool JSObject::isWith() const { return hasClass(&js::WithClass); }
-inline bool JSObject::isBlock() const { return hasClass(&js::BlockClass); }
-inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); }
-inline bool JSObject::isClonedBlock() const { return isBlock() && !!getProto(); }
-inline bool JSObject::isCall() const { return hasClass(&js::CallClass); }
-inline bool JSObject::isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
-inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); }
-inline bool JSObject::isScript() const { return hasClass(&js::ScriptClass); }
+inline bool JSObject::isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
 inline bool JSObject::isGenerator() const { return hasClass(&js::GeneratorClass); }
 inline bool JSObject::isIterator() const { return hasClass(&js::IteratorClass); }
+inline bool JSObject::isNamespace() const { return hasClass(&js::NamespaceClass); }
+inline bool JSObject::isNestedScope() const { return isBlock() || isWith(); }
+inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
+inline bool JSObject::isNumber() const { return hasClass(&js::NumberClass); }
+inline bool JSObject::isObject() const { return hasClass(&js::ObjectClass); }
+inline bool JSObject::isPrimitive() const { return isNumber() || isString() || isBoolean(); }
+inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); }
+inline bool JSObject::isScope() const { return isCall() || isDeclEnv() || isNestedScope(); }
+inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); }
 inline bool JSObject::isStopIteration() const { return hasClass(&js::StopIterationClass); }
-inline bool JSObject::isError() const { return hasClass(&js::ErrorClass); }
+inline bool JSObject::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
+inline bool JSObject::isString() const { return hasClass(&js::StringClass); }
+inline bool JSObject::isWeakMap() const { return hasClass(&js::WeakMapClass); }
+inline bool JSObject::isWith() const { return hasClass(&js::WithClass); }
 inline bool JSObject::isXML() const { return hasClass(&js::XMLClass); }
-inline bool JSObject::isNamespace() const { return hasClass(&js::NamespaceClass); }
-inline bool JSObject::isWeakMap() const { return hasClass(&js::WeakMapClass); }
-inline bool JSObject::isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
 
 inline bool JSObject::isArray() const
 {
     return isSlowArray() || isDenseArray();
 }
 
 inline bool JSObject::isDenseArray() const
 {
@@ -1427,38 +1370,31 @@ JSObject::isCrossCompartmentWrapper() co
 }
 
 inline bool
 JSObject::isWrapper() const
 {
     return js::IsWrapper(this);
 }
 
-inline js::GlobalObject *
-JSObject::getGlobal() const
+inline js::GlobalObject &
+JSObject::global() const
 {
     JSObject *obj = const_cast<JSObject *>(this);
     while (JSObject *parent = obj->getParent())
         obj = parent;
     return obj->asGlobal();
 }
 
 static inline bool
 js_IsCallable(const js::Value &v)
 {
     return v.isObject() && v.toObject().isCallable();
 }
 
-inline JSObject *
-js_UnwrapWithObject(JSContext *cx, JSObject *withobj)
-{
-    JS_ASSERT(withobj->isWith());
-    return withobj->getProto();
-}
-
 namespace js {
 
 inline void
 OBJ_TO_INNER_OBJECT(JSContext *cx, JSObject *&obj)
 {
     if (JSObjectOp op = obj->getClass()->ext.innerObject)
         obj = op(cx, obj);
 }
@@ -1768,17 +1704,17 @@ NewBuiltinClassInstance(JSContext *cx, C
     gc::AllocKind kind = gc::GetGCObjectKind(clasp);
     return NewBuiltinClassInstance(cx, clasp, kind);
 }
 
 inline GlobalObject *
 GetCurrentGlobal(JSContext *cx)
 {
     JSObject *scopeChain = (cx->hasfp()) ? &cx->fp()->scopeChain() : cx->globalObject;
-    return scopeChain ? scopeChain->getGlobal() : NULL;
+    return scopeChain ? &scopeChain->global() : NULL;
 }
 
 bool
 FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
                    Class *clasp);
 
 /*
  * Create a plain object with the specified type. This bypasses getNewType to
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -223,17 +223,17 @@ static uint32_t
 NumBlockSlots(JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(*pc == JSOP_ENTERBLOCK || *pc == JSOP_ENTERLET0 || *pc == JSOP_ENTERLET1);
     JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET0_LENGTH);
     JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET1_LENGTH);
 
     JSObject *obj = NULL;
     GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj);
-    return OBJ_BLOCK_COUNT(NULL, obj);
+    return obj->asStaticBlock().slotCount();
 }
 
 uintN
 js::StackUses(JSScript *script, jsbytecode *pc)
 {
     JSOp op = (JSOp) *pc;
     const JSCodeSpec &cs = js_CodeSpec[op];
     if (cs.nuses >= 0)
@@ -489,20 +489,18 @@ ToDisassemblySource(JSContext *cx, jsval
         if (!source)
             return false;
         bytes->initBytes(source);
         return true;
     }
 
     if (!JSVAL_IS_PRIMITIVE(v)) {
         JSObject *obj = JSVAL_TO_OBJECT(v);
-        Class *clasp = obj->getClass();
-
-        if (clasp == &BlockClass) {
-            char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj));
+        if (obj->isBlock()) {
+            char *source = JS_sprintf_append(NULL, "depth %d {", obj->asBlock().stackDepth());
             if (!source)
                 return false;
 
             Shape::Range r = obj->lastProperty()->all();
             while (!r.empty()) {
                 const Shape &shape = r.front();
                 JSAtom *atom = JSID_IS_INT(shape.propid())
                                ? cx->runtime->atomState.emptyAtom
@@ -522,25 +520,25 @@ ToDisassemblySource(JSContext *cx, jsval
 
             source = JS_sprintf_append(source, "}");
             if (!source)
                 return false;
             bytes->initBytes(source);
             return true;
         }
 
-        if (clasp == &FunctionClass) {
+        if (obj->isFunction()) {
             JSString *str = JS_DecompileFunction(cx, obj->toFunction(), JS_DONT_PRETTY_PRINT);
             if (!str)
                 return false;
             return bytes->encode(cx, str);
         }
 
-        if (clasp == &RegExpClass) {
-            JSString *source = obj->asRegExp()->toString(cx);
+        if (obj->isRegExp()) {
+            JSString *source = obj->asRegExp().toString(cx);
             if (!source)
                 return false;
             JS::Anchor<JSString *> anchor(source);
             return bytes->encode(cx, source);
         }
     }
 
     return !!js_ValueToPrintable(cx, v, bytes, true);
@@ -1753,33 +1751,31 @@ GetLocal(SprintStack *ss, jsint i)
         JS_ASSERT(ss->printer->script->code <= pc);
         JS_ASSERT(pc < (ss->printer->script->code + ss->printer->script->length));
 
         if (JSOP_ENTERBLOCK == (JSOp)*pc) {
             jsatomid j = js_GetIndexFromBytecode(ss->printer->script, pc, 0);
             JSObject *obj = script->getObject(j);
 
             if (obj->isBlock()) {
-                jsint depth = OBJ_BLOCK_DEPTH(cx, obj);
-                jsint count = OBJ_BLOCK_COUNT(cx, obj);
-
+                uint32_t depth = obj->asBlock().stackDepth();
+                uint32_t count = obj->asBlock().slotCount();
                 if (jsuint(i - depth) < jsuint(count))
                     return GetLocalInSlot(ss, i, jsint(i - depth), obj);
             }
         }
     }
 
     // Iterate over all objects.
     for (jsatomid j = 0, n = script->objects()->length; j != n; j++) {
         JSObject *obj = script->getObject(j);
 
         if (obj->isBlock()) {
-            jsint depth = OBJ_BLOCK_DEPTH(cx, obj);
-            jsint count = OBJ_BLOCK_COUNT(cx, obj);
-
+            uint32_t depth = obj->asBlock().stackDepth();
+            uint32_t count = obj->asBlock().slotCount();
             if (jsuint(i - depth) < jsuint(count))
                 return GetLocalInSlot(ss, i, jsint(i - depth), obj);
         }
     }
 
     return GetStr(ss, i);
 }
 
@@ -2247,25 +2243,25 @@ DecompileGroupAssignment(SprintStack *ss
 
 /*
  * The names of the vars of a let block/expr are stored as the ids of the
  * shapes of the block object. Shapes are stored in a singly-linked list in
  * reverse order of addition. This function takes care of putting the names
  * back in declaration order.
  */
 static bool
-GetBlockNames(JSContext *cx, JSObject *blockObj, AtomVector *atoms)
+GetBlockNames(JSContext *cx, StaticBlockObject &blockObj, AtomVector *atoms)
 {
-    size_t numAtoms = OBJ_BLOCK_COUNT(cx, blockObj);
+    size_t numAtoms = blockObj.slotCount();
     LOCAL_ASSERT(numAtoms > 0);
     if (!atoms->resize(numAtoms))
         return false;
 
     uintN i = numAtoms;
-    for (Shape::Range r = blockObj->lastProperty()->all(); !r.empty(); r.popFront()) {
+    for (Shape::Range r = blockObj.lastProperty()->all(); !r.empty(); r.popFront()) {
         const Shape &shape = r.front();
         LOCAL_ASSERT(shape.hasShortID());
         --i;
         LOCAL_ASSERT((uintN)shape.shortid() == i);
         (*atoms)[i] = JSID_IS_INT(shape.propid())
                       ? cx->runtime->atomState.emptyAtom
                       : JSID_TO_ATOM(shape.propid());
     }
@@ -3183,17 +3179,19 @@ Decompile(SprintStack *ss, jsbytecode *p
                 jp->indent -= 4;
                 js_printf(jp, "\t}\n");
                 break;
 
               case JSOP_ENTERBLOCK:
               {
                 LOAD_OBJECT(0);
                 AtomVector atoms(cx);
-                if (!GetBlockNames(cx, obj, &atoms) || !PushBlockNames(cx, ss, atoms))
+                StaticBlockObject &blockObj = obj->asStaticBlock();
+
+                if (!GetBlockNames(cx, blockObj, &atoms) || !PushBlockNames(cx, ss, atoms))
                     return NULL;
 
                 sn = js_GetSrcNote(jp->script, pc);
                 switch (sn ? SN_TYPE(sn) : SRC_NULL) {
 #if JS_HAS_BLOCK_SCOPE
                   case SRC_BRACE:
                     js_printf(jp, "\t{\n");
                     jp->indent += 4;
@@ -3241,17 +3239,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                         LOCAL_ASSERT(*pc == JSOP_POP);
                         pc += JSOP_POP_LENGTH;
                         lval = PopStr(ss, JSOP_NOP);
                         js_puts(jp, lval);
                     } else {
 #endif
                         LOCAL_ASSERT(*pc == JSOP_SETLOCALPOP);
                         pc += JSOP_SETLOCALPOP_LENGTH;
-                        LOCAL_ASSERT(OBJ_BLOCK_COUNT(cx, obj) >= 1);
+                        LOCAL_ASSERT(blockObj.slotCount() >= 1);
                         if (!QuoteString(&jp->sprinter, atoms[0], 0))
                             return NULL;
 #if JS_HAS_DESTRUCTURING
                     }
 #endif
 
                     /*
                      * Pop the exception_cookie (or its dup in the case of a
@@ -3323,28 +3321,29 @@ Decompile(SprintStack *ss, jsbytecode *p
                 if (op == JSOP_LEAVEBLOCKEXPR)
                     todo = SprintCString(&ss->sprinter, rval);
                 break;
               }
 
               case JSOP_ENTERLET0:
               {
                 LOAD_OBJECT(0);
+                StaticBlockObject &blockObj = obj->asStaticBlock();
 
                 AtomVector atoms(cx);
-                if (!GetBlockNames(cx, obj, &atoms))
+                if (!GetBlockNames(cx, blockObj, &atoms))
                     return NULL;
 
                 sn = js_GetSrcNote(jp->script, pc);
                 LOCAL_ASSERT(SN_TYPE(sn) == SRC_DECL);
                 ptrdiff_t letData = js_GetSrcNoteOffset(sn, 0);
                 bool groupAssign = LetDataToGroupAssign(letData);
-                uintN letDepth = OBJ_BLOCK_DEPTH(cx, obj);
-                LOCAL_ASSERT(letDepth == (uintN)ss->top - OBJ_BLOCK_COUNT(cx, obj));
-                LOCAL_ASSERT(atoms.length() == OBJ_BLOCK_COUNT(cx, obj));
+                uintN letDepth = blockObj.stackDepth();
+                LOCAL_ASSERT(letDepth == (uintN)ss->top - blockObj.slotCount());
+                LOCAL_ASSERT(atoms.length() == blockObj.slotCount());
 
                 /*
                  * Build the list of decompiled rhs expressions. Do this before
                  * sprinting the let-head since GetStr can inject stuff on top
                  * of the stack (in case js_DecompileValueGenerator).
                  */
                 Vector<const char *> rhsExprs(cx);
                 if (!rhsExprs.resize(atoms.length()))
@@ -3444,23 +3443,24 @@ Decompile(SprintStack *ss, jsbytecode *p
                *    with switch.
                * Hence, the only thing to do is update the let vars' slots with
                * their names, taking care to preserve the iter/condition value
                * on top of the stack.
                */
               case JSOP_ENTERLET1:
               {
                 LOAD_OBJECT(0);
+                StaticBlockObject &blockObj = obj->asStaticBlock();
 
                 AtomVector atoms(cx);
-                if (!GetBlockNames(cx, obj, &atoms))
+                if (!GetBlockNames(cx, blockObj, &atoms))
                     return NULL;
 
                 LOCAL_ASSERT(js_GetSrcNote(jp->script, pc) == NULL);
-                LOCAL_ASSERT(ss->top - 1 == OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj));
+                LOCAL_ASSERT(ss->top - 1 == blockObj.stackDepth() + blockObj.slotCount());
                 jsbytecode *nextpc = pc + JSOP_ENTERLET1_LENGTH;
                 if (*nextpc == JSOP_GOTO || *nextpc == JSOP_GOTOX) {
                     LOCAL_ASSERT(SN_TYPE(js_GetSrcNote(jp->script, nextpc)) == SRC_FOR_IN);
                 } else {
                     LOCAL_ASSERT(*nextpc == JSOP_CONDSWITCH ||
                                  *nextpc == JSOP_TABLESWITCH || *nextpc == JSOP_TABLESWITCHX ||
                                  *nextpc == JSOP_LOOKUPSWITCH || *nextpc == JSOP_LOOKUPSWITCHX);
                 }
@@ -4121,23 +4121,24 @@ Decompile(SprintStack *ss, jsbytecode *p
                         len = 0;
                     } else {
                         LOCAL_ASSERT(SN_TYPE(sn) == SRC_DESTRUCTLET);
 
                         ptrdiff_t offsetToLet = js_GetSrcNoteOffset(sn, 0);
                         LOCAL_ASSERT(*(pc + offsetToLet) == JSOP_ENTERLET0);
 
                         GET_OBJECT_FROM_BYTECODE(jp->script, pc + offsetToLet, 0, obj);
-
-                        uint32_t blockDepth = OBJ_BLOCK_DEPTH(cx, obj);
+                        StaticBlockObject &blockObj = obj->asStaticBlock();
+
+                        uint32_t blockDepth = blockObj.stackDepth();
                         LOCAL_ASSERT(blockDepth < ss->top);
-                        LOCAL_ASSERT(ss->top <= blockDepth + OBJ_BLOCK_COUNT(cx, obj));
+                        LOCAL_ASSERT(ss->top <= blockDepth + blockObj.slotCount());
 
                         AtomVector atoms(cx);
-                        if (!GetBlockNames(cx, obj, &atoms))
+                        if (!GetBlockNames(cx, blockObj, &atoms))
                             return NULL;
 
                         /*
                          * Skip any initializers preceding this one. E.g., in
                          *   let (w=1, x=2, [y,z] = a) { ... }
                          * skip 'w' and 'x' for the JSOP_DUP of '[y,z] = a'.
                          */
                         AtomRange letNames = atoms.all();
@@ -4820,17 +4821,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 LOAD_OBJECT(0);
                 str = js_ValueToSource(cx, ObjectValue(*obj));
                 if (!str)
                     return NULL;
                 goto sprint_string;
 
               case JSOP_REGEXP:
                 GET_REGEXP_FROM_BYTECODE(jp->script, pc, 0, obj);
-                str = obj->asRegExp()->toString(cx);
+                str = obj->asRegExp().toString(cx);
                 if (!str)
                     return NULL;
                 goto sprint_string;
 
               case JSOP_TABLESWITCH:
               case JSOP_TABLESWITCHX:
               {
                 ptrdiff_t jmplen, off, off2;
--- a/js/src/jspropertycache.cpp
+++ b/js/src/jspropertycache.cpp
@@ -41,17 +41,17 @@
 #include "jspropertycache.h"
 #include "jscntxt.h"
 #include "jsnum.h"
 #include "jsobjinlines.h"
 #include "jspropertycacheinlines.h"
 
 using namespace js;
 
-JS_REQUIRES_STACK PropertyCacheEntry *
+PropertyCacheEntry *
 PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, JSObject *pobj,
                     const Shape *shape)
 {
     JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
     JS_ASSERT(!cx->runtime->gcRunning);
 
     /*
      * Check for fill from js_SetPropertyHelper where the setter removed shape
@@ -72,17 +72,17 @@ PropertyCache::fill(JSContext *cx, JSObj
      * before any running script might consult a parent-linked scope chain. If
      * this requirement is not satisfied, the fill in progress will never hit,
      * but scope shape tests ensure nothing malfunctions.
      */
     JS_ASSERT_IF(obj == pobj, scopeIndex == 0);
 
     JSObject *tmp = obj;
     for (uintN i = 0; i < scopeIndex; i++)
-        tmp = tmp->internalScopeChain();
+        tmp = &tmp->asScope().enclosingScope();
 
     uintN protoIndex = 0;
     while (tmp != pobj) {
         /*
          * Don't cache entries across prototype lookups which can mutate in
          * arbitrary ways without a shape change.
          */
         if (tmp->hasUncacheableProto()) {
@@ -171,17 +171,17 @@ GetAtomFromBytecode(JSContext *cx, jsbyt
 
     JSScript *script = cx->stack.currentScript();
     ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
     JSAtom *atom;
     GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom);
     return atom;
 }
 
-JS_REQUIRES_STACK JSAtom *
+JSAtom *
 PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject **pobjp,
                         PropertyCacheEntry *entry)
 {
     JSObject *obj, *pobj, *tmp;
 #ifdef DEBUG
     JSScript *script = cx->stack.currentScript();
 #endif
 
@@ -226,17 +226,17 @@ PropertyCache::fullTest(JSContext *cx, j
      * PropertyCache::test handles only the direct and immediate-prototype hit
      * cases. All others go here.
      */
     pobj = obj;
 
     if (JOF_MODE(cs.format) == JOF_NAME) {
         uint8_t scopeIndex = entry->scopeIndex;
         while (scopeIndex > 0) {
-            tmp = pobj->scopeChain();
+            tmp = pobj->enclosingScope();
             if (!tmp || !tmp->isNative())
                 break;
             pobj = tmp;
             scopeIndex--;
         }
 
         *objp = pobj;
     }
--- a/js/src/jspropertycache.h
+++ b/js/src/jspropertycache.h
@@ -175,29 +175,29 @@ class PropertyCache
     static inline jsuword
     hash(jsbytecode *pc, const Shape *kshape)
     {
         return (((jsuword(pc) >> SIZE_LOG2) ^ jsuword(pc) ^ ((jsuword)kshape >> 3)) & MASK);
     }
 
     static inline bool matchShape(JSContext *cx, JSObject *obj, uint32_t shape);
 
-    JS_REQUIRES_STACK JSAtom *fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp,
-                                       JSObject **pobjp, PropertyCacheEntry *entry);
+    JSAtom *fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp,
+                     JSObject **pobjp, PropertyCacheEntry *entry);
 
 #ifdef DEBUG
     void assertEmpty();
 #else
     inline void assertEmpty() {}
 #endif
 
   public:
-    JS_ALWAYS_INLINE JS_REQUIRES_STACK void test(JSContext *cx, jsbytecode *pc,
-                                                 JSObject *&obj, JSObject *&pobj,
-                                                 PropertyCacheEntry *&entry, JSAtom *&atom);
+    JS_ALWAYS_INLINE void test(JSContext *cx, jsbytecode *pc,
+                               JSObject *&obj, JSObject *&pobj,
+                               PropertyCacheEntry *&entry, JSAtom *&atom);
 
     /*
      * Test for cached information about a property set on *objp at pc.
      *
      * On a hit, set *entryp to the entry and return true.
      *
      * On a miss, set *atomp to the name of the property being set and return false.
      */
@@ -208,18 +208,18 @@ class PropertyCache
     /*
      * Fill property cache entry for key cx->fp->pc, optimized value word
      * computed from obj and shape, and entry capability forged from 24-bit
      * obj->shape(), 4-bit scopeIndex, and 4-bit protoIndex.
      *
      * Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was
      * not possible.
      */
-    JS_REQUIRES_STACK PropertyCacheEntry *fill(JSContext *cx, JSObject *obj, uintN scopeIndex,
-                                               JSObject *pobj, const js::Shape *shape);
+    PropertyCacheEntry *fill(JSContext *cx, JSObject *obj, uintN scopeIndex,
+                             JSObject *pobj, const js::Shape *shape);
 
     void purge(JSContext *cx);
 
     /* Restore an entry that may have been purged during a GC. */
     void restore(PropertyCacheEntry *entry);
 };
 
 } /* namespace js */
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1534,17 +1534,17 @@ proxy_createFunction(JSContext *cx, uint
                              "createFunction", "1", "");
         return false;
     }
     JSObject *handler = NonNullObject(cx, vp[2]);
     if (!handler)
         return false;
     JSObject *proto, *parent;
     parent = vp[0].toObject().getParent();
-    proto = parent->getGlobal()->getOrCreateFunctionPrototype(cx);
+    proto = parent->global().getOrCreateFunctionPrototype(cx);
     if (!proto)
         return false;
     parent = proto->getParent();
 
     JSObject *call = js_ValueToCallableObject(cx, &vp[3], JSV2F_SEARCH_STACK);
     if (!call)
         return false;
     JSObject *construct = NULL;
@@ -1648,17 +1648,17 @@ callable_Construct(JSContext *cx, uintN 
         Value protov;
         if (!callable->getProperty(cx, ATOM(classPrototype), &protov))
             return false;
 
         JSObject *proto;
         if (protov.isObject()) {
             proto = &protov.toObject();
         } else {
-            proto = callable->getGlobal()->getOrCreateObjectPrototype(cx);
+            proto = callable->global().getOrCreateObjectPrototype(cx);
             if (!proto)
                 return false;
         }
 
         JSObject *newobj = NewObjectWithGivenProto(cx, &ObjectClass, proto, NULL);
         if (!newobj)
             return false;
 
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -38,18 +38,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsproxy_h___
 #define jsproxy_h___
 
 #include "jsapi.h"
-
-#include "jscntxt.h"
 #include "jsfriendapi.h"
 
 namespace js {
 
 /* Base class for all C++ proxy handlers. */
 class JS_FRIEND_API(ProxyHandler) {
     void *mFamily;
   public:
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -50,18 +50,22 @@
  * declaring a pointer to struct type, or defining a member of struct type.
  *
  * A few fundamental scalar types are defined here too.  Neither the scalar
  * nor the struct typedefs should change much, therefore the nearly-global
  * make dependency induced by this file should not prove painful.
  */
 
 #include "jsapi.h"
+#include "jsutil.h"
 
-#include "jsutil.h"
+#ifdef __cplusplus
+#include "js/HashTable.h"
+#include "js/Vector.h"
+#endif
 
 JS_BEGIN_EXTERN_C
 
 /*
  * Convenience constants.
  */
 #define JS_BITS_PER_UINT32_LOG2 5
 #define JS_BITS_PER_UINT32      32
@@ -183,35 +187,16 @@ class ProxyHandler;
 class Wrapper;
 class CrossCompartmentWrapper;
 
 class TempAllocPolicy;
 class RuntimeAllocPolicy;
 
 class GlobalObject;
 
-template <class T,
-          size_t MinInlineCapacity = 0,
-          class AllocPolicy = TempAllocPolicy>
-class Vector;
-
-template <class>
-struct DefaultHasher;
-
-template <class Key,
-          class Value,
-          class HashPolicy = DefaultHasher<Key>,
-          class AllocPolicy = TempAllocPolicy>
-class HashMap;
-
-template <class T,
-          class HashPolicy = DefaultHasher<T>,
-          class AllocPolicy = TempAllocPolicy>
-class HashSet;
-
 template <typename K,
           typename V,
           size_t InlineElems>
 class InlineMap;
 
 class LifoAlloc;
 
 class PropertyCache;
@@ -326,16 +311,17 @@ class Handle
     T value() { return *ptr; }
 
     template <typename S>
     void testAssign() {
 #ifdef DEBUG
         T a = RootMethods<T>::initial();
         S b = RootMethods<S>::initial();
         a = b;
+        (void)a;
 #endif
     }
 };
 
 typedef Handle<JSObject*>          HandleObject;
 typedef Handle<JSFunction*>        HandleFunction;
 typedef Handle<Shape*>             HandleShape;
 typedef Handle<BaseShape*>         HandleBaseShape;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -1455,17 +1455,17 @@ void
 NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto)
 {
     Class *clasp = shape->getObjectClass();
 
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     if (CanBeFinalizedInBackground(kind, clasp))
         kind = GetBackgroundAllocKind(kind);
 
-    GlobalObject *global = shape->getObjectParent()->getGlobal();
+    GlobalObject *global = &shape->getObjectParent()->global();
     types::TypeObject *type = proto->getNewType(cx);
 
     EntryIndex entry;
     if (lookupGlobal(clasp, global, kind, &entry))
         PodZero(&entries[entry]);
     if (!proto->isGlobal() && lookupProto(clasp, proto, kind, &entry))
         PodZero(&entries[entry]);
     if (lookupType(clasp, type, kind, &entry))
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -530,16 +530,17 @@ struct StackBaseShape
 typedef HashSet<ReadBarriered<UnownedBaseShape>,
                 StackBaseShape,
                 SystemAllocPolicy> BaseShapeSet;
 
 struct Shape : public js::gc::Cell
 {
     friend struct ::JSObject;
     friend struct ::JSFunction;
+    friend class js::StaticBlockObject;
     friend class js::PropertyTree;
     friend class js::Bindings;
     friend struct js::StackShape;
     friend struct js::StackBaseShape;
     friend bool IsShapeAboutToBeFinalized(JSContext *cx, const js::Shape *shape);
 
   protected:
     HeapPtrBaseShape    base_;
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -36,33 +36,37 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsscopeinlines_h___
 #define jsscopeinlines_h___
 
 #include <new>
+
 #include "jsarray.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsobj.h"
 #include "jsscope.h"
 #include "jsgc.h"
 #include "jsgcmark.h"
 
 #include "vm/ArgumentsObject.h"
+#include "vm/ScopeObject.h"
 #include "vm/StringObject.h"
 
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
+#include "vm/ScopeObject-inl.h"
+
 namespace js {
 
 inline
 BaseShape::BaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags)
 {
     JS_ASSERT(!(objectFlags & ~OBJECT_FLAG_MASK));
     PodZero(this);
     this->clasp = clasp;
@@ -260,17 +264,17 @@ Shape::get(JSContext* cx, JSObject *rece
         return pobj->methodReadBarrier(cx, *this, vp);
     }
 
     /*
      * |with (it) color;| ends up here, as do XML filter-expressions.
      * Avoid exposing the With object to native getters.
      */
     if (obj->isWith())
-        obj = js_UnwrapWithObject(cx, obj);
+        obj = &obj->asWith().object();
     return js::CallJSPropertyOp(cx, getterOp(), receiver, getUserId(), vp);
 }
 
 inline bool
 Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const
 {
     JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
 
@@ -279,17 +283,17 @@ Shape::set(JSContext* cx, JSObject* obj,
         return js::InvokeGetterOrSetter(cx, obj, fval, 1, vp, vp);
     }
 
     if (attrs & JSPROP_GETTER)
         return js_ReportGetterOnlyAssignment(cx);
 
     /* See the comment in js::Shape::get as to why we check for With. */
     if (obj->isWith())
-        obj = js_UnwrapWithObject(cx, obj);
+        obj = &obj->asWith().object();
     return js::CallJSPropertyOpSetter(cx, setterOp(), obj, getUserId(), strict, vp);
 }
 
 inline void
 Shape::setParent(js::Shape *p)
 {
     JS_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(),
                  p->maybeSlot() <= maybeSlot());
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -649,33 +649,34 @@ js_XDRScript(JSXDRState *xdr, JSScript *
      * that block objects from the script->objects array will be written and
      * restored in the outer-to-inner order. js_XDRBlockObject relies on this
      * to restore the parent chain.
      */
     for (i = 0; i != nobjects; ++i) {
         HeapPtr<JSObject> *objp = &script->objects()->vector[i];
         uint32_t isBlock;
         if (xdr->mode == JSXDR_ENCODE) {
-            Class *clasp = (*objp)->getClass();
-            JS_ASSERT(clasp == &FunctionClass ||
-                      clasp == &BlockClass);
-            isBlock = (clasp == &BlockClass) ? 1 : 0;
+            JSObject *obj = *objp;
+            JS_ASSERT(obj->isFunction() || obj->isStaticBlock());
+            isBlock = obj->isBlock() ? 1 : 0;
         }
         if (!JS_XDRUint32(xdr, &isBlock))
             goto error;
-        JSObject *tmp = *objp;
         if (isBlock == 0) {
+            JSObject *tmp = *objp;
             if (!js_XDRFunctionObject(xdr, &tmp))
                 goto error;
+            *objp = tmp;
         } else {
             JS_ASSERT(isBlock == 1);
-            if (!js_XDRBlockObject(xdr, &tmp))
+            StaticBlockObject *tmp = static_cast<StaticBlockObject *>(objp->get());
+            if (!js_XDRStaticBlockObject(xdr, &tmp))
                 goto error;
+            *objp = tmp;
         }
-        *objp = tmp;
     }
     for (i = 0; i != nupvars; ++i) {
         if (!JS_XDRUint32(xdr, reinterpret_cast<uint32_t *>(&script->upvars()->vector[i])))
             goto error;
     }
     for (i = 0; i != nregexps; ++i) {
         JSObject *tmp = script->regexps()->vector[i];
         if (!js_XDRRegExpObject(xdr, &tmp))
@@ -1257,34 +1258,34 @@ JSScript::NewScriptFromEmitter(JSContext
             bce->parent->compiling() &&
             bce->parent->asBytecodeEmitter()->checkSingletonContext() &&
             !fun->isFlatClosure();
 
         if (!script->typeSetFunction(cx, fun, singleton))
             return NULL;
 
         fun->setScript(script);
-        script->globalObject = fun->getParent() ? fun->getParent()->getGlobal() : NULL;
+        script->globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
     } else {
         /*
          * Initialize script->object, if necessary, so that the debugger has a
          * valid holder object.
          */
         if (bce->flags & TCF_NEED_SCRIPT_GLOBAL)
             script->globalObject = GetCurrentGlobal(cx);
     }
 
     /* Tell the debugger about this compiled script. */
     js_CallNewScriptHook(cx, script, fun);
     if (!bce->parent) {
         GlobalObject *compileAndGoGlobal = NULL;
         if (script->compileAndGo) {
             compileAndGoGlobal = script->globalObject;
             if (!compileAndGoGlobal)
-                compileAndGoGlobal = bce->scopeChain()->getGlobal();
+                compileAndGoGlobal = &bce->scopeChain()->global();
         }
         Debugger::onNewScript(cx, script, compileAndGoGlobal);
     }
 
     if (cx->hasRunOption(JSOPTION_PCCOUNT))
         (void) script->initCounts(cx);
 
     return script;
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -43,17 +43,17 @@
 
 #include "jsautooplen.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jsscope.h"
 
-#include "vm/CallObject.h"
+#include "vm/ScopeObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/RegExpObject.h"
 
 #include "jsscopeinlines.h"
 
 namespace js {
 
 inline
deleted file mode 100644
--- a/js/src/jsstack.js
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Check that only JS_REQUIRES_STACK/JS_FORCES_STACK functions, and functions
- * that have called a JS_FORCES_STACK function, access cx->fp directly or
- * indirectly.
- */
-
-require({ after_gcc_pass: 'cfg' });
-include('gcc_util.js');
-include('unstable/adts.js');
-include('unstable/analysis.js');
-include('unstable/lazy_types.js');
-include('unstable/esp.js');
-
-var Zero_NonZero = {};
-include('unstable/zero_nonzero.js', Zero_NonZero);
-
-// Tell MapFactory we don't need multimaps (a speed optimization).
-MapFactory.use_injective = true;
-
-/*
- * There are two regions in the program: RED and GREEN.  Functions and member
- * variables may be declared RED in the C++ source.  GREEN is the default.
- *
- * RED signals danger.  A GREEN part of a function must not call a RED function
- * or access a RED member.
- *
- * The body of a RED function is all red.  The body of a GREEN function is all
- * GREEN by default, but parts dominated by a call to a TURN_RED function are
- * red.  This way GREEN functions can safely access RED stuff by calling a
- * TURN_RED function as preparation.
- *
- * The analysis does not attempt to prove anything about the body of a TURN_RED
- * function.  (Both annotations are trusted; only unannotated code is checked
- * for errors.)
- */
-const RED = 'JS_REQUIRES_STACK';
-const TURN_RED = 'JS_FORCES_STACK';
-const IGNORE_ERRORS = 'JS_IGNORE_STACK';
-
-function attrs(tree) {
-  let a = DECL_P(tree) ? DECL_ATTRIBUTES(tree) : TYPE_ATTRIBUTES(tree);
-  return translate_attributes(a);
-}
-
-function hasUserAttribute(tree, attrname) {
-  let attributes = attrs(tree);
-  if (attributes) {
-    for (let i = 0; i < attributes.length; i++) {
-      let attr = attributes[i];
-      if (attr.name == 'user' && attr.value.length == 1 && attr.value[0] == attrname)
-        return true;
-    }
-  }
-  return false;
-}
-
-function process_tree_type(d)
-{
-  let t = dehydra_convert(d);
-  if (t.isFunction)
-    return;
-
-  if (t.typedef !== undefined)
-    if (isRed(TYPE_NAME(d)))
-      warning("Typedef declaration is annotated JS_REQUIRES_STACK: the annotation should be on the type itself", t.loc);
-  
-  if (hasAttribute(t, RED)) {
-    warning("Non-function is annotated JS_REQUIRES_STACK", t.loc);
-    return;
-  }
-  
-  for (let st = t; st !== undefined && st.isPointer; st = st.type) {
-    if (hasAttribute(st, RED)) {
-      warning("Non-function is annotated JS_REQUIRES_STACK", t.loc);
-      return;
-    }
-    
-    if (st.parameters)
-      return;
-  }
-}
-
-function process_tree_decl(d)
-{
-  // For VAR_DECLs, walk the DECL_INITIAL looking for bad assignments
-  if (TREE_CODE(d) != VAR_DECL)
-    return;
-  
-  let i = DECL_INITIAL(d);
-  if (!i)
-    return;
-  
-  assignCheck(i, TREE_TYPE(d), function() { return location_of(d); });
-
-  functionPointerWalk(i, d);
-}
-
-/*
- * x is an expression or decl.  These functions assume that 
- */
-function isRed(x) { return hasUserAttribute(x, RED); }
-function isTurnRed(x) { return hasUserAttribute(x, TURN_RED); }
-
-function process_tree(fndecl)
-{
-  if (hasUserAttribute(fndecl, IGNORE_ERRORS))
-    return;
-
-  if (!(isRed(fndecl) || isTurnRed(fndecl))) {
-    // Ordinarily a user of ESP runs the analysis, then generates output based
-    // on the results.  But in our case (a) we need sub-basic-block resolution,
-    // which ESP doesn't keep; (b) it so happens that even though ESP can
-    // iterate over blocks multiple times, in our case that won't cause
-    // spurious output.  (It could cause us to the same error message each time
-    // through--but that's easily avoided.)  Therefore we generate the output
-    // while the ESP analysis is running.
-    let a = new RedGreenCheck(fndecl, 0);
-    if (a.hasRed)
-      a.run();
-  }
-  
-  functionPointerCheck(fndecl);
-}
-
-function RedGreenCheck(fndecl, trace) {
-  //print("RedGreenCheck: " + fndecl.toCString());
-  this._fndecl = fndecl;
-
-  // Tell ESP that fndecl is a "property variable".  This makes ESP track it in
-  // a flow-sensitive way.  The variable will be 1 in RED regions and "don't
-  // know" in GREEN regions.  (We are technically lying to ESP about fndecl
-  // being a variable--what we really want is a synthetic variable indicating
-  // RED/GREEN state, but ESP operates on GCC decl nodes.)
-  this._state_var_decl = fndecl;
-  let state_var = new ESP.PropVarSpec(this._state_var_decl, true, undefined);
-
-  // Call base class constructor.
-  let cfg = function_decl_cfg(fndecl);
-  ESP.Analysis.apply(this, [cfg, [state_var], Zero_NonZero.meet, trace]);
-  this.join = Zero_NonZero.join;
-
-  // Preprocess all instructions in the cfg to determine whether this analysis
-  // is necessary and gather some information we'll use later.
-  //
-  // Each isn may include a function call, an assignment, and/or some reads.
-  // Using walk_tree to walk the isns is a little crazy but robust.
-  //
-  this.hasRed = false;
-  let self = this;         // Allow our 'this' to be accessed inside closure
-  for (let bb in cfg_bb_iterator(cfg)) {
-    for (let isn in bb_isn_iterator(bb)) {
-      // Treehydra objects don't support reading never-defined properties