Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <emorley@mozilla.com>
Fri, 04 May 2012 13:47:16 +0100
changeset 93191 9ebf3dc839c52b39045f7fb5b411328db0d6d206
parent 93190 f099b606dad42159a4bc2b7810f17fdd008f0aec (current diff)
parent 93106 e53c3fb93f8b73fa5701022c5a5115895e9959ef (diff)
child 93207 db1f131884deee171945b025d1149c80495d8e69
push id9028
push usereakhgari@mozilla.com
push dateFri, 04 May 2012 20:29:50 +0000
treeherdermozilla-inbound@41dc6249bd08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone15.0a1
first release with
nightly linux32
9ebf3dc839c5 / 15.0a1 / 20120504122939 / files
nightly linux64
9ebf3dc839c5 / 15.0a1 / 20120504122939 / files
nightly mac
9ebf3dc839c5 / 15.0a1 / 20120504122939 / files
nightly win32
9ebf3dc839c5 / 15.0a1 / 20120504122939 / files
nightly win64
9ebf3dc839c5 / 15.0a1 / 20120504122939 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
dom/bluetooth/BluetoothDevice.cpp
dom/bluetooth/BluetoothDevice.h
dom/bluetooth/nsIDOMBluetoothDevice.idl
js/src/jscell.h
js/src/jsgcmark.cpp
js/src/jsgcmark.h
--- a/.hgignore
+++ b/.hgignore
@@ -8,17 +8,17 @@
 (^|/)\.DS_Store$
 
 # Vim swap files.
 ^\.sw.$
 .[^/]*\.sw.$
 
 # User files that may appear at the root
 ^\.mozconfig
-^mozconfig$
+^mozconfig*
 ^configure$
 ^config\.cache$
 ^config\.log$
 
 # Empty marker file that's generated when we check out NSS
 ^security/manager/\.nss\.checkout$
 
 # Build directories
@@ -39,9 +39,8 @@
 
 # SVN directories
 \.svn/
 
 # Ignore the files and directory that Eclipse IDE creates
 \.project$
 \.cproject$
 \.settings/
-
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -11,47 +11,49 @@ const Cr = Components.results;
 
 var EXPORTED_SYMBOLS = ['AccessFu'];
 
 Cu.import('resource://gre/modules/Services.jsm');
 
 Cu.import('resource://gre/modules/accessibility/Presenters.jsm');
 Cu.import('resource://gre/modules/accessibility/VirtualCursorController.jsm');
 
+const ACCESSFU_DISABLE = 0;
+const ACCESSFU_ENABLE = 1;
+const ACCESSFU_AUTO = 2;
+
 var AccessFu = {
   /**
    * Attach chrome-layer accessibility functionality to the given chrome window.
    * If accessibility is enabled on the platform (currently Android-only), then
    * a special accessibility mode is started (see startup()).
    * @param {ChromeWindow} aWindow Chrome window to attach to.
    * @param {boolean} aForceEnabled Skip platform accessibility check and enable
    *  AccessFu.
    */
   attach: function attach(aWindow) {
+    if (this.chromeWin)
+      // XXX: only supports attaching to one window now.
+      throw new Error('Only one window could be attached to AccessFu');
+
     dump('AccessFu attach!! ' + Services.appinfo.OS + '\n');
     this.chromeWin = aWindow;
     this.presenters = [];
 
-    function checkA11y() {
-      if (Services.appinfo.OS == 'Android') {
-        let msg = Cc['@mozilla.org/android/bridge;1'].
-          getService(Ci.nsIAndroidBridge).handleGeckoMessage(
-            JSON.stringify(
-                { gecko: {
-                    type: 'Accessibility:IsEnabled',
-                    eventType: 1,
-                    text: []
-                  }
-                }));
-        return JSON.parse(msg).enabled;
-      }
-      return false;
+    this.prefsBranch = Cc['@mozilla.org/preferences-service;1']
+      .getService(Ci.nsIPrefService).getBranch('accessibility.');
+    this.prefsBranch.addObserver('accessfu', this, false);
+
+    let accessPref = ACCESSFU_DISABLE;
+    try {
+      accessPref = this.prefsBranch.getIntPref('accessfu');
+    } catch (x) {
     }
 
-    if (checkA11y())
+    if (this.amINeeded(accessPref))
       this.enable();
   },
 
   /**
    * Start the special AccessFu mode, this primarily means controlling the virtual
    * cursor with arrow keys. Currently, on platforms other than Android this needs
    * to be called explicitly.
    */
@@ -89,16 +91,38 @@ var AccessFu = {
     this.chromeWin.removeEventListener('DOMActivate', this);
     this.chromeWin.removeEventListener('resize', this);
     this.chromeWin.removeEventListener('scroll', this);
     this.chromeWin.removeEventListener('TabOpen', this);
     this.chromeWin.removeEventListener('TabSelect', this);
     this.chromeWin.removeEventListener('TabClose', this);
   },
 
+  amINeeded: function(aPref) {
+    switch (aPref) {
+      case ACCESSFU_ENABLE:
+        return true;
+      case ACCESSFU_AUTO:
+        if (Services.appinfo.OS == 'Android') {
+          let msg = Cc['@mozilla.org/android/bridge;1'].
+            getService(Ci.nsIAndroidBridge).handleGeckoMessage(
+              JSON.stringify(
+                { gecko: {
+                    type: 'Accessibility:IsEnabled',
+                    eventType: 1,
+                    text: []
+                  }
+                }));
+          return JSON.parse(msg).enabled;
+        }
+      default:
+        return false;
+    }
+  },
+
   addPresenter: function addPresenter(presenter) {
     this.presenters.push(presenter);
     presenter.attach(this.chromeWin);
   },
 
   handleEvent: function handleEvent(aEvent) {
     switch (aEvent.type) {
       case 'TabSelect':
@@ -145,16 +169,24 @@ var AccessFu = {
       this._pendingDocuments[browserApp.selectedBrowser] = aCallback;
     } else {
       aCallback.apply(this, [docAcc]);
     }
   },
 
   observe: function observe(aSubject, aTopic, aData) {
     switch (aTopic) {
+      case 'nsPref:changed':
+        if (aData == 'accessfu') {
+          if (this.amINeeded(this.prefsBranch.getIntPref('accessfu')))
+            this.enable();
+          else
+            this.disable();
+        }
+        break;
       case 'accessible-event':
         let event;
         try {
           event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
           this.handleAccEvent(event);
         } catch (ex) {
           dump(ex);
           return;
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -425,30 +425,21 @@ window[chromehidden~="toolbar"] toolbar:
   -moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton-image");
   margin: 0;
 }
 
 
 /* notification anchors should only be visible when their associated
    notifications are */
 .notification-anchor-icon {
-  display: none;
   -moz-user-focus: normal;
 }
 
-/* We use the iconBox as the notification anchor when a popup notification is
-   created with a null anchorID, so in that case use a default anchor icon. */
-#notification-popup-box[anchorid="notification-popup-box"] > #default-notification-icon,
-#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
-#notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
-#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon,
-#notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon,
-#notification-popup-box[anchorid="webapps-notification-icon"] > #webapps-notification-icon,
-#notification-popup-box[anchorid="plugins-notification-icon"] > #plugins-notification-icon {
-  display: -moz-box;
+.notification-anchor-icon:not([showing]) {
+  display: none;
 }
 
 #invalid-form-popup > description {
   max-width: 280px;
 }
 
 #geolocation-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#geolocation-notification");
--- a/browser/base/content/test/browser_popupNotification.js
+++ b/browser/base/content/test/browser_popupNotification.js
@@ -637,16 +637,94 @@ var tests = [
       checkPopup(popup, this.notifyObj);
       dismissNotification(popup);
     },
     onHidden: function (popup) {
       ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered");
       ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
     }
   },
+  // Test multiple notification icons are shown
+  { // Test #21
+    run: function () {
+      this.notifyObj1 = new basicNotification();
+      this.notifyObj1.id += "_1";
+      this.notifyObj1.anchorID = "default-notification-icon";
+      this.notification1 = showNotification(this.notifyObj1);
+
+      this.notifyObj2 = new basicNotification();
+      this.notifyObj2.id += "_2";
+      this.notifyObj2.anchorID = "geo-notification-icon";
+      this.notification2 = showNotification(this.notifyObj2);
+    },
+    onShown: function (popup) {
+      checkPopup(popup, this.notifyObj2);
+
+      // check notifyObj1 anchor icon is showing
+      isnot(document.getElementById("default-notification-icon").boxObject.width, 0,
+            "default anchor should be visible");
+      // check notifyObj2 anchor icon is showing
+      isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
+            "geo anchor should be visible");
+
+      dismissNotification(popup);
+    },
+    onHidden: [
+      function (popup) {
+      },
+      function (popup) {
+        this.notification1.remove();
+        ok(this.notifyObj1.removedCallbackTriggered, "removed callback triggered");
+
+        this.notification2.remove();
+        ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered");
+      }
+    ],
+  },
+  // Test that multiple notification icons are removed when switching tabs
+  { // Test #22
+    run: function () {
+      // show the notification on old tab.
+      this.notifyObjOld = new basicNotification();
+      this.notifyObjOld.anchorID = "default-notification-icon";
+      this.notificationOld = showNotification(this.notifyObjOld);
+
+      // switch tab
+      this.oldSelectedTab = gBrowser.selectedTab;
+      gBrowser.selectedTab = gBrowser.addTab("about:blank");
+
+      // show the notification on new tab.
+      this.notifyObjNew = new basicNotification();
+      this.notifyObjNew.anchorID = "geo-notification-icon";
+      this.notificationNew = showNotification(this.notifyObjNew);
+    },
+    onShown: function (popup) {
+      checkPopup(popup, this.notifyObjNew);
+
+      // check notifyObjOld anchor icon is removed
+      is(document.getElementById("default-notification-icon").boxObject.width, 0,
+         "default anchor shouldn't be visible");
+      // check notifyObjNew anchor icon is showing
+      isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
+            "geo anchor should be visible");
+
+      dismissNotification(popup);
+    },
+    onHidden: [
+      function (popup) {
+      },
+      function (popup) {
+        this.notificationNew.remove();
+        gBrowser.removeTab(gBrowser.selectedTab);
+
+        gBrowser.selectedTab = this.oldSelectedTab;
+        this.notificationOld.remove();
+      }
+    ],
+  }
 ];
 
 function showNotification(notifyObj) {
   return PopupNotifications.show(notifyObj.browser,
                                  notifyObj.id,
                                  notifyObj.message,
                                  notifyObj.anchorID,
                                  notifyObj.mainAction,
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1255,16 +1255,17 @@ toolbar[iconsize="small"] #feed-button {
 #notification-popup-box:-moz-locale-dir(rtl),
 .notification-anchor-icon:-moz-locale-dir(rtl) {
   -moz-transform: scaleX(-1);
 }
 
 .notification-anchor-icon {
   width: 16px;
   height: 16px;
+  margin: 0 2px;
 }
 
 .notification-anchor-icon:-moz-focusring {
   outline: 1px dotted -moz-DialogText;
 }
 
 #default-notification-icon {
   list-style-image: url(chrome://global/skin/icons/information-16.png);
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -2316,16 +2316,17 @@ toolbarbutton.bookmark-item[dragover="tr
 #notification-popup-box:-moz-locale-dir(rtl),
 .notification-anchor-icon:-moz-locale-dir(rtl) {
   -moz-transform: scaleX(-1);
 }
 
 .notification-anchor-icon {
   width: 16px;
   height: 16px;
+  margin: 0 2px;
 }
 
 .notification-anchor-icon:-moz-focusring {
   outline: 1px dotted -moz-DialogText;
   outline-offset: -3px;
 }
 
 #default-notification-icon {
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -1,10 +1,58 @@
 dnl Add compiler specific options
 
+AC_DEFUN([MOZ_DEFAULT_COMPILER],
+[
+dnl Default to MSVC for win32 and gcc-4.2 for darwin
+dnl ==============================================================
+if test -z "$CROSS_COMPILE"; then
+case "$target" in
+*-mingw*)
+    if test -z "$CC"; then CC=cl; fi
+    if test -z "$CXX"; then CXX=cl; fi
+    if test -z "$CPP"; then CPP="cl -E -nologo"; fi
+    if test -z "$CXXCPP"; then CXXCPP="cl -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
+    if test -z "$LD"; then LD=link; fi
+    if test -z "$AS"; then
+        case "${target_cpu}" in
+        i*86)
+            AS=ml;
+            ;;
+        x86_64)
+            AS=ml64;
+            ;;
+        esac
+    fi
+    if test -z "$MIDL"; then MIDL=midl; fi
+
+    # need override this flag since we don't use $(LDFLAGS) for this.
+    if test -z "$HOST_LDFLAGS" ; then
+        HOST_LDFLAGS=" "
+    fi
+    ;;
+*-darwin*)
+    # we prefer gcc-4.2 over gcc on older darwin, so
+    # use that specific version if it's available.
+    # On newer versions of darwin, gcc is llvm-gcc while gcc-4.2 is the plain
+    # one, so we also try that first. If that fails, we fall back to clang
+    # as llvm-gcc is an unsupported dead end.
+    MOZ_PATH_PROGS(CC, $CC gcc-4.2 clang gcc)
+    MOZ_PATH_PROGS(CXX, $CXX g++-4.2 clang++ g++)
+    IS_LLVM_GCC=$($CC -v 2>&1 | grep llvm-gcc)
+    if test -n "$IS_LLVM_GCC"
+    then
+      echo llvm-gcc is known to be broken, please use gcc-4.2 or clang.
+      exit 1
+    fi
+    ;;
+esac
+fi
+])
+
 AC_DEFUN([MOZ_COMPILER_OPTS],
 [
 if test "$CLANG_CXX"; then
     ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
     ## returned by C functions. This is possible because we use knowledge about the ABI
     ## to typedef it to a C type with the same layout when the headers are included
     ## from C.
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
--- a/build/mobile/robocop/FennecNativeDriver.java.in
+++ b/build/mobile/robocop/FennecNativeDriver.java.in
@@ -65,17 +65,17 @@ import android.opengl.GLSurfaceView;
 import android.view.View;
 import android.util.Log;
 
 import org.json.*;
 
 import com.jayway.android.robotium.solo.Solo;
 
 public class FennecNativeDriver implements Driver {
-    private static final int FRAME_TIME_THRESHOLD = 17;     // allow 17ms per frame (~60fps)
+    private static final int FRAME_TIME_THRESHOLD = 25;     // allow 25ms per frame (40fps)
 
     // Map of IDs to element names.
     private HashMap mLocators = null;
     private Activity mActivity;
     private Solo mSolo;
 
     private static String mLogFile = null;
     private static LogLevel mLogLevel = LogLevel.INFO;
@@ -226,30 +226,37 @@ public class FennecNativeDriver implemen
 
     public int stopFrameRecording() {
         Class [] parameters = new Class[1];
         parameters[0] = null;
 
         try {
             Object [] params = null;
             List<Long> frames = (List<Long>)_stopFrameRecording.invoke(null, params);
-            int numDelays = 0;
+            int badness = 0;
             for (int i = 1; i < frames.size(); i++) {
-                if (frames.get(i) - frames.get(i-1) > FRAME_TIME_THRESHOLD) {
-                    numDelays++;
+                long frameTime = frames.get(i) - frames.get(i - 1);
+                int delay = (int)(frameTime - FRAME_TIME_THRESHOLD);
+                // for each frame we miss, add the square of the delay. This
+                // makes large delays much worse than small delays.
+                if (delay > 0) {
+                    badness += delay * delay;
                 }
             }
-            return numDelays;
+            // Don't do any averaging of the numbers because really we want to
+            // know how bad the jank was at its worst
+            return badness;
         } catch (IllegalAccessException e) {
             log(LogLevel.ERROR, e);
         } catch (InvocationTargetException e) {
             log(LogLevel.ERROR, e);
         }
 
-        return 0;
+        // higher values are worse, and the test failing is the worst!
+        return Integer.MAX_VALUE;
     }
 
     public void startCheckerboardRecording() {
         try {
             Object [] params = null;
             _startCheckerboardRecording.invoke(null, params);
         } catch (IllegalAccessException e) {
             log(LogLevel.ERROR, e);
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -87,17 +87,17 @@ def build_glibc_aux(stage_dir, inst_dir)
                    "--enable-kernel=%s" % linux_version,
                    "--libdir=%s/lib64" % inst_dir,
                    "--prefix=%s" % inst_dir])
 
 def build_linux_headers_aux(inst_dir):
     run_in(linux_source_dir, [old_make, "headers_check"])
     run_in(linux_source_dir, [old_make, "INSTALL_HDR_PATH=dest",
                                "headers_install"])
-    shutil.move(linux_source_dir + "/dest", inst_dir)
+    shutil.move(linux_source_dir + "/dest/include", inst_dir + '/include')
 
 def build_linux_headers(inst_dir):
     def f():
         build_linux_headers_aux(inst_dir)
     with_env({"PATH" : aux_inst_dir + "/bin:%s" % os.environ["PATH"]}, f)
 
 def build_gcc(stage_dir, is_stage_one):
     gcc_build_dir = stage_dir + '/gcc'
@@ -146,16 +146,20 @@ def build_one_stage_aux(stage_dir, is_st
                    "--with-gmp=%s" % lib_inst_dir])
     mpc_build_dir = stage_dir + '/mpc'
     build_package(mpc_source_dir, mpc_build_dir,
                   ["--prefix=%s" % lib_inst_dir, "--disable-shared",
                    "--with-gmp=%s" % lib_inst_dir,
                    "--with-mpfr=%s" % lib_inst_dir])
 
     tool_inst_dir = stage_dir + '/inst'
+    os.mkdir(tool_inst_dir)
+    os.mkdir(tool_inst_dir + '/lib64')
+    os.symlink('lib64', tool_inst_dir + '/lib')
+
     build_linux_headers(tool_inst_dir)
 
     binutils_build_dir = stage_dir + '/binutils'
     build_package(binutils_source_dir, binutils_build_dir,
                   ["--prefix=%s" % tool_inst_dir,
                    "--without-zlib"])
 
     # During stage one we have to build gcc first, this glibc doesn't even
--- a/configure.in
+++ b/configure.in
@@ -175,51 +175,17 @@ then
 	***
 	EOF
     exit 1
     break
   fi
 fi
 MOZ_BUILD_ROOT=`pwd`
 
-dnl Default to MSVC for win32 and gcc for darwin
-dnl ==============================================================
-if test -z "$CROSS_COMPILE"; then
-case "$target" in
-*-mingw*)
-    if test -z "$CC"; then CC=cl; fi
-    if test -z "$CXX"; then CXX=cl; fi
-    if test -z "$CPP"; then CPP="cl -E -nologo"; fi
-    if test -z "$CXXCPP"; then CXXCPP="cl -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
-    if test -z "$LD"; then LD=link; fi
-    if test -z "$AS"; then
-        case "${target_cpu}" in
-        i*86)
-            AS=ml;
-            ;;
-        x86_64)
-            AS=ml64;
-            ;;
-        esac
-    fi
-    if test -z "$MIDL"; then MIDL=midl; fi
-
-    # need override this flag since we don't use $(LDFLAGS) for this.
-    if test -z "$HOST_LDFLAGS" ; then
-        HOST_LDFLAGS=" "
-    fi
-    ;;
-*-darwin*)
-    # we prefer gcc-4.2 over gcc on older darwin, so
-    # use that specific version if it's available.
-    MOZ_PATH_PROGS(CC, $CC gcc-4.2 gcc)
-    MOZ_PATH_PROGS(CXX, $CXX g++-4.2 g++)
-    ;;
-esac
-fi
+MOZ_DEFAULT_COMPILER
 
 COMPILE_ENVIRONMENT=1
 MOZ_ARG_DISABLE_BOOL(compile-environment,
 [  --disable-compile-environment
                           Disable compiler/library checks.],
     COMPILE_ENVIRONMENT= )
 AC_SUBST(COMPILE_ENVIRONMENT)
 
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6074,27 +6074,31 @@ public:
                                            const char *objName)
   {
   }
   NS_IMETHOD_(void) DescribeGCedNode(bool isMarked,
                                      size_t objSz,
                                      const char *objName)
   {
   }
+
   NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root)
   {
   }
-  NS_IMETHOD_(void) NoteRoot(PRUint32 langID, void* root,
-                             nsCycleCollectionParticipant* helper)
+  NS_IMETHOD_(void) NoteJSRoot(void* root)
+  {
+  }
+  NS_IMETHOD_(void) NoteNativeRoot(void* root,
+                                   nsCycleCollectionParticipant* helper)
   {
   }
-  NS_IMETHOD_(void) NoteScriptChild(PRUint32 langID, void* child)
+
+  NS_IMETHOD_(void) NoteJSChild(void* child)
   {
-    if (langID == nsIProgrammingLanguage::JAVASCRIPT &&
-        child == mWrapper) {
+    if (child == mWrapper) {
       mFound = true;
     }
   }
   NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child)
   {
   }
   NS_IMETHOD_(void) NoteNativeChild(void* child,
                                     nsCycleCollectionParticipant* helper)
@@ -6111,22 +6115,21 @@ public:
 
   bool mFound;
 
 private:
   void* mWrapper;
 };
 
 static void
-DebugWrapperTraceCallback(PRUint32 langID, void *p, const char *name,
-                          void *closure)
+DebugWrapperTraceCallback(void *p, const char *name, void *closure)
 {
   DebugWrapperTraversalCallback* callback =
     static_cast<DebugWrapperTraversalCallback*>(closure);
-  callback->NoteScriptChild(langID, p);
+  callback->NoteJSChild(p);
 }
 
 // static
 void
 nsContentUtils::CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder,
                                         nsWrapperCache* aCache)
 {
   JSObject* wrapper = aCache->GetWrapper();
@@ -6634,18 +6637,17 @@ nsContentUtils::ReleaseWrapper(nsISuppor
 // static
 void
 nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
                              void *aClosure)
 {
   if (aCache->PreservingWrapper()) {
     JSObject *wrapper = aCache->GetWrapperPreserveColor();
     if (wrapper) {
-      aCallback(nsIProgrammingLanguage::JAVASCRIPT, wrapper,
-                "Preserved wrapper", aClosure);
+      aCallback(wrapper, "Preserved wrapper", aClosure);
     }
   }
 }
 
 nsresult
 nsContentUtils::JSArrayToAtomArray(JSContext* aCx, const JS::Value& aJSArray,
                                    nsCOMArray<nsIAtom>& aRetVal)
 {
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -6627,19 +6627,19 @@ nsDocument::RemoveFromRadioGroup(const n
   nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
   NS_ENSURE_TRUE(radioGroup, NS_OK);
 
   radioGroup->mRadioButtons.RemoveObject(aRadio);
 
   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
   NS_ASSERTION(element, "radio controls have to be content elements");
   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
+    NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
+                 "mRequiredRadioCount about to wrap below 0!");
     radioGroup->mRequiredRadioCount--;
-    NS_ASSERTION(radioGroup->mRequiredRadioCount >= 0,
-                 "mRequiredRadioCount shouldn't be negative!");
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::WalkRadioGroup(const nsAString& aName,
                            nsIRadioVisitor* aVisitor,
                            bool aFlushContent)
@@ -6680,19 +6680,19 @@ nsDocument::RadioRequiredChanged(const n
     return;
   }
 
   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
   NS_ASSERTION(element, "radio controls have to be content elements");
   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
     radioGroup->mRequiredRadioCount++;
   } else {
+    NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
+                 "mRequiredRadioCount about to wrap below 0!");
     radioGroup->mRequiredRadioCount--;
-    NS_ASSERTION(radioGroup->mRequiredRadioCount >= 0,
-                 "mRequiredRadioCount shouldn't be negative!");
   }
 }
 
 bool
 nsDocument::GetValueMissingState(const nsAString& aName) const
 {
   nsRadioGroupStruct* radioGroup = nsnull;
   // TODO: we should call GetRadioGroup here (and make it const) but for that
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1706,18 +1706,22 @@ GK_ATOM(onMozTapGesture, "onMozTapGestur
 GK_ATOM(onMozPressTapGesture, "onMozPressTapGesture")
 
 // Touch events
 GK_ATOM(onMozTouchDown, "onMozTouchDown")
 GK_ATOM(onMozTouchMove, "onMozTouchMove")
 GK_ATOM(onMozTouchUp, "onMozTouchUp")
 
 // orientation support
+GK_ATOM(ondevicemotion, "ondevicemotion")
 GK_ATOM(ondeviceorientation, "ondeviceorientation")
-GK_ATOM(ondevicemotion, "ondevicemotion")
+GK_ATOM(ondeviceproximity, "ondeviceproximity")
+
+// light sensor support
+GK_ATOM(ondevicelight, "ondevicelight")
 
 //---------------------------------------------------------------------------
 // Special atoms
 //---------------------------------------------------------------------------
 
 // Node types
 GK_ATOM(cdataTagName, "#cdata-section")
 GK_ATOM(commentTagName, "#comment")
--- a/content/events/public/nsEventNameList.h
+++ b/content/events/public/nsEventNameList.h
@@ -450,16 +450,24 @@ WINDOW_EVENT(unload,
 WINDOW_ONLY_EVENT(devicemotion,
                   NS_DEVICE_MOTION,
                   EventNameType_None,
                   NS_EVENT)
 WINDOW_ONLY_EVENT(deviceorientation,
                   NS_DEVICE_ORIENTATION,
                   EventNameType_None,
                   NS_EVENT)
+WINDOW_ONLY_EVENT(deviceproximity,
+                  NS_DEVICE_PROXIMITY,
+                  EventNameType_None,
+                  NS_EVENT)
+WINDOW_ONLY_EVENT(devicelight,
+                  NS_DEVICE_LIGHT,
+                  EventNameType_None,
+                  NS_EVENT)
 
 TOUCH_EVENT(touchstart,
             NS_TOUCH_START,
             EventNameType_All,
             NS_TOUCH_EVENT)
 TOUCH_EVENT(touchend,
             NS_TOUCH_END,
             EventNameType_All,
--- a/content/events/public/nsIPrivateDOMEvent.h
+++ b/content/events/public/nsIPrivateDOMEvent.h
@@ -87,18 +87,22 @@ nsresult
 NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsKeyEvent *aEvent);
 nsresult
 NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsCompositionEvent *aEvent);
 nsresult
 NS_NewDOMMutationEvent(nsIDOMEvent** aResult NS_OUTPARAM, nsPresContext* aPresContext, class nsMutationEvent* aEvent);
 nsresult
 NS_NewDOMPopupBlockedEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
+NS_NewDOMDeviceProximityEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent *aEvent);
+nsresult
 NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
+NS_NewDOMDeviceLightEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
+nsresult
 NS_NewDOMDeviceMotionEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMTextEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsTextEvent* aEvent);
 nsresult
 NS_NewDOMBeforeUnloadEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMPageTransitionEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -46,30 +46,32 @@ MODULE		= content
 LIBRARY_NAME	= gkconevents_s
 LIBXUL_LIBRARY  = 1
 
 EXPORTS		= \
 		nsEventStateManager.h \
 		nsEventListenerManager.h \
 		nsDOMEventTargetHelper.h \
 		$(NULL)
-		
+
 CPPSRCS		= \
 		nsEventListenerManager.cpp \
 		nsEventStateManager.cpp \
 		nsDOMEvent.cpp \
 		nsDOMDataContainerEvent.cpp \
 		nsDOMUIEvent.cpp \
 		nsDOMKeyboardEvent.cpp \
 		nsDOMTextEvent.cpp \
 		nsDOMMouseEvent.cpp \
 		nsDOMMouseScrollEvent.cpp \
 		nsDOMDragEvent.cpp \
 		nsDOMMutationEvent.cpp \
 		nsDOMPopupBlockedEvent.cpp \
+		nsDOMDeviceProximityEvent.cpp \
+		nsDOMDeviceLightEvent.cpp \
 		nsDOMDeviceOrientationEvent.cpp \
 		nsDOMDeviceMotionEvent.cpp \
 		nsDOMBeforeUnloadEvent.cpp \
 		nsDOMPageTransitionEvent.cpp \
 		nsDOMXULCommandEvent.cpp \
 		nsDOMCommandEvent.cpp \
 		nsDOMMessageEvent.cpp \
 		nsPaintRequest.cpp \
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMDeviceLightEvent.cpp
@@ -0,0 +1,58 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDOMDeviceLightEvent.h"
+#include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
+
+NS_IMPL_ADDREF_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
+
+DOMCI_DATA(DeviceLightEvent, nsDOMDeviceLightEvent)
+
+NS_INTERFACE_MAP_BEGIN(nsDOMDeviceLightEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceLightEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceLightEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMETHODIMP
+nsDOMDeviceLightEvent::InitDeviceLightEvent(const nsAString & aEventTypeArg,
+                                            bool aCanBubbleArg,
+                                            bool aCancelableArg,
+                                            double aValue)
+{
+  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mValue = aValue;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceLightEvent::GetValue(double *aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+  *aValue = mValue;
+  return NS_OK;
+}
+
+nsresult
+nsDOMDeviceLightEvent::InitFromCtor(const nsAString& aType,
+                                    JSContext* aCx, jsval* aVal)
+{
+  mozilla::dom::DeviceLightEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitDeviceLightEvent(aType, d.bubbles, d.cancelable, d.value);
+}
+
+nsresult
+NS_NewDOMDeviceLightEvent(nsIDOMEvent** aInstancePtrResult,
+                          nsPresContext* aPresContext,
+                          nsEvent *aEvent) 
+{
+  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
+  nsDOMDeviceLightEvent* it = new nsDOMDeviceLightEvent(aPresContext, aEvent);
+  return CallQueryInterface(it, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMDeviceLightEvent.h
@@ -0,0 +1,36 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsDOMDeviceLightEvent_h__
+#define nsDOMDeviceLightEvent_h__
+
+#include "nsIDOMDeviceLightEvent.h"
+#include "nsDOMEvent.h"
+
+class nsDOMDeviceLightEvent
+ : public nsDOMEvent
+ , public nsIDOMDeviceLightEvent
+{
+public:
+
+  nsDOMDeviceLightEvent(nsPresContext* aPresContext, nsEvent* aEvent)
+  : nsDOMEvent(aPresContext, aEvent),
+    mValue(0) {}
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // Forward to nsDOMEvent
+  NS_FORWARD_TO_NSDOMEVENT
+
+  // nsIDOMDeviceLightEvent Interface
+  NS_DECL_NSIDOMDEVICELIGHTEVENT
+
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx,
+                                jsval* aVal);
+protected:
+  double mValue;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMDeviceProximityEvent.cpp
@@ -0,0 +1,81 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDOMDeviceProximityEvent.h"
+#include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
+
+NS_IMPL_ADDREF_INHERITED(nsDOMDeviceProximityEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(nsDOMDeviceProximityEvent, nsDOMEvent)
+
+DOMCI_DATA(DeviceProximityEvent, nsDOMDeviceProximityEvent)
+
+NS_INTERFACE_MAP_BEGIN(nsDOMDeviceProximityEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceProximityEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceProximityEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMETHODIMP
+nsDOMDeviceProximityEvent::InitDeviceProximityEvent(const nsAString & aEventTypeArg,
+                                                    bool aCanBubbleArg,
+                                                    bool aCancelableArg,
+                                                    double aValue,
+                                                    double aMin,
+                                                    double aMax)
+{
+  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
+  NS_ENSURE_SUCCESS(rv, rv);
+    
+  mValue = aValue;
+  mMin = aMin;
+  mMax = aMax;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceProximityEvent::GetValue(double *aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+
+  *aValue = mValue;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceProximityEvent::GetMin(double *aMin)
+{
+  NS_ENSURE_ARG_POINTER(aMin);
+
+  *aMin = mMin;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMDeviceProximityEvent::GetMax(double *aMax)
+{
+  NS_ENSURE_ARG_POINTER(aMax);
+
+  *aMax = mMax;
+  return NS_OK;
+}
+
+nsresult
+nsDOMDeviceProximityEvent::InitFromCtor(const nsAString& aType,
+                                        JSContext* aCx, jsval* aVal)
+{
+  mozilla::dom::DeviceProximityEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return InitDeviceProximityEvent(aType, d.bubbles, d.cancelable, d.value, d.min, d.max);
+}
+
+nsresult
+NS_NewDOMDeviceProximityEvent(nsIDOMEvent** aInstancePtrResult,
+                              nsPresContext* aPresContext,
+                              nsEvent *aEvent)
+{
+  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
+  nsDOMDeviceProximityEvent* it = new nsDOMDeviceProximityEvent(aPresContext, aEvent);
+  return CallQueryInterface(it, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/nsDOMDeviceProximityEvent.h
@@ -0,0 +1,38 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsDOMDeviceProximityEvent_h__
+#define nsDOMDeviceProximityEvent_h__
+
+#include "nsIDOMDeviceProximityEvent.h"
+#include "nsDOMEvent.h"
+
+class nsDOMDeviceProximityEvent
+ : public nsDOMEvent
+ , public nsIDOMDeviceProximityEvent
+{
+public:
+
+ nsDOMDeviceProximityEvent(nsPresContext* aPresContext, nsEvent* aEvent)
+  : nsDOMEvent(aPresContext, aEvent),
+    mValue(-1),
+    mMin(0),
+    mMax(0) {}
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // Forward to nsDOMEvent
+  NS_FORWARD_TO_NSDOMEVENT
+
+  // nsIDOMDeviceProximityEvent Interface
+  NS_DECL_NSIDOMDEVICEPROXIMITYEVENT
+
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx,
+                                jsval* aVal);
+protected:
+  double mValue, mMin, mMax;
+};
+
+#endif
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -121,17 +121,19 @@ static const char* const sEventNames[] =
   "touchenter",
   "touchleave",
   "MozScrolledAreaChanged",
   "transitionend",
   "animationstart",
   "animationend",
   "animationiteration",
   "devicemotion",
-  "deviceorientation"
+  "deviceorientation",
+  "deviceproximity",
+  "devicelight"
 };
 
 static char *sPopupAllowedEvents;
 
 
 nsDOMEvent::nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent)
 {
   mPrivateDataDuplicated = false;
@@ -1548,16 +1550,20 @@ const char* nsDOMEvent::GetEventName(PRU
   case NS_ANIMATION_END:
     return sEventNames[eDOMEvents_animationend];
   case NS_ANIMATION_ITERATION:
     return sEventNames[eDOMEvents_animationiteration];
   case NS_DEVICE_MOTION:
     return sEventNames[eDOMEvents_devicemotion];
   case NS_DEVICE_ORIENTATION:
     return sEventNames[eDOMEvents_deviceorientation];
+  case NS_DEVICE_PROXIMITY:
+    return sEventNames[eDOMEvents_deviceproximity];
+  case NS_DEVICE_LIGHT:
+    return sEventNames[eDOMEvents_devicelight];
   case NS_FULLSCREENCHANGE:
     return sEventNames[eDOMEvents_mozfullscreenchange];
   case NS_FULLSCREENERROR:
     return sEventNames[eDOMEvents_mozfullscreenerror];
   default:
     break;
   }
   // XXXldb We can hit this case for nsEvent objects that we didn't
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -204,17 +204,19 @@ public:
     eDOMEvents_touchenter,
     eDOMEvents_touchleave,
     eDOMEvents_MozScrolledAreaChanged,
     eDOMEvents_transitionend,
     eDOMEvents_animationstart,
     eDOMEvents_animationend,
     eDOMEvents_animationiteration,
     eDOMEvents_devicemotion,
-    eDOMEvents_deviceorientation
+    eDOMEvents_deviceorientation,
+    eDOMEvents_deviceproximity,
+    eDOMEvents_devicelight
   };
 
   nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent);
   virtual ~nsDOMEvent();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMEvent, nsIDOMEvent)
 
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -285,16 +285,20 @@ nsEventListenerManager::AddEventListener
       // If aType is NS_MUTATION_SUBTREEMODIFIED, we need to listen all
       // mutations. nsContentUtils::HasMutationListeners relies on this.
       window->SetMutationListeners((aType == NS_MUTATION_SUBTREEMODIFIED) ?
                                    kAllMutationBits :
                                    MutationBitForEventType(aType));
     }
   } else if (aTypeAtom == nsGkAtoms::ondeviceorientation) {
     EnableDevice(NS_DEVICE_ORIENTATION);
+  } else if (aTypeAtom == nsGkAtoms::ondeviceproximity) {
+    EnableDevice(NS_DEVICE_PROXIMITY);
+  } else if (aTypeAtom == nsGkAtoms::ondevicelight) {
+    EnableDevice(NS_DEVICE_LIGHT);
   } else if (aTypeAtom == nsGkAtoms::ondevicemotion) {
     EnableDevice(NS_DEVICE_MOTION);
   } else if ((aType >= NS_MOZTOUCH_DOWN && aType <= NS_MOZTOUCH_UP) ||
              (aTypeAtom == nsGkAtoms::ontouchstart ||
               aTypeAtom == nsGkAtoms::ontouchend ||
               aTypeAtom == nsGkAtoms::ontouchmove ||
               aTypeAtom == nsGkAtoms::ontouchenter ||
               aTypeAtom == nsGkAtoms::ontouchleave ||
@@ -341,16 +345,22 @@ nsEventListenerManager::EnableDevice(PRU
   }
 
   NS_ASSERTION(window->IsInnerWindow(), "Target should not be an outer window");
 
   switch (aType) {
     case NS_DEVICE_ORIENTATION:
       window->EnableDeviceSensor(SENSOR_ORIENTATION);
       break;
+    case NS_DEVICE_PROXIMITY:
+      window->EnableDeviceSensor(SENSOR_PROXIMITY);
+      break;
+    case NS_DEVICE_LIGHT:
+      window->EnableDeviceSensor(SENSOR_LIGHT);
+      break;
     case NS_DEVICE_MOTION:
       window->EnableDeviceSensor(SENSOR_ACCELERATION);
       window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
       window->EnableDeviceSensor(SENSOR_GYROSCOPE);
       break;
     default:
       NS_WARNING("Enabling an unknown device sensor.");
       break;
@@ -371,16 +381,22 @@ nsEventListenerManager::DisableDevice(PR
     case NS_DEVICE_ORIENTATION:
       window->DisableDeviceSensor(SENSOR_ORIENTATION);
       break;
     case NS_DEVICE_MOTION:
       window->DisableDeviceSensor(SENSOR_ACCELERATION);
       window->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
       window->DisableDeviceSensor(SENSOR_GYROSCOPE);
       break;
+    case NS_DEVICE_PROXIMITY:
+      window->DisableDeviceSensor(SENSOR_PROXIMITY);
+      break;
+    case NS_DEVICE_LIGHT:
+      window->DisableDeviceSensor(SENSOR_LIGHT);
+      break;
     default:
       NS_WARNING("Disabling an unknown device sensor.");
       break;
   }
 }
 
 void
 nsEventListenerManager::RemoveEventListener(nsIDOMEventListener *aListener, 
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -364,16 +364,35 @@ ok(e.cancelable, "Event should be cancel
 is(e.key, "key", "Wrong value");
 is(e.oldValue, "oldValue", "Wrong value");
 is(e.newValue, "newValue", "Wrong value");
 is(e.url, "url", "Wrong value");
 is(e.storageArea, localStorage, "Wrong value");
 document.dispatchEvent(e);
 is(receivedEvent, e, "Wrong event!");
 
+// DeviceProximityEvent
+e = new DeviceProximityEvent("hello", {min: 0, value: 1, max: 2});
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event should not be trusted");
+is(e.value, 1, "value should be 1");
+is(e.min, 0, "min should be 0");
+is(e.max, 2, "max should be 2");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+// DeviceLightEvent
+e = new DeviceLightEvent("hello", {value: 1} );
+ok(e.type, "hello", "Wrong event type!");
+ok(!e.isTrusted, "Event should not be trusted");
+is(e.value, 1, "value should be 1");
+document.dispatchEvent(e);
+is(receivedEvent, e, "Wrong event!");
+
+
 // MouseEvent
 
 try {
   e = new MouseEvent();
 } catch(exp) {
   ex = true;
 }
 ok(ex, "First parameter is required!");
--- a/content/media/test/test_played.html
+++ b/content/media/test/test_played.html
@@ -157,24 +157,23 @@ var tests = [
     }, false);
   }
 },
 // Seek repeatedly without playing. No range should appear.
 {
   setup : function(element) {
     let index = 1;
 
-    element.addEventListener('ended', function() {
-      is(element.played.length, 0, "element.played.length should be 0");
-      finish_test(element);
-    }, false);
-
     element.addEventListener('seeked', function() {
       index++;
       element.currentTime = index * element.duration / 5;
+      is(element.played.length, 0, "element.played.length should be 0");
+      if (index == 5) {
+        finish_test(element);
+      }
     }, false);
 
     element.addEventListener('loadedmetadata', function() {
       element.currentTime = element.duration / 5;
     }, false);
   }
 }
 ];
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -489,21 +489,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo)
   if (tmp->mBindingTable) {
     ProtoTracer closure = { aCallback, aClosure };
     tmp->mBindingTable->Enumerate(TraceProtos, &closure);
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 static void
-UnmarkXBLJSObject(PRUint32 aLangID, void* aP, const char* aName, void* aClosure)
+UnmarkXBLJSObject(void* aP, const char* aName, void* aClosure)
 {
-  if (aLangID == nsIProgrammingLanguage::JAVASCRIPT) {
-    xpc_UnmarkGrayObject(static_cast<JSObject*>(aP));
-  }
+  xpc_UnmarkGrayObject(static_cast<JSObject*>(aP));
 }
 
 static bool
 UnmarkProtos(nsHashKey* aKey, void* aData, void* aClosure)
 {
   nsXBLPrototypeBinding* proto = static_cast<nsXBLPrototypeBinding*>(aData);
   proto->Trace(UnmarkXBLJSObject, nsnull);
   return kHashEnumerateNext;
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -258,17 +258,17 @@ nsXBLProtoImplMethod::CompileMember(nsIS
 
   return NS_OK;
 }
 
 void
 nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const
 {
   if (IsCompiled() && mJSMethodObject) {
-    aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSMethodObject, "mJSMethodObject", aClosure);
+    aCallback(mJSMethodObject, "mJSMethodObject", aClosure);
   }
 }
 
 nsresult
 nsXBLProtoImplMethod::Read(nsIScriptContext* aContext,
                            nsIObjectInputStream* aStream)
 {
   nsresult rv = XBL_DeserializeFunction(aContext, aStream, &mJSMethodObject);
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -339,23 +339,21 @@ nsXBLProtoImplProperty::CompileMember(ns
   
   return rv;
 }
 
 void
 nsXBLProtoImplProperty::Trace(TraceCallback aCallback, void *aClosure) const
 {
   if (mJSAttributes & JSPROP_GETTER) {
-    aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSGetterObject,
-              "mJSGetterObject", aClosure);
+    aCallback(mJSGetterObject, "mJSGetterObject", aClosure);
   }
 
   if (mJSAttributes & JSPROP_SETTER) {
-    aCallback(nsIProgrammingLanguage::JAVASCRIPT, mJSSetterObject,
-              "mJSSetterObject", aClosure);
+    aCallback(mJSSetterObject, "mJSSetterObject", aClosure);
   }
 }
 
 nsresult
 nsXBLProtoImplProperty::Read(nsIScriptContext* aContext,
                              nsIObjectInputStream* aStream,
                              XBLBindingSerializeDetails aType)
 {
--- a/content/xslt/src/base/txList.cpp
+++ b/content/xslt/src/base/txList.cpp
@@ -55,68 +55,22 @@ txList::txList() {
 /**
  * txList destructor, cleans up ListItems, but will not delete the Object
  * references
 */
 txList::~txList() {
     clear();
 } //-- ~txList
 
-nsresult txList::insert(int index, void* objPtr)
-{
-    if (index >= itemCount) {
-        return insertBefore(objPtr, 0);
-    }
-    // add inside the list
-    ListItem* nextItem = firstItem;
-    for (int i = 0; i < index; i++)
-        nextItem = nextItem->nextItem;
-    return insertBefore(objPtr, nextItem);
-} //-- insert
-
 nsresult txList::add(void* objPtr)
 {
     return insertBefore(objPtr, 0);
 } //-- add
 
 /**
- * Returns the object located at the given index. This may
- * be slow or fast depending on the implementation.
- * Note:
- * Currently this list is implemented via a linked list, so
- * this method will be slow (unless the list only has a couple
- * members) as it will need traverse the links each time
- * @return the object located at the given index
-**/
-void* txList::get(int index) {
-
-    if (index < 0 || index >= itemCount)
-        return 0;
-
-    int c = 0;
-    ListItem* item = firstItem;
-    while ((c != index) && item) {
-        item = item->nextItem;
-        ++c;
-    }
-
-    if (item)
-        return item->objPtr;
-    return 0;
-} //-- get(int)
-
-txList::ListItem* txList::getFirstItem() {
-    return firstItem;
-} //-- getFirstItem
-
-txList::ListItem* txList::getLastItem() {
-    return lastItem;
-} //-- getLastItem
-
-/**
  * Returns the number of items in this txList
 **/
 PRInt32 List::getLength() {
    return itemCount;
 } //-- getLength
 
 
 /**
@@ -174,30 +128,16 @@ nsresult txList::insertBefore(void* objP
     }
 
     // increase the item count
     ++itemCount;
     
     return NS_OK;
 } //-- insertBefore
 
-void* txList::remove(void* objPtr) {
-   ListItem* item = firstItem;
-   while (item) {
-      if (item->objPtr == objPtr) {
-         remove(item);
-         delete item;
-         return objPtr;
-      }
-      item = item->nextItem;
-   }
-   // not in list
-   return 0;
-} //-- remove
-
 txList::ListItem* txList::remove(ListItem* item) {
 
     if (!item)
         return item;
 
     //-- adjust the previous item's next pointer
     if (item->prevItem) {
         item->prevItem->nextItem = item->nextItem;
@@ -285,31 +225,16 @@ bool txListIterator::hasNext() {
         hasNext = (currentItem->nextItem != 0);
     else if (!atEndOfList)
         hasNext = (list->firstItem != 0);
 
     return hasNext;
 } //-- hasNext
 
 /**
- * Returns true if a successful call to the previous() method can be made
- * @return true if a successful call to the previous() method can be made,
- * otherwise false
-**/
-bool txListIterator::hasPrevious() {
-    bool hasPrevious = false;
-    if (currentItem)
-        hasPrevious = (currentItem->prevItem != 0);
-    else if (atEndOfList)
-        hasPrevious = (list->lastItem != 0);
-
-    return hasPrevious;
-} //-- hasPrevious
-
-/**
  * Returns the next Object pointer in the list
 **/
 void* txListIterator::next() {
 
     void* obj = 0;
     if (currentItem)
         currentItem = currentItem->nextItem;
     else if (!atEndOfList)
@@ -350,50 +275,16 @@ void* txListIterator::current() {
 
     if (currentItem)
         return currentItem->objPtr;
 
     return 0;
 } //-- current
 
 /**
- * Moves the specified number of steps
-**/
-void* txListIterator::advance(int i) {
-
-    void* obj = 0;
-
-    if (i > 0) {
-        if (!currentItem && !atEndOfList) {
-            currentItem = list->firstItem;
-            --i;
-        }
-        for (; currentItem && i > 0; i--)
-            currentItem = currentItem->nextItem;
-        
-        atEndOfList = currentItem == 0;
-    }
-    else if (i < 0) {
-        if (!currentItem && atEndOfList) {
-            currentItem = list->lastItem;
-            ++i;
-        }
-        for (; currentItem && i < 0; i++)
-            currentItem = currentItem->prevItem;
-
-        atEndOfList = false;
-    }
-
-    if (currentItem)
-        obj = currentItem->objPtr;
-
-    return obj;
-} //-- advance
-
-/**
  * Removes the Object last returned by the next() or previous() methods;
  * @return the removed Object pointer
 **/
 void* txListIterator::remove() {
 
     void* obj = 0;
     if (currentItem) {
         obj = currentItem->objPtr;
--- a/content/xslt/src/base/txList.h
+++ b/content/xslt/src/base/txList.h
@@ -58,66 +58,46 @@ public:
     txList();
 
     /**
      * txList destructor, object references will not be deleted.
     **/
     ~txList();
 
     /**
-     * Returns the object located at the given index. This may
-     * be slow or fast depending on the implementation.
-     * @return the object located at the given index
-    **/
-    void* get(int index);
-
-    /**
      * Returns the number of items in this txList
     **/
     PRInt32 getLength();
 
     /**
      * Returns true if there are no items in this txList
      */
     inline bool isEmpty()
     {
         return itemCount == 0;
     }
 
     /**
-     * Adds the given Object to the specified position in the list
-    **/
-    nsresult insert(int index, void* objPtr);
-
-    /**
      * Adds the given Object to the list
     **/
     nsresult add(void* objPtr);
 
-    /**
-     * Removes the given Object pointer from the list
-    **/
-    void* remove(void* objPtr);
-    
     /*
      * Removes all the objects from the list
      */
     void clear();
 
 protected:
 
     struct ListItem {
         ListItem* nextItem;
         ListItem* prevItem;
         void* objPtr;
     };
 
-    ListItem* getFirstItem();
-    ListItem* getLastItem();
-
     /**
      * Removes the given ListItem pointer from the list
     **/
     ListItem* remove(ListItem* sItem);
 
 private:
       txList(const txList& aOther); // not implemented
 
@@ -162,43 +142,31 @@ public:
     /**
      * Returns true if a successful call to the next() method can be made
      * @return true if a successful call to the next() method can be made,
      * otherwise false
     **/
     bool  hasNext();
 
     /**
-     * Returns true if a successful call to the previous() method can be made
-     * @return true if a successful call to the previous() method can be made,
-     * otherwise false
-    **/
-    bool  hasPrevious();
-
-    /**
      * Returns the next Object pointer from the list
     **/
     void* next();
 
     /**
      * Returns the previous Object pointer from the list
     **/
     void* previous();
     
     /**
      * Returns the current Object
     **/
     void* current();
     
     /**
-     * Moves the specified number of steps
-    **/
-    void* advance(int i);
-
-    /**
      * Removes the Object last returned by the next() or previous() methods;
      * @return the removed Object pointer
     **/
     void* remove();
 
     /**
      * Resets the current location within the txList to the beginning of the txList
     **/
--- a/content/xslt/src/xpath/txExprLexer.cpp
+++ b/content/xslt/src/xpath/txExprLexer.cpp
@@ -70,33 +70,35 @@ txExprLexer::~txExprLexer()
     tok = temp;
   }
   mCurrentItem = nsnull;
 }
 
 Token*
 txExprLexer::nextToken()
 {
-  NS_ASSERTION(mCurrentItem, "nextToken called beyoned the end");
+  if (!mCurrentItem) {
+    NS_NOTREACHED("nextToken called on uninitialized lexer");
+    return nsnull;
+  }
+
+  if (mCurrentItem->mType == Token::END) {
+    // Do not progress beyond the end token
+    return mCurrentItem;
+  }
+
   Token* token = mCurrentItem;
   mCurrentItem = mCurrentItem->mNext;
   return token;
 }
 
 void
-txExprLexer::pushBack()
-{
-  mCurrentItem = mCurrentItem ? mCurrentItem->mPrevious : mLastItem;
-}
-
-void
 txExprLexer::addToken(Token* aToken)
 {
   if (mLastItem) {
-    aToken->mPrevious = mLastItem;
     mLastItem->mNext = aToken;
   }
   if (!mFirstItem) {
     mFirstItem = aToken;
     mCurrentItem = aToken;
   }
   mLastItem = aToken;
   ++mTokenCount;
--- a/content/xslt/src/xpath/txExprLexer.h
+++ b/content/xslt/src/xpath/txExprLexer.h
@@ -123,39 +123,35 @@ public:
      * Constructors
      */
     typedef nsASingleFragmentString::const_char_iterator iterator;
 
     Token(iterator aStart, iterator aEnd, Type aType)
         : mStart(aStart),
           mEnd(aEnd),
           mType(aType),
-          mNext(nsnull),
-          mPrevious(nsnull)
+          mNext(nsnull)
     {
     }
     Token(iterator aChar, Type aType)
         : mStart(aChar),
           mEnd(aChar + 1),
           mType(aType),
-          mNext(nsnull),
-          mPrevious(nsnull)
+          mNext(nsnull)
     {
     }
 
     const nsDependentSubstring Value()
     {
         return Substring(mStart, mEnd);
     }
 
     iterator mStart, mEnd;
     Type mType;
     Token* mNext;
-    // XXX mPrevious needed for pushBack(), do we pushBack more than once?
-    Token* mPrevious;
 };
 
 /**
  * A class for splitting an "Expr" String into tokens and
  * performing  basic Lexical Analysis.
  *
  * This class was ported from XSL:P, an open source Java based XSL processor
  */
@@ -181,22 +177,29 @@ public:
 
     /**
      * Functions for iterating over the TokenList
      */
 
     Token* nextToken();
     Token* peek()
     {
+        NS_ASSERTION(mCurrentItem, "peek called uninitialized lexer");
         return mCurrentItem;
     }
-    void pushBack();
+    Token* peekAhead()
+    {
+        NS_ASSERTION(mCurrentItem, "peekAhead called on uninitialized lexer");
+        // Don't peek past the end node
+        return (mCurrentItem && mCurrentItem->mNext) ? mCurrentItem->mNext : mCurrentItem;
+    }
     bool hasMoreTokens()
     {
-        return (mCurrentItem->mType != Token::END);
+        NS_ASSERTION(mCurrentItem, "HasMoreTokens called on uninitialized lexer");
+        return (mCurrentItem && mCurrentItem->mType != Token::END);
     }
 
     /**
      * Trivial Tokens
      */
     //-- LF, changed to enum
     enum _TrivialTokens {
         D_QUOTE        = '\"',
--- a/content/xslt/src/xpath/txExprParser.cpp
+++ b/content/xslt/src/xpath/txExprParser.cpp
@@ -332,19 +332,19 @@ txExprParser::createExpr(txExprLexer& le
                 expr.forget();
                 expr = fcExpr;
             }
             else {
                 expr = new UnaryExpr(expr.forget());
             }
         }
 
-        Token* tok = lexer.nextToken();
-        short tokPrecedence = precedence(tok);
+        short tokPrecedence = precedence(lexer.peek());
         if (tokPrecedence != 0) {
+            Token* tok = lexer.nextToken();
             while (!exprs.isEmpty() && tokPrecedence
                    <= precedence(static_cast<Token*>(ops.peek()))) {
                 // can't use expr as argument due to order of evaluation
                 nsAutoPtr<Expr> left(static_cast<Expr*>(exprs.pop()));
                 nsAutoPtr<Expr> right(expr);
                 rv = createBinaryExpr(left, right,
                                       static_cast<Token*>(ops.pop()),
                                       getter_Transfers(expr));
@@ -352,17 +352,16 @@ txExprParser::createExpr(txExprLexer& le
                     done = true;
                     break;
                 }
             }
             exprs.push(expr.forget());
             ops.push(tok);
         }
         else {
-            lexer.pushBack();
             done = true;
         }
     }
 
     while (NS_SUCCEEDED(rv) && !exprs.isEmpty()) {
         nsAutoPtr<Expr> left(static_cast<Expr*>(exprs.pop()));
         nsAutoPtr<Expr> right(expr);
         rv = createBinaryExpr(left, right, static_cast<Token*>(ops.pop()),
@@ -380,55 +379,57 @@ txExprParser::createExpr(txExprLexer& le
 
 nsresult
 txExprParser::createFilterOrStep(txExprLexer& lexer, txIParseContext* aContext,
                                  Expr** aResult)
 {
     *aResult = nsnull;
 
     nsresult rv = NS_OK;
-    Token* tok = lexer.nextToken();
+    Token* tok = lexer.peek();
 
     nsAutoPtr<Expr> expr;
     switch (tok->mType) {
         case Token::FUNCTION_NAME_AND_PAREN:
-            lexer.pushBack();
             rv = createFunctionCall(lexer, aContext, getter_Transfers(expr));
             NS_ENSURE_SUCCESS(rv, rv);
             break;
         case Token::VAR_REFERENCE :
+            lexer.nextToken();
             {
                 nsCOMPtr<nsIAtom> prefix, lName;
                 PRInt32 nspace;
                 nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix),
                                            aContext, getter_AddRefs(lName),
                                            nspace);
                 NS_ENSURE_SUCCESS(rv, rv);
                 expr = new VariableRefExpr(prefix, lName, nspace);
             }
             break;
         case Token::L_PAREN:
+            lexer.nextToken();
             rv = createExpr(lexer, aContext, getter_Transfers(expr));
             NS_ENSURE_SUCCESS(rv, rv);
 
-            if (lexer.nextToken()->mType != Token::R_PAREN) {
-                lexer.pushBack();
+            if (lexer.peek()->mType != Token::R_PAREN) {
                 return NS_ERROR_XPATH_PAREN_EXPECTED;
             }
+            lexer.nextToken();
             break;
         case Token::LITERAL :
+            lexer.nextToken();
             expr = new txLiteralExpr(tok->Value());
             break;
         case Token::NUMBER:
         {
+            lexer.nextToken();
             expr = new txLiteralExpr(txDouble::toDouble(tok->Value()));
             break;
         }
         default:
-            lexer.pushBack();
             return createLocationStep(lexer, aContext, aResult);
     }
 
     if (lexer.peek()->mType == Token::L_BRACKET) {
         nsAutoPtr<FilterExpr> filterExpr(new FilterExpr(expr));
 
         expr.forget();
 
@@ -577,35 +578,35 @@ txExprParser::createLocationStep(txExprL
             break;
         default:
             break;
     }
 
     //-- get NodeTest unless an AbbreviatedStep was found
     nsresult rv = NS_OK;
     if (!nodeTest) {
-        tok = lexer.nextToken();
+        tok = lexer.peek();
 
         if (tok->mType == Token::CNAME) {
+            lexer.nextToken();
             // resolve QName
             nsCOMPtr<nsIAtom> prefix, lName;
             PRInt32 nspace;
             rv = resolveQName(tok->Value(), getter_AddRefs(prefix),
                               aContext, getter_AddRefs(lName),
                               nspace, true);
             NS_ENSURE_SUCCESS(rv, rv);
 
             nodeTest =
               new txNameTest(prefix, lName, nspace,
                              axisIdentifier == LocationStep::ATTRIBUTE_AXIS ?
                              static_cast<PRUint16>(txXPathNodeType::ATTRIBUTE_NODE) :
                              static_cast<PRUint16>(txXPathNodeType::ELEMENT_NODE));
         }
         else {
-            lexer.pushBack();
             rv = createNodeTypeTest(lexer, getter_Transfers(nodeTest));
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
     
     nsAutoPtr<LocationStep> lstep(new LocationStep(nodeTest, axisIdentifier));
 
     nodeTest.forget();
@@ -623,46 +624,50 @@ txExprParser::createLocationStep(txExprL
  * and node()
  */
 nsresult
 txExprParser::createNodeTypeTest(txExprLexer& lexer, txNodeTest** aTest)
 {
     *aTest = 0;
     nsAutoPtr<txNodeTypeTest> nodeTest;
 
-    Token* nodeTok = lexer.nextToken();
+    Token* nodeTok = lexer.peek();
 
     switch (nodeTok->mType) {
         case Token::COMMENT_AND_PAREN:
+            lexer.nextToken();
             nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE);
             break;
         case Token::NODE_AND_PAREN:
+            lexer.nextToken();
             nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE);
             break;
         case Token::PROC_INST_AND_PAREN:
+            lexer.nextToken();
             nodeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE);
             break;
         case Token::TEXT_AND_PAREN:
+            lexer.nextToken();
             nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE);
             break;
         default:
-            lexer.pushBack();
             return NS_ERROR_XPATH_NO_NODE_TYPE_TEST;
     }
+
     NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);
 
     if (nodeTok->mType == Token::PROC_INST_AND_PAREN &&
         lexer.peek()->mType == Token::LITERAL) {
         Token* tok = lexer.nextToken();
         nodeTest->setNodeName(tok->Value());
     }
-    if (lexer.nextToken()->mType != Token::R_PAREN) {
-        lexer.pushBack();
+    if (lexer.peek()->mType != Token::R_PAREN) {
         return NS_ERROR_XPATH_PAREN_EXPECTED;
     }
+    lexer.nextToken();
 
     *aTest = nodeTest.forget();
     return NS_OK;
 }
 
 /**
  * Creates a PathExpr using the given txExprLexer
  * @param lexer the txExprLexer for retrieving Tokens
@@ -674,22 +679,21 @@ txExprParser::createPathExpr(txExprLexer
     *aResult = nsnull;
 
     nsAutoPtr<Expr> expr;
 
     Token* tok = lexer.peek();
 
     // is this a root expression?
     if (tok->mType == Token::PARENT_OP) {
-        lexer.nextToken();
-        if (!isLocationStepToken(lexer.peek())) {
+        if (!isLocationStepToken(lexer.peekAhead())) {
+            lexer.nextToken();
             *aResult = new RootExpr();
             return NS_OK;
         }
-        lexer.pushBack();
     }
 
     // parse first step (possibly a FilterExpr)
     nsresult rv = NS_OK;
     if (tok->mType != Token::PARENT_OP &&
         tok->mType != Token::ANCESTOR_OP) {
         rv = createFilterOrStep(lexer, aContext, getter_Transfers(expr));
         NS_ENSURE_SUCCESS(rv, rv);
@@ -716,30 +720,29 @@ txExprParser::createPathExpr(txExprLexer
     rv = pathExpr->addExpr(expr, PathExpr::RELATIVE_OP);
     NS_ENSURE_SUCCESS(rv, rv);
 
     expr.forget();
 
     // this is ugly
     while (1) {
         PathExpr::PathOperator pathOp;
-        tok = lexer.nextToken();
-        switch (tok->mType) {
+        switch (lexer.peek()->mType) {
             case Token::ANCESTOR_OP :
                 pathOp = PathExpr::DESCENDANT_OP;
                 break;
             case Token::PARENT_OP :
                 pathOp = PathExpr::RELATIVE_OP;
                 break;
             default:
-                lexer.pushBack();
                 *aResult = pathExpr.forget();
                 return NS_OK;
         }
-        
+        lexer.nextToken();
+
         rv = createLocationStep(lexer, aContext, getter_Transfers(expr));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = pathExpr->addExpr(expr, pathOp);
         NS_ENSURE_SUCCESS(rv, rv);
 
         expr.forget();
     }
@@ -823,20 +826,20 @@ txExprParser::parsePredicates(PredicateL
         rv = createExpr(lexer, aContext, getter_Transfers(expr));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = aPredicateList->add(expr);
         NS_ENSURE_SUCCESS(rv, rv);
 
         expr.forget();
 
-        if (lexer.nextToken()->mType != Token::R_BRACKET) {
-            lexer.pushBack();
+        if (lexer.peek()->mType != Token::R_BRACKET) {
             return NS_ERROR_XPATH_BRACKET_EXPECTED;
         }
+        lexer.nextToken();
     }
     return NS_OK;
 }
 
 
 /**
  * Using the given lexer, parses the tokens if they represent a parameter list
  * If an error occurs a non-zero String pointer will be returned containing the
@@ -860,23 +863,24 @@ txExprParser::parseParameters(FunctionCa
         rv = createExpr(lexer, aContext, getter_Transfers(expr));
         NS_ENSURE_SUCCESS(rv, rv);
 
         if (aFnCall) {
             rv = aFnCall->addParam(expr.forget());
             NS_ENSURE_SUCCESS(rv, rv);
         }
                     
-        switch (lexer.nextToken()->mType) {
+        switch (lexer.peek()->mType) {
             case Token::R_PAREN :
+                lexer.nextToken();
                 return NS_OK;
             case Token::COMMA: //-- param separator
+                lexer.nextToken();
                 break;
             default:
-                lexer.pushBack();
                 return NS_ERROR_XPATH_PAREN_EXPECTED;
         }
     }
 
     NS_NOTREACHED("internal xpath parser error");
     return NS_ERROR_UNEXPECTED;
 }
 
--- a/content/xslt/src/xslt/txPatternParser.cpp
+++ b/content/xslt/src/xslt/txPatternParser.cpp
@@ -311,20 +311,21 @@ nsresult txPatternParser::createStepPatt
             return NS_ERROR_XPATH_PARSE_FAILURE;
         }
         aLexer.nextToken();
     }
     else if (tok->mType == Token::AT_SIGN) {
         aLexer.nextToken();
         isAttr = true;
     }
-    tok = aLexer.nextToken();
 
     txNodeTest* nodeTest;
-    if (tok->mType == Token::CNAME) {
+    if (aLexer.peek()->mType == Token::CNAME) {
+        tok = aLexer.nextToken();
+
         // resolve QName
         nsCOMPtr<nsIAtom> prefix, lName;
         PRInt32 nspace;
         rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
                           getter_AddRefs(lName), nspace, true);
         if (NS_FAILED(rv)) {
             // XXX error report namespace resolve failed
             return rv;
@@ -334,17 +335,16 @@ nsresult txPatternParser::createStepPatt
                             (PRUint16)txXPathNodeType::ATTRIBUTE_NODE :
                             (PRUint16)txXPathNodeType::ELEMENT_NODE;
         nodeTest = new txNameTest(prefix, lName, nspace, nodeType);
         if (!nodeTest) {
             return NS_ERROR_OUT_OF_MEMORY;
         }
     }
     else {
-        aLexer.pushBack();
         rv = createNodeTypeTest(aLexer, &nodeTest);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     nsAutoPtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr));
     if (!step) {
         delete nodeTest;
         return NS_ERROR_OUT_OF_MEMORY;
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -767,17 +767,17 @@ nsXULPDGlobalObject::GetScriptContext()
   }
 
   return mContext;
 }
 
 JSObject*
 nsXULPDGlobalObject::GetGlobalJSObject()
 {
-  return mJSObject;
+  return xpc_UnmarkGrayObject(mJSObject);
 }
 
 
 void
 nsXULPDGlobalObject::ClearGlobalObjectOwner()
 {
   NS_ASSERTION(!mCachedPrincipal, "This shouldn't ever be set until now!");
 
--- a/docshell/test/unit/test_pb_notification.js
+++ b/docshell/test/unit/test_pb_notification.js
@@ -2,22 +2,22 @@ if (typeof Cc === "undefined")
   Cc = Components.classes;
 if (typeof Ci === "undefined")
   Ci = Components.interfaces;
 
 function destroy_transient_docshell() {
   var docshell = Cc["@mozilla.org/docshell;1"].createInstance(Ci.nsIDocShell);
   docshell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing = true;
   do_test_pending();
-  do_timeout(0, Components.utils.forceGC);
+  Components.utils.schedulePreciseGC(function(){});
 }
 
 function run_test() {
   var obs = {
     observe: function(aSubject, aTopic, aData) {
       do_check_eq(aTopic, "last-pb-context-exited");
       do_test_finished();
     }
   };
   var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
   os.addObserver(obs, "last-pb-context-exited", false);
   destroy_transient_docshell();
-}
\ No newline at end of file
+}
--- a/docshell/test/unit_ipc/xpcshell.ini
+++ b/docshell/test/unit_ipc/xpcshell.ini
@@ -1,7 +1,5 @@
 [DEFAULT]
 head =
 tail =
 
 [test_pb_notification_ipc.js]
-# Bug 751575: Perma-fails with: command timed out: 1200 seconds without output
-skip-if = true
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -320,16 +320,18 @@
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsIDOMCSSMozDocumentRule.h"
 #include "nsIDOMMozCSSKeyframeRule.h"
 #include "nsIDOMMozCSSKeyframesRule.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsDOMCSSValueList.h"
+#include "nsIDOMDeviceProximityEvent.h"
+#include "nsIDOMDeviceLightEvent.h"
 #include "nsIDOMDeviceOrientationEvent.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMNodeIterator.h"
 #include "nsIDOMTreeWalker.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMXULCommandDispatcher.h"
@@ -527,17 +529,16 @@ using mozilla::dom::indexedDB::IDBWrappe
 #ifdef MOZ_B2G_RIL
 #include "Telephony.h"
 #include "TelephonyCall.h"
 #include "CallEvent.h"
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothAdapter.h"
-#include "BluetoothDevice.h"
 #endif
 
 #include "DOMError.h"
 #include "DOMRequest.h"
 
 #include "mozilla/Likely.h"
 
 #undef None // something included above defines this preprocessor symbol, maybe Xlib headers
@@ -809,16 +810,22 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(DragEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(KeyboardEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CompositionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PopupBlockedEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  // Device Light
+  NS_DEFINE_CLASSINFO_DATA(DeviceLightEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  // Device Proximity
+  NS_DEFINE_CLASSINFO_DATA(DeviceProximityEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   // Device Orientation
   NS_DEFINE_CLASSINFO_DATA(DeviceOrientationEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceMotionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceRotationRate, nsDOMGenericSH,
@@ -1635,18 +1642,16 @@ static nsDOMClassInfoData sClassInfoData
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
 #ifdef MOZ_B2G_BT
   NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
-                           EVENTTARGET_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 };
@@ -1690,16 +1695,19 @@ NS_DEFINE_EVENT_CTOR(Event)
 NS_DEFINE_EVENT_CTOR(CustomEvent)
 NS_DEFINE_EVENT_CTOR(PopStateEvent)
 NS_DEFINE_EVENT_CTOR(HashChangeEvent)
 NS_DEFINE_EVENT_CTOR(PageTransitionEvent)
 NS_DEFINE_EVENT_CTOR(CloseEvent)
 NS_DEFINE_EVENT_CTOR(MozSettingsEvent)
 NS_DEFINE_EVENT_CTOR(UIEvent)
 NS_DEFINE_EVENT_CTOR(MouseEvent)
+NS_DEFINE_EVENT_CTOR(DeviceLightEvent)
+NS_DEFINE_EVENT_CTOR(DeviceProximityEvent)
+
 nsresult
 NS_DOMStorageEventCtor(nsISupports** aInstancePtrResult)
 {
   nsDOMStorageEvent* e = new nsDOMStorageEvent();
   return CallQueryInterface(e, aInstancePtrResult);
 }
 
 struct nsConstructorFuncMapData
@@ -1723,16 +1731,18 @@ static const nsConstructorFuncMapData kC
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CustomEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PopStateEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(HashChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(PageTransitionEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(CloseEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozSettingsEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
+  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(DeviceProximityEvent)
+  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(DeviceLightEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
 };
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nsnull;
 nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nsnull;
 bool nsDOMClassInfo::sIsInitialized = false;
 bool nsDOMClassInfo::sDisableDocumentAllSupport = false;
@@ -2603,16 +2613,26 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(PopupBlockedEvent, nsIDOMPopupBlockedEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPopupBlockedEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(DeviceLightEvent, nsIDOMDeviceLightEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceLightEvent)
+    DOM_CLASSINFO_EVENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(DeviceProximityEvent, nsIDOMDeviceProximityEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceProximityEvent)
+    DOM_CLASSINFO_EVENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(DeviceOrientationEvent, nsIDOMDeviceOrientationEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DeviceMotionEvent, nsIDOMDeviceMotionEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceMotionEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
@@ -4412,20 +4432,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCallEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
   DOM_CLASSINFO_MAP_END
 #endif
 
 #ifdef MOZ_B2G_BT
   DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
-  DOM_CLASSINFO_MAP_END  
-  
-  DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(DOMError, nsIDOMDOMError)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMRequest, nsIDOMDOMRequest)
@@ -5476,18 +5492,18 @@ nsWindowSH::GetProperty(nsIXPConnectWrap
 
       nsGlobalWindow *frameWin = (nsGlobalWindow *)frame.get();
       NS_ASSERTION(frameWin->IsOuterWindow(), "GetChildFrame gave us an inner?");
 
       frameWin->EnsureInnerWindow();
 
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
       jsval v;
-      rv = WrapNative(cx, frameWin->GetGlobalJSObject(), frame,
-                      &NS_GET_IID(nsIDOMWindow), true, &v,
+      rv = WrapNative(cx, xpc_UnmarkGrayObject(frameWin->GetGlobalJSObject()),
+                      frame, &NS_GET_IID(nsIDOMWindow), true, &v,
                       getter_AddRefs(holder));
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (!JS_WrapValue(cx, &v)) {
         return NS_ERROR_FAILURE;
       }
 
       *vp = v;
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -74,16 +74,18 @@ DOMCI_CLASS(Event)
 DOMCI_CLASS(MutationEvent)
 DOMCI_CLASS(UIEvent)
 DOMCI_CLASS(MouseEvent)
 DOMCI_CLASS(MouseScrollEvent)
 DOMCI_CLASS(DragEvent)
 DOMCI_CLASS(KeyboardEvent)
 DOMCI_CLASS(CompositionEvent)
 DOMCI_CLASS(PopupBlockedEvent)
+DOMCI_CLASS(DeviceLightEvent)
+DOMCI_CLASS(DeviceProximityEvent)
 DOMCI_CLASS(DeviceOrientationEvent)
 DOMCI_CLASS(DeviceMotionEvent)
 DOMCI_CLASS(DeviceAcceleration)
 DOMCI_CLASS(DeviceRotationRate)
 
 // HTML classes
 DOMCI_CLASS(HTMLDocument)
 DOMCI_CLASS(HTMLOptionsCollection)
@@ -542,13 +544,12 @@ DOMCI_CLASS(MozSettingsEvent)
 #ifdef MOZ_B2G_RIL
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 #endif
 
 #ifdef MOZ_B2G_BT
 DOMCI_CLASS(BluetoothAdapter)
-DOMCI_CLASS(BluetoothDevice)
 #endif
 
 DOMCI_CLASS(DOMError)
 DOMCI_CLASS(DOMRequest)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1348,18 +1348,17 @@ struct TraceData
   TraceCallback& callback;
   void* closure;
 };
 
 static PLDHashOperator
 TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JSObject* aData, void* aClosure)
 {
   TraceData* data = static_cast<TraceData*>(aClosure);
-  data->callback(nsIProgrammingLanguage::JAVASCRIPT, aData,
-                 "Cached XBL prototype handler", data->closure);
+  data->callback(aData, "Cached XBL prototype handler", data->closure);
   return PL_DHASH_NEXT;
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
   if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
     TraceData data(aCallback, aClosure);
     tmp->mCachedXBLPrototypeHandlers.EnumerateRead(TraceXBLHandlers, &data);
   }
@@ -1823,36 +1822,38 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
   bool isChrome = false;
 
   nsCxPusher cxPusher;
   if (!cxPusher.Push(cx)) {
     return NS_ERROR_FAILURE;
   }
 
-  JSAutoRequest ar(cx);
+  XPCAutoRequest ar(cx);
 
   nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
   NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
 
   if (reUseInnerWindow) {
     // We're reusing the current inner window.
     NS_ASSERTION(!currentInner->IsFrozen(),
                  "We should never be reusing a shared inner window");
     newInnerWindow = currentInner;
 
     if (aDocument != oldDoc) {
+      xpc_UnmarkGrayObject(currentInner->mJSObject);
       nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
     }
 
     // The API we're really looking for here is to go clear all of the
     // Xray wrappers associated with our outer window. However, we
     // don't expose that API because the implementation would be
     // identical to that of JS_TransplantObject, so we just call that
     // instead.
+    xpc_UnmarkGrayObject(mJSObject);
     if (!JS_TransplantObject(cx, mJSObject, mJSObject)) {
       return NS_ERROR_FAILURE;
     }
   } else {
     if (aState) {
       newInnerWindow = wsh->GetInnerWindow();
       mInnerWindowHolder = wsh->GetInnerWindowHolder();
 
@@ -1925,17 +1926,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
     if (!mJSObject) {
       CreateOuterObject(newInnerWindow);
       mContext->DidInitializeContext();
 
       mJSObject = mContext->GetNativeGlobal();
       SetWrapper(mJSObject);
     } else {
-      JSObject *outerObject = NewOuterWindowProxy(cx, newInnerWindow->mJSObject);
+      JSObject *outerObject = NewOuterWindowProxy(cx, xpc_UnmarkGrayObject(newInnerWindow->mJSObject));
       if (!outerObject) {
         NS_ERROR("out of memory");
         return NS_ERROR_FAILURE;
       }
 
       js::SetProxyExtra(mJSObject, 0, js::PrivateValue(NULL));
 
       outerObject = JS_TransplantObject(cx, mJSObject, outerObject);
@@ -1996,17 +1997,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     if (aState) {
       JSObject *proto;
       if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
         holder->GetJSObject(&proto);
       } else {
         proto = nsnull;
       }
 
-      if (!JS_SetPrototype(cx, mJSObject, proto)) {
+      if (!JS_SetPrototype(cx, mJSObject, xpc_UnmarkGrayObject(proto))) {
         NS_ERROR("can't set prototype");
         return NS_ERROR_FAILURE;
       }
     } else {
       if (!JS_DefineProperty(cx, newInnerWindow->mJSObject, "window",
                              OBJECT_TO_JSVAL(mJSObject),
                              JS_PropertyStub, JS_StrictPropertyStub,
                              JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
--- a/dom/base/nsIJSEventListener.h
+++ b/dom/base/nsIJSEventListener.h
@@ -35,16 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsIJSEventListener_h__
 #define nsIJSEventListener_h__
 
 #include "nsIScriptContext.h"
 #include "jsapi.h"
+#include "xpcpublic.h"
 #include "nsIDOMEventListener.h"
 
 class nsIScriptObjectOwner;
 class nsIAtom;
 
 #define NS_IJSEVENTLISTENER_IID \
 { 0x92f9212b, 0xa6aa, 0x4867, \
   { 0x93, 0x8a, 0x56, 0xbe, 0x17, 0x67, 0x4f, 0xd4 } }
@@ -81,22 +82,22 @@ public:
 
   void Disconnect()
   {
     mTarget = nsnull;
   }
 
   JSObject* GetEventScope() const
   {
-    return mScopeObject;
+    return xpc_UnmarkGrayObject(mScopeObject);
   }
 
   JSObject *GetHandler() const
   {
-    return mHandler;
+    return xpc_UnmarkGrayObject(mHandler);
   }
 
   // Set a handler for this event listener.  Must not be called if
   // there is already a handler!  The handler must already be bound to
   // the right target.
   virtual void SetHandler(JSObject *aHandler) = 0;
 
   // Among the sub-classes that inherit (directly or indirectly) from nsINode,
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1189,16 +1189,17 @@ nsJSContext::EvaluateStringWithValue(con
   if (!mScriptsEnabled) {
     if (aIsUndefined) {
       *aIsUndefined = true;
     }
 
     return NS_OK;
   }
 
+  xpc_UnmarkGrayObject(aScopeObject);
   nsAutoMicroTask mt;
 
   // Safety first: get an object representing the script's principals, i.e.,
   // the entities who signed this script, or the fully-qualified-domain-name
   // or "codebase" from which it was loaded.
   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
   nsresult rv;
   if (!aPrincipal) {
@@ -1238,17 +1239,17 @@ nsJSContext::EvaluateStringWithValue(con
 
   nsJSContext::TerminationFuncHolder holder(this);
 
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
 
-    JSAutoRequest ar(mContext);
+    XPCAutoRequest ar(mContext);
 
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
       stack->Pop(nsnull);
       return NS_ERROR_FAILURE;
     }
 
     ++mExecuteDepth;
@@ -1391,16 +1392,18 @@ nsJSContext::EvaluateString(const nsAStr
   }
 
   nsAutoMicroTask mt;
 
   if (!aScopeObject) {
     aScopeObject = JS_GetGlobalObject(mContext);
   }
 
+  xpc_UnmarkGrayObject(aScopeObject);
+
   // Safety first: get an object representing the script's principals, i.e.,
   // the entities who signed this script, or the fully-qualified-domain-name
   // or "codebase" from which it was loaded.
   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
   if (!aPrincipal) {
     nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
       do_QueryInterface(GetGlobalObject());
     if (!objPrincipal)
@@ -1439,17 +1442,17 @@ nsJSContext::EvaluateString(const nsAStr
   nsJSContext::TerminationFuncHolder holder(this);
 
   ++mExecuteDepth;
 
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && JSVersion(aVersion) != JSVERSION_UNKNOWN) {
-    JSAutoRequest ar(mContext);
+    XPCAutoRequest ar(mContext);
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
       stack->Pop(nsnull);
       return NS_ERROR_FAILURE;
     }
 
     ok = JS_EvaluateUCScriptForPrincipalsVersionOrigin(
       mContext, aScopeObject,
@@ -1463,17 +1466,17 @@ nsJSContext::EvaluateString(const nsAStr
       // nested calls through XPConnect.
 
       ReportPendingException();
     }
   }
 
   // If all went well, convert val to a string if one is wanted.
   if (ok) {
-    JSAutoRequest ar(mContext);
+    XPCAutoRequest ar(mContext);
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
       stack->Pop(nsnull);
     }
     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
   }
   else {
     if (aIsUndefined) {
@@ -1508,33 +1511,35 @@ nsJSContext::CompileScript(const PRUnich
                            PRUint32 aVersion,
                            nsScriptObjectHolder<JSScript>& aScriptObject)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
   JSObject* scopeObject = ::JS_GetGlobalObject(mContext);
+  xpc_UnmarkGrayObject(scopeObject);
 
   bool ok = false;
 
   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, aPrincipal, &ok);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
 
   aScriptObject.drop(); // ensure old object not used on failure...
 
   // Don't compile if SecurityManager said "not ok" or aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (!ok || JSVersion(aVersion) == JSVERSION_UNKNOWN)
     return NS_OK;
     
-  JSAutoRequest ar(mContext);
+  XPCAutoRequest ar(mContext);
+
 
   JSScript* script =
     ::JS_CompileUCScriptForPrincipalsVersion(mContext,
                                              scopeObject,
                                              nsJSPrincipals::get(aPrincipal),
                                              static_cast<const jschar*>(aText),
                                              aTextLength,
                                              aURL,
@@ -1567,16 +1572,19 @@ nsJSContext::ExecuteScript(JSScript* aSc
   }
 
   nsAutoMicroTask mt;
 
   if (!aScopeObject) {
     aScopeObject = JS_GetGlobalObject(mContext);
   }
 
+  xpc_UnmarkGrayScript(aScriptObject);
+  xpc_UnmarkGrayObject(aScopeObject);
+
   // Push our JSContext on our thread's context stack, in case native code
   // called from JS calls back into JS via XPConnect.
   nsresult rv;
   nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
     return NS_ERROR_FAILURE;
   }
@@ -1586,17 +1594,17 @@ nsJSContext::ExecuteScript(JSScript* aSc
                                             JS_GetGlobalFromScript(aScriptObject),
                                             getter_AddRefs(principal));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsJSContext::TerminationFuncHolder holder(this);
-  JSAutoRequest ar(mContext);
+  XPCAutoRequest ar(mContext);
   ++mExecuteDepth;
 
   // The result of evaluation, used only if there were no errors. This need
   // not be a GC root currently, provided we run the GC only from the
   // operation callback or from ScriptEvaluated.
   jsval val;
   bool ok = JS_ExecuteScript(mContext, aScopeObject, aScriptObject, &val);
   if (ok) {
@@ -1669,17 +1677,17 @@ nsJSContext::JSObjectFromInterface(nsISu
 #ifdef NS_DEBUG
   nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
   nsCOMPtr<nsISupports> native =
     nsContentUtils::XPConnect()->GetNativeOfWrapper(mContext,
                                                     JSVAL_TO_OBJECT(v));
   NS_ASSERTION(native == targetSupp, "Native should be the target!");
 #endif
 
-  *aRet = JSVAL_TO_OBJECT(v);
+  *aRet = xpc_UnmarkGrayObject(JSVAL_TO_OBJECT(v));
 
   return NS_OK;
 }
 
 
 nsresult
 nsJSContext::CompileEventHandler(nsIAtom *aName,
                                  PRUint32 aArgCount,
@@ -1714,17 +1722,17 @@ nsJSContext::CompileEventHandler(nsIAtom
 #ifdef DEBUG
   JSContext* top = nsContentUtils::GetCurrentJSContext();
   NS_ASSERTION(mContext == top, "Context not properly pushed!");
 #endif
 
   // Event handlers are always shared, and must be bound before use.
   // Therefore we never bother compiling with principals.
   // (that probably means we should avoid JS_CompileUCFunctionForPrincipals!)
-  JSAutoRequest ar(mContext);
+  XPCAutoRequest ar(mContext);
 
   JSFunction* fun =
       ::JS_CompileUCFunctionForPrincipalsVersion(mContext,
                                                  nsnull, nsnull,
                                                  nsAtomCString(aName).get(), aArgCount, aArgNames,
                                                  (jschar*)PromiseFlatString(aBody).get(),
                                                  aBody.Length(),
                                                  aURL, aLineNo, JSVersion(aVersion));
@@ -1761,31 +1769,33 @@ nsJSContext::CompileFunction(JSObject* a
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   // Don't compile if aVersion is unknown.  Since the caller is responsible for
   // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
   if ((JSVersion)aVersion == JSVERSION_UNKNOWN) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
+  xpc_UnmarkGrayObject(aTarget);
+
   nsIScriptGlobalObject *global = GetGlobalObject();
   nsCOMPtr<nsIPrincipal> principal;
   if (global) {
     // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func?
     nsCOMPtr<nsIScriptObjectPrincipal> globalData = do_QueryInterface(global);
     if (globalData) {
       principal = globalData->GetPrincipal();
       if (!principal)
         return NS_ERROR_FAILURE;
     }
   }
 
   JSObject *target = aTarget;
 
-  JSAutoRequest ar(mContext);
+  XPCAutoRequest ar(mContext);
 
   JSFunction* fun =
       ::JS_CompileUCFunctionForPrincipalsVersion(mContext,
                                                  aShared ? nsnull : target,
                                                  nsJSPrincipals::get(principal),
                                                  PromiseFlatCString(aName).get(),
                                                  aArgCount, aArgArray,
                                                  static_cast<const jschar*>(PromiseFlatString(aBody).get()),
@@ -1820,17 +1830,20 @@ nsJSContext::CallEventHandler(nsISupport
     JSAutoByteString bytes;
     const char *name = !id ? "anonymous" : bytes.encode(mContext, id) ? bytes.ptr() : "<error>";
     NS_TIME_FUNCTION_FMT(1.0, "%s (line %d) (function: %s)", MOZ_FUNCTION_NAME, __LINE__, name);
   }
 #endif
   SAMPLE_LABEL("JS", "CallEventHandler");
 
   nsAutoMicroTask mt;
-  JSAutoRequest ar(mContext);
+  xpc_UnmarkGrayObject(aScope);
+  xpc_UnmarkGrayObject(aHandler);
+
+  XPCAutoRequest ar(mContext);
   JSObject* target = nsnull;
   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JS::AutoObjectRooter targetVal(mContext, target);
   jsval rval = JSVAL_VOID;
 
   // This one's a lot easier than EvaluateString because we don't have to
@@ -1878,16 +1891,21 @@ nsJSContext::CallEventHandler(nsISupport
 
     // Use |target| as the scope for wrapping the arguments, since aScope is
     // the safe scope in many cases, which isn't very useful.  Wrapping aTarget
     // was OK because those typically have PreCreate methods that give them the
     // right scope anyway, and we want to make sure that the arguments end up
     // in the same scope as aTarget.
     rv = ConvertSupportsTojsvals(aargv, target, &argc, &argv, tempStorage);
     NS_ENSURE_SUCCESS(rv, rv);
+    for (uint32_t i = 0; i < argc; i++) {
+      if (!JSVAL_IS_PRIMITIVE(argv[i])) {
+        xpc_UnmarkGrayObject(JSVAL_TO_OBJECT(argv[i]));
+      }
+    }
 
     ++mExecuteDepth;
     bool ok = ::JS_CallFunctionValue(mContext, target,
                                        funval, argc, argv, &rval);
     --mExecuteDepth;
 
     if (!ok) {
       // Don't pass back results from failed calls.
@@ -1924,17 +1942,20 @@ nsresult
 nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, JSObject* aScope,
                                       JSObject* aHandler,
                                       nsScriptObjectHolder<JSObject>& aBoundHandler)
 {
   NS_ENSURE_ARG(aHandler);
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
   NS_PRECONDITION(!aBoundHandler, "Shouldn't already have a bound handler!");
 
-  JSAutoRequest ar(mContext);
+  xpc_UnmarkGrayObject(aScope);
+  xpc_UnmarkGrayObject(aHandler);
+
+  XPCAutoRequest ar(mContext);
 
   // Get the jsobject associated with this target
   JSObject *target = nsnull;
   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   {
@@ -1973,16 +1994,18 @@ nsJSContext::BindCompiledEventHandler(ns
 // serialization
 nsresult
 nsJSContext::Serialize(nsIObjectOutputStream* aStream, JSScript* aScriptObject)
 {
   if (!aScriptObject)
     return NS_ERROR_FAILURE;
 
   return nsContentUtils::XPConnect()->WriteScript(aStream, mContext, aScriptObject);
+    xpc_UnmarkGrayScript(aScriptObject);
+
 }
 
 nsresult
 nsJSContext::Deserialize(nsIObjectInputStream* aStream,
                          nsScriptObjectHolder<JSScript>& aResult)
 {
   NS_TIME_FUNCTION_MIN(1.0);
   
@@ -2079,17 +2102,17 @@ nsJSContext::CreateNativeGlobalForInner(
   jsholder->GetJSObject(aNativeGlobal);
   jsholder.forget(aHolder);
   return NS_OK;
 }
 
 JSContext*
 nsJSContext::GetNativeContext()
 {
-  return mContext;
+  return xpc_UnmarkGrayContext(mContext);
 }
 
 nsresult
 nsJSContext::InitContext()
 {
   // Make sure callers of this use
   // WillInitializeContext/DidInitializeContext around this call.
   NS_ENSURE_TRUE(!mIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
@@ -2125,17 +2148,17 @@ nsJSContext::InitializeExternalClasses()
 }
 
 nsresult
 nsJSContext::SetProperty(JSObject* aTarget, const char* aPropName, nsISupports* aArgs)
 {
   PRUint32  argc;
   jsval    *argv = nsnull;
 
-  JSAutoRequest ar(mContext);
+  XPCAutoRequest ar(mContext);
 
   Maybe<nsRootedJSValueArray> tempStorage;
 
   nsresult rv =
     ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, &argv, tempStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   jsval vargs;
@@ -2436,18 +2459,19 @@ nsJSContext::AddSupportsPrimitiveTojsval
 
       p->GetData(getter_AddRefs(data));
       p->GetDataIID(&iid);
       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
 
       AutoFree iidGuard(iid); // Free iid upon destruction.
 
       nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
+      JSObject *global = xpc_UnmarkGrayObject(::JS_GetGlobalObject(cx));
       jsval v;
-      nsresult rv = nsContentUtils::WrapNative(cx, ::JS_GetGlobalObject(cx),
+      nsresult rv = nsContentUtils::WrapNative(cx, global,
                                                data, iid, &v,
                                                getter_AddRefs(wrapper));
       NS_ENSURE_SUCCESS(rv, rv);
 
       *aArgv = v;
 
       break;
     }
@@ -3941,19 +3965,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSArgArray)
   jsval *argv = tmp->mArgv;
   if (argv) {
     jsval *end;
     for (end = argv + tmp->mArgc; argv < end; ++argv) {
       if (JSVAL_IS_GCTHING(*argv))
-        NS_IMPL_CYCLE_COLLECTION_TRACE_CALLBACK(JAVASCRIPT,
-                                                JSVAL_TO_GCTHING(*argv),
-                                                "mArgv[i]")
+        NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(JSVAL_TO_GCTHING(*argv),
+                                                   "mArgv[i]")
     }
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSArgArray)
   NS_INTERFACE_MAP_ENTRY(nsIArray)
   NS_INTERFACE_MAP_ENTRY(nsIJSArgArray)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIJSArgArray)
deleted file mode 100644
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "BluetoothDevice.h"
-#include "nsDOMClassInfo.h"
-
-USING_BLUETOOTH_NAMESPACE
-
-DOMCI_DATA(BluetoothDevice, BluetoothDevice)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
-                                                  nsDOMEventTargetHelper)
-  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)
-  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disconnectrequested)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
-                                                nsDOMEventTargetHelper)
-  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)
-  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disconnectrequested)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDevice)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMBluetoothDevice)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDevice)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
-
-NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
-
-BluetoothDevice::BluetoothDevice()
-{
-}
-
-nsresult
-BluetoothDevice::GetAdapter(nsAString& aAdapter)
-{
-  aAdapter = mAdapter;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetAddress(nsAString& aAddress)
-{
-  aAddress = mAddress;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetName(nsAString& aName)
-{
-  aName = mName;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetClass(PRUint32* aClass)
-{
-  *aClass = mClass;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetConnected(bool* aConnected)
-{
-  *aConnected = mConnected;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetPaired(bool* aPaired)
-{
-  *aPaired = mPaired;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetLegacyPairing(bool* aLegacyPairing)
-{
-  *aLegacyPairing = mLegacyPairing;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetTrusted(bool* aTrusted)
-{
-  *aTrusted = mTrusted;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::SetTrusted(bool aTrusted)
-{
-  mTrusted = aTrusted;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetAlias(nsAString& aAlias)
-{
-  aAlias = mAlias;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::SetAlias(const nsAString& aAlias)
-{
-  mAlias = aAlias;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetUuids(jsval* aUuids)
-{
-  //TODO: convert mUuids to jsval and assign to aUuids;
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::Disconnect()
-{
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::GetProperties(jsval* aProperties)
-{
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::SetProperty(const nsAString& aName, const nsAString& aValue)
-{
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::DiscoverServices(const nsAString& aPattern, jsval* aServices)
-{
-  return NS_OK;
-}
-
-nsresult
-BluetoothDevice::CancelDiscovery()
-{
-  return NS_OK;
-}
-
-NS_IMPL_EVENT_HANDLER(BluetoothDevice, propertychanged)
-NS_IMPL_EVENT_HANDLER(BluetoothDevice, disconnectrequested)
deleted file mode 100644
--- a/dom/bluetooth/BluetoothDevice.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_bluetoothdevice_h__
-#define mozilla_dom_bluetooth_bluetoothdevice_h__
-
-#include "BluetoothCommon.h"
-#include "nsDOMEventTargetHelper.h"
-#include "nsIDOMBluetoothDevice.h"
-#include "nsString.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-class BluetoothDevice : public nsDOMEventTargetHelper
-                      , public nsIDOMBluetoothDevice
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIDOMBLUETOOTHDEVICE
-
-  NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDevice,
-                                           nsDOMEventTargetHelper)
-
-  BluetoothDevice();
-
-protected:
-  nsString mAdapter;
-  nsString mAddress;
-  PRUint32 mClass;
-  bool mConnected;
-  bool mLegacyPairing;
-  nsString mName;
-  bool mPaired;
-  nsTArray<nsString> mUuids;
-
-  bool mTrusted;
-  nsString mAlias;
-
-  NS_DECL_EVENT_HANDLER(propertychanged)
-  NS_DECL_EVENT_HANDLER(disconnectrequested)
-};
-
-END_BLUETOOTH_NAMESPACE
-
-#endif
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -14,19 +14,17 @@ LIBRARY_NAME     = dombluetooth_s
 XPIDL_MODULE     = dom_bluetooth
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
 CPPSRCS = \
   BluetoothAdapter.cpp \
-  BluetoothDevice.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothAdapter.idl \
-  nsIDOMBluetoothDevice.idl \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/dom/bluetooth/nsIDOMBluetoothDevice.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEventTarget.idl"
-
-[scriptable, builtinclass, uuid(2da61f89-a7d2-4f7d-9f4c-fb8a99d9add2)]
-interface nsIDOMBluetoothDevice : nsIDOMEventTarget
-{
-  readonly attribute DOMString adapter;
-  readonly attribute DOMString address;
-  readonly attribute unsigned long class;
-  readonly attribute boolean connected;
-  readonly attribute boolean legacyPairing;
-  readonly attribute DOMString name;
-  readonly attribute boolean paired;
-  readonly attribute jsval uuids;
-
-  attribute boolean trusted;
-  attribute DOMString alias;
-
-  attribute nsIDOMEventListener onpropertychanged;
-  attribute nsIDOMEventListener ondisconnectrequested;
-
-  void disconnect();
-  jsval getProperties();
-  void setProperty(in DOMString name, in DOMString value);
-  jsval discoverServices(in DOMString pattern);
-  void cancelDiscovery();
-};
--- a/dom/interfaces/base/nsIDOMWindow.idl
+++ b/dom/interfaces/base/nsIDOMWindow.idl
@@ -64,17 +64,17 @@ interface nsIDOMMozURLProperty : nsISupp
  * The nsIDOMWindow interface is the primary interface for a DOM
  * window object. It represents a single window object that may
  * contain child windows if the document in the window contains a
  * HTML frameset document or if the document contains iframe elements.
  *
  * @see <http://www.whatwg.org/html/#window>
  */
 
-[scriptable, uuid(f6e3b10d-d5f4-4fcd-aa4c-5f98626d428a)]
+[scriptable, uuid(e6198a86-1a46-46ec-9501-dfcd84a5f630)]
 interface nsIDOMWindow : nsISupports
 {
   // the current browsing context
   readonly attribute nsIDOMWindow                       window;
 
   /* [replaceable] self */
   readonly attribute nsIDOMWindow                       self;
 
@@ -459,16 +459,18 @@ interface nsIDOMWindow : nsISupports
   // [implicit_jscontext] attribute jsval onundo;
   [implicit_jscontext] attribute jsval onunload;
 
   /**
    * Non-HTML5 window-specific event attributes
    */
   [implicit_jscontext] attribute jsval ondevicemotion;
   [implicit_jscontext] attribute jsval ondeviceorientation;
+  [implicit_jscontext] attribute jsval ondeviceproximity;
+  [implicit_jscontext] attribute jsval ondevicelight;
 
   [implicit_jscontext] attribute jsval onmouseenter;
   [implicit_jscontext] attribute jsval onmouseleave;
 };
 
 [scriptable, uuid(2146c906-57f7-486c-a1b4-8cdb57ef577f)]
 interface nsIDOMWindowPerformance : nsISupports
 {
--- a/dom/interfaces/events/Makefile.in
+++ b/dom/interfaces/events/Makefile.in
@@ -70,17 +70,19 @@ XPIDLSRCS =					\
 	nsIDOMCommandEvent.idl			\
 	nsIDOMMessageEvent.idl			\
 	nsIDOMNotifyPaintEvent.idl              \
 	nsIDOMNotifyAudioAvailableEvent.idl     \
 	nsIDOMPaintRequest.idl			\
 	nsIDOMPaintRequestList.idl		\
 	nsIDOMSimpleGestureEvent.idl		\
 	nsIDOMMozTouchEvent.idl			\
-	nsIDOMDeviceOrientationEvent.idl\
+	nsIDOMDeviceLightEvent.idl              \
+	nsIDOMDeviceProximityEvent.idl          \
+	nsIDOMDeviceOrientationEvent.idl        \
 	nsIDOMDeviceMotionEvent.idl		\
 	nsIDOMScrollAreaEvent.idl		\
 	nsIDOMTransitionEvent.idl		\
 	nsIDOMAnimationEvent.idl		\
 	nsIDOMPopStateEvent.idl			\
 	nsIDOMCloseEvent.idl			\
 	nsIDOMTouchEvent.idl			\
 	nsIDOMHashChangeEvent.idl		\
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/events/nsIDOMDeviceLightEvent.idl
@@ -0,0 +1,21 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEvent.idl"
+
+[scriptable, uuid(c6f68e93-9eaf-4bba-852b-c9c534a8d079)]
+interface nsIDOMDeviceLightEvent : nsIDOMEvent
+{
+  [noscript] void initDeviceLightEvent(in DOMString eventTypeArg,
+                                       in boolean canBubbleArg,
+                                       in boolean cancelableArg,
+                                       in double value);
+
+  readonly attribute double value;
+};
+
+dictionary DeviceLightEventInit : EventInit
+{
+   double value;
+};
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/events/nsIDOMDeviceProximityEvent.idl
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEvent.idl"
+
+[scriptable, uuid(4bb21c9b-381f-4c73-9000-5eb838f58738)]
+interface nsIDOMDeviceProximityEvent : nsIDOMEvent
+{
+  [noscript] void initDeviceProximityEvent(in DOMString eventTypeArg,
+                                           in boolean canBubbleArg,
+                                           in boolean cancelableArg,
+                                           in double value,
+                                           in double min,
+                                           in double max);
+  readonly attribute double value;
+  readonly attribute double min;
+  readonly attribute double max;
+};
+
+
+dictionary DeviceProximityEventInit : EventInit
+{
+   double value;
+   double min;
+   double max;
+};
--- a/dom/plugins/base/android/ANPEvent.cpp
+++ b/dom/plugins/base/android/ANPEvent.cpp
@@ -62,30 +62,21 @@ private:
   NPPluginFuncs* mFuncs;
 };
 
 void
 anp_event_postEvent(NPP inst, const ANPEvent* event)
 {
   LOG("%s", __PRETTY_FUNCTION__);
 
-  JNIEnv* env = GetJNIForThread();
-  if (!env)
-    return;
-
-  if (!mozilla::AndroidBridge::Bridge()) {
-    LOG("no bridge in %s!!!!", __PRETTY_FUNCTION__);
-    return;
-  }
-
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(inst->ndata);
   NPPluginFuncs* pluginFunctions = pinst->GetPlugin()->PluginFuncs();
-  mozilla::AndroidBridge::Bridge()->PostToJavaThread(env,
-                                                     new PluginEventRunnable(inst, const_cast<ANPEvent*>(event), pluginFunctions),
-                                                     true);
+  PluginEventRunnable* e = new PluginEventRunnable(inst, const_cast<ANPEvent*>(event), pluginFunctions);
+  
+  NS_DispatchToMainThread(e);
   LOG("returning from %s", __PRETTY_FUNCTION__);
 }
 
 
 void InitEventInterface(ANPEventInterfaceV0 *i) {
   _assert(i->inSize == sizeof(*i));
   ASSIGN(i, postEvent);
 }
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -2548,42 +2548,30 @@ nsPluginHost::WritePluginInfo()
       //description, name & mtypecount are on separate line
       PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
         (tag->mDescription.get()),
         PLUGIN_REGISTRY_FIELD_DELIMITER,
         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
         (tag->mName.get()),
         PLUGIN_REGISTRY_FIELD_DELIMITER,
         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
-        tag->mMimeTypes.Length() + 1);
+        tag->mMimeTypes.Length());
 
       // Add in each mimetype this plugin supports
       for (PRUint32 i = 0; i < tag->mMimeTypes.Length(); i++) {
         PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
           i,PLUGIN_REGISTRY_FIELD_DELIMITER,
           (tag->mMimeTypes[i].get()),
           PLUGIN_REGISTRY_FIELD_DELIMITER,
           (tag->mMimeDescriptions[i].get()),
           PLUGIN_REGISTRY_FIELD_DELIMITER,
           (tag->mExtensions[i].get()),
           PLUGIN_REGISTRY_FIELD_DELIMITER,
           PLUGIN_REGISTRY_END_OF_LINE_MARKER);
       }
-
-      // This used to depend on whether or not we had an npruntime-enabled
-      // Java plugin but we don't care any more, we just assume we do.
-      PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
-        tag->mMimeTypes.Length(), PLUGIN_REGISTRY_FIELD_DELIMITER,
-        "application/x-java-vm-npruntime",
-        PLUGIN_REGISTRY_FIELD_DELIMITER,
-        "",
-        PLUGIN_REGISTRY_FIELD_DELIMITER,
-        "",
-        PLUGIN_REGISTRY_FIELD_DELIMITER,
-        PLUGIN_REGISTRY_END_OF_LINE_MARKER);
     }
   }
   
   PR_fprintf(fd, "\n[INVALID]\n");
   
   nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
   while (invalidPlugins) {
     // fullPath
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -154,29 +154,16 @@ void nsPluginTag::InitMime(const char* c
     return;
   }
 
   for (PRUint32 i = 0; i < aVariantCount; i++) {
     if (!aMimeTypes[i]) {
       continue;
     }
 
-    // If we already marked this as a Java plugin, a later MIME type will tell
-    // us if it is npruntime-enabled. We don't actually care any more because we
-    // don't support Java access via the "java" and "packages" DOM objects, so
-    // we don't save the value, but we skip the MIME type.
-    if (mIsJavaPlugin) {
-      if (strcmp(aMimeTypes[i], "application/x-java-vm-npruntime") == 0) {
-        // This "magic MIME type" should not be exposed, but is just a signal
-        // to the browser that this is new-style java.
-        // Don't add it or its associated information to our arrays.
-        continue;
-      }
-    }
-
     // Look for certain special plugins.
     if (nsPluginHost::IsJavaMIMEType(aMimeTypes[i])) {
       mIsJavaPlugin = true;
     } else if (strcmp(aMimeTypes[i], "application/x-shockwave-flash") == 0) {
       mIsFlashPlugin = true;
     }
 
     // Fill in our MIME type array.
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -105,20 +105,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsJSEventListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(nsIProgrammingLanguage::JAVASCRIPT,
-                                                 mScopeObject)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(nsIProgrammingLanguage::JAVASCRIPT,
-                                                 mHandler)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScopeObject)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mHandler)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsJSEventListener)
   return tmp->IsBlackForCC();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsJSEventListener)
   return tmp->IsBlackForCC();
--- a/dom/system/nsDeviceSensors.cpp
+++ b/dom/system/nsDeviceSensors.cpp
@@ -120,17 +120,17 @@ NS_IMETHODIMP nsDeviceSensorData::GetZ(d
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS1(nsDeviceSensors, nsIDeviceSensors)
 
 nsDeviceSensors::nsDeviceSensors()
 {
   mLastDOMMotionEventTime = TimeStamp::Now();
-  mEnabled = Preferences::GetBool("device.motion.enabled", true);
+  mEnabled = Preferences::GetBool("device.sensors.enabled", true);
 
   for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
     nsTArray<nsIDOMWindow*> *windows = new nsTArray<nsIDOMWindow*>();
     mWindowListeners.AppendElement(windows);
   }
 
   mLastDOMMotionEventTime = TimeStamp::Now();
 }
@@ -144,16 +144,19 @@ nsDeviceSensors::~nsDeviceSensors()
 
   for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
     delete mWindowListeners[i];
   }
 }
 
 NS_IMETHODIMP nsDeviceSensors::AddWindowListener(PRUint32 aType, nsIDOMWindow *aWindow)
 {
+  if (!mEnabled)
+    return NS_OK;
+
   if (mWindowListeners[aType]->IndexOf(aWindow) != NoIndex)
     return NS_OK;
 
   if (!IsSensorEnabled(aType)) {
     RegisterSensorObserver((SensorType)aType, this);
   }
 
   mWindowListeners[aType]->AppendElement(aWindow);
@@ -179,19 +182,16 @@ NS_IMETHODIMP nsDeviceSensors::RemoveWin
     RemoveWindowListener((SensorType)i, aWindow);
   }
   return NS_OK;
 }
 
 void 
 nsDeviceSensors::Notify(const mozilla::hal::SensorData& aSensorData)
 {
-  if (!mEnabled)
-    return;
-
   PRUint32 type = aSensorData.sensor();
 
   double x = aSensorData.values()[0];
   double y = aSensorData.values()[1];
   double z = aSensorData.values()[2];
 
   nsCOMArray<nsIDOMWindow> windowListeners;
   for (PRUint32 i = 0; i < mWindowListeners[type]->Length(); i++) {
@@ -215,21 +215,73 @@ nsDeviceSensors::Notify(const mozilla::h
     if (domdoc) {
       nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(windowListeners[i]);
       if (type == nsIDeviceSensorData::TYPE_ACCELERATION || 
         type == nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION || 
         type == nsIDeviceSensorData::TYPE_GYROSCOPE)
         FireDOMMotionEvent(domdoc, target, type, x, y, z);
       else if (type == nsIDeviceSensorData::TYPE_ORIENTATION)
         FireDOMOrientationEvent(domdoc, target, x, y, z);
+      else if (type == nsIDeviceSensorData::TYPE_PROXIMITY)
+        FireDOMProximityEvent(target, x, y, z);
+      else if (type == nsIDeviceSensorData::TYPE_LIGHT)
+        FireDOMLightEvent(target, x);
+
     }
   }
 }
 
 void
+nsDeviceSensors::FireDOMLightEvent(nsIDOMEventTarget *aTarget,
+                                  double aValue)
+{
+  nsCOMPtr<nsIDOMEvent> event;
+  NS_NewDOMDeviceLightEvent(getter_AddRefs(event), nsnull, nsnull);
+
+  nsCOMPtr<nsIDOMDeviceLightEvent> oe = do_QueryInterface(event);
+  oe->InitDeviceLightEvent(NS_LITERAL_STRING("devicelight"),
+                          true,
+                          false,
+                          aValue);
+
+  nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
+  if (privateEvent) {
+    privateEvent->SetTrusted(true);
+  }
+
+  bool defaultActionEnabled;
+  aTarget->DispatchEvent(event, &defaultActionEnabled);
+}
+
+void
+nsDeviceSensors::FireDOMProximityEvent(nsIDOMEventTarget *aTarget,
+                                       double aValue,
+                                       double aMin,
+                                       double aMax)
+{
+  nsCOMPtr<nsIDOMEvent> event;
+  NS_NewDOMDeviceProximityEvent(getter_AddRefs(event), nsnull, nsnull);
+  nsCOMPtr<nsIDOMDeviceProximityEvent> oe = do_QueryInterface(event);
+
+  oe->InitDeviceProximityEvent(NS_LITERAL_STRING("deviceproximity"),
+                               true,
+                               false,
+                               aValue,
+                               aMin,
+                               aMax);
+
+  nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
+  if (privateEvent) {
+    privateEvent->SetTrusted(true);
+  }
+  bool defaultActionEnabled;
+  aTarget->DispatchEvent(event, &defaultActionEnabled);
+}
+
+void
 nsDeviceSensors::FireDOMOrientationEvent(nsIDOMDocument *domdoc,
                                         nsIDOMEventTarget *target,
                                         double alpha,
                                         double beta,
                                         double gamma)
 {
   nsCOMPtr<nsIDOMEvent> event;
   bool defaultActionEnabled = true;
--- a/dom/system/nsDeviceSensors.h
+++ b/dom/system/nsDeviceSensors.h
@@ -38,17 +38,19 @@
 #define nsDeviceSensors_h
 
 #include "nsIDeviceSensors.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsCOMArray.h"
 #include "nsTArray.h"
 #include "nsCOMPtr.h"
 #include "nsITimer.h"
+#include "nsIDOMDeviceLightEvent.h"
 #include "nsIDOMDeviceOrientationEvent.h"
+#include "nsIDOMDeviceProximityEvent.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsDOMDeviceMotionEvent.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/HalSensor.h"
 #include "nsDataHashtable.h"
 
 #define NS_DEVICE_SENSORS_CID \
 { 0xecba5203, 0x77da, 0x465a, \
@@ -68,17 +70,25 @@ public:
 
   virtual ~nsDeviceSensors();
 
   void Notify(const mozilla::hal::SensorData& aSensorData);
 
 private:
   // sensor -> window listener
   nsTArray<nsTArray<nsIDOMWindow*>* > mWindowListeners;
-  
+
+  void FireDOMLightEvent(nsIDOMEventTarget *target,
+                         double value);
+
+  void FireDOMProximityEvent(nsIDOMEventTarget *aTarget,
+                             double aValue,
+                             double aMin,
+                             double aMax);
+
   void FireDOMOrientationEvent(class nsIDOMDocument *domDoc, 
                                class nsIDOMEventTarget *target,
                                double alpha,
                                double beta,
                                double gamma);
 
   void FireDOMMotionEvent(class nsIDOMDocument *domDoc, 
                           class nsIDOMEventTarget *target,
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -774,25 +774,39 @@ public:
   virtual void *GetNativeSurface(NativeSurfaceType aType) { return NULL; }
 
   void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
     mUserData.Add(key, userData, destroy);
   }
   void *GetUserData(UserDataKey *key) {
     return mUserData.Get(key);
   }
+
+  /* Within this rectangle all pixels will be opaque by the time the result of
+   * this DrawTarget is first used for drawing. Either by the underlying surface
+   * being used as an input to external drawing, or Snapshot() being called.
+   * This rectangle is specified in device space.
+   */
+  void SetOpaqueRect(const IntRect &aRect) {
+    mOpaqueRect = aRect;
+  }
+
+  const IntRect &GetOpaqueRect() const {
+    return mOpaqueRect;
+  }
 protected:
   UserData mUserData;
   Matrix mTransform;
+  IntRect mOpaqueRect;
   bool mTransformDirty : 1;
 
   SurfaceFormat mFormat;
 };
 
-class Factory
+class GFX2D_API Factory
 {
 public:
   static TemporaryRef<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface);
 
   static TemporaryRef<DrawTarget>
     CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
   
   static TemporaryRef<DrawTarget>
--- a/gfx/2d/Blur.h
+++ b/gfx/2d/Blur.h
@@ -55,17 +55,17 @@ namespace gfx {
  *
  * A spread N makes each output pixel the maximum value of all source
  * pixels within a square of side length 2N+1 centered on the output pixel.
  *
  * A temporary surface is created in the Init function. The caller then draws
  * any desired content onto the context acquired through GetContext, and lastly
  * calls Paint to apply the blurred content as an alpha mask.
  */
-class AlphaBoxBlur
+class GFX2D_API AlphaBoxBlur
 {
 public:
 
   /** Constructs a box blur and initializes the backing surface.
    *
    * @param aRect The coordinates of the surface to create in device units.
    *
    * @param aBlurRadius The blur radius in pixels.  This is the radius of the
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -275,23 +275,23 @@ Factory::CreateDWriteGlyphRenderingOptio
   RefPtr<GlyphRenderingOptions> options =
     new GlyphRenderingOptionsDWrite(aParams);
 
   return options;
 }
 
 #endif // XP_WIN
 
-#ifdef USE_CAIRO
 TemporaryRef<DrawTarget>
 Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface)
 {
+#ifdef USE_CAIRO
   RefPtr<DrawTargetCairo> newTarget = new DrawTargetCairo();
   if (newTarget->Init(aSurface)) {
     return newTarget;
   }
 
+#endif
   return NULL;
 }
-#endif
 
 }
 }
--- a/gfx/2d/Makefile.in
+++ b/gfx/2d/Makefile.in
@@ -79,17 +79,17 @@ CPPSRCS	= \
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS	+= \
 	   SourceSurfaceCG.cpp \
 	   DrawTargetCG.cpp \
 	   PathCG.cpp \
 	   $(NULL)
 endif
 
-DEFINES += -DMOZ_GFX -DUSE_CAIRO
+DEFINES += -DMOZ_GFX -DUSE_CAIRO -DGFX2D_INTERNAL
 
 ifdef MOZ_ENABLE_SKIA
 CPPSRCS	+= \
         SourceSurfaceSkia.cpp \
         DrawTargetSkia.cpp \
         PathSkia.cpp \
         ScaledFontFreetype.cpp
         $(NULL)
@@ -120,17 +120,17 @@ endif
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 CPPSRCS	+= \
         DrawTargetD2D.cpp \
         SourceSurfaceD2D.cpp \
         SourceSurfaceD2DTarget.cpp \
         PathD2D.cpp \
         ScaledFontDWrite.cpp \
         $(NULL)
-DEFINES += -DWIN32
+DEFINES += -DWIN32 -DINITGUID
 
 ifdef MOZ_ENABLE_SKIA
 CPPSRCS += \
         ScaledFontWin.cpp \
         $(NULL)
 endif
 endif
 
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -78,17 +78,17 @@ public:
     Size retSize;
 
     retSize.width = aSize.width * _11 + aSize.height * _21;
     retSize.height = aSize.width * _12 + aSize.height * _22;
 
     return retSize;
   }
 
-  Rect TransformBounds(const Rect& rect) const;
+  GFX2D_API Rect TransformBounds(const Rect& rect) const;
 
   // Apply a scale to this matrix. This scale will be applied -before- the
   // existing transformation of the matrix.
   Matrix &Scale(Float aX, Float aY)
   {
     _11 *= aX;
     _12 *= aX;
     _21 *= aY;
@@ -133,17 +133,17 @@ public:
     return true;
   }
 
   Float Determinant() const
   {
     return _11 * _22 - _12 * _21;
   }
   
-  static Matrix Rotation(Float aAngle);
+  GFX2D_API static Matrix Rotation(Float aAngle);
 
   Matrix operator*(const Matrix &aMatrix) const
   {
     Matrix resultMatrix;
 
     resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21;
     resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22;
     resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21;
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -78,14 +78,21 @@ struct Rect :
     Rect() : Super() {}
     Rect(Point aPos, mozilla::gfx::Size aSize) :
         Super(aPos, aSize) {}
     Rect(Float _x, Float _y, Float _width, Float _height) :
         Super(_x, _y, _width, _height) {}
     explicit Rect(const IntRect& rect) :
         Super(float(rect.x), float(rect.y),
               float(rect.width), float(rect.height)) {}
+
+    bool ToIntRect(IntRect *aOut)
+    {
+      *aOut = IntRect(int32_t(X()), int32_t(Y()),
+                    int32_t(Width()), int32_t(Height()));
+      return Rect(aOut->x, aOut->y, aOut->width, aOut->height).IsEqualEdges(*this);
+    }
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_RECT_H_ */
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -149,16 +149,26 @@ struct GradientStop
 
   Float offset;
   Color color;
 };
 
 }
 }
 
+#ifdef XP_WIN
+#ifdef GFX2D_INTERNAL
+#define GFX2D_API __declspec(dllexport)
+#else
+#define GFX2D_API __declspec(dllimport)
+#endif
+#else
+#define GFX2D_API
+#endif
+
 // Side constants for use in various places
 namespace mozilla {
   namespace css {
     enum Side {eSideTop, eSideRight, eSideBottom, eSideLeft};
   }
 }
 
 // XXX - These don't really belong here. But for now this is where they go.
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -173,16 +173,18 @@ lround-c99-only.patch: Only use lround i
 unicode-printing.patch: Print as unicode (bug 454532)
 
 quartz-mark-dirty.patch: Add a quartz implementation of mark_dirty_rectangle (bug 715704)
 
 expose-snapshot.patch: Make functions to add snapshots public, as well as allow creating null surfaces publically. (bug 715658)
 
 fix-build-with-Werror=return-type.patch: Fix builds with -Werror=return-type (bug 737909)
 
+avoid-extend-none.patch: Avoid incorrectly using EXTEND_NONE (bug 751668)
+
 ==== pixman patches ====
 
 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
 
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/avoid-extend-none.patch
@@ -0,0 +1,39 @@
+changeset:   93076:25d0c8a38d7d
+tag:         none
+tag:         qbase
+tag:         qtip
+tag:         tip
+user:        Jeff Muizelaar <jmuizelaar@mozilla.com>
+date:        Thu May 03 15:21:52 2012 -0400
+summary:     Bug 751668. Avoid incorrectly using EXTEND_NONE. r=joe
+
+diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c
+--- a/gfx/cairo/cairo/src/cairo-image-surface.c
++++ b/gfx/cairo/cairo/src/cairo-image-surface.c
+@@ -1390,25 +1390,16 @@ static pixman_image_t *
+ 	cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
+ 	cairo_surface_type_t type;
+ 
+ 	if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
+ 	    source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
+ 
+ 	type = source->base.backend->type;
+ 	if (type == CAIRO_SURFACE_TYPE_IMAGE) {
+-	    if (extend != CAIRO_EXTEND_NONE &&
+-		sample.x >= 0 &&
+-		sample.y >= 0 &&
+-		sample.x + sample.width  <= source->width &&
+-		sample.y + sample.height <= source->height)
+-	    {
+-		extend = CAIRO_EXTEND_NONE;
+-	    }
+-
+ 	    if (sample.width == 1 && sample.height == 1) {
+ 		if (sample.x < 0 ||
+ 		    sample.y < 0 ||
+ 		    sample.x >= source->width ||
+ 		    sample.y >= source->height)
+ 		{
+ 		    if (extend == CAIRO_EXTEND_NONE)
+ 			return _pixman_transparent_image ();
+
--- a/gfx/cairo/cairo/src/cairo-image-surface.c
+++ b/gfx/cairo/cairo/src/cairo-image-surface.c
@@ -1390,25 +1390,16 @@ static pixman_image_t *
 	cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
 	cairo_surface_type_t type;
 
 	if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
 	    source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
 
 	type = source->base.backend->type;
 	if (type == CAIRO_SURFACE_TYPE_IMAGE) {
-	    if (extend != CAIRO_EXTEND_NONE &&
-		sample.x >= 0 &&
-		sample.y >= 0 &&
-		sample.x + sample.width  <= source->width &&
-		sample.y + sample.height <= source->height)
-	    {
-		extend = CAIRO_EXTEND_NONE;
-	    }
-
 	    if (sample.width == 1 && sample.height == 1) {
 		if (sample.x < 0 ||
 		    sample.y < 0 ||
 		    sample.x >= source->width ||
 		    sample.y >= source->height)
 		{
 		    if (extend == CAIRO_EXTEND_NONE)
 			return _pixman_transparent_image ();
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -1933,17 +1933,17 @@ GLContextProviderEGL::CreateOffscreen(co
 #elif defined(MOZ_X11)
     nsRefPtr<GLContextEGL> glContext =
         GLContextEGL::CreateEGLPixmapOffscreenContext(gfxIntSize(16, 16), aFormat, true);
 
     if (!glContext) {
         return nsnull;
     }
 
-    if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBO(aSize, true)) {
+    if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBOs(aSize, true)) {
         // we weren't able to create the initial
         // offscreen FBO, so this is dead
         return nsnull;
     }
     return glContext.forget();
 #else
     return nsnull;
 #endif
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -69,16 +69,18 @@
 #endif
 
 #include "sampler.h"
 #include "GLContext.h"
 
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace layers {
 
 class BasicContainerLayer;
 class ShadowableLayer;
 
 class AutoSetOperator {
 public:
@@ -1941,41 +1943,66 @@ BasicLayerManager::PaintLayer(gfxContext
   if (needsClipToVisibleRegion && !needsGroup) {
     gfxUtils::ClipToRegion(aTarget, visibleRegion);
     // Don't need to clip to visible region again
     needsClipToVisibleRegion = false;
   }
 
   bool pushedTargetOpaqueRect = false;
   nsRefPtr<gfxASurface> currentSurface = aTarget->CurrentSurface();
+  DrawTarget *dt = aTarget->GetDrawTarget();
   const nsIntRect& bounds = visibleRegion.GetBounds();
   
-  if (aTarget->IsCairo()) {
-    const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
-
-    // Try to annotate currentSurface with a region of pixels that have been
-    // (or will be) painted opaque, if no such region is currently set.
-    if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
-        (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
-        !transform.HasNonAxisAlignedTransform()) {
-      currentSurface->SetOpaqueRect(
-          aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
-      pushedTargetOpaqueRect = true;
+  if (is2D) {
+    if (aTarget->IsCairo()) {
+      const gfxRect& targetOpaqueRect = currentSurface->GetOpaqueRect();
+
+      // Try to annotate currentSurface with a region of pixels that have been
+      // (or will be) painted opaque, if no such region is currently set.
+      if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
+          (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
+          !transform.HasNonAxisAlignedTransform()) {
+        currentSurface->SetOpaqueRect(
+            aTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)));
+        pushedTargetOpaqueRect = true;
+      }
+    } else {
+      const IntRect& targetOpaqueRect = dt->GetOpaqueRect();
+
+      // Try to annotate currentSurface with a region of pixels that have been
+      // (or will be) painted opaque, if no such region is currently set.
+      if (targetOpaqueRect.IsEmpty() && visibleRegion.GetNumRects() == 1 &&
+          (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
+          !transform.HasNonAxisAlignedTransform()) {
+
+        Rect opaqueRect = dt->GetTransform().TransformBounds(
+          Rect(bounds.x, bounds.y, bounds.width, bounds.height));
+        opaqueRect.RoundIn();
+        IntRect intOpaqueRect;
+        if (opaqueRect.ToIntRect(&intOpaqueRect)) {
+          aTarget->GetDrawTarget()->SetOpaqueRect(intOpaqueRect);
+          pushedTargetOpaqueRect = true;
+        }
+      }
     }
   }
 
   nsRefPtr<gfxContext> groupTarget;
   nsRefPtr<gfxASurface> untransformedSurface;
   if (!is2D) {
     untransformedSurface = 
       gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), 
                                                          gfxASurface::CONTENT_COLOR_ALPHA);
     if (!untransformedSurface) {
       if (pushedTargetOpaqueRect) {
-        currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0));
+        if (aTarget->IsCairo()) {
+          currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0));
+        } else {
+          dt->SetOpaqueRect(IntRect());
+        }
       }
       NS_ASSERTION(needsSaveRestore, "Should always need to restore with 3d transforms!");
       aTarget->Restore();
       return;
     }
     untransformedSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y));
     groupTarget = new gfxContext(untransformedSurface);
   } else if (needsGroup) {
@@ -2080,17 +2107,21 @@ BasicLayerManager::PaintLayer(gfxContext
       AutoSetOperator setOperator(aTarget, container->GetOperator());
       gfxMatrix temp = aTarget->CurrentMatrix();
       PaintWithMask(aTarget, aLayer->GetEffectiveOpacity(),
                     HasShadowManager() ? nsnull : aLayer->GetMaskLayer());
     }
   }
 
   if (pushedTargetOpaqueRect) {
-    currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0));
+    if (aTarget->IsCairo()) {
+      currentSurface->SetOpaqueRect(gfxRect(0, 0, 0, 0));
+    } else {
+      dt->SetOpaqueRect(IntRect());
+    }
   }
 
   if (needsSaveRestore) {
     aTarget->Restore();
   } else {
     aTarget->SetMatrix(savedMatrix);
   }
 }
--- a/gfx/layers/opengl/ReusableTileStoreOGL.cpp
+++ b/gfx/layers/opengl/ReusableTileStoreOGL.cpp
@@ -14,73 +14,112 @@ ReusableTileStoreOGL::~ReusableTileStore
 
   mContext->MakeCurrent();
   for (PRUint32 i = 0; i < mTiles.Length(); i++)
     mContext->fDeleteTextures(1, &mTiles[i]->mTexture.mTextureHandle);
   mTiles.Clear();
 }
 
 void
-ReusableTileStoreOGL::HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer,
-                                   const nsIntSize& aContentSize,
-                                   const nsIntRegion& aOldValidRegion,
-                                   const nsIntRegion& aNewValidRegion,
-                                   const gfxSize& aOldResolution,
-                                   const gfxSize& aNewResolution)
+ReusableTileStoreOGL::InvalidateTiles(TiledThebesLayerOGL* aLayer,
+                                      const nsIntRegion& aValidRegion,
+                                      const gfxSize& aResolution)
 {
-  gfxSize scaleFactor = gfxSize(aNewResolution.width / aOldResolution.width,
-                                aNewResolution.height / aOldResolution.height);
-
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
-  printf_stderr("Seeing if there are any tiles we can reuse\n");
+  printf_stderr("Invalidating reused tiles\n");
 #endif
 
+  // Find out the area of the nearest display-port to invalidate retained
+  // tiles.
+  gfxRect renderBounds;
+  for (ContainerLayer* parent = aLayer->GetParent(); parent; parent = parent->GetParent()) {
+      const FrameMetrics& metrics = parent->GetFrameMetrics();
+      if (!metrics.mDisplayPort.IsEmpty()) {
+          // We use the bounds to cut down on complication/computation time.
+          // This will be incorrect when the transform involves rotation, but
+          // it'd be quite hard to retain invalid tiles correctly in this
+          // situation anyway.
+          renderBounds = parent->GetEffectiveTransform().TransformBounds(gfxRect(metrics.mDisplayPort));
+          break;
+      }
+  }
+
+  // If no display port was found, use the widget size from the layer manager.
+  if (renderBounds.IsEmpty()) {
+      LayerManagerOGL* manager = static_cast<LayerManagerOGL*>(aLayer->Manager());
+      const nsIntSize& widgetSize = manager->GetWidgetSize();
+      renderBounds.width = widgetSize.width;
+      renderBounds.height = widgetSize.height;
+  }
+
   // Iterate over existing harvested tiles and release any that are contained
-  // within the new valid region, or that fall outside of the layer.
+  // within the new valid region, the display-port or the widget area. The
+  // assumption is that anything within this area should be valid, so there's
+  // no need to keep invalid tiles there.
   mContext->MakeCurrent();
   for (PRUint32 i = 0; i < mTiles.Length();) {
     ReusableTiledTextureOGL* tile = mTiles[i];
 
+    // Check if the tile region is contained within the new valid region.
     nsIntRect tileRect;
     bool release = false;
-    if (tile->mResolution == aNewResolution) {
-      if (aNewValidRegion.Contains(tile->mTileRegion)) {
+    if (tile->mResolution == aResolution) {
+      if (aValidRegion.Contains(tile->mTileRegion)) {
         release = true;
       } else {
         tileRect = tile->mTileRegion.GetBounds();
       }
     } else {
       nsIntRegion transformedTileRegion(tile->mTileRegion);
-      transformedTileRegion.ScaleRoundOut(tile->mResolution.width / aNewResolution.width,
-                                          tile->mResolution.height / aNewResolution.height);
-      if (aNewValidRegion.Contains(transformedTileRegion))
+      transformedTileRegion.ScaleRoundOut(tile->mResolution.width / aResolution.width,
+                                          tile->mResolution.height / aResolution.height);
+      if (aValidRegion.Contains(transformedTileRegion))
         release = true;
       else
         tileRect = transformedTileRegion.GetBounds();
     }
 
+    // If the tile region wasn't contained within the valid region, check if
+    // it intersects with the currently rendered region.
     if (!release) {
-      if (tileRect.width > aContentSize.width ||
-          tileRect.height > aContentSize.height)
+      // Transform the tile region to see if it falls inside the rendered bounds
+      gfxRect tileBounds = aLayer->GetEffectiveTransform().TransformBounds(gfxRect(tileRect));
+      if (renderBounds.Contains(tileBounds))
         release = true;
     }
 
     if (release) {
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
       nsIntRect tileBounds = tile->mTileRegion.GetBounds();
       printf_stderr("Releasing obsolete reused tile at %d,%d, x%f\n",
                     tileBounds.x, tileBounds.y, tile->mResolution.width);
 #endif
       mContext->fDeleteTextures(1, &tile->mTexture.mTextureHandle);
       mTiles.RemoveElementAt(i);
       continue;
     }
 
     i++;
   }
+}
+
+void
+ReusableTileStoreOGL::HarvestTiles(TiledThebesLayerOGL* aLayer,
+                                   TiledLayerBufferOGL* aVideoMemoryTiledBuffer,
+                                   const nsIntRegion& aOldValidRegion,
+                                   const nsIntRegion& aNewValidRegion,
+                                   const gfxSize& aOldResolution,
+                                   const gfxSize& aNewResolution)
+{
+  gfxSize scaleFactor = gfxSize(aNewResolution.width / aOldResolution.width,
+                                aNewResolution.height / aOldResolution.height);
+
+#ifdef GFX_TILEDLAYER_PREF_WARNINGS
+  printf_stderr("Seeing if there are any tiles we can reuse\n");
+#endif
 
   // Iterate over the tiles and decide which ones we're going to harvest.
   // We harvest any tile that is entirely outside of the new valid region, or
   // any tile that is partially outside of the valid region and whose
   // resolution has changed.
   // XXX Tile iteration needs to be abstracted, or have some utility functions
   //     to make it simpler.
   uint16_t tileSize = aVideoMemoryTiledBuffer->GetTileLength();
@@ -133,16 +172,19 @@ ReusableTileStoreOGL::HarvestTiles(Tiled
       }
 
       y += h;
     }
 
     x += w;
   }
 
+  // Make sure we don't hold onto tiles that may cause visible rendering glitches
+  InvalidateTiles(aLayer, aNewValidRegion, aNewResolution);
+
   // Now prune our reused tile store of its oldest tiles if it gets too large.
   while (mTiles.Length() > aVideoMemoryTiledBuffer->GetTileCount() * mSizeLimit) {
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
     nsIntRect tileBounds = mTiles[0]->mTileRegion.GetBounds();
     printf_stderr("Releasing old reused tile at %d,%d, x%f\n",
                   tileBounds.x, tileBounds.y, mTiles[0]->mResolution.width);
 #endif
     mContext->fDeleteTextures(1, &mTiles[0]->mTexture.mTextureHandle);
@@ -151,59 +193,93 @@ ReusableTileStoreOGL::HarvestTiles(Tiled
 
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   printf_stderr("Retained %d tiles\n", mTiles.Length());
 #endif
 }
 
 void
 ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
-                                const nsIntSize& aContentSize,
                                 const nsIntRegion& aValidRegion,
                                 const gfxSize& aResolution,
                                 const gfx3DMatrix& aTransform,
                                 const nsIntPoint& aRenderOffset,
                                 Layer* aMaskLayer)
 {
+  // Walk up the tree, looking for a display-port - if we find one, we know
+  // that this layer represents a content node and we can use its first
+  // scrollable child, in conjunction with its content area and viewport offset
+  // to establish the screen coordinates to which the content area will be
+  // rendered.
+  gfxRect contentBounds, displayPort;
+  ContainerLayer* scrollableLayer = nsnull;
+  for (ContainerLayer* parent = aLayer->GetParent(); parent; parent = parent->GetParent()) {
+      const FrameMetrics& parentMetrics = parent->GetFrameMetrics();
+      if (parentMetrics.IsScrollable())
+        scrollableLayer = parent;
+      if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
+          displayPort = parent->GetEffectiveTransform().
+            TransformBounds(gfxRect(parentMetrics.mDisplayPort));
+          const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
+          const nsIntSize& contentSize = metrics.mContentSize;
+          const nsIntPoint& contentOrigin = metrics.mViewportScrollOffset;
+          gfxRect contentRect = gfxRect(-contentOrigin.x, -contentOrigin.y,
+                                        contentSize.width, contentSize.height);
+          contentBounds = scrollableLayer->GetEffectiveTransform().TransformBounds(contentRect);
+          break;
+      }
+  }
+
   // Render old tiles to fill in gaps we haven't had the time to render yet.
   for (PRUint32 i = 0; i < mTiles.Length(); i++) {
     ReusableTiledTextureOGL* tile = mTiles[i];
 
     // Work out the scaling factor in case of resolution differences.
     gfxSize scaleFactor = gfxSize(aResolution.width / tile->mResolution.width,
                                   aResolution.height / tile->mResolution.height);
 
-    // Get the valid tile region, in the given coordinate space.
-    nsIntRegion transformedTileRegion(tile->mTileRegion);
-    if (aResolution != tile->mResolution)
-      transformedTileRegion.ScaleRoundOut(scaleFactor.width, scaleFactor.height);
-
-    // Skip drawing tiles that will be completely drawn over.
-    if (aValidRegion.Contains(transformedTileRegion))
-      continue;
-
-    // Skip drawing tiles that have fallen outside of the layer area (these
-    // will be discarded next time tiles are harvested).
-    nsIntRect transformedTileRect = transformedTileRegion.GetBounds();
-    if (transformedTileRect.XMost() > aContentSize.width ||
-        transformedTileRect.YMost() > aContentSize.height)
-      continue;
-
     // Reconcile the resolution difference by adjusting the transform.
     gfx3DMatrix transform = aTransform;
     if (aResolution != tile->mResolution)
       transform.Scale(scaleFactor.width, scaleFactor.height, 1);
 
-    // XXX We should clip here to make sure we don't overlap with the valid
-    //     region, otherwise we may end up with rendering artifacts on
-    //     semi-transparent layers.
-    //     Similarly, if we have multiple tiles covering the same area, we will
+    // Subtract the layer's valid region from the tile region.
+    nsIntRegion transformedValidRegion(aValidRegion);
+    if (aResolution != tile->mResolution)
+      transformedValidRegion.ScaleRoundOut(1.0f/scaleFactor.width,
+                                           1.0f/scaleFactor.height);
+    nsIntRegion tileRegion;
+    tileRegion.Sub(tile->mTileRegion, transformedValidRegion);
+
+    // Subtract the display-port from the tile region.
+    if (!displayPort.IsEmpty()) {
+      gfxRect transformedRenderBounds = transform.Inverse().TransformBounds(displayPort);
+      tileRegion.Sub(tileRegion, nsIntRect(transformedRenderBounds.x,
+                                           transformedRenderBounds.y,
+                                           transformedRenderBounds.width,
+                                           transformedRenderBounds.height));
+    }
+
+    // Intersect the tile region with the content area.
+    if (!contentBounds.IsEmpty()) {
+      gfxRect transformedRenderBounds = transform.Inverse().TransformBounds(contentBounds);
+      tileRegion.And(tileRegion, nsIntRect(transformedRenderBounds.x,
+                                           transformedRenderBounds.y,
+                                           transformedRenderBounds.width,
+                                           transformedRenderBounds.height));
+    }
+
+    // If the tile region is empty, skip drawing.
+    if (tileRegion.IsEmpty())
+      continue;
+
+    // XXX If we have multiple tiles covering the same area, we will
     //     end up with rendering artifacts if the aLayer isn't opaque.
     uint16_t tileStartX = tile->mTileOrigin.x % tile->mTileSize;
     uint16_t tileStartY = tile->mTileOrigin.y % tile->mTileSize;
     nsIntPoint tileOffset(tile->mTileOrigin.x - tileStartX, tile->mTileOrigin.y - tileStartY);
     nsIntSize textureSize(tile->mTileSize, tile->mTileSize);
-    aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tile->mTileRegion, tileOffset, textureSize, aMaskLayer);
+    aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tileRegion, tileOffset, textureSize, aMaskLayer);
   }
 }
 
 } // mozilla
 } // layers
--- a/gfx/layers/opengl/ReusableTileStoreOGL.h
+++ b/gfx/layers/opengl/ReusableTileStoreOGL.h
@@ -59,34 +59,41 @@ public:
 
   ~ReusableTileStoreOGL();
 
   // Harvests tiles from a TiledLayerBufferOGL that are about to become
   // invalid. aOldValidRegion and aOldResolution should be the valid region
   // and resolution of the data currently in aVideoMemoryTiledBuffer, and
   // aNewValidRegion and aNewResolution should be the valid region and
   // resolution of the data that is about to update aVideoMemoryTiledBuffer.
-  void HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer,
-                    const nsIntSize& aContentSize,
+  void HarvestTiles(TiledThebesLayerOGL* aLayer,
+                    TiledLayerBufferOGL* aVideoMemoryTiledBuffer,
                     const nsIntRegion& aOldValidRegion,
                     const nsIntRegion& aNewValidRegion,
                     const gfxSize& aOldResolution,
                     const gfxSize& aNewResolution);
 
   // Draws all harvested tiles that don't intersect with the given valid region.
   // Differences in resolution will be reconciled via altering the given
   // transformation.
   void DrawTiles(TiledThebesLayerOGL* aLayer,
-                 const nsIntSize& aContentSize,
                  const nsIntRegion& aValidRegion,
                  const gfxSize& aResolution,
                  const gfx3DMatrix& aTransform,
                  const nsIntPoint& aRenderOffset,
                  Layer* aMaskLayer);
 
+protected:
+  // Invalidates tiles contained within the valid region, or intersecting with
+  // the currently rendered region (discovered by looking for a display-port,
+  // or failing that, looking at the widget size).
+  void InvalidateTiles(TiledThebesLayerOGL* aLayer,
+                       const nsIntRegion& aValidRegion,
+                       const gfxSize& aResolution);
+
 private:
   // This GLContext should correspond to the one used in any TiledLayerBufferOGL
   // that is passed into HarvestTiles and DrawTiles.
   nsRefPtr<gl::GLContext> mContext;
 
   // This determines the maximum number of tiles stored in this tile store,
   // as a fraction of the amount of tiles stored in the TiledLayerBufferOGL
   // given to HarvestTiles.
--- a/gfx/layers/opengl/TiledThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/TiledThebesLayerOGL.cpp
@@ -150,19 +150,18 @@ TiledThebesLayerOGL::ProcessUploadQueue(
     // XXX For large layer trees, it would be faster to do this once from the
     //     root node upwards and store the value on each layer.
     for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
       const FrameMetrics& metrics = parent->GetFrameMetrics();
       resolution.width *= metrics.mResolution.width;
       resolution.height *= metrics.mResolution.height;
     }
 
-    const FrameMetrics& metrics = GetParent()->GetFrameMetrics();
-    mReusableTileStore->HarvestTiles(&mVideoMemoryTiledBuffer,
-                                     metrics.mContentSize,
+    mReusableTileStore->HarvestTiles(this,
+                                     &mVideoMemoryTiledBuffer,
                                      mVideoMemoryTiledBuffer.GetValidRegion(),
                                      mMainMemoryTiledBuffer.GetValidRegion(),
                                      mVideoMemoryTiledBuffer.GetResolution(),
                                      resolution);
   }
 
   mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer,
                                  mMainMemoryTiledBuffer.GetValidRegion(),
@@ -220,18 +219,17 @@ TiledThebesLayerOGL::RenderLayer(int aPr
   gl()->MakeCurrent();
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   ProcessUploadQueue();
 
   Layer* maskLayer = GetMaskLayer();
 
   // Render old tiles to fill in gaps we haven't had the time to render yet.
   if (mReusableTileStore) {
-    const FrameMetrics& metrics = GetParent()->GetFrameMetrics();
-    mReusableTileStore->DrawTiles(this, metrics.mContentSize,
+    mReusableTileStore->DrawTiles(this,
                                   mVideoMemoryTiledBuffer.GetValidRegion(),
                                   mVideoMemoryTiledBuffer.GetResolution(),
                                   GetEffectiveTransform(), aOffset, maskLayer);
   }
 
   // Render valid tiles.
   const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
   const nsIntRect visibleRect = visibleRegion.GetBounds();
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 20; 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/
  *
@@ -1531,49 +1531,63 @@ CopySurface(gfxASurface* aSrc, gfxASurfa
   cairo_destroy(cr);
 }
 
 void
 gfxContext::PushGroupAndCopyBackground(gfxASurface::gfxContentType content)
 {
   if (mCairo) {
     if (content == gfxASurface::CONTENT_COLOR_ALPHA &&
-        !(GetFlags() & FLAG_DISABLE_COPY_BACKGROUND)) {
-        nsRefPtr<gfxASurface> s = CurrentSurface();
-        if ((s->GetAllowUseAsSource() || s->GetType() == gfxASurface::SurfaceTypeTee) &&
-            (s->GetContentType() == gfxASurface::CONTENT_COLOR ||
-             s->GetOpaqueRect().Contains(GetRoundOutDeviceClipExtents(this)))) {
-            cairo_push_group_with_content(mCairo, CAIRO_CONTENT_COLOR);
-            nsRefPtr<gfxASurface> d = CurrentSurface();
+      !(GetFlags() & FLAG_DISABLE_COPY_BACKGROUND)) {
+      nsRefPtr<gfxASurface> s = CurrentSurface();
+      if ((s->GetAllowUseAsSource() || s->GetType() == gfxASurface::SurfaceTypeTee) &&
+          (s->GetContentType() == gfxASurface::CONTENT_COLOR ||
+              s->GetOpaqueRect().Contains(GetRoundOutDeviceClipExtents(this)))) {
+        cairo_push_group_with_content(mCairo, CAIRO_CONTENT_COLOR);
+        nsRefPtr<gfxASurface> d = CurrentSurface();
 
-            if (d->GetType() == gfxASurface::SurfaceTypeTee) {
-                NS_ASSERTION(s->GetType() == gfxASurface::SurfaceTypeTee, "Mismatched types");
-                nsAutoTArray<nsRefPtr<gfxASurface>,2> ss;
-                nsAutoTArray<nsRefPtr<gfxASurface>,2> ds;
-                static_cast<gfxTeeSurface*>(s.get())->GetSurfaces(&ss);
-                static_cast<gfxTeeSurface*>(d.get())->GetSurfaces(&ds);
-                NS_ASSERTION(ss.Length() == ds.Length(), "Mismatched lengths");
-                gfxPoint translation = d->GetDeviceOffset() - s->GetDeviceOffset();
-                for (PRUint32 i = 0; i < ss.Length(); ++i) {
-                    CopySurface(ss[i], ds[i], translation);
-                }
-            } else {
-                CopySurface(s, d, gfxPoint(0, 0));
-            }
-            d->SetOpaqueRect(s->GetOpaqueRect());
-            return;
+        if (d->GetType() == gfxASurface::SurfaceTypeTee) {
+          NS_ASSERTION(s->GetType() == gfxASurface::SurfaceTypeTee, "Mismatched types");
+          nsAutoTArray<nsRefPtr<gfxASurface>,2> ss;
+          nsAutoTArray<nsRefPtr<gfxASurface>,2> ds;
+          static_cast<gfxTeeSurface*>(s.get())->GetSurfaces(&ss);
+          static_cast<gfxTeeSurface*>(d.get())->GetSurfaces(&ds);
+          NS_ASSERTION(ss.Length() == ds.Length(), "Mismatched lengths");
+          gfxPoint translation = d->GetDeviceOffset() - s->GetDeviceOffset();
+          for (PRUint32 i = 0; i < ss.Length(); ++i) {
+              CopySurface(ss[i], ds[i], translation);
+          }
+        } else {
+          CopySurface(s, d, gfxPoint(0, 0));
         }
+        d->SetOpaqueRect(s->GetOpaqueRect());
+        return;
+      }
     }
-    cairo_push_group_with_content(mCairo, (cairo_content_t) content);
   } else {
-    RefPtr<SourceSurface> source = mDT->Snapshot();
-    PushGroup(content);
-    Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
-    mDT->DrawSurface(source, surfRect, surfRect); 
+    IntRect clipExtents;
+    if (mDT->GetFormat() != FORMAT_B8G8R8X8) {
+      gfxRect clipRect = GetRoundOutDeviceClipExtents(this);
+      clipExtents = IntRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
+    }
+    if (mDT->GetFormat() == FORMAT_B8G8R8X8 ||
+        mDT->GetOpaqueRect().Contains(clipExtents)) {
+      DrawTarget *oldDT = mDT;
+      RefPtr<SourceSurface> source = mDT->Snapshot();
+      PushGroup(content);
+      Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
+      Matrix oldTransform = mDT->GetTransform();
+      mDT->SetTransform(Matrix());
+      mDT->DrawSurface(source, surfRect, surfRect); 
+      mDT->SetTransform(oldTransform);
+      mDT->SetOpaqueRect(oldDT->GetOpaqueRect());
+      return;
+    }
   }
+  PushGroup(content);
 }
 
 already_AddRefed<gfxPattern>
 gfxContext::PopGroup()
 {
   if (mCairo) {
     cairo_pattern_t *pat = cairo_pop_group(mCairo);
     gfxPattern *wrapper = new gfxPattern(pat);
--- a/hal/HalSensor.h
+++ b/hal/HalSensor.h
@@ -51,16 +51,17 @@ namespace hal {
  */
 enum SensorType {
   SENSOR_UNKNOWN = -1,
   SENSOR_ORIENTATION,
   SENSOR_ACCELERATION,
   SENSOR_PROXIMITY,
   SENSOR_LINEAR_ACCELERATION,
   SENSOR_GYROSCOPE,
+  SENSOR_LIGHT,
   NUM_SENSOR_TYPE
 };
 
 class SensorData;
 
 typedef Observer<SensorData> ISensorObserver;
 
 /**
--- a/hal/gonk/GonkSensor.cpp
+++ b/hal/gonk/GonkSensor.cpp
@@ -33,16 +33,18 @@ HardwareSensorToHalSensor(int type)
 {     
   switch(type) {
     case SENSOR_TYPE_ORIENTATION:
       return SENSOR_ORIENTATION;
     case SENSOR_TYPE_ACCELEROMETER:
       return SENSOR_ACCELERATION;
     case SENSOR_TYPE_PROXIMITY:
       return SENSOR_PROXIMITY;
+    case SENSOR_TYPE_LIGHT:
+      return SENSOR_LIGHT;
     case SENSOR_TYPE_GYROSCOPE:
       return SENSOR_GYROSCOPE;
     case SENSOR_TYPE_LINEAR_ACCELERATION:
       return SENSOR_LINEAR_ACCELERATION;
     default:
       return SENSOR_UNKNOWN;
   }
 }
@@ -57,16 +59,18 @@ HalSensorToHardwareSensor(SensorType typ
 {
   switch(type) {
     case SENSOR_ORIENTATION:
       return SENSOR_TYPE_ORIENTATION;
     case SENSOR_ACCELERATION:
       return SENSOR_TYPE_ACCELEROMETER;
     case SENSOR_PROXIMITY:
       return SENSOR_TYPE_PROXIMITY;
+    case SENSOR_LIGHT:
+      return SENSOR_TYPE_LIGHT;
     case SENSOR_GYROSCOPE:
       return SENSOR_TYPE_GYROSCOPE;
     case SENSOR_LINEAR_ACCELERATION:
       return SENSOR_TYPE_LINEAR_ACCELERATION;
     default:
       return -1;
   }
 }
@@ -104,16 +108,30 @@ public:
     }
     mSensorData.accuracy() = HardwareStatusToHalAccuracy(SensorseventStatus(data));
     mSensorData.timestamp() = data.timestamp;
     if (mSensorData.sensor() == SENSOR_GYROSCOPE) {
       // libhardware returns gyro as rad.  convert.
       mSensorValues.AppendElement(radToDeg(data.data[0]));
       mSensorValues.AppendElement(radToDeg(data.data[1]));
       mSensorValues.AppendElement(radToDeg(data.data[2]));
+    } else if (mSensorData.sensor() == SENSOR_PROXIMITY) {
+      mSensorValues.AppendElement(data.data[0]);
+      mSensorValues.AppendElement(0);     
+
+      // Determine the maxRange for this sensor.
+      const sensor_t* sensors = NULL;
+      size_t size = SensorDevice::getInstance().getSensorList(&sensors);
+      for (size_t i = 0; i < size; i++) {
+        if (sensors[i].type == SENSOR_TYPE_PROXIMITY) {
+          mSensorValues.AppendElement(sensors[i].maxRange);     
+        }
+      }
+    } else if (mSensorData.sensor() == SENSOR_LIGHT) {
+      mSensorValues.AppendElement(data.data[0]);
     } else {
       mSensorValues.AppendElement(data.data[0]);
       mSensorValues.AppendElement(data.data[1]);
       mSensorValues.AppendElement(data.data[2]);
     }
     mSensorData.values() = mSensorValues;
   }
 
--- a/ipc/chromium/src/base/platform_thread_posix.cc
+++ b/ipc/chromium/src/base/platform_thread_posix.cc
@@ -6,16 +6,17 @@
 
 #include <errno.h>
 #include <sched.h>
 
 #if defined(OS_MACOSX)
 #include <mach/mach.h>
 #elif defined(OS_LINUX)
 #include <sys/syscall.h>
+#include <sys/prctl.h>
 #include <unistd.h>
 #endif
 
 #if defined(OS_MACOSX)
 namespace base {
 void InitThreading();
 }  // namespace
 #endif
@@ -61,22 +62,29 @@ void PlatformThread::Sleep(int duration_
     sleep_time = remaining;
 }
 
 #ifndef OS_MACOSX
 // Mac is implemented in platform_thread_mac.mm.
 
 // static
 void PlatformThread::SetName(const char* name) {
-  // The POSIX standard does not provide for naming threads, and neither Linux
-  // nor Mac OS X (our two POSIX targets) provide any non-portable way of doing
-  // it either. (Some BSDs provide pthread_set_name_np but that isn't much of a
-  // consolation prize.)
-  // TODO(darin): decide whether stuffing the name in TLS or other in-memory
-  // structure would be useful for debugging or not.
+  // On linux we can get the thread names to show up in the debugger by setting
+  // the process name for the LWP.  We don't want to do this for the main
+  // thread because that would rename the process, causing tools like killall
+  // to stop working.
+  if (PlatformThread::CurrentId() == getpid())
+    return;
+
+  // http://0pointer.de/blog/projects/name-your-threads.html
+  // Set the name for the LWP (which gets truncated to 15 characters).
+  // Note that glibc also has a 'pthread_setname_np' api, but it may not be
+  // available everywhere and it's only benefit over using prctl directly is
+  // that it can set the name of threads other than the current thread.
+  prctl(PR_SET_NAME, reinterpret_cast<uintptr_t>(name), 0, 0, 0); 
 }
 #endif // !OS_MACOSX
 
 namespace {
 
 bool CreateThread(size_t stack_size, bool joinable,
                   PlatformThread::Delegate* delegate,
                   PlatformThreadHandle* thread_handle) {
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -42,16 +42,20 @@
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "pratom.h"
 #include "prthread.h"
 
 #include "base/logging.h"
 #include "base/scoped_nsautorelease_pool.h"
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidBridge.h"
+#endif
+
 using mozilla::ipc::DoWorkRunnable;
 using mozilla::ipc::MessagePump;
 using mozilla::ipc::MessagePumpForChildProcess;
 using base::Time;
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(DoWorkRunnable, nsIRunnable, nsITimerCallback)
 
 NS_IMETHODIMP
@@ -110,16 +114,23 @@ MessagePump::Run(MessagePump::Delegate* 
     bool did_work = NS_ProcessNextEvent(mThread, false) ? true : false;
     if (!keep_running_)
       break;
 
     did_work |= aDelegate->DoWork();
     if (!keep_running_)
       break;
 
+#ifdef MOZ_WIDGET_ANDROID
+    // This processes messages in the Android Looper. Note that we only
+    // get here if the normal Gecko event loop has been awoken above.
+    // Bug 750713
+    AndroidBridge::Bridge()->PumpMessageLoop();
+#endif
+
     did_work |= aDelegate->DoDelayedWork(&delayed_work_time_);
 
     if (did_work && delayed_work_time_.is_null())
       mDelayedWorkTimer->Cancel();
 
     if (!keep_running_)
       break;
 
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -517,46 +517,29 @@ DumpHeap(JSContext *cx,
     fprintf(stderr,
             "dumpHeap: argument %u is not null or a heap-allocated thing\n",
             (unsigned)(vp - argv));
     return JS_FALSE;
 }
 
 #endif /* DEBUG */
 
-static JSBool
-Clear(JSContext *cx,
-      unsigned argc,
-      jsval *vp)
-{
-    jsval *argv = JS_ARGV(cx, vp);
-    if (argc > 0 && !JSVAL_IS_PRIMITIVE(argv[0])) {
-        JS_ClearScope(cx, JSVAL_TO_OBJECT(argv[0]));
-    } else {
-        JS_ReportError(cx, "'clear' requires an object");
-        return JS_FALSE;
-    }
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    return JS_TRUE;
-}
-
 JSFunctionSpec gGlobalFunctions[] =
 {
     {"print",           Print,          0,0},
     {"load",            Load,           1,0},
     {"quit",            Quit,           0,0},
     {"version",         Version,        1,0},
     {"build",           BuildDate,      0,0},
     {"dumpXPC",         DumpXPC,        1,0},
     {"dump",            Dump,           1,0},
     {"gc",              GC,             0,0},
 #ifdef JS_GC_ZEAL
     {"gczeal",          GCZeal,         1,0},
 #endif
-    {"clear",           Clear,          1,0},
 #ifdef DEBUG
     {"dumpHeap",        DumpHeap,       5,0},
 #endif
     {nsnull,nsnull,0,0}
 };
 
 typedef enum JSShellErrNum
 {
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -487,17 +487,17 @@ jsd_NewScriptHookProc(
                 const char  *filename,      /* URL this script loads from */
                 unsigned       lineno,         /* line where this script starts */
                 JSScript    *script,
                 JSFunction  *fun,
                 void*       callerdata);
 
 extern void
 jsd_DestroyScriptHookProc(
-                JSContext   *cx,
+                JSFreeOp    *fop,
                 JSScript    *script,
                 void*       callerdata);
 
 /* Script execution hook functions */
 
 extern JSBool
 jsd_SetExecutionHook(JSDContext*           jsdc,
                      JSDScript*            jsdscript,
@@ -521,17 +521,17 @@ jsd_ScriptCreated(JSDContext* jsdc,
                   JSContext   *cx,
                   const char  *filename,    /* URL this script loads from */
                   unsigned       lineno,       /* line where this script starts */
                   JSScript    *script,
                   JSFunction  *fun);
 
 extern void
 jsd_ScriptDestroyed(JSDContext* jsdc,
-                    JSContext   *cx,
+                    JSFreeOp    *fop,
                     JSScript    *script);
 
 /***************************************************************************/
 /* Source Text functions */
 
 extern JSDSourceText*
 jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp);
 
--- a/js/jsd/jsd_high.c
+++ b/js/jsd/jsd_high.c
@@ -143,16 +143,19 @@ static JSDContext*
 
     if( ! jsdc->glob )
         goto label_newJSDContext_failure;
 
     call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
     if( ! call )
         goto label_newJSDContext_failure;
 
+    if ( ! JS_AddNamedObjectRoot(jsdc->dumbContext, &jsdc->glob, "JSD context global") )
+        goto label_newJSDContext_failure;
+
     ok = JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob);
 
     JS_LeaveCrossCompartmentCall(call);
     if( ! ok )
         goto label_newJSDContext_failure;
 
     JS_EndRequest(jsdc->dumbContext);
 
@@ -162,16 +165,18 @@ static JSDContext*
     JSD_LOCK();
     JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
     JSD_UNLOCK();
 
     return jsdc;
 
 label_newJSDContext_failure:
     if( jsdc ) {
+        if ( jsdc->dumbContext && jsdc->glob )
+            JS_RemoveObjectRootRT(JS_GetRuntime(jsdc->dumbContext), &jsdc->glob);
         jsd_DestroyObjectManager(jsdc);
         jsd_DestroyAtomTable(jsdc);
         if( jsdc->dumbContext )
             JS_EndRequest(jsdc->dumbContext);
         free(jsdc);
     }
     return NULL;
 }
@@ -180,16 +185,19 @@ static void
 _destroyJSDContext(JSDContext* jsdc)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
 
     JSD_LOCK();
     JS_REMOVE_LINK(&jsdc->links);
     JSD_UNLOCK();
 
+    if ( jsdc->dumbContext && jsdc->glob ) {
+        JS_RemoveObjectRootRT(JS_GetRuntime(jsdc->dumbContext), &jsdc->glob);
+    }
     jsd_DestroyObjectManager(jsdc);
     jsd_DestroyAtomTable(jsdc);
 
     jsdc->inited = JS_FALSE;
 
     /*
     * We should free jsdc here, but we let it leak in case there are any 
     * asynchronous hooks calling into the system using it as a handle
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -698,17 +698,17 @@ jsd_NewScriptHookProc(
     JSD_UNLOCK();
 
     if( hook )
         hook(jsdc, jsdscript, JS_TRUE, hookData);
 }
 
 void
 jsd_DestroyScriptHookProc( 
-                JSContext   *cx,
+                JSFreeOp    *fop,
                 JSScript    *script,
                 void*       callerdata )
 {
     JSDScript* jsdscript = NULL;
     JSDContext* jsdc = (JSDContext*) callerdata;
     JSD_ScriptHookProc      hook;
     void*                   hookData;
     
@@ -990,13 +990,13 @@ jsd_ScriptCreated(JSDContext* jsdc,
                   JSScript    *script,
                   JSFunction  *fun)
 {
     jsd_NewScriptHookProc(cx, filename, lineno, script, fun, jsdc);
 }
 
 void
 jsd_ScriptDestroyed(JSDContext* jsdc,
-                    JSContext   *cx,
+                    JSFreeOp    *fop,
                     JSScript    *script)
 {
-    jsd_DestroyScriptHookProc(cx, script, jsdc);
+    jsd_DestroyScriptHookProc(fop, script, jsdc);
 }
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -3353,17 +3353,16 @@ jsdService::~jsdService()
     mBreakpointHook = nsnull;
     mDebugHook = nsnull;
     mDebuggerHook = nsnull;
     mInterruptHook = nsnull;
     mScriptHook = nsnull;
     mThrowHook = nsnull;
     mTopLevelHook = nsnull;
     mFunctionHook = nsnull;
-    gGCRunning = false;
     Off();
     gJsds = nsnull;
 }
 
 jsdService *
 jsdService::GetService ()
 {
     if (!gJsds)
--- a/js/jsd/jsdebug.c
+++ b/js/jsd/jsdebug.c
@@ -382,21 +382,21 @@ JSD_ScriptCreated(JSDContext* jsdc,
                   JSFunction  *fun)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     jsd_ScriptCreated(jsdc, cx, filename, lineno, script, fun);
 }
 
 JSD_PUBLIC_API(void)
 JSD_ScriptDestroyed(JSDContext* jsdc,
-                    JSContext   *cx,
+                    JSFreeOp    *fop,
                     JSScript    *script)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
-    jsd_ScriptDestroyed(jsdc, cx, script);
+    jsd_ScriptDestroyed(jsdc, fop, script);
 }
 
 /***************************************************************************/
 /* Source Text functions */
 
 JSD_PUBLIC_API(void)
 JSD_LockSourceTextSubsystem(JSDContext* jsdc)
 {
--- a/js/jsd/jsdebug.h
+++ b/js/jsd/jsdebug.h
@@ -530,17 +530,17 @@ JSD_ScriptCreated(JSDContext* jsdc,
                   JSScript    *script,
                   JSFunction  *fun);
 
 /*
 * see JSD_ScriptCreated
 */
 extern JSD_PUBLIC_API(void)
 JSD_ScriptDestroyed(JSDContext* jsdc,
-                    JSContext   *cx,
+                    JSFreeOp    *fop,
                     JSScript    *script);
 
 /***************************************************************************/
 /* Source Text functions */
 
 /*
 * In some embeddings (e.g. mozilla) JavaScript source code from a 'file' may be
 * execute before the entire 'file' has even been loaded. This system supports
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -113,17 +113,16 @@ CPPSRCS		= \
 		jsdate.cpp \
 		jsdbgapi.cpp \
 		jsdhash.cpp \
 		jsdtoa.cpp \
 		jsexn.cpp \
 		jsfriendapi.cpp \
 		jsfun.cpp \
 		jsgc.cpp \
-		jsgcmark.cpp \
 		jscrashreport.cpp \
 		jshash.cpp \
 		jsinfer.cpp \
 		jsinterp.cpp \
 		jsiter.cpp \
 		jslog2.cpp \
 		jsmath.cpp \
 		jsnativestack.cpp \
@@ -167,16 +166,17 @@ CPPSRCS		= \
 		TokenStream.cpp \
 		TestingFunctions.cpp \
 		LifoAlloc.cpp \
 		MapObject.cpp \
 		MemoryMetrics.cpp \
 		RegExpObject.cpp \
 		RegExpStatics.cpp \
 		RegExp.cpp \
+		Marking.cpp \
 		Memory.cpp \
 		Statistics.cpp \
 		StringBuffer.cpp \
 		Unicode.cpp \
 		Xdr.cpp \
 		$(NULL)
 
 # Changes to internal header files, used externally, massively slow down
@@ -191,17 +191,16 @@ INSTALLED_HEADERS = \
 		jsatom.h \
 		jsatom.tbl \
 		jsclass.h \
 		jsclist.h \
 		jsdbgapi.h \
 		jsdhash.h \
 		jsfriendapi.h \
 		jsgc.h \
-		jscell.h \
 		jshash.h \
 		jslock.h \
 		json.h \
 		jsproxy.h \
 		jsprf.h \
 		jsproto.tbl \
 		jsprvtd.h \
 		jspubtd.h \
@@ -218,19 +217,20 @@ INSTALLED_HEADERS = \
 #
 EXPORTS_NAMESPACES += ds gc
 
 EXPORTS_ds = \
 		BitArray.h \
 		$(NULL)
 
 EXPORTS_gc = \
+		Barrier.h \
+		Heap.h \
+		Root.h \
 		Statistics.h \
-		Barrier.h \
-		Root.h \
 		$(NULL)
 
 ######################################################
 # BEGIN include exported headers from the JS engine
 #
 #       Ultimately, after cleansing INSTALLED_HEADERS,
 #       these will be the ONLY headers exported by
 #       the js engine
--- a/js/src/build/autoconf/compiler-opts.m4
+++ b/js/src/build/autoconf/compiler-opts.m4
@@ -1,10 +1,58 @@
 dnl Add compiler specific options
 
+AC_DEFUN([MOZ_DEFAULT_COMPILER],
+[
+dnl Default to MSVC for win32 and gcc-4.2 for darwin
+dnl ==============================================================
+if test -z "$CROSS_COMPILE"; then
+case "$target" in
+*-mingw*)
+    if test -z "$CC"; then CC=cl; fi
+    if test -z "$CXX"; then CXX=cl; fi
+    if test -z "$CPP"; then CPP="cl -E -nologo"; fi
+    if test -z "$CXXCPP"; then CXXCPP="cl -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
+    if test -z "$LD"; then LD=link; fi
+    if test -z "$AS"; then
+        case "${target_cpu}" in
+        i*86)
+            AS=ml;
+            ;;
+        x86_64)
+            AS=ml64;
+            ;;
+        esac
+    fi
+    if test -z "$MIDL"; then MIDL=midl; fi
+
+    # need override this flag since we don't use $(LDFLAGS) for this.
+    if test -z "$HOST_LDFLAGS" ; then
+        HOST_LDFLAGS=" "
+    fi
+    ;;
+*-darwin*)
+    # we prefer gcc-4.2 over gcc on older darwin, so
+    # use that specific version if it's available.
+    # On newer versions of darwin, gcc is llvm-gcc while gcc-4.2 is the plain
+    # one, so we also try that first. If that fails, we fall back to clang
+    # as llvm-gcc is an unsupported dead end.
+    MOZ_PATH_PROGS(CC, $CC gcc-4.2 clang gcc)
+    MOZ_PATH_PROGS(CXX, $CXX g++-4.2 clang++ g++)
+    IS_LLVM_GCC=$($CC -v 2>&1 | grep llvm-gcc)
+    if test -n "$IS_LLVM_GCC"
+    then
+      echo llvm-gcc is known to be broken, please use gcc-4.2 or clang.
+      exit 1
+    fi
+    ;;
+esac
+fi
+])
+
 AC_DEFUN([MOZ_COMPILER_OPTS],
 [
 if test "$CLANG_CXX"; then
     ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
     ## returned by C functions. This is possible because we use knowledge about the ABI
     ## to typedef it to a C type with the same layout when the headers are included
     ## from C.
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -38,20 +38,20 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/FloatingPoint.h"
 
 #include "builtin/MapObject.h"
 
 #include "jscntxt.h"
-#include "jsgcmark.h"
 #include "jsiter.h"
 #include "jsobj.h"
 
+#include "gc/Marking.h"
 #include "vm/GlobalObject.h"
 #include "vm/MethodGuard.h"
 #include "vm/Stack.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -168,50 +168,17 @@ dnl ====================================
 MOZ_ARG_WITH_STRING(dist-dir,
 [  --with-dist-dir=DIR     Use DIR as 'dist' staging area.  DIR may be
                           relative to the top of SpiderMonkey build tree,
                           or absolute.],
     TOP_DIST=$withval,
     TOP_DIST=dist)
 AC_SUBST(TOP_DIST)
 
-dnl Default to MSVC for win32
-dnl ==============================================================
-if test -z "$CROSS_COMPILE"; then
-case "$target" in
-*-mingw*)
-    if test -z "$CC"; then CC=cl; fi
-    if test -z "$CXX"; then CXX=cl; fi
-    if test -z "$CPP"; then CPP="cl -E -nologo"; fi
-    if test -z "$CXXCPP"; then CXXCPP="cl -TP -E -nologo"; ac_cv_prog_CXXCPP="$CXXCPP"; fi
-    if test -z "$LD"; then LD=link; fi
-    if test -z "$AS"; then
-        case "${target_cpu}" in
-        i*86)
-            AS=ml;
-            ;;
-        x86_64)
-            AS=ml64;
-            ;;
-        esac
-    fi
-    if test -z "$MIDL"; then MIDL=midl; fi
-
-    # need override this flag since we don't use $(LDFLAGS) for this.
-    if test -z "$HOST_LDFLAGS" ; then
-        HOST_LDFLAGS=" "
-    fi
-    ;;
-*-darwin*)
-    # prefer gcc-4.2 to default cc on older xcode
-    MOZ_PATH_PROGS(CC, $CC gcc-4.2 gcc)
-    MOZ_PATH_PROGS(CXX, $CXX g++-4.2 g++)
-    ;;
-esac
-fi
+MOZ_DEFAULT_COMPILER
 
 COMPILE_ENVIRONMENT=1
 MOZ_ARG_DISABLE_BOOL(compile-environment,
 [  --disable-compile-environment
                           Disable compiler/library checks.],
     COMPILE_ENVIRONMENT= )
 AC_SUBST(COMPILE_ENVIRONMENT)
 
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -607,19 +607,17 @@ struct ParseNode {
     bool isUsed() const                    { return pn_used; }
     void setUsed(bool enabled)             { pn_used = enabled; }
     bool isDefn() const                    { return pn_defn; }
     void setDefn(bool enabled)             { pn_defn = enabled; }
 
     TokenPos            pn_pos;         /* two 16-bit pairs here, for 64 bits */
     int32_t             pn_offset;      /* first generated bytecode offset */
     ParseNode           *pn_next;       /* intrinsic link in parent PN_LIST */
-    ParseNode           *pn_link;       /* def/use link (alignment freebie);
-                                           also links FunctionBox::methods
-                                           lists of would-be |this| methods */
+    ParseNode           *pn_link;       /* def/use link (alignment freebie) */
 
     union {
         struct {                        /* list of next-linked nodes */
             ParseNode   *head;          /* first node in list */
             ParseNode   **tail;         /* ptr to ptr to last node in list */
             uint32_t    count;          /* number of nodes in list */
             uint32_t    xflags:12,      /* extra flags, see below */
                         blockid:20;     /* see name variant below */
@@ -1542,21 +1540,16 @@ struct ObjectBox {
 #define JSFB_LEVEL_BITS 14
 
 struct FunctionBox : public ObjectBox
 {
     ParseNode           *node;
     FunctionBox         *siblings;
     FunctionBox         *kids;
     FunctionBox         *parent;
-    ParseNode           *methods;               /* would-be methods set on this;
-                                                   these nodes are linked via
-                                                   pn_link, since lambdas are
-                                                   neither definitions nor uses
-                                                   of a binding */
     Bindings            bindings;               /* bindings for this function */
     uint32_t            queued:1,
                         inLoop:1,               /* in a loop in parent function */
                         level:JSFB_LEVEL_BITS;
     uint32_t            tcflags;
 
     JSFunction *function() const { return (JSFunction *) object; }
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -60,31 +60,31 @@
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/ParseMaps.h"
 #include "frontend/TokenStream.h"
+#include "gc/Marking.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsscriptinlines.h"
 
@@ -219,17 +219,16 @@ Parser::newFunctionBox(JSObject *obj, Pa
     funbox->object = obj;
     funbox->isFunctionBox = true;
     funbox->node = fn;
     funbox->siblings = tc->functionList;
     tc->functionList = funbox;
     ++tc->parser->functionCount;
     funbox->kids = NULL;
     funbox->parent = tc->funbox;
-    funbox->methods = NULL;
     new (&funbox->bindings) Bindings(context);
     funbox->queued = false;
     funbox->inLoop = false;
     for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
         if (STMT_IS_LOOP(stmt)) {
             funbox->inLoop = true;
             break;
         }
@@ -2447,16 +2446,54 @@ NoteLValue(JSContext *cx, ParseNode *pn,
      * the function name. For assignment to function name to fail in strict
      * mode, we must have a binding for it in the scope chain; we ensure this
      * happens by making such functions heavyweight.
      */
     if (tc->inFunction() && pn->pn_atom == tc->fun()->atom)
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
 }
 
+static bool
+NoteNameUse(ParseNode *pn, TreeContext *tc)
+{
+    PropertyName *name = pn->pn_atom->asPropertyName();
+    StmtInfo *stmt = LexicalLookup(tc, name, NULL);
+
+    MultiDeclRange mdl = tc->decls.lookupMulti(name);
+
+    Definition *dn;
+    if (!mdl.empty()) {
+        dn = mdl.front();
+    } else {
+        if (AtomDefnAddPtr p = tc->lexdeps->lookupForAdd(name)) {
+            dn = p.value();
+        } else {
+            /*
+             * No definition before this use in any lexical scope.
+             * Create a placeholder definition node to either:
+             * - Be adopted when we parse the real defining
+             *   declaration, or
+             * - Be left as a free variable definition if we never
+             *   see the real definition.
+             */
+            dn = MakePlaceholder(pn, tc);
+            if (!dn || !tc->lexdeps->add(p, name, dn))
+                return false;
+        }
+    }
+
+    JS_ASSERT(dn->isDefn());
+    LinkUseToDef(pn, dn, tc);
+
+    if (stmt && stmt->type == STMT_WITH)
+        pn->pn_dflags |= PND_DEOPTIMIZED;
+
+    return true;
+}
+
 #if JS_HAS_DESTRUCTURING
 
 static JSBool
 BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc)
 {
     JS_ASSERT(pn->isKind(PNK_NAME));
 
     data->pn = pn;
@@ -2631,16 +2668,25 @@ CheckDestructuring(JSContext *cx, BindDa
             } else if (data) {
                 if (!pn->isKind(PNK_NAME)) {
                     ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
                                              JSMSG_NO_VARIABLE_NAME);
                     return false;
                 }
                 ok = BindDestructuringVar(cx, data, pn, tc);
             } else {
+                /*
+                 * If right and left point to the same node, then this is
+                 * destructuring shorthand ({x} = ...). In that case,
+                 * identifierName was not used to parse 'x' so 'x' has not been
+                 * officially linked to its def or registered in lexdeps. Do
+                 * that now.
+                 */
+                if (pair->pn_right == pair->pn_left && !NoteNameUse(pn, tc))
+                    return false;
                 ok = BindDestructuringLHS(cx, pn, tc);
             }
             if (!ok)
                 return false;
         }
     }
 
     /*
@@ -3917,35 +3963,16 @@ Parser::expressionStatement()
     }
 
     ParseNode *pn = UnaryNode::create(PNK_SEMI, tc);
     if (!pn)
         return NULL;
     pn->pn_pos = pn2->pn_pos;
     pn->pn_kid = pn2;
 
-    if (pn2->getKind() == PNK_ASSIGN) {
-        /*
-         * Keep track of all apparent methods created by assignments such
-         * as this.foo = function (...) {...} in a function that could end
-         * up a constructor function. See Parser::setFunctionKinds.
-         */
-        JS_ASSERT(pn2->isOp(JSOP_NOP));
-        if (tc->funbox &&
-            pn2->pn_left->isOp(JSOP_SETPROP) &&
-            pn2->pn_left->pn_expr->isKind(PNK_THIS) &&
-            pn2->pn_right->isOp(JSOP_LAMBDA))
-        {
-            JS_ASSERT(!pn2->isDefn());
-            JS_ASSERT(!pn2->isUsed());
-            pn2->pn_right->pn_link = tc->funbox->methods;
-            tc->funbox->methods = pn2->pn_right;
-        }
-    }
-
     /* Check termination of this primitive statement. */
     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
 }
 
 ParseNode *
 Parser::statement()
 {
     ParseNode *pn;
@@ -6631,46 +6658,18 @@ Parser::identifierName(bool afterDoubleD
     node->setOp(JSOP_NAME);
 
     if ((!afterDoubleDot
 #if JS_HAS_XML_SUPPORT
                 || (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON)
 #endif
                ) && !(tc->flags & TCF_DECL_DESTRUCTURING))
     {
-        StmtInfo *stmt = LexicalLookup(tc, name, NULL);
-
-        MultiDeclRange mdl = tc->decls.lookupMulti(name);
-
-        Definition *dn;
-        if (!mdl.empty()) {
-            dn = mdl.front();
-        } else {
-            if (AtomDefnAddPtr p = tc->lexdeps->lookupForAdd(name)) {
-                dn = p.value();
-            } else {
-                /*
-                 * No definition before this use in any lexical scope.
-                 * Create a placeholder definition node to either:
-                 * - Be adopted when we parse the real defining
-                 *   declaration, or
-                 * - Be left as a free variable definition if we never
-                 *   see the real definition.
-                 */
-                dn = MakePlaceholder(node, tc);
-                if (!dn || !tc->lexdeps->add(p, name, dn))
-                    return NULL;
-            }
-        }
-
-        JS_ASSERT(dn->isDefn());
-        LinkUseToDef(node, dn, tc);
-
-        if (stmt && stmt->type == STMT_WITH)
-            node->pn_dflags |= PND_DEOPTIMIZED;
+        if (!NoteNameUse(node, tc))
+            return NULL;
     }
 
 #if JS_HAS_XML_SUPPORT
     if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON)) {
         if (afterDoubleDot) {
             if (!checkForFunctionNode(name, node))
                 return NULL;
         }
--- a/js/src/frontend/SemanticAnalysis.cpp
+++ b/js/src/frontend/SemanticAnalysis.cpp
@@ -46,91 +46,16 @@
 #include "frontend/Parser.h"
 
 #include "jsobjinlines.h"
 #include "jsfuninlines.h"
 
 using namespace js;
 using namespace js::frontend;
 
-/*
- * Walk the function box list at |*funboxHead|, removing boxes for deleted
- * functions and cleaning up method lists. We do this once, before
- * performing function analysis, to avoid traversing possibly long function
- * lists repeatedly when recycling nodes.
- *
- * There are actually three possible states for function boxes and their
- * nodes:
- *
- * - Live: funbox->node points to the node, and funbox->node->pn_funbox
- *   points back to the funbox.
- *
- * - Recycled: funbox->node points to the node, but funbox->node->pn_funbox
- *   is NULL. When a function node is part of a tree that gets recycled, we
- *   must avoid corrupting any method list the node is on, so we leave the
- *   function node unrecycled until we call CleanFunctionList. At recycle
- *   time, we clear such nodes' pn_funbox pointers to indicate that they
- *   are deleted and should be recycled once we get here.
- *
- * - Mutated: funbox->node is NULL; the contents of the node itself could
- *   be anything. When we mutate a function node into some other kind of
- *   node, we lose all indication that the node was ever part of the
- *   function box tree; it could later be recycled, reallocated, and turned
- *   into anything at all. (Fortunately, method list members never get
- *   mutated, so we don't have to worry about that case.)
- *   ParseNodeAllocator::prepareNodeForMutation clears the node's function
- *   box's node pointer, disconnecting it entirely from the function box tree,
- *   and marking the function box to be trimmed out.
- */
-static void
-CleanFunctionList(ParseNodeAllocator *allocator, FunctionBox **funboxHead)
-{
-    FunctionBox **link = funboxHead;
-    while (FunctionBox *box = *link) {
-        if (!box->node) {
-            /*
-             * This funbox's parse node was mutated into something else. Drop the box,
-             * and stay at the same link.
-             */
-            *link = box->siblings;
-        } else if (!box->node->pn_funbox) {
-            /*
-             * This funbox's parse node is ready to be recycled. Drop the box, recycle
-             * the node, and stay at the same link.
-             */
-            *link = box->siblings;
-            allocator->freeNode(box->node);
-        } else {
-            /* The function is still live. */
-
-            /* First, remove nodes for deleted functions from our methods list. */
-            {
-                ParseNode **methodLink = &box->methods;
-                while (ParseNode *method = *methodLink) {
-                    /* Method nodes are never rewritten in place to be other kinds of nodes. */
-                    JS_ASSERT(method->isArity(PN_FUNC));
-                    if (!method->pn_funbox) {
-                        /* Deleted: drop the node, and stay on this link. */
-                        *methodLink = method->pn_link;
-                    } else {
-                        /* Live: keep the node, and move to the next link. */
-                        methodLink = &method->pn_link;
-                    }
-                }
-            }
-
-            /* Second, remove boxes for deleted functions from our kids list. */
-            CleanFunctionList(allocator, &box->kids);
-
-            /* Keep the box on the list, and move to the next link. */
-            link = &box->siblings;
-        }
-    }
-}
-
 static void
 FlagHeavyweights(Definition *dn, FunctionBox *funbox, uint32_t *tcflags)
 {
     unsigned dnLevel = dn->frameLevel();
 
     while ((funbox = funbox->parent) != NULL) {
         /*
          * Notice that funbox->level is the static level of the definition or
@@ -148,17 +73,22 @@ FlagHeavyweights(Definition *dn, Functio
         *tcflags |= TCF_FUN_HEAVYWEIGHT;
 }
 
 static void
 SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool isDirectEval)
 {
     for (; funbox; funbox = funbox->siblings) {
         ParseNode *fn = funbox->node;
+        if (!fn)
+            continue;
+
         ParseNode *pn = fn->pn_body;
+        if (!pn)
+            continue;
 
         if (funbox->kids)
             SetFunctionKinds(funbox->kids, tcflags, isDirectEval);
 
         JSFunction *fun = funbox->function();
 
         JS_ASSERT(fun->kind() == JSFUN_INTERPRETED);
 
@@ -256,17 +186,16 @@ MarkExtensibleScopeDescendants(JSContext
     }
 
     return true;
 }
 
 bool
 frontend::AnalyzeFunctions(TreeContext *tc)
 {
-    CleanFunctionList(&tc->parser->allocator, &tc->functionList);
     if (!tc->functionList)
         return true;
     if (!MarkExtensibleScopeDescendants(tc->parser->context, tc->functionList, false))
         return false;
     bool isDirectEval = !!tc->parser->callerFrame;
     SetFunctionKinds(tc->functionList, &tc->flags, isDirectEval);
     return true;
 }
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -35,19 +35,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsgc_barrier_inl_h___
 #define jsgc_barrier_inl_h___
 
-#include "jsgcmark.h"
-
 #include "gc/Barrier.h"
+#include "gc/Marking.h"
 
 #include "vm/ObjectImpl-inl.h"
 #include "vm/String-inl.h"
 
 namespace js {
 
 inline void
 EncapsulatedValue::writeBarrierPre(const Value &value)
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -36,18 +36,18 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsgc_barrier_h___
 #define jsgc_barrier_h___
 
 #include "jsapi.h"
-#include "jscell.h"
 
+#include "gc/Heap.h"
 #include "js/HashTable.h"
 
 /*
  * A write barrier is a mechanism used by incremental or generation GCs to
  * ensure that every value that needs to be marked is marked. In general, the
  * write barrier should be invoked whenever a write can cause the set of things
  * traced through by the GC to change. This includes:
  *   - writes to object properties
@@ -242,17 +242,16 @@ BarrieredSetPair(JSCompartment *comp,
     v1.post();
     v2.post();
 }
 
 struct Shape;
 class BaseShape;
 namespace types { struct TypeObject; }
 
-typedef HeapPtr<JSAtom> HeapPtrAtom;
 typedef HeapPtr<JSObject> HeapPtrObject;
 typedef HeapPtr<JSFunction> HeapPtrFunction;
 typedef HeapPtr<JSString> HeapPtrString;
 typedef HeapPtr<JSScript> HeapPtrScript;
 typedef HeapPtr<Shape> HeapPtrShape;
 typedef HeapPtr<BaseShape> HeapPtrBaseShape;
 typedef HeapPtr<types::TypeObject> HeapPtrTypeObject;
 typedef HeapPtr<JSXML> HeapPtrXML;
new file mode 100644
--- /dev/null
+++ b/js/src/gc/Heap.h
@@ -0,0 +1,984 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef gc_heap_h___
+#define gc_heap_h___
+
+#include "mozilla/Attributes.h"
+#include "mozilla/StandardInteger.h"
+
+#include <stddef.h>
+
+#include "jstypes.h"
+#include "jsutil.h"
+
+#include "ds/BitArray.h"
+
+struct JSCompartment;
+
+extern "C" {
+struct JSRuntime;
+}
+
+namespace js {
+
+class FreeOp;
+
+namespace gc {
+
+struct Arena;
+struct ArenaHeader;
+struct Chunk;
+
+/*
+ * Live objects are marked black. How many other additional colors are available
+ * depends on the size of the GCThing. Objects marked gray are eligible for
+ * cycle collection.
+ */
+static const uint32_t BLACK = 0;
+static const uint32_t GRAY = 1;
+
+/* The GC allocation kinds. */
+enum AllocKind {
+    FINALIZE_OBJECT0,
+    FINALIZE_OBJECT0_BACKGROUND,
+    FINALIZE_OBJECT2,
+    FINALIZE_OBJECT2_BACKGROUND,
+    FINALIZE_OBJECT4,
+    FINALIZE_OBJECT4_BACKGROUND,
+    FINALIZE_OBJECT8,
+    FINALIZE_OBJECT8_BACKGROUND,
+    FINALIZE_OBJECT12,
+    FINALIZE_OBJECT12_BACKGROUND,
+    FINALIZE_OBJECT16,
+    FINALIZE_OBJECT16_BACKGROUND,
+    FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
+    FINALIZE_SCRIPT,
+    FINALIZE_SHAPE,
+    FINALIZE_BASE_SHAPE,
+    FINALIZE_TYPE_OBJECT,
+#if JS_HAS_XML_SUPPORT
+    FINALIZE_XML,
+#endif
+    FINALIZE_SHORT_STRING,
+    FINALIZE_STRING,
+    FINALIZE_EXTERNAL_STRING,
+    FINALIZE_LAST = FINALIZE_EXTERNAL_STRING
+};
+
+static const unsigned FINALIZE_LIMIT = FINALIZE_LAST + 1;
+static const unsigned FINALIZE_OBJECT_LIMIT = FINALIZE_OBJECT_LAST + 1;
+
+/*
+ * This must be an upper bound, but we do not need the least upper bound, so
+ * we just exclude non-background objects.
+ */
+static const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - FINALIZE_OBJECT_LIMIT / 2;
+
+/*
+ * A GC cell is the base class for all GC things.
+ */
+struct Cell
+{
+    static const size_t CellShift = 3;
+    static const size_t CellSize = size_t(1) << CellShift;
+    static const size_t CellMask = CellSize - 1;
+
+    inline uintptr_t address() const;
+    inline ArenaHeader *arenaHeader() const;
+    inline Chunk *chunk() const;
+    inline AllocKind getAllocKind() const;
+    MOZ_ALWAYS_INLINE bool isMarked(uint32_t color = BLACK) const;
+    MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
+    MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
+
+    inline JSCompartment *compartment() const;
+
+#ifdef DEBUG
+    inline bool isAligned() const;
+#endif
+};
+
+/*
+ * Page size is 4096 by default, except for SPARC, where it is 8192.
+ * Note: Do not use JS_CPU_SPARC here, this header is used outside JS.
+ * Bug 692267: Move page size definition to gc/Memory.h and include it
+ *             directly once jsgc.h is no longer an installed header.
+ */
+#if defined(SOLARIS) && (defined(__sparc) || defined(__sparcv9))
+const size_t PageShift = 13;
+#else
+const size_t PageShift = 12;
+#endif
+const size_t PageSize = size_t(1) << PageShift;
+
+const size_t ChunkShift = 20;
+const size_t ChunkSize = size_t(1) << ChunkShift;
+const size_t ChunkMask = ChunkSize - 1;
+
+const size_t ArenaShift = PageShift;
+const size_t ArenaSize = PageSize;
+const size_t ArenaMask = ArenaSize - 1;
+
+/*
+ * This is the maximum number of arenas we allow in the FreeCommitted state
+ * before we trigger a GC_SHRINK to release free arenas to the OS.
+ */
+const static uint32_t FreeCommittedArenasThreshold = (32 << 20) / ArenaSize;
+
+/*
+ * The mark bitmap has one bit per each GC cell. For multi-cell GC things this
+ * wastes space but allows to avoid expensive devisions by thing's size when
+ * accessing the bitmap. In addition this allows to use some bits for colored
+ * marking during the cycle GC.
+ */
+const size_t ArenaCellCount = size_t(1) << (ArenaShift - Cell::CellShift);
+const size_t ArenaBitmapBits = ArenaCellCount;
+const size_t ArenaBitmapBytes = ArenaBitmapBits / 8;
+const size_t ArenaBitmapWords = ArenaBitmapBits / JS_BITS_PER_WORD;
+
+/*
+ * A FreeSpan represents a contiguous sequence of free cells in an Arena.
+ * |first| is the address of the first free cell in the span. |last| is the
+ * address of the last free cell in the span. This last cell holds a FreeSpan
+ * data structure for the next span unless this is the last span on the list
+ * of spans in the arena. For this last span |last| points to the last byte of
+ * the last thing in the arena and no linkage is stored there, so
+ * |last| == arenaStart + ArenaSize - 1. If the space at the arena end is
+ * fully used this last span is empty and |first| == |last + 1|.
+ *
+ * Thus |first| < |last| implies that we have either the last span with at least
+ * one element or that the span is not the last and contains at least 2
+ * elements. In both cases to allocate a thing from this span we need simply
+ * to increment |first| by the allocation size.
+ *
+ * |first| == |last| implies that we have a one element span that records the
+ * next span. So to allocate from it we need to update the span list head
+ * with a copy of the span stored at |last| address so the following
+ * allocations will use that span.
+ *
+ * |first| > |last| implies that we have an empty last span and the arena is
+ * fully used.
+ *
+ * Also only for the last span (|last| & 1)! = 0 as all allocation sizes are
+ * multiples of Cell::CellSize.
+ */
+struct FreeSpan
+{
+    uintptr_t   first;
+    uintptr_t   last;
+
+  public:
+    FreeSpan() {}
+
+    FreeSpan(uintptr_t first, uintptr_t last)
+      : first(first), last(last) {
+        checkSpan();
+    }
+
+    /*
+     * To minimize the size of the arena header the first span is encoded
+     * there as offsets from the arena start.
+     */
+    static size_t encodeOffsets(size_t firstOffset, size_t lastOffset) {
+        /* Check that we can pack the offsets into uint16. */
+        JS_STATIC_ASSERT(ArenaShift < 16);
+        JS_ASSERT(firstOffset <= ArenaSize);
+        JS_ASSERT(lastOffset < ArenaSize);
+        JS_ASSERT(firstOffset <= ((lastOffset + 1) & ~size_t(1)));
+        return firstOffset | (lastOffset << 16);
+    }
+
+    /*
+     * Encoded offsets for a full arena when its first span is the last one
+     * and empty.
+     */
+    static const size_t FullArenaOffsets = ArenaSize | ((ArenaSize - 1) << 16);
+
+    static FreeSpan decodeOffsets(uintptr_t arenaAddr, size_t offsets) {
+        JS_ASSERT(!(arenaAddr & ArenaMask));
+
+        size_t firstOffset = offsets & 0xFFFF;
+        size_t lastOffset = offsets >> 16;
+        JS_ASSERT(firstOffset <= ArenaSize);
+        JS_ASSERT(lastOffset < ArenaSize);
+
+        /*
+         * We must not use | when calculating first as firstOffset is
+         * ArenaMask + 1 for the empty span.
+         */
+        return FreeSpan(arenaAddr + firstOffset, arenaAddr | lastOffset);
+    }
+
+    void initAsEmpty(uintptr_t arenaAddr = 0) {
+        JS_ASSERT(!(arenaAddr & ArenaMask));
+        first = arenaAddr + ArenaSize;
+        last = arenaAddr | (ArenaSize  - 1);
+        JS_ASSERT(isEmpty());
+    }
+
+    bool isEmpty() const {
+        checkSpan();
+        return first > last;
+    }
+
+    bool hasNext() const {
+        checkSpan();
+        return !(last & uintptr_t(1));
+    }
+
+    const FreeSpan *nextSpan() const {
+        JS_ASSERT(hasNext());
+        return reinterpret_cast<FreeSpan *>(last);
+    }
+
+    FreeSpan *nextSpanUnchecked(size_t thingSize) const {
+#ifdef DEBUG
+        uintptr_t lastOffset = last & ArenaMask;
+        JS_ASSERT(!(lastOffset & 1));
+        JS_ASSERT((ArenaSize - lastOffset) % thingSize == 0);
+#endif
+        return reinterpret_cast<FreeSpan *>(last);
+    }
+
+    uintptr_t arenaAddressUnchecked() const {
+        return last & ~ArenaMask;
+    }
+
+    uintptr_t arenaAddress() const {
+        checkSpan();
+        return arenaAddressUnchecked();
+    }
+
+    ArenaHeader *arenaHeader() const {
+        return reinterpret_cast<ArenaHeader *>(arenaAddress());
+    }
+
+    bool isSameNonEmptySpan(const FreeSpan *another) const {
+        JS_ASSERT(!isEmpty());
+        JS_ASSERT(!another->isEmpty());
+        return first == another->first && last == another->last;
+    }
+
+    bool isWithinArena(uintptr_t arenaAddr) const {
+        JS_ASSERT(!(arenaAddr & ArenaMask));
+
+        /* Return true for the last empty span as well. */
+        return arenaAddress() == arenaAddr;
+    }
+
+    size_t encodeAsOffsets() const {
+        /*
+         * We must use first - arenaAddress(), not first & ArenaMask as
+         * first == ArenaMask + 1 for an empty span.
+         */
+        uintptr_t arenaAddr = arenaAddress();
+        return encodeOffsets(first - arenaAddr, last & ArenaMask);
+    }
+
+    /* See comments before FreeSpan for details. */
+    MOZ_ALWAYS_INLINE void *allocate(size_t thingSize) {
+        JS_ASSERT(thingSize % Cell::CellSize == 0);
+        checkSpan();
+        uintptr_t thing = first;
+        if (thing < last) {
+            /* Bump-allocate from the current span. */
+            first = thing + thingSize;
+        } else if (JS_LIKELY(thing == last)) {
+            /*
+             * Move to the next span. We use JS_LIKELY as without PGO
+             * compilers mis-predict == here as unlikely to succeed.
+             */
+            *this = *reinterpret_cast<FreeSpan *>(thing);
+        } else {
+            return NULL;
+        }
+        checkSpan();
+        return reinterpret_cast<void *>(thing);
+    }
+
+    /* A version of allocate when we know that the span is not empty. */
+    MOZ_ALWAYS_INLINE void *infallibleAllocate(size_t thingSize) {
+        JS_ASSERT(thingSize % Cell::CellSize == 0);
+        checkSpan();
+        uintptr_t thing = first;
+        if (thing < last) {
+            first = thing + thingSize;
+        } else {
+            JS_ASSERT(thing == last);
+            *this = *reinterpret_cast<FreeSpan *>(thing);
+        }
+        checkSpan();
+        return reinterpret_cast<void *>(thing);
+    }
+
+    /*
+     * Allocate from a newly allocated arena. We do not move the free list
+     * from the arena. Rather we set the arena up as fully used during the
+     * initialization so to allocate we simply return the first thing in the
+     * arena and set the free list to point to the second.
+     */
+    MOZ_ALWAYS_INLINE void *allocateFromNewArena(uintptr_t arenaAddr, size_t firstThingOffset,
+                                                size_t thingSize) {
+        JS_ASSERT(!(arenaAddr & ArenaMask));
+        uintptr_t thing = arenaAddr | firstThingOffset;
+        first = thing + thingSize;
+        last = arenaAddr | ArenaMask;
+        checkSpan();
+        return reinterpret_cast<void *>(thing);
+    }
+
+    void checkSpan() const {
+#ifdef DEBUG
+        /* We do not allow spans at the end of the address space. */
+        JS_ASSERT(last != uintptr_t(-1));
+        JS_ASSERT(first);
+        JS_ASSERT(last);
+        JS_ASSERT(first - 1 <= last);
+        uintptr_t arenaAddr = arenaAddressUnchecked();
+        if (last & 1) {
+            /* The span is the last. */
+            JS_ASSERT((last & ArenaMask) == ArenaMask);
+
+            if (first - 1 == last) {
+                /* The span is last and empty. The above start != 0 check
+                 * implies that we are not at the end of the address space.
+                 */
+                return;
+            }
+            size_t spanLength = last - first + 1;
+            JS_ASSERT(spanLength % Cell::CellSize == 0);
+
+            /* Start and end must belong to the same arena. */
+            JS_ASSERT((first & ~ArenaMask) == arenaAddr);
+            return;
+        }
+
+        /* The span is not the last and we have more spans to follow. */
+        JS_ASSERT(first <= last);
+        size_t spanLengthWithoutOneThing = last - first;
+        JS_ASSERT(spanLengthWithoutOneThing % Cell::CellSize == 0);
+
+        JS_ASSERT((first & ~ArenaMask) == arenaAddr);
+
+        /*
+         * If there is not enough space before the arena end to allocate one
+         * more thing, then the span must be marked as the last one to avoid
+         * storing useless empty span reference.
+         */
+        size_t beforeTail = ArenaSize - (last & ArenaMask);
+        JS_ASSERT(beforeTail >= sizeof(FreeSpan) + Cell::CellSize);
+
+        FreeSpan *next = reinterpret_cast<FreeSpan *>(last);
+
+        /*
+         * The GC things on the list of free spans come from one arena
+         * and the spans are linked in ascending address order with
+         * at least one non-free thing between spans.
+         */
+        JS_ASSERT(last < next->first);
+        JS_ASSERT(arenaAddr == next->arenaAddressUnchecked());
+
+        if (next->first > next->last) {
+            /*
+             * The next span is the empty span that terminates the list for
+             * arenas that do not have any free things at the end.
+             */
+            JS_ASSERT(next->first - 1 == next->last);
+            JS_ASSERT(arenaAddr + ArenaSize == next->first);
+        }
+#endif
+    }
+
+};
+
+/* Every arena has a header. */
+struct ArenaHeader
+{
+    friend struct FreeLists;
+
+    JSCompartment   *compartment;
+
+    /*
+     * ArenaHeader::next has two purposes: when unallocated, it points to the
+     * next available Arena's header. When allocated, it points to the next
+     * arena of the same size class and compartment.
+     */
+    ArenaHeader     *next;
+
+  private:
+    /*
+     * The first span of free things in the arena. We encode it as the start
+     * and end offsets within the arena, not as FreeSpan structure, to
+     * minimize the header size.
+     */
+    size_t          firstFreeSpanOffsets;
+
+    /*
+     * One of AllocKind constants or FINALIZE_LIMIT when the arena does not
+     * contain any GC things and is on the list of empty arenas in the GC
+     * chunk. The latter allows to quickly check if the arena is allocated
+     * during the conservative GC scanning without searching the arena in the
+     * list.
+     */
+    size_t       allocKind          : 8;
+
+    /*
+     * When recursive marking uses too much stack the marking is delayed and
+     * the corresponding arenas are put into a stack using the following field
+     * as a linkage. To distinguish the bottom of the stack from the arenas
+     * not present in the stack we use an extra flag to tag arenas on the
+     * stack.
+     *
+     * Delayed marking is also used for arenas that we allocate into during an
+     * incremental GC. In this case, we intend to mark all the objects in the
+     * arena, and it's faster to do this marking in bulk.
+     *
+     * To minimize the ArenaHeader size we record the next delayed marking
+     * linkage as arenaAddress() >> ArenaShift and pack it with the allocKind
+     * field and hasDelayedMarking flag. We use 8 bits for the allocKind, not
+     * ArenaShift - 1, so the compiler can use byte-level memory instructions
+     * to access it.
+     */
+  public:
+    size_t       hasDelayedMarking  : 1;
+    size_t       allocatedDuringIncremental : 1;
+    size_t       markOverflow : 1;
+    size_t       nextDelayedMarking : JS_BITS_PER_WORD - 8 - 1 - 1 - 1;
+
+    static void staticAsserts() {
+        /* We must be able to fit the allockind into uint8_t. */
+        JS_STATIC_ASSERT(FINALIZE_LIMIT <= 255);
+
+        /*
+         * nextDelayedMarkingpacking assumes that ArenaShift has enough bits
+         * to cover allocKind and hasDelayedMarking.
+         */
+        JS_STATIC_ASSERT(ArenaShift >= 8 + 1 + 1 + 1);
+    }
+
+    inline uintptr_t address() const;
+    inline Chunk *chunk() const;
+
+    bool allocated() const {
+        JS_ASSERT(allocKind <= size_t(FINALIZE_LIMIT));
+        return allocKind < size_t(FINALIZE_LIMIT);
+    }
+
+    void init(JSCompartment *comp, AllocKind kind) {
+        JS_ASSERT(!allocated());
+        JS_ASSERT(!markOverflow);
+        JS_ASSERT(!allocatedDuringIncremental);
+        JS_ASSERT(!hasDelayedMarking);
+        compartment = comp;
+
+        JS_STATIC_ASSERT(FINALIZE_LIMIT <= 255);
+        allocKind = size_t(kind);
+
+        /* See comments in FreeSpan::allocateFromNewArena. */
+        firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
+    }
+
+    void setAsNotAllocated() {
+        allocKind = size_t(FINALIZE_LIMIT);
+        markOverflow = 0;
+        allocatedDuringIncremental = 0;
+        hasDelayedMarking = 0;
+        nextDelayedMarking = 0;
+    }
+
+    inline uintptr_t arenaAddress() const;
+    inline Arena *getArena();
+
+    AllocKind getAllocKind() const {
+        JS_ASSERT(allocated());
+        return AllocKind(allocKind);
+    }
+
+    inline size_t getThingSize() const;
+
+    bool hasFreeThings() const {
+        return firstFreeSpanOffsets != FreeSpan::FullArenaOffsets;
+    }
+
+    inline bool isEmpty() const;
+
+    void setAsFullyUsed() {
+        firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
+    }
+
+    inline FreeSpan getFirstFreeSpan() const;
+    inline void setFirstFreeSpan(const FreeSpan *span);
+
+#ifdef DEBUG
+    void checkSynchronizedWithFreeList() const;
+#endif
+
+    inline ArenaHeader *getNextDelayedMarking() const;
+    inline void setNextDelayedMarking(ArenaHeader *aheader);
+};
+
+struct Arena
+{
+    /*
+     * Layout of an arena:
+     * An arena is 4K in size and 4K-aligned. It starts with the ArenaHeader
+     * descriptor followed by some pad bytes. The remainder of the arena is
+     * filled with the array of T things. The pad bytes ensure that the thing
+     * array ends exactly at the end of the arena.
+     *
+     * +-------------+-----+----+----+-----+----+
+     * | ArenaHeader | pad | T0 | T1 | ... | Tn |
+     * +-------------+-----+----+----+-----+----+
+     *
+     * <----------------------------------------> = ArenaSize bytes
+     * <-------------------> = first thing offset
+     */
+    ArenaHeader aheader;
+    uint8_t     data[ArenaSize - sizeof(ArenaHeader)];
+
+  private:
+    static JS_FRIEND_DATA(const uint32_t) ThingSizes[];
+    static JS_FRIEND_DATA(const uint32_t) FirstThingOffsets[];
+
+  public:
+    static void staticAsserts();
+
+    static size_t thingSize(AllocKind kind) {
+        return ThingSizes[kind];
+    }
+
+    static size_t firstThingOffset(AllocKind kind) {
+        return FirstThingOffsets[kind];
+    }
+
+    static size_t thingsPerArena(size_t thingSize) {
+        JS_ASSERT(thingSize % Cell::CellSize == 0);
+
+        /* We should be able to fit FreeSpan in any GC thing. */
+        JS_ASSERT(thingSize >= sizeof(FreeSpan));
+
+        return (ArenaSize - sizeof(ArenaHeader)) / thingSize;
+    }
+
+    static size_t thingsSpan(size_t thingSize) {
+        return thingsPerArena(thingSize) * thingSize;
+    }
+
+    static bool isAligned(uintptr_t thing, size_t thingSize) {
+        /* Things ends at the arena end. */
+        uintptr_t tailOffset = (ArenaSize - thing) & ArenaMask;
+        return tailOffset % thingSize == 0;
+    }
+
+    uintptr_t address() const {
+        return aheader.address();
+    }
+
+    uintptr_t thingsStart(AllocKind thingKind) {
+        return address() | firstThingOffset(thingKind);
+    }
+
+    uintptr_t thingsEnd() {
+        return address() + ArenaSize;
+    }
+
+    template <typename T>
+    bool finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize);
+};
+
+inline size_t
+ArenaHeader::getThingSize() const
+{
+    JS_ASSERT(allocated());
+    return Arena::thingSize(getAllocKind());
+}
+
+/* The chunk header (located at the end of the chunk to preserve arena alignment). */
+struct ChunkInfo
+{
+    Chunk           *next;
+    Chunk           **prevp;
+
+    /* Free arenas are linked together with aheader.next. */
+    ArenaHeader     *freeArenasHead;
+
+    /*
+     * Decommitted arenas are tracked by a bitmap in the chunk header. We use
+     * this offset to start our search iteration close to a decommitted arena
+     * that we can allocate.
+     */
+    uint32_t        lastDecommittedArenaOffset;
+
+    /* Number of free arenas, either committed or decommitted. */
+    uint32_t        numArenasFree;
+
+    /* Number of free, committed arenas. */
+    uint32_t        numArenasFreeCommitted;
+
+    /* Number of GC cycles this chunk has survived. */
+    uint32_t        age;
+};
+
+/*
+ * Calculating ArenasPerChunk:
+ *
+ * In order to figure out how many Arenas will fit in a chunk, we need to know
+ * how much extra space is available after we allocate the header data. This
+ * is a problem because the header size depends on the number of arenas in the
+ * chunk. The two dependent fields are bitmap and decommittedArenas.
+ *
+ * For the mark bitmap, we know that each arena will use a fixed number of full
+ * bytes: ArenaBitmapBytes. The full size of the header data is this number
+ * multiplied by the eventual number of arenas we have in the header. We,
+ * conceptually, distribute this header data among the individual arenas and do
+ * not include it in the header. This way we do not have to worry about its
+ * variable size: it gets attached to the variable number we are computing.
+ *
+ * For the decommitted arena bitmap, we only have 1 bit per arena, so this
+ * technique will not work. Instead, we observe that we do not have enough
+ * header info to fill 8 full arenas: it is currently 4 on 64bit, less on
+ * 32bit. Thus, with current numbers, we need 64 bytes for decommittedArenas.
+ * This will not become 63 bytes unless we double the data required in the
+ * header. Therefore, we just compute the number of bytes required to track
+ * every possible arena and do not worry about slop bits, since there are too
+ * few to usefully allocate.
+ *
+ * To actually compute the number of arenas we can allocate in a chunk, we
+ * divide the amount of available space less the header info (not including
+ * the mark bitmap which is distributed into the arena size) by the size of
+ * the arena (with the mark bitmap bytes it uses).
+ */
+const size_t BytesPerArenaWithHeader = ArenaSize + ArenaBitmapBytes;
+const size_t ChunkDecommitBitmapBytes = ChunkSize / ArenaSize / JS_BITS_PER_BYTE;
+const size_t ChunkBytesAvailable = ChunkSize - sizeof(ChunkInfo) - ChunkDecommitBitmapBytes;
+const size_t ArenasPerChunk = ChunkBytesAvailable / BytesPerArenaWithHeader;
+
+/* A chunk bitmap contains enough mark bits for all the cells in a chunk. */
+struct ChunkBitmap
+{
+    uintptr_t bitmap[ArenaBitmapWords * ArenasPerChunk];
+
+    MOZ_ALWAYS_INLINE void getMarkWordAndMask(const Cell *cell, uint32_t color,
+                                             uintptr_t **wordp, uintptr_t *maskp);
+
+    MOZ_ALWAYS_INLINE bool isMarked(const Cell *cell, uint32_t color) {
+        uintptr_t *word, mask;
+        getMarkWordAndMask(cell, color, &word, &mask);
+        return *word & mask;
+    }
+
+    MOZ_ALWAYS_INLINE bool markIfUnmarked(const Cell *cell, uint32_t color) {
+        uintptr_t *word, mask;
+        getMarkWordAndMask(cell, BLACK, &word, &mask);
+        if (*word & mask)
+            return false;
+        *word |= mask;
+        if (color != BLACK) {
+            /*
+             * We use getMarkWordAndMask to recalculate both mask and word as
+             * doing just mask << color may overflow the mask.
+             */
+            getMarkWordAndMask(cell, color, &word, &mask);
+            if (*word & mask)
+                return false;
+            *word |= mask;
+        }
+        return true;
+    }
+
+    MOZ_ALWAYS_INLINE void unmark(const Cell *cell, uint32_t color) {
+        uintptr_t *word, mask;
+        getMarkWordAndMask(cell, color, &word, &mask);
+        *word &= ~mask;
+    }
+
+    void clear() {
+        PodArrayZero(bitmap);
+    }
+
+#ifdef DEBUG
+    bool noBitsSet(ArenaHeader *aheader) {
+        /*
+         * We assume that the part of the bitmap corresponding to the arena
+         * has the exact number of words so we do not need to deal with a word
+         * that covers bits from two arenas.
+         */
+        JS_STATIC_ASSERT(ArenaBitmapBits == ArenaBitmapWords * JS_BITS_PER_WORD);
+
+        uintptr_t *word, unused;
+        getMarkWordAndMask(reinterpret_cast<Cell *>(aheader->address()), BLACK, &word, &unused);
+        for (size_t i = 0; i != ArenaBitmapWords; i++) {
+            if (word[i])
+                return false;
+        }
+        return true;
+    }
+#endif
+};
+
+JS_STATIC_ASSERT(ArenaBitmapBytes * ArenasPerChunk == sizeof(ChunkBitmap));
+
+typedef BitArray<ArenasPerChunk> PerArenaBitmap;
+
+const size_t ChunkPadSize = ChunkSize
+                            - (sizeof(Arena) * ArenasPerChunk)
+                            - sizeof(ChunkBitmap)
+                            - sizeof(PerArenaBitmap)
+                            - sizeof(ChunkInfo);
+JS_STATIC_ASSERT(ChunkPadSize < BytesPerArenaWithHeader);
+
+/*
+ * Chunks contain arenas and associated data structures (mark bitmap, delayed
+ * marking state).
+ */
+struct Chunk
+{
+    Arena           arenas[ArenasPerChunk];
+
+    /* Pad to full size to ensure cache alignment of ChunkInfo. */
+    uint8_t         padding[ChunkPadSize];
+
+    ChunkBitmap     bitmap;
+    PerArenaBitmap  decommittedArenas;
+    ChunkInfo       info;
+
+    static Chunk *fromAddress(uintptr_t addr) {
+        addr &= ~ChunkMask;
+        return reinterpret_cast<Chunk *>(addr);
+    }
+
+    static bool withinArenasRange(uintptr_t addr) {
+        uintptr_t offset = addr & ChunkMask;
+        return offset < ArenasPerChunk * ArenaSize;
+    }
+
+    static size_t arenaIndex(uintptr_t addr) {
+        JS_ASSERT(withinArenasRange(addr));
+        return (addr & ChunkMask) >> ArenaShift;
+    }
+
+    uintptr_t address() const {
+        uintptr_t addr = reinterpret_cast<uintptr_t>(this);
+        JS_ASSERT(!(addr & ChunkMask));
+        return addr;
+    }
+
+    bool unused() const {
+        return info.numArenasFree == ArenasPerChunk;
+    }
+
+    bool hasAvailableArenas() const {
+        return info.numArenasFree != 0;
+    }
+
+    inline void addToAvailableList(JSCompartment *compartment);
+    inline void insertToAvailableList(Chunk **insertPoint);
+    inline void removeFromAvailableList();
+
+    ArenaHeader *allocateArena(JSCompartment *comp, AllocKind kind);
+
+    void releaseArena(ArenaHeader *aheader);
+
+    static Chunk *allocate(JSRuntime *rt);
+
+    /* Must be called with the GC lock taken. */
+    static inline void release(JSRuntime *rt, Chunk *chunk);
+    static inline void releaseList(JSRuntime *rt, Chunk *chunkListHead);
+
+    /* Must be called with the GC lock taken. */
+    inline void prepareToBeFreed(JSRuntime *rt);
+
+    /*
+     * Assuming that the info.prevp points to the next field of the previous
+     * chunk in a doubly-linked list, get that chunk.
+     */
+    Chunk *getPrevious() {
+        JS_ASSERT(info.prevp);
+        return fromPointerToNext(info.prevp);
+    }
+
+    /* Get the chunk from a pointer to its info.next field. */
+    static Chunk *fromPointerToNext(Chunk **nextFieldPtr) {
+        uintptr_t addr = reinterpret_cast<uintptr_t>(nextFieldPtr);
+        JS_ASSERT((addr & ChunkMask) == offsetof(Chunk, info.next));
+        return reinterpret_cast<Chunk *>(addr - offsetof(Chunk, info.next));
+    }
+
+  private:
+    inline void init();
+
+    /* Search for a decommitted arena to allocate. */
+    unsigned findDecommittedArenaOffset();
+    ArenaHeader* fetchNextDecommittedArena();
+
+  public:
+    /* Unlink and return the freeArenasHead. */
+    inline ArenaHeader* fetchNextFreeArena(JSRuntime *rt);
+
+    inline void addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader);
+};
+
+JS_STATIC_ASSERT(sizeof(Chunk) == ChunkSize);
+
+inline uintptr_t
+Cell::address() const
+{
+    uintptr_t addr = uintptr_t(this);
+    JS_ASSERT(addr % Cell::CellSize == 0);
+    JS_ASSERT(Chunk::withinArenasRange(addr));
+    return addr;
+}
+
+inline uintptr_t
+ArenaHeader::address() const
+{
+    uintptr_t addr = reinterpret_cast<uintptr_t>(this);
+    JS_ASSERT(!(addr & ArenaMask));
+    JS_ASSERT(Chunk::withinArenasRange(addr));
+    return addr;
+}
+
+inline Chunk *
+ArenaHeader::chunk() const
+{
+    return Chunk::fromAddress(address());
+}
+
+inline uintptr_t
+ArenaHeader::arenaAddress() const
+{
+    return address();
+}
+
+inline Arena *
+ArenaHeader::getArena()
+{
+    return reinterpret_cast<Arena *>(arenaAddress());
+}
+
+inline bool
+ArenaHeader::isEmpty() const
+{
+    /* Arena is empty if its first span covers the whole arena. */
+    JS_ASSERT(allocated());
+    size_t firstThingOffset = Arena::firstThingOffset(getAllocKind());
+    return firstFreeSpanOffsets == FreeSpan::encodeOffsets(firstThingOffset, ArenaMask);
+}
+
+FreeSpan
+ArenaHeader::getFirstFreeSpan() const
+{
+#ifdef DEBUG
+    checkSynchronizedWithFreeList();
+#endif
+    return FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
+}
+
+void
+ArenaHeader::setFirstFreeSpan(const FreeSpan *span)
+{
+    JS_ASSERT(span->isWithinArena(arenaAddress()));
+    firstFreeSpanOffsets = span->encodeAsOffsets();
+}
+
+inline ArenaHeader *
+ArenaHeader::getNextDelayedMarking() const
+{
+    return &reinterpret_cast<Arena *>(nextDelayedMarking << ArenaShift)->aheader;
+}
+
+inline void
+ArenaHeader::setNextDelayedMarking(ArenaHeader *aheader)
+{
+    JS_ASSERT(!(uintptr_t(aheader) & ArenaMask));
+    hasDelayedMarking = 1;
+    nextDelayedMarking = aheader->arenaAddress() >> ArenaShift;
+}
+
+JS_ALWAYS_INLINE void
+ChunkBitmap::getMarkWordAndMask(const Cell *cell, uint32_t color,
+                                uintptr_t **wordp, uintptr_t *maskp)
+{
+    size_t bit = (cell->address() & ChunkMask) / Cell::CellSize + color;
+    JS_ASSERT(bit < ArenaBitmapBits * ArenasPerChunk);
+    *maskp = uintptr_t(1) << (bit % JS_BITS_PER_WORD);
+    *wordp = &bitmap[bit / JS_BITS_PER_WORD];
+}
+
+static void
+AssertValidColor(const void *thing, uint32_t color)
+{
+#ifdef DEBUG
+    ArenaHeader *aheader = reinterpret_cast<const Cell *>(thing)->arenaHeader();
+    JS_ASSERT_IF(color, color < aheader->getThingSize() / Cell::CellSize);
+#endif
+}
+
+inline ArenaHeader *
+Cell::arenaHeader() const
+{
+    uintptr_t addr = address();
+    addr &= ~ArenaMask;
+    return reinterpret_cast<ArenaHeader *>(addr);
+}
+
+Chunk *
+Cell::chunk() const
+{
+    uintptr_t addr = uintptr_t(this);
+    JS_ASSERT(addr % Cell::CellSize == 0);
+    addr &= ~(ChunkSize - 1);
+    return reinterpret_cast<Chunk *>(addr);
+}
+
+AllocKind
+Cell::getAllocKind() const
+{
+    return arenaHeader()->getAllocKind();
+}
+
+bool
+Cell::isMarked(uint32_t color /* = BLACK */) const
+{
+    AssertValidColor(this, color);
+    return chunk()->bitmap.isMarked(this, color);
+}
+
+bool
+Cell::markIfUnmarked(uint32_t color /* = BLACK */) const
+{
+    AssertValidColor(this, color);
+    return chunk()->bitmap.markIfUnmarked(this, color);
+}
+
+void
+Cell::unmark(uint32_t color) const
+{
+    JS_ASSERT(color != BLACK);
+    AssertValidColor(this, color);
+    chunk()->bitmap.unmark(this, color);
+}
+
+JSCompartment *
+Cell::compartment() const
+{
+    return arenaHeader()->compartment;
+}
+
+#ifdef DEBUG
+bool
+Cell::isAligned() const
+{
+    return Arena::isAligned(address(), arenaHeader()->getThingSize());
+}
+#endif
+
+} /* namespace gc */
+
+} /* namespace js */
+
+#endif /* gc_heap_h___ */
rename from js/src/jsgcmark.cpp
rename to js/src/gc/Marking.cpp
--- a/js/src/jsgcmark.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1,41 +1,42 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "jsgcmark.h"
 #include "jsprf.h"
 #include "jsscope.h"
 #include "jsstr.h"
 
+#include "gc/Marking.h"
+#include "methodjit/MethodJIT.h"
+
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 
 #include "vm/String-inl.h"
-#include "methodjit/MethodJIT.h"
 
 /*
  * There are two mostly separate mark paths. The first is a fast path used
  * internally in the GC. The second is a slow path used for root marking and
  * for API consumers like the cycle collector or Class::trace implementations.
  *
  * The fast path uses explicit stacks. The basic marking process during a GC is
  * that all roots are pushed on to a mark stack, and then each item on the
  * stack is scanned (possibly pushing more stuff) until the stack is empty.
  *
  * PushMarkStack pushes a GC thing onto the mark stack. In some cases (shapes
  * or strings) it eagerly marks the object rather than pushing it. Popping and
  * scanning is done by the processMarkStackTop method. For efficiency reasons
  * like tail recursion elimination that method also implements the scanning of
  * objects. For other GC things it uses helper methods.
  *
- * Most of the marking code outside jsgcmark uses functions like MarkObject,
+ * Most of the marking code outside Marking.cpp uses functions like MarkObject,
  * MarkString, etc. These functions check if an object is in the compartment
  * currently being GCed. If it is, they call PushMarkStack. Roots are pushed
  * this way as well as pointers traversed inside trace hooks (for things like
  * IteratorClass). It it always valid to call a MarkX function instead of
  * PushMarkStack, although it may be slower.
  *
  * The MarkX functions also handle non-GC object traversal. In this case, they
  * call a callback for each object visited. This is a recursive process; the
rename from js/src/jsgcmark.h
rename to js/src/gc/Marking.h
--- a/js/src/jsgcmark.h
+++ b/js/src/gc/Marking.h
@@ -1,26 +1,44 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef jsgcmark_h___
-#define jsgcmark_h___
+#ifndef gc_marking_h___
+#define gc_marking_h___
 
 #include "jsgc.h"
 #include "jscntxt.h"
-#include "jscompartment.h"
 #include "jslock.h"
 
 #include "gc/Barrier.h"
 #include "js/TemplateLib.h"
 
+extern "C" {
+struct JSContext;
+struct JSFunction;
+struct JSObject;
+struct JSScript;
+}
+
+class JSAtom;
+class JSLinearString;
+
 namespace js {
+
+class ArgumentsObject;
+class BaseShape;
+class GlobalObject;
+class UnownedBaseShape;
+struct Shape;
+
+template<class, typename> class HeapPtr;
+
 namespace gc {
 
 /*** Object Marking ***/
 
 /*
  * These functions expose marking functionality for all of the different GC
  * thing kinds. For each GC thing, there are several variants. As an example,
  * these are the variants generated for JSObject. They are listed from most to
@@ -63,16 +81,18 @@ DeclMarker(String, JSAtom)
 DeclMarker(String, JSString)
 DeclMarker(String, JSFlatString)
 DeclMarker(String, JSLinearString)
 DeclMarker(TypeObject, types::TypeObject)
 #if JS_HAS_XML_SUPPORT
 DeclMarker(XML, JSXML)
 #endif
 
+#undef DeclMarker
+
 /*** Externally Typed Marking ***/
 
 /*
  * Note: this must only be called by the GC and only when we are tracing through
  * MarkRoots. It is explicitly for ConservativeStackMarking and should go away
  * after we transition to exact rooting.
  */
 void
@@ -256,9 +276,9 @@ TraceKind(JSScript *script)
 void
 TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind);
 
 void
 CallTracer(JSTracer *trc, void *thing, JSGCTraceKind kind);
 
 } /* namespace js */
 
-#endif
+#endif /* gc_marking_h___ */
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -401,16 +401,17 @@ Statistics::formatJSON(uint64_t timestam
     return ss.finishJSString();
 }
 
 Statistics::Statistics(JSRuntime *rt)
   : runtime(rt),
     startupTime(PRMJ_Now()),
     fp(NULL),
     fullFormat(false),
+    gcDepth(0),
     collectedCount(0),
     compartmentCount(0),
     nonincrementalReason(NULL)
 {
     PodArrayZero(phaseTotals);
     PodArrayZero(counts);
 
     char *env = getenv("MOZ_GCTIMER");
@@ -527,41 +528,43 @@ Statistics::beginSlice(int collectedCoun
         beginGC();
 
     SliceData data(reason, PRMJ_Now());
     (void) slices.append(data); /* Ignore any OOMs here. */
 
     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback)
         (*cb)(JS_TELEMETRY_GC_REASON, reason);
 
-    bool wasFullGC = collectedCount == compartmentCount;
-    if (GCSliceCallback cb = runtime->gcSliceCallback)
-        (*cb)(runtime, first ? GC_CYCLE_BEGIN : GC_SLICE_BEGIN, GCDescription(!wasFullGC));
+    // Slice callbacks should only fire for the outermost level
+    if (++gcDepth == 1) {
+        bool wasFullGC = collectedCount == compartmentCount;
+        if (GCSliceCallback cb = runtime->gcSliceCallback)
+            (*cb)(runtime, first ? GC_CYCLE_BEGIN : GC_SLICE_BEGIN, GCDescription(!wasFullGC));
+    }
 }
 
 void
 Statistics::endSlice()
 {
     slices.back().end = PRMJ_Now();
 
     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
         (*cb)(JS_TELEMETRY_GC_SLICE_MS, t(slices.back().end - slices.back().start));
         (*cb)(JS_TELEMETRY_GC_RESET, !!slices.back().resetReason);
     }
 
     bool last = runtime->gcIncrementalState == gc::NO_INCREMENTAL;
     if (last)
         endGC();
 
-    bool wasFullGC = collectedCount == compartmentCount;
-    if (GCSliceCallback cb = runtime->gcSliceCallback) {
-        if (last)
-            (*cb)(runtime, GC_CYCLE_END, GCDescription(!wasFullGC));
-        else
-            (*cb)(runtime, GC_SLICE_END, GCDescription(!wasFullGC));
+    // Slice callbacks should only fire for the outermost level
+    if (--gcDepth == 0) {
+        bool wasFullGC = collectedCount == compartmentCount;
+        if (GCSliceCallback cb = runtime->gcSliceCallback)
+            (*cb)(runtime, last ? GC_CYCLE_END : GC_SLICE_END, GCDescription(!wasFullGC));
     }
 
     /* Do this after the slice callback since it uses these values. */
     if (last)
         PodArrayZero(counts);
 }
 
 void
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -111,16 +111,22 @@ struct Statistics {
   private:
     JSRuntime *runtime;
 
     int64_t startupTime;
 
     FILE *fp;
     bool fullFormat;
 
+    /*
+     * GCs can't really nest, but a second GC can be triggered from within the
+     * JSGC_END callback.
+     */
+    int gcDepth;
+
     int collectedCount;
     int compartmentCount;
     const char *nonincrementalReason;
 
     struct SliceData {
         SliceData(gcreason::Reason reason, int64_t start)
           : reason(reason), resetReason(NULL), start(start)
         {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug747554.js
@@ -0,0 +1,6 @@
+assertEq((function(x) {
+    (function () { x++ })();
+    var z;
+    ({ z } = { z:'ponies' })
+    return z;
+})(), 'ponies');
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -142,17 +142,17 @@ MSG_DEF(JSMSG_UNTERM_CLASS,            5
 MSG_DEF(JSMSG_TRAILING_SLASH,          56, 0, JSEXN_SYNTAXERR, "trailing \\ in regular expression")
 MSG_DEF(JSMSG_BAD_CLASS_RANGE,         57, 0, JSEXN_SYNTAXERR, "invalid range in character class")
 MSG_DEF(JSMSG_BAD_REGEXP_FLAG,         58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
 MSG_DEF(JSMSG_NO_INPUT,                59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}")
 MSG_DEF(JSMSG_CANT_OPEN,               60, 2, JSEXN_ERR, "can't open {0}: {1}")
 MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 61, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
 MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN,   62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
 MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE,       63, 0, JSEXN_INTERNALERR, "data are to big to encode")
-MSG_DEF(JSMSG_UNUSED64,                64, 0, JSEXN_NONE,    "")
+MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE,  64, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range")
 MSG_DEF(JSMSG_UNUSED65,                65, 0, JSEXN_NONE,    "")
 MSG_DEF(JSMSG_UNUSED66,                66, 0, JSEXN_NONE,    "")
 MSG_DEF(JSMSG_UNUSED67,                67, 0, JSEXN_NONE,    "")
 MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC,        68, 0, JSEXN_INTERNALERR, "bad script XDR magic number")
 MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL,     69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
 MSG_DEF(JSMSG_MISSING_FORMAL,          70, 0, JSEXN_SYNTAXERR, "missing formal parameter")
 MSG_DEF(JSMSG_PAREN_AFTER_FORMAL,      71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
 MSG_DEF(JSMSG_CURLY_BEFORE_BODY,       72, 0, JSEXN_SYNTAXERR, "missing { before function body")
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -284,37 +284,8 @@ BEGIN_TEST(testDebugger_singleStepThrow)
     }
 
     static JSTrapStatus
     onStep(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure)
     {
         return JSTRAP_CONTINUE;
     }
 END_TEST(testDebugger_singleStepThrow)
-
-BEGIN_TEST(testDebugger_emptyObjectPropertyIterator)
-{
-    JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
-    JSScopeProperty *prop = NULL;
-    CHECK(!JS_PropertyIterator(obj, &prop));
-    CHECK(!prop);
-
-    return true;
-}
-END_TEST(testDebugger_emptyObjectPropertyIterator)
-
-BEGIN_TEST(testDebugger_nonEmptyObjectPropertyIterator)
-{
-    jsval v;
-    EVAL("({a: 15})", &v);
-    JSObject *obj = JSVAL_TO_OBJECT(v);
-    JSScopeProperty *prop = NULL;
-    CHECK(JS_PropertyIterator(obj, &prop));
-    JSPropertyDesc desc;
-    CHECK(JS_GetPropertyDesc(cx, obj, prop, &desc));
-    CHECK_EQUAL(JSVAL_IS_INT(desc.value), true);
-    CHECK_EQUAL(JSVAL_TO_INT(desc.value), 15);
-    CHECK(!JS_PropertyIterator(obj, &prop));
-    CHECK(!prop);
-
-    return true;
-}
-END_TEST(testDebugger_nonEmptyObjectPropertyIterator)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -60,17 +60,16 @@
 #include "jsclone.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdate.h"
 #include "jsdtoa.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
 #include "jsnativestack.h"
 #include "jsnum.h"
 #include "json.h"
 #include "jsobj.h"
@@ -86,16 +85,17 @@
 #include "jstypedarray.h"
 #include "jsxml.h"
 
 #include "ds/LifoAlloc.h"
 #include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
+#include "gc/Marking.h"
 #include "gc/Memory.h"
 #include "js/MemoryMetrics.h"
 #include "yarr/BumpPointerAllocator.h"
 #include "vm/MethodGuard.h"
 #include "vm/NumericConversions.h"
 #include "vm/StringBuffer.h"
 #include "vm/Xdr.h"
 
@@ -1736,17 +1736,17 @@ JS_InitStandardClasses(JSContext *cx, JS
         JS_SetGlobalObject(cx, obj);
 
     assertSameCompartment(cx, obj);
 
     return GlobalObject::initStandardClasses(cx, RootedVar<GlobalObject*>(cx, &obj->global()));
 }
 
 #define CLASP(name)                 (&name##Class)
-#define TYPED_ARRAY_CLASP(type)     (&TypedArray::fastClasses[TypedArray::type])
+#define TYPED_ARRAY_CLASP(type)     (&TypedArray::classes[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
 
 typedef struct JSStdName {
     JSObjectOp  init;
     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
@@ -1857,16 +1857,17 @@ static JSStdName standard_class_names[] 
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int16Array),   TYPED_ARRAY_CLASP(TYPE_INT16)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint16Array),  TYPED_ARRAY_CLASP(TYPE_UINT16)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int32Array),   TYPED_ARRAY_CLASP(TYPE_INT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint32Array),  TYPED_ARRAY_CLASP(TYPE_UINT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8ClampedArray),
                                 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
+    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(DataView),     &DataViewClass},
 
     {js_InitWeakMapClass,       EAGER_ATOM_AND_CLASP(WeakMap)},
     {js_InitProxyClass,         EAGER_ATOM_AND_CLASP(Proxy)},
 
     {NULL,                      0, NULL, NULL}
 };
 
 static JSStdName object_prototype_names[] = {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3728,17 +3728,17 @@ struct JSClass {
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
 
 /* Fast access to the original value of each standard class's prototype. */
 #define JSCLASS_CACHED_PROTO_SHIFT      (JSCLASS_HIGH_FLAGS_SHIFT + 10)
 #define JSCLASS_CACHED_PROTO_WIDTH      6
 #define JSCLASS_CACHED_PROTO_MASK       JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
-#define JSCLASS_HAS_CACHED_PROTO(key)   ((key) << JSCLASS_CACHED_PROTO_SHIFT)
+#define JSCLASS_HAS_CACHED_PROTO(key)   (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT)
 #define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey)                         \
                                          (((clasp)->flags                     \
                                            >> JSCLASS_CACHED_PROTO_SHIFT)     \
                                           & JSCLASS_CACHED_PROTO_MASK))
 
 /* Initializer for unused members of statically initialized JSClass structs. */
 #define JSCLASS_NO_INTERNAL_MEMBERS     {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
 #define JSCLASS_NO_OPTIONAL_MEMBERS     0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -110,28 +110,28 @@
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsscope.h"
 #include "jswrapper.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/StubCalls.h"
 #include "methodjit/StubCalls-inl.h"
 
+#include "gc/Marking.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/MethodGuard.h"
 #include "vm/NumericConversions.h"
 #include "vm/StringBuffer.h"
 
 #include "ds/Sort.h"
 
 #include "jsarrayinlines.h"
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -49,24 +49,24 @@
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsstr.h"
 #include "jsversion.h"
 #include "jsxml.h"
 
 #include "frontend/Parser.h"
+#include "gc/Marking.h"
 
 #include "jsstrinlines.h"
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/String-inl.h"
 #include "vm/Xdr.h"
 
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -473,17 +473,17 @@ js_InternNonIntElementId(JSContext *cx, 
 namespace js {
 
 /*
  * For all unmapped atoms recorded in al, add a mapping from the atom's index
  * to its address. map->length must already be set to the number of atoms in
  * the list and map->vector must point to pre-allocated memory.
  */
 extern void
-InitAtomMap(JSContext *cx, AtomIndexMap *indices, HeapPtrAtom *atoms);
+InitAtomMap(JSContext *cx, AtomIndexMap *indices, HeapPtr<JSAtom> *atoms);
 
 template<XDRMode mode>
 bool
 XDRAtom(XDRState<mode> *xdr, JSAtom **atomp);
 
 } /* namespace js */
 
 #endif /* jsatom_h___ */
deleted file mode 100644
--- a/js/src/jscell.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is SpiderMonkey code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Gregor Wagner <anygregor@gmail.com>
- *
- * 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 jscell_h___
-#define jscell_h___
-
-#include "jspubtd.h"
-
-struct JSCompartment;
-
-namespace js {
-namespace gc {
-
-struct ArenaHeader;
-struct Chunk;
-
-/* The GC allocation kinds. */
-enum AllocKind {
-    FINALIZE_OBJECT0,
-    FINALIZE_OBJECT0_BACKGROUND,
-    FINALIZE_OBJECT2,
-    FINALIZE_OBJECT2_BACKGROUND,
-    FINALIZE_OBJECT4,
-    FINALIZE_OBJECT4_BACKGROUND,
-    FINALIZE_OBJECT8,
-    FINALIZE_OBJECT8_BACKGROUND,
-    FINALIZE_OBJECT12,
-    FINALIZE_OBJECT12_BACKGROUND,
-    FINALIZE_OBJECT16,
-    FINALIZE_OBJECT16_BACKGROUND,
-    FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
-    FINALIZE_SCRIPT,
-    FINALIZE_SHAPE,
-    FINALIZE_BASE_SHAPE,
-    FINALIZE_TYPE_OBJECT,
-#if JS_HAS_XML_SUPPORT
-    FINALIZE_XML,
-#endif
-    FINALIZE_SHORT_STRING,
-    FINALIZE_STRING,
-    FINALIZE_EXTERNAL_STRING,
-    FINALIZE_LAST = FINALIZE_EXTERNAL_STRING
-};
-
-static const unsigned FINALIZE_LIMIT = FINALIZE_LAST + 1;
-static const unsigned FINALIZE_OBJECT_LIMIT = FINALIZE_OBJECT_LAST + 1;
-
-/*
- * Live objects are marked black. How many other additional colors are available
- * depends on the size of the GCThing. Objects marked gray are eligible for
- * cycle collection.
- */
-static const uint32_t BLACK = 0;
-static const uint32_t GRAY = 1;
-
-/*
- * A GC cell is the base class for all GC things.
- */
-struct Cell {
-    static const size_t CellShift = 3;
-    static const size_t CellSize = size_t(1) << CellShift;
-    static const size_t CellMask = CellSize - 1;
-
-    inline uintptr_t address() const;
-    inline ArenaHeader *arenaHeader() const;
-    inline Chunk *chunk() const;
-    inline AllocKind getAllocKind() const;
-
-    JS_ALWAYS_INLINE bool isMarked(uint32_t color = BLACK) const;
-    JS_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
-    JS_ALWAYS_INLINE void unmark(uint32_t color) const;
-
-    inline JSCompartment *compartment() const;
-
-#ifdef DEBUG
-    inline bool isAligned() const;
-#endif
-};
-
-} /* namespace gc */
-} /* namespace js */
-
-#endif /* jscell_h___ */
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -429,19 +429,18 @@ JSStructuredCloneWriter::checkStack()
 JS_PUBLIC_API(JSBool)
 JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v)
 {
     JS_ASSERT(v.isObject());
     return w->writeTypedArray(&v.toObject());
 }
 
 bool
-JSStructuredCloneWriter::writeTypedArray(JSObject *obj)
+JSStructuredCloneWriter::writeTypedArray(JSObject *arr)
 {
-    JSObject *arr = TypedArray::getTypedArray(obj);
     if (!out.writePair(ArrayTypeToTag(TypedArray::getType(arr)), TypedArray::getLength(arr)))
         return false;
 
     switch (TypedArray::getType(arr)) {
     case TypedArray::TYPE_INT8:
     case TypedArray::TYPE_UINT8:
     case TypedArray::TYPE_UINT8_CLAMPED:
         return out.writeArray((const uint8_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
@@ -745,37 +744,36 @@ JSStructuredCloneReader::readTypedArray(
         JS_NOT_REACHED("unknown TypedArray type");
         return false;
     }
 
     if (!obj)
         return false;
     vp->setObject(*obj);
 
-    JSObject *arr = TypedArray::getTypedArray(obj);
-    JS_ASSERT(TypedArray::getLength(arr) == nelems);
+    JS_ASSERT(TypedArray::getLength(obj) == nelems);
     switch (tag) {
       case SCTAG_TYPED_ARRAY_INT8:
-        return in.readArray((uint8_t *) JS_GetInt8ArrayData(arr, context()), nelems);
+        return in.readArray((uint8_t*) JS_GetInt8ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_UINT8:
-        return in.readArray((uint8_t *) JS_GetUint8ArrayData(arr, context()), nelems);
+        return in.readArray(JS_GetUint8ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_INT16:
-        return in.readArray((uint16_t *) JS_GetInt16ArrayData(arr, context()), nelems);
+        return in.readArray((uint16_t*) JS_GetInt16ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_UINT16:
-        return in.readArray((uint16_t *) JS_GetUint16ArrayData(arr, context()), nelems);
+        return in.readArray(JS_GetUint16ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_INT32:
-        return in.readArray((uint32_t *) JS_GetInt32ArrayData(arr, context()), nelems);
+        return in.readArray((uint32_t*) JS_GetInt32ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_UINT32:
-        return in.readArray((uint32_t *) JS_GetUint32ArrayData(arr, context()), nelems);
+        return in.readArray(JS_GetUint32ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_FLOAT32:
-        return in.readArray((uint32_t *) JS_GetFloat32ArrayData(arr, context()), nelems);
+        return in.readArray((uint32_t*) JS_GetFloat32ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_FLOAT64:
-        return in.readArray((uint64_t *) JS_GetFloat64ArrayData(arr, context()), nelems);
+        return in.readArray((uint64_t*) JS_GetFloat64ArrayData(obj, context()), nelems);
       case SCTAG_TYPED_ARRAY_UINT8_CLAMPED:
-        return in.readArray((uint8_t *) JS_GetUint8ClampedArrayData(arr, context()), nelems);
+        return in.readArray(JS_GetUint8ClampedArrayData(obj, context()), nelems);
       default:
         JS_NOT_REACHED("unknown TypedArray type");
         return false;
     }
 }
 
 bool
 JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -60,32 +60,32 @@
 #include "jsprf.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jspubtd.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #ifdef JS_METHODJIT
 # include "assembler/assembler/MacroAssembler.h"
 # include "methodjit/MethodJIT.h"
 #endif
+#include "gc/Marking.h"
 #include "frontend/TokenStream.h"
 #include "frontend/ParseMaps.h"
 #include "yarr/BumpPointerAllocator.h"
 
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
 #include "jscompartment.h"
 #include "jsobjinlines.h"
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -589,22 +589,16 @@ struct JSRuntime : js::RuntimeFriendFiel
         void *thing;
         JSGCTraceKind kind;
 
         SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
     };
     js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
 #endif
 
-    /*
-     * We can pack these flags as only the GC thread writes to them. Atomic
-     * updates to packed bytes are not guaranteed, so stores issued by one
-     * thread may be lost due to unsynchronized read-modify-write cycles on
-     * other threads.
-     */
     bool                gcPoke;
     bool                gcRunning;
 
     /*
      * These options control the zealousness of the GC. The fundamental values
      * are gcNextScheduled and gcDebugCompartmentGC. At every allocation,
      * gcNextScheduled is decremented. When it reaches zero, we do either a
      * full or a compartmental GC, based on gcDebugCompartmentGC.
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -36,25 +36,25 @@
  * 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 "jscntxt.h"
 #include "jscompartment.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsiter.h"
 #include "jsmath.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
 #include "assembler/wtf/Platform.h"
+#include "gc/Marking.h"
 #include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/MonoIC.h"
 #include "vm/Debugger.h"
 #include "yarr/BumpPointerAllocator.h"
 
 #include "jsgcinlines.h"
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -49,27 +49,27 @@
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jslock.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
+#include "gc/Marking.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "vm/Debugger.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsinterpinlines.h"
@@ -777,42 +777,20 @@ JS_EvaluateInStackFrame(JSContext *cx, J
 
     return ok;
 }
 
 /************************************************************************/
 
 /* This all should be reworked to avoid requiring JSScopeProperty types. */
 
-JS_PUBLIC_API(JSScopeProperty *)
-JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp)
-{
-    const Shape *shape;
-
-    /* The caller passes null in *iteratorp to get things started. */
-    shape = (Shape *) *iteratorp;
-    if (!shape)
-        shape = obj->lastProperty();
-    else
-        shape = shape->previous();
-
-    if (!shape->previous()) {
-        JS_ASSERT(shape->isEmptyShape());
-        shape = NULL;
-    }
-
-    return *iteratorp = reinterpret_cast<JSScopeProperty *>(const_cast<Shape *>(shape));
-}
-
-JS_PUBLIC_API(JSBool)
-JS_GetPropertyDesc(JSContext *cx, JSObject *obj_, JSScopeProperty *sprop,
-                   JSPropertyDesc *pd)
+static JSBool
+GetPropertyDesc(JSContext *cx, JSObject *obj_, Shape *shape, JSPropertyDesc *pd)
 {
     assertSameCompartment(cx, obj_);
-    Shape *shape = (Shape *) sprop;
     pd->id = IdToJsval(shape->propid());
 
     RootedVarObject obj(cx, obj_);
 
     JSBool wasThrowing = cx->isExceptionPending();
     Value lastException = UndefinedValue();
     if (wasThrowing)
         lastException = cx->getPendingException();
@@ -850,16 +828,17 @@ JS_GetPropertyDesc(JSContext *cx, JSObje
 
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda)
 {
     assertSameCompartment(cx, obj);
+
     Class *clasp = obj->getClass();
     if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_CANT_DESCRIBE_PROPS, clasp->name);
         return JS_FALSE;
     }
     if (!clasp->enumerate(cx, obj))
         return JS_FALSE;
@@ -877,17 +856,17 @@ JS_GetPropertyDescArray(JSContext *cx, J
         return JS_FALSE;
     uint32_t i = 0;
     for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) {
         if (!js_AddRoot(cx, &pd[i].id, NULL))
             goto bad;
         if (!js_AddRoot(cx, &pd[i].value, NULL))
             goto bad;
         Shape *shape = const_cast<Shape *>(&r.front());
-        if (!JS_GetPropertyDesc(cx, obj, reinterpret_cast<JSScopeProperty *>(shape), &pd[i]))
+        if (!GetPropertyDesc(cx, obj, shape, &pd[i]))
             goto bad;
         if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL))
             goto bad;
         if (++i == n)
             break;
     }
     pda->length = i;
     pda->array = pd;
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -369,23 +369,16 @@ typedef struct JSPropertyDesc {
 
 typedef struct JSPropertyDescArray {
     uint32_t        length;     /* number of elements in array */
     JSPropertyDesc  *array;     /* alloc'd by Get, freed by Put */
 } JSPropertyDescArray;
 
 typedef struct JSScopeProperty JSScopeProperty;
 
-extern JS_PUBLIC_API(JSScopeProperty *)
-JS_PropertyIterator(JSObject *obj, JSScopeProperty **iteratorp);
-
-extern JS_PUBLIC_API(JSBool)
-JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *shape,
-                   JSPropertyDesc *pd);
-
 extern JS_PUBLIC_API(JSBool)
 JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda);
 
 extern JS_PUBLIC_API(void)
 JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda);
 
 /************************************************************************/
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -50,25 +50,25 @@
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jswrapper.h"
 
+#include "gc/Marking.h"
 #include "vm/GlobalObject.h"
 #include "vm/StringBuffer.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -764,16 +764,22 @@ IsIncrementalBarrierNeeded(JSContext *cx
 }
 
 JS_FRIEND_API(bool)
 IsIncrementalBarrierNeededOnObject(JSObject *obj)
 {
     return obj->compartment()->needsBarrier();
 }
 
+JS_FRIEND_API(bool)
+IsIncrementalBarrierNeededOnScript(JSScript *script)
+{
+    return script->compartment()->needsBarrier();
+}
+
 extern JS_FRIEND_API(void)
 IncrementalReferenceBarrier(void *ptr)
 {
     if (!ptr)
         return;
     JS_ASSERT(!static_cast<gc::Cell *>(ptr)->compartment()->rt->gcRunning);
     uint32_t kind = gc::GetGCThingTraceKind(ptr);
     if (kind == JSTRACE_OBJECT)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -719,16 +719,19 @@ extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSRuntime *rt);
 
 extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSContext *cx);
 
 extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeededOnObject(JSObject *obj);
 
+extern JS_FRIEND_API(bool)
+IsIncrementalBarrierNeededOnScript(JSScript *obj);
+
 extern JS_FRIEND_API(void)
 IncrementalReferenceBarrier(void *ptr);
 
 extern JS_FRIEND_API(void)
 IncrementalValueBarrier(const Value &v);
 
 class ObjectPtr
 {
@@ -969,16 +972,26 @@ JS_NewArrayBuffer(JSContext *cx, uint32_
  * false if a security wrapper is encountered that denies the unwrapping. If
  * this test or one of the JS_Is*Array tests succeeds, then it is safe to call
  * the various accessor JSAPI calls defined below.
  */
 extern JS_FRIEND_API(JSBool)
 JS_IsTypedArrayObject(JSObject *obj, JSContext *cx);
 
 /*
+ * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may
+ * return false if a security wrapper is encountered that denies the
+ * unwrapping. If this test or one of the more specific tests succeeds, then it
+ * is safe to call the various ArrayBufferView accessor JSAPI calls defined
+ * below. cx MUST be non-NULL and valid.
+ */
+extern JS_FRIEND_API(JSBool)
+JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx);
+
+/*
  * Test for specific typed array types (ArrayBufferView subtypes)
  */
 
 extern JS_FRIEND_API(JSBool)
 JS_IsInt8Array(JSObject *obj, JSContext *cx);
 extern JS_FRIEND_API(JSBool)
 JS_IsUint8Array(JSObject *obj, JSContext *cx);
 extern JS_FRIEND_API(JSBool)
@@ -1119,9 +1132,51 @@ JS_GetFloat64ArrayData(JSObject *obj, JS
 
 /*
  * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
  * versions when possible.
  */
 extern JS_FRIEND_API(void *)
 JS_GetArrayBufferViewData(JSObject *obj, JSContext *cx);
 
+/*
+ * Check whether obj supports JS_GetDataView* APIs. Note that this may fail and
+ * throw an exception if a security wrapper is encountered that denies the
+ * operation.
+ */
+JS_FRIEND_API(JSBool)
+JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView);
+
+/*
+ * Return the byte offset of a data view into its array buffer. |obj| must be a
+ * DataView.
+ *
+ * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
+ * it would pass such a test: it is a data view or a wrapper of a data view,
+ * and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
+ * unable to assert when unwrapping should be disallowed.
+ */
+JS_FRIEND_API(uint32_t)
+JS_GetDataViewByteOffset(JSObject *obj, JSContext *cx);
+
+/*
+ * Return the byte length of a data view.
+ *
+ * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
+ * it would pass such a test: it is a data view or a wrapper of a data view,
+ * and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
+ * unable to assert when unwrapping should be disallowed.
+ */
+JS_FRIEND_API(uint32_t)
+JS_GetDataViewByteLength(JSObject *obj, JSContext *cx);
+
+/*
+ * Return a pointer to the beginning of the data referenced by a DataView.
+ *
+ * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
+ * it would pass such a test: it is a data view or a wrapper of a data view,
+ * and the unwrapping will succeed. If cx is NULL, then DEBUG builds may be
+ * unable to assert when unwrapping should be disallowed.
+ */
+JS_FRIEND_API(void *)
+JS_GetDataViewData(JSObject *obj, JSContext *cx);
+
 #endif /* jsfriendapi_h___ */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -50,31 +50,31 @@
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jspropertytree.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/TokenStream.h"
+#include "gc/Marking.h"
 #include "vm/Debugger.h"
 #include "vm/MethodGuard.h"
 #include "vm/ScopeObject.h"
 #include "vm/Xdr.h"
 
 #if JS_HAS_GENERATORS
 # include "jsiter.h"
 #endif
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -86,33 +86,33 @@
 #include "jscrashreport.h"
 #include "jscrashformat.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsprobes.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jswatchpoint.h"
 #include "jsweakmap.h"
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 #include "frontend/Parser.h"
+#include "gc/Marking.h"
 #include "gc/Memory.h"
 #include "methodjit/MethodJIT.h"
 #include "vm/Debugger.h"
 #include "vm/String.h"
 
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -49,19 +49,19 @@
 
 #include "jsalloc.h"
 #include "jstypes.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jslock.h"
 #include "jsutil.h"
 #include "jsversion.h"
-#include "jscell.h"
 
 #include "ds/BitArray.h"
+#include "gc/Heap.h"
 #include "gc/Statistics.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 #include "js/TemplateLib.h"
 
 struct JSCompartment;
 
 extern void
@@ -82,747 +82,16 @@ namespace gc {
 
 enum State {
     NO_INCREMENTAL,
     MARK_ROOTS,
     MARK,
     INVALID
 };
 
-struct Arena;
-
-/*
- * This must be an upper bound, but we do not need the least upper bound, so
- * we just exclude non-background objects.
- */
-const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - FINALIZE_OBJECT_LIMIT / 2;
-
-/*
- * Page size is 4096 by default, except for SPARC, where it is 8192.
- * Note: Do not use JS_CPU_SPARC here, this header is used outside JS.
- * Bug 692267: Move page size definition to gc/Memory.h and include it
- *             directly once jsgc.h is no longer an installed header.
- */
-#if defined(SOLARIS) && (defined(__sparc) || defined(__sparcv9))
-const size_t PageShift = 13;
-#else
-const size_t PageShift = 12;
-#endif
-const size_t PageSize = size_t(1) << PageShift;
-
-const size_t ChunkShift = 20;
-const size_t ChunkSize = size_t(1) << ChunkShift;
-const size_t ChunkMask = ChunkSize - 1;
-
-const size_t ArenaShift = PageShift;
-const size_t ArenaSize = PageSize;
-const size_t ArenaMask = ArenaSize - 1;
-
-/*
- * This is the maximum number of arenas we allow in the FreeCommitted state
- * before we trigger a GC_SHRINK to release free arenas to the OS.
- */
-const static uint32_t FreeCommittedArenasThreshold = (32 << 20) / ArenaSize;
-
-/*
- * The mark bitmap has one bit per each GC cell. For multi-cell GC things this
- * wastes space but allows to avoid expensive devisions by thing's size when
- * accessing the bitmap. In addition this allows to use some bits for colored
- * marking during the cycle GC.
- */
-const size_t ArenaCellCount = size_t(1) << (ArenaShift - Cell::CellShift);
-const size_t ArenaBitmapBits = ArenaCellCount;
-const size_t ArenaBitmapBytes = ArenaBitmapBits / 8;
-const size_t ArenaBitmapWords = ArenaBitmapBits / JS_BITS_PER_WORD;
-
-/*
- * A FreeSpan represents a contiguous sequence of free cells in an Arena.
- * |first| is the address of the first free cell in the span. |last| is the
- * address of the last free cell in the span. This last cell holds a FreeSpan
- * data structure for the next span unless this is the last span on the list
- * of spans in the arena. For this last span |last| points to the last byte of
- * the last thing in the arena and no linkage is stored there, so
- * |last| == arenaStart + ArenaSize - 1. If the space at the arena end is
- * fully used this last span is empty and |first| == |last + 1|.
- *
- * Thus |first| < |last| implies that we have either the last span with at least
- * one element or that the span is not the last and contains at least 2
- * elements. In both cases to allocate a thing from this span we need simply
- * to increment |first| by the allocation size.
- *
- * |first| == |last| implies that we have a one element span that records the
- * next span. So to allocate from it we need to update the span list head
- * with a copy of the span stored at |last| address so the following
- * allocations will use that span.
- *
- * |first| > |last| implies that we have an empty last span and the arena is
- * fully used.
- *
- * Also only for the last span (|last| & 1)! = 0 as all allocation sizes are
- * multiples of Cell::CellSize.
- */
-struct FreeSpan {
-    uintptr_t   first;
-    uintptr_t   last;
-
-  public:
-    FreeSpan() {}
-
-    FreeSpan(uintptr_t first, uintptr_t last)
-      : first(first), last(last) {
-        checkSpan();
-    }
-
-    /*
-     * To minimize the size of the arena header the first span is encoded
-     * there as offsets from the arena start.
-     */
-    static size_t encodeOffsets(size_t firstOffset, size_t lastOffset) {
-        /* Check that we can pack the offsets into uint16. */
-        JS_STATIC_ASSERT(ArenaShift < 16);
-        JS_ASSERT(firstOffset <= ArenaSize);
-        JS_ASSERT(lastOffset < ArenaSize);
-        JS_ASSERT(firstOffset <= ((lastOffset + 1) & ~size_t(1)));
-        return firstOffset | (lastOffset << 16);
-    }
-
-    /*
-     * Encoded offsets for a full arena when its first span is the last one
-     * and empty.
-     */
-    static const size_t FullArenaOffsets = ArenaSize | ((ArenaSize - 1) << 16);
-
-    static FreeSpan decodeOffsets(uintptr_t arenaAddr, size_t offsets) {
-        JS_ASSERT(!(arenaAddr & ArenaMask));
-
-        size_t firstOffset = offsets & 0xFFFF;
-        size_t lastOffset = offsets >> 16;
-        JS_ASSERT(firstOffset <= ArenaSize);
-        JS_ASSERT(lastOffset < ArenaSize);
-
-        /*
-         * We must not use | when calculating first as firstOffset is
-         * ArenaMask + 1 for the empty span.
-         */
-        return FreeSpan(arenaAddr + firstOffset, arenaAddr | lastOffset);
-    }
-
-    void initAsEmpty(uintptr_t arenaAddr = 0) {
-        JS_ASSERT(!(arenaAddr & ArenaMask));
-        first = arenaAddr + ArenaSize;
-        last = arenaAddr | (ArenaSize  - 1);
-        JS_ASSERT(isEmpty());
-    }
-
-    bool isEmpty() const {
-        checkSpan();
-        return first > last;
-    }
-
-    bool hasNext() const {
-        checkSpan();
-        return !(last & uintptr_t(1));
-    }
-
-    const FreeSpan *nextSpan() const {
-        JS_ASSERT(hasNext());
-        return reinterpret_cast<FreeSpan *>(last);
-    }
-
-    FreeSpan *nextSpanUnchecked(size_t thingSize) const {
-#ifdef DEBUG
-        uintptr_t lastOffset = last & ArenaMask;
-        JS_ASSERT(!(lastOffset & 1));
-        JS_ASSERT((ArenaSize - lastOffset) % thingSize == 0);
-#endif
-        return reinterpret_cast<FreeSpan *>(last);
-    }
-
-    uintptr_t arenaAddressUnchecked() const {
-        return last & ~ArenaMask;
-    }
-
-    uintptr_t arenaAddress() const {
-        checkSpan();
-        return arenaAddressUnchecked();
-    }
-
-    ArenaHeader *arenaHeader() const {
-        return reinterpret_cast<ArenaHeader *>(arenaAddress());
-    }
-
-    bool isSameNonEmptySpan(const FreeSpan *another) const {
-        JS_ASSERT(!isEmpty());
-        JS_ASSERT(!another->isEmpty());
-        return first == another->first && last == another->last;
-    }
-
-    bool isWithinArena(uintptr_t arenaAddr) const {
-        JS_ASSERT(!(arenaAddr & ArenaMask));
-
-        /* Return true for the last empty span as well. */
-        return arenaAddress() == arenaAddr;
-    }
-
-    size_t encodeAsOffsets() const {
-        /*
-         * We must use first - arenaAddress(), not first & ArenaMask as
-         * first == ArenaMask + 1 for an empty span.
-         */
-        uintptr_t arenaAddr = arenaAddress();
-        return encodeOffsets(first - arenaAddr, last & ArenaMask);
-    }
-
-    /* See comments before FreeSpan for details. */
-    JS_ALWAYS_INLINE void *allocate(size_t thingSize) {
-        JS_ASSERT(thingSize % Cell::CellSize == 0);
-        checkSpan();
-        uintptr_t thing = first;
-        if (thing < last) {
-            /* Bump-allocate from the current span. */
-            first = thing + thingSize;
-        } else if (JS_LIKELY(thing == last)) {
-            /*
-             * Move to the next span. We use JS_LIKELY as without PGO
-             * compilers mis-predict == here as unlikely to succeed.
-             */
-            *this = *reinterpret_cast<FreeSpan *>(thing);
-        } else {
-            return NULL;
-        }
-        checkSpan();
-        return reinterpret_cast<void *>(thing);
-    }
-
-    /* A version of allocate when we know that the span is not empty. */
-    JS_ALWAYS_INLINE void *infallibleAllocate(size_t thingSize) {
-        JS_ASSERT(thingSize % Cell::CellSize == 0);
-        checkSpan();
-        uintptr_t thing = first;
-        if (thing < last) {
-            first = thing + thingSize;
-        } else {
-            JS_ASSERT(thing == last);
-            *this = *reinterpret_cast<FreeSpan *>(thing);
-        }
-        checkSpan();
-        return reinterpret_cast<void *>(thing);
-    }
-
-    /*
-     * Allocate from a newly allocated arena. We do not move the free list
-     * from the arena. Rather we set the arena up as fully used during the
-     * initialization so to allocate we simply return the first thing in the
-     * arena and set the free list to point to the second.
-     */
-    JS_ALWAYS_INLINE void *allocateFromNewArena(uintptr_t arenaAddr, size_t firstThingOffset,
-                                                size_t thingSize) {
-        JS_ASSERT(!(arenaAddr & ArenaMask));
-        uintptr_t thing = arenaAddr | firstThingOffset;
-        first = thing + thingSize;
-        last = arenaAddr | ArenaMask;
-        checkSpan();
-        return reinterpret_cast<void *>(thing);
-    }
-
-    void checkSpan() const {
-#ifdef DEBUG
-        /* We do not allow spans at the end of the address space. */
-        JS_ASSERT(last != uintptr_t(-1));
-        JS_ASSERT(first);
-        JS_ASSERT(last);
-        JS_ASSERT(first - 1 <= last);
-        uintptr_t arenaAddr = arenaAddressUnchecked();
-        if (last & 1) {
-            /* The span is the last. */
-            JS_ASSERT((last & ArenaMask) == ArenaMask);
-
-            if (first - 1 == last) {
-                /* The span is last and empty. The above start != 0 check
-                 * implies that we are not at the end of the address space.
-                 */
-                return;
-            }
-            size_t spanLength = last - first + 1;
-            JS_ASSERT(spanLength % Cell::CellSize == 0);
-
-            /* Start and end must belong to the same arena. */
-            JS_ASSERT((first & ~ArenaMask) == arenaAddr);
-            return;
-        }
-
-        /* The span is not the last and we have more spans to follow. */
-        JS_ASSERT(first <= last);
-        size_t spanLengthWithoutOneThing = last - first;
-        JS_ASSERT(spanLengthWithoutOneThing % Cell::CellSize == 0);
-
-        JS_ASSERT((first & ~ArenaMask) == arenaAddr);
-
-        /*
-         * If there is not enough space before the arena end to allocate one
-         * more thing, then the span must be marked as the last one to avoid
-         * storing useless empty span reference.
-         */
-        size_t beforeTail = ArenaSize - (last & ArenaMask);
-        JS_ASSERT(beforeTail >= sizeof(FreeSpan) + Cell::CellSize);
-
-        FreeSpan *next = reinterpret_cast<FreeSpan *>(last);
-
-        /*
-         * The GC things on the list of free spans come from one arena
-         * and the spans are linked in ascending address order with
-         * at least one non-free thing between spans.
-         */
-        JS_ASSERT(last < next->first);
-        JS_ASSERT(arenaAddr == next->arenaAddressUnchecked());
-
-        if (next->first > next->last) {
-            /*
-             * The next span is the empty span that terminates the list for
-             * arenas that do not have any free things at the end.
-             */
-            JS_ASSERT(next->first - 1 == next->last);
-            JS_ASSERT(arenaAddr + ArenaSize == next->first);
-        }
-#endif
-    }
-
-};
-
-/* Every arena has a header. */
-struct ArenaHeader {
-    friend struct FreeLists;
-
-    JSCompartment   *compartment;
-
-    /*
-     * ArenaHeader::next has two purposes: when unallocated, it points to the
-     * next available Arena's header. When allocated, it points to the next
-     * arena of the same size class and compartment.
-     */
-    ArenaHeader     *next;
-
-  private:
-    /*
-     * The first span of free things in the arena. We encode it as the start
-     * and end offsets within the arena, not as FreeSpan structure, to
-     * minimize the header size.
-     */
-    size_t          firstFreeSpanOffsets;
-
-    /*
-     * One of AllocKind constants or FINALIZE_LIMIT when the arena does not
-     * contain any GC things and is on the list of empty arenas in the GC
-     * chunk. The latter allows to quickly check if the arena is allocated
-     * during the conservative GC scanning without searching the arena in the
-     * list.
-     */
-    size_t       allocKind          : 8;
-
-    /*
-     * When recursive marking uses too much stack the marking is delayed and
-     * the corresponding arenas are put into a stack using the following field
-     * as a linkage. To distinguish the bottom of the stack from the arenas
-     * not present in the stack we use an extra flag to tag arenas on the
-     * stack.
-     *
-     * Delayed marking is also used for arenas that we allocate into during an
-     * incremental GC. In this case, we intend to mark all the objects in the
-     * arena, and it's faster to do this marking in bulk.
-     *
-     * To minimize the ArenaHeader size we record the next delayed marking
-     * linkage as arenaAddress() >> ArenaShift and pack it with the allocKind
-     * field and hasDelayedMarking flag. We use 8 bits for the allocKind, not
-     * ArenaShift - 1, so the compiler can use byte-level memory instructions
-     * to access it.
-     */
-  public:
-    size_t       hasDelayedMarking  : 1;
-    size_t       allocatedDuringIncremental : 1;
-    size_t       markOverflow : 1;
-    size_t       nextDelayedMarking : JS_BITS_PER_WORD - 8 - 1 - 1 - 1;
-
-    static void staticAsserts() {
-        /* We must be able to fit the allockind into uint8_t. */
-        JS_STATIC_ASSERT(FINALIZE_LIMIT <= 255);
-
-        /*
-         * nextDelayedMarkingpacking assumes that ArenaShift has enough bits
-         * to cover allocKind and hasDelayedMarking.
-         */
-        JS_STATIC_ASSERT(ArenaShift >= 8 + 1 + 1 + 1);
-    }
-
-    inline uintptr_t address() const;
-    inline Chunk *chunk() const;
-
-    bool allocated() const {
-        JS_ASSERT(allocKind <= size_t(FINALIZE_LIMIT));
-        return allocKind < size_t(FINALIZE_LIMIT);
-    }
-
-    void init(JSCompartment *comp, AllocKind kind) {
-        JS_ASSERT(!allocated());
-        JS_ASSERT(!markOverflow);
-        JS_ASSERT(!allocatedDuringIncremental);
-        JS_ASSERT(!hasDelayedMarking);
-        compartment = comp;
-
-        JS_STATIC_ASSERT(FINALIZE_LIMIT <= 255);
-        allocKind = size_t(kind);
-
-        /* See comments in FreeSpan::allocateFromNewArena. */
-        firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
-    }
-
-    void setAsNotAllocated() {
-        allocKind = size_t(FINALIZE_LIMIT);
-        markOverflow = 0;
-        allocatedDuringIncremental = 0;
-        hasDelayedMarking = 0;
-        nextDelayedMarking = 0;
-    }
-
-    uintptr_t arenaAddress() const {
-        return address();
-    }
-
-    Arena *getArena() {
-        return reinterpret_cast<Arena *>(arenaAddress());
-    }
-
-    AllocKind getAllocKind() const {
-        JS_ASSERT(allocated());
-        return AllocKind(allocKind);
-    }
-
-    inline size_t getThingSize() const;
-
-    bool hasFreeThings() const {
-        return firstFreeSpanOffsets != FreeSpan::FullArenaOffsets;
-    }
-
-    inline bool isEmpty() const;
-
-    void setAsFullyUsed() {
-        firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
-    }
-
-    FreeSpan getFirstFreeSpan() const {
-#ifdef DEBUG
-        checkSynchronizedWithFreeList();
-#endif
-        return FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets);
-    }
-
-    void setFirstFreeSpan(const FreeSpan *span) {
-        JS_ASSERT(span->isWithinArena(arenaAddress()));
-        firstFreeSpanOffsets = span->encodeAsOffsets();
-    }
-
-#ifdef DEBUG
-    void checkSynchronizedWithFreeList() const;
-#endif
-
-    inline ArenaHeader *getNextDelayedMarking() const;
-    inline void setNextDelayedMarking(ArenaHeader *aheader);
-};
-
-struct Arena {
-    /*
-     * Layout of an arena:
-     * An arena is 4K in size and 4K-aligned. It starts with the ArenaHeader
-     * descriptor followed by some pad bytes. The remainder of the arena is
-     * filled with the array of T things. The pad bytes ensure that the thing
-     * array ends exactly at the end of the arena.
-     *
-     * +-------------+-----+----+----+-----+----+
-     * | ArenaHeader | pad | T0 | T1 | ... | Tn |
-     * +-------------+-----+----+----+-----+----+
-     *
-     * <----------------------------------------> = ArenaSize bytes
-     * <-------------------> = first thing offset
-     */
-    ArenaHeader aheader;
-    uint8_t     data[ArenaSize - sizeof(ArenaHeader)];
-
-  private:
-    static JS_FRIEND_DATA(const uint32_t) ThingSizes[];
-    static JS_FRIEND_DATA(const uint32_t) FirstThingOffsets[];
-
-  public:
-    static void staticAsserts();
-
-    static size_t thingSize(AllocKind kind) {
-        return ThingSizes[kind];
-    }
-
-    static size_t firstThingOffset(AllocKind kind) {
-        return FirstThingOffsets[kind];
-    }
-
-    static size_t thingsPerArena(size_t thingSize) {
-        JS_ASSERT(thingSize % Cell::CellSize == 0);
-
-        /* We should be able to fit FreeSpan in any GC thing. */
-        JS_ASSERT(thingSize >= sizeof(FreeSpan));
-
-        return (ArenaSize - sizeof(ArenaHeader)) / thingSize;
-    }
-
-    static size_t thingsSpan(size_t thingSize) {
-        return thingsPerArena(thingSize) * thingSize;
-    }
-
-    static bool isAligned(uintptr_t thing, size_t thingSize) {
-        /* Things ends at the arena end. */
-        uintptr_t tailOffset = (ArenaSize - thing) & ArenaMask;
-        return tailOffset % thingSize == 0;
-    }
-
-    uintptr_t address() const {
-        return aheader.address();
-    }
-
-    uintptr_t thingsStart(AllocKind thingKind) {
-        return address() | firstThingOffset(thingKind);
-    }
-
-    uintptr_t thingsEnd() {
-        return address() + ArenaSize;
-    }
-
-    template <typename T>
-    bool finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize);
-};
-
-/* The chunk header (located at the end of the chunk to preserve arena alignment). */
-struct ChunkInfo {
-    Chunk           *next;
-    Chunk           **prevp;
-
-    /* Free arenas are linked together with aheader.next. */
-    ArenaHeader     *freeArenasHead;
-
-    /*
-     * Decommitted arenas are tracked by a bitmap in the chunk header. We use
-     * this offset to start our search iteration close to a decommitted arena
-     * that we can allocate.
-     */
-    uint32_t        lastDecommittedArenaOffset;
-
-    /* Number of free arenas, either committed or decommitted. */
-    uint32_t        numArenasFree;
-
-    /* Number of free, committed arenas. */
-    uint32_t        numArenasFreeCommitted;
-
-    /* Number of GC cycles this chunk has survived. */
-    uint32_t        age;
-};
-
-/*
- * Calculating ArenasPerChunk:
- *
- * In order to figure out how many Arenas will fit in a chunk, we need to know
- * how much extra space is available after we allocate the header data. This
- * is a problem because the header size depends on the number of arenas in the
- * chunk. The two dependent fields are bitmap and decommittedArenas.
- *
- * For the mark bitmap, we know that each arena will use a fixed number of full
- * bytes: ArenaBitmapBytes. The full size of the header data is this number
- * multiplied by the eventual number of arenas we have in the header. We,
- * conceptually, distribute this header data among the individual arenas and do
- * not include it in the header. This way we do not have to worry about its
- * variable size: it gets attached to the variable number we are computing.
- *
- * For the decommitted arena bitmap, we only have 1 bit per arena, so this
- * technique will not work. Instead, we observe that we do not have enough
- * header info to fill 8 full arenas: it is currently 4 on 64bit, less on
- * 32bit. Thus, with current numbers, we need 64 bytes for decommittedArenas.
- * This will not become 63 bytes unless we double the data required in the
- * header. Therefore, we just compute the number of bytes required to track
- * every possible arena and do not worry about slop bits, since there are too
- * few to usefully allocate.
- *
- * To actually compute the number of arenas we can allocate in a chunk, we
- * divide the amount of available space less the header info (not including
- * the mark bitmap which is distributed into the arena size) by the size of
- * the arena (with the mark bitmap bytes it uses).
- */
-const size_t BytesPerArenaWithHeader = ArenaSize + ArenaBitmapBytes;
-const size_t ChunkDecommitBitmapBytes = ChunkSize / ArenaSize / JS_BITS_PER_BYTE;
-const size_t ChunkBytesAvailable = ChunkSize - sizeof(ChunkInfo) - ChunkDecommitBitmapBytes;
-const size_t ArenasPerChunk = ChunkBytesAvailable / BytesPerArenaWithHeader;
-
-/* A chunk bitmap contains enough mark bits for all the cells in a chunk. */
-struct ChunkBitmap {
-    uintptr_t bitmap[ArenaBitmapWords * ArenasPerChunk];
-
-    JS_ALWAYS_INLINE void getMarkWordAndMask(const Cell *cell, uint32_t color,
-                                             uintptr_t **wordp, uintptr_t *maskp);
-
-    JS_ALWAYS_INLINE bool isMarked(const Cell *cell, uint32_t color) {
-        uintptr_t *word, mask;
-        getMarkWordAndMask(cell, color, &word, &mask);
-        return *word & mask;
-    }
-
-    JS_ALWAYS_INLINE bool markIfUnmarked(const Cell *cell, uint32_t color) {
-        uintptr_t *word, mask;
-        getMarkWordAndMask(cell, BLACK, &word, &mask);
-        if (*word & mask)
-            return false;
-        *word |= mask;
-        if (color != BLACK) {
-            /*
-             * We use getMarkWordAndMask to recalculate both mask and word as
-             * doing just mask << color may overflow the mask.
-             */
-            getMarkWordAndMask(cell, color, &word, &mask);
-            if (*word & mask)
-                return false;
-            *word |= mask;
-        }
-        return true;
-    }
-
-    JS_ALWAYS_INLINE void unmark(const Cell *cell, uint32_t color) {
-        uintptr_t *word, mask;
-        getMarkWordAndMask(cell, color, &word, &mask);
-        *word &= ~mask;
-    }
-
-    void clear() {
-        PodArrayZero(bitmap);
-    }
-
-#ifdef DEBUG
-    bool noBitsSet(ArenaHeader *aheader) {
-        /*
-         * We assume that the part of the bitmap corresponding to the arena
-         * has the exact number of words so we do not need to deal with a word
-         * that covers bits from two arenas.
-         */
-        JS_STATIC_ASSERT(ArenaBitmapBits == ArenaBitmapWords * JS_BITS_PER_WORD);
-
-        uintptr_t *word, unused;
-        getMarkWordAndMask(reinterpret_cast<Cell *>(aheader->address()), BLACK, &word, &unused);
-        for (size_t i = 0; i != ArenaBitmapWords; i++) {
-            if (word[i])
-                return false;
-        }
-        return true;
-    }
-#endif
-};
-
-JS_STATIC_ASSERT(ArenaBitmapBytes * ArenasPerChunk == sizeof(ChunkBitmap));
-
-typedef BitArray<ArenasPerChunk> PerArenaBitmap;
-
-const size_t ChunkPadSize = ChunkSize
-                            - (sizeof(Arena) * ArenasPerChunk)
-                            - sizeof(ChunkBitmap)
-                            - sizeof(PerArenaBitmap)
-                            - sizeof(ChunkInfo);
-JS_STATIC_ASSERT(ChunkPadSize < BytesPerArenaWithHeader);
-
-/*
- * Chunks contain arenas and associated data structures (mark bitmap, delayed
- * marking state).
- */
-struct Chunk {
-    Arena           arenas[ArenasPerChunk];
-
-    /* Pad to full size to ensure cache alignment of ChunkInfo. */
-    uint8_t         padding[ChunkPadSize];
-
-    ChunkBitmap     bitmap;
-    PerArenaBitmap  decommittedArenas;
-    ChunkInfo       info;
-
-    static Chunk *fromAddress(uintptr_t addr) {
-        addr &= ~ChunkMask;
-        return reinterpret_cast<Chunk *>(addr);
-    }
-
-    static bool withinArenasRange(uintptr_t addr) {
-        uintptr_t offset = addr & ChunkMask;
-        return offset < ArenasPerChunk * ArenaSize;
-    }
-
-    static size_t arenaIndex(uintptr_t addr) {
-        JS_ASSERT(withinArenasRange(addr));
-        return (addr & ChunkMask) >> ArenaShift;
-    }
-
-    uintptr_t address() const {
-        uintptr_t addr = reinterpret_cast<uintptr_t>(this);
-        JS_ASSERT(!(addr & ChunkMask));
-        return addr;
-    }
-
-    bool unused() const {
-        return info.numArenasFree == ArenasPerChunk;
-    }
-
-    bool hasAvailableArenas() const {
-        return info.numArenasFree != 0;
-    }
-
-    inline void addToAvailableList(JSCompartment *compartment);
-    inline void insertToAvailableList(Chunk **insertPoint);
-    inline void removeFromAvailableList();
-
-    ArenaHeader *allocateArena(JSCompartment *comp, AllocKind kind);
-
-    void releaseArena(ArenaHeader *aheader);
-
-    static Chunk *allocate(JSRuntime *rt);
-
-    /* Must be called with the GC lock taken. */
-    static inline void release(JSRuntime *rt, Chunk *chunk);
-    static inline void releaseList(JSRuntime *rt, Chunk *chunkListHead);
-
-    /* Must be called with the GC lock taken. */
-    inline void prepareToBeFreed(JSRuntime *rt);
-
-    /*
-     * Assuming that the info.prevp points to the next field of the previous
-     * chunk in a doubly-linked list, get that chunk.
-     */
-    Chunk *getPrevious() {
-        JS_ASSERT(info.prevp);
-        return fromPointerToNext(info.prevp);
-    }
-
-    /* Get the chunk from a pointer to its info.next field. */
-    static Chunk *fromPointerToNext(Chunk **nextFieldPtr) {
-        uintptr_t addr = reinterpret_cast<uintptr_t>(nextFieldPtr);
-        JS_ASSERT((addr & ChunkMask) == offsetof(Chunk, info.next));
-        return reinterpret_cast<Chunk *>(addr - offsetof(Chunk, info.next));
-    }
-
-  private:
-    inline void init();
-
-    /* Search for a decommitted arena to allocate. */
-    unsigned findDecommittedArenaOffset();
-    ArenaHeader* fetchNextDecommittedArena();
-
-  public:
-    /* Unlink and return the freeArenasHead. */
-    inline ArenaHeader* fetchNextFreeArena(JSRuntime *rt);
-
-    inline void addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader);
-};
-
-JS_STATIC_ASSERT(sizeof(Chunk) == ChunkSize);
-
 class ChunkPool {
     Chunk   *emptyChunkListHead;
     size_t  emptyCount;
 
   public:
     ChunkPool()
       : emptyChunkListHead(NULL),
         emptyCount(0) { }
@@ -847,148 +116,16 @@ class ChunkPool {
 
     /* Must be called with the GC lock taken. */
     void expireAndFree(JSRuntime *rt, bool releaseAll);
 
     /* Must be called either during the GC or with the GC lock taken. */
     JS_FRIEND_API(int64_t) countCleanDecommittedArenas(JSRuntime *rt);
 };
 
-inline uintptr_t
-Cell::address() const
-{
-    uintptr_t addr = uintptr_t(this);
-    JS_ASSERT(addr % Cell::CellSize == 0);
-    JS_ASSERT(Chunk::withinArenasRange(addr));
-    return addr;
-}
-
-inline ArenaHeader *
-Cell::arenaHeader() const
-{
-    uintptr_t addr = address();
-    addr &= ~ArenaMask;
-    return reinterpret_cast<ArenaHeader *>(addr);
-}
-
-Chunk *
-Cell::chunk() const
-{
-    uintptr_t addr = uintptr_t(this);
-    JS_ASSERT(addr % Cell::CellSize == 0);
-    addr &= ~(ChunkSize - 1);
-    return reinterpret_cast<Chunk *>(addr);
-}
-
-AllocKind
-Cell::getAllocKind() const
-{
-    return arenaHeader()->getAllocKind();
-}
-
-#ifdef DEBUG
-inline bool
-Cell::isAligned() const
-{
-    return Arena::isAligned(address(), arenaHeader()->getThingSize());
-}
-#endif
-
-inline uintptr_t
-ArenaHeader::address() const
-{
-    uintptr_t addr = reinterpret_cast<uintptr_t>(this);
-    JS_ASSERT(!(addr & ArenaMask));
-    JS_ASSERT(Chunk::withinArenasRange(addr));
-    return addr;
-}
-
-inline Chunk *
-ArenaHeader::chunk() const
-{
-    return Chunk::fromAddress(address());
-}
-
-inline bool
-ArenaHeader::isEmpty() const
-{
-    /* Arena is empty if its first span covers the whole arena. */
-    JS_ASSERT(allocated());
-    size_t firstThingOffset = Arena::firstThingOffset(getAllocKind());
-    return firstFreeSpanOffsets == FreeSpan::encodeOffsets(firstThingOffset, ArenaMask);
-}
-
-inline size_t
-ArenaHeader::getThingSize() const
-{
-    JS_ASSERT(allocated());
-    return Arena::thingSize(getAllocKind());
-}
-
-inline ArenaHeader *
-ArenaHeader::getNextDelayedMarking() const
-{
-    return &reinterpret_cast<Arena *>(nextDelayedMarking << ArenaShift)->aheader;
-}
-
-inline void
-ArenaHeader::setNextDelayedMarking(ArenaHeader *aheader)
-{
-    JS_ASSERT(!(uintptr_t(aheader) & ArenaMask));
-    hasDelayedMarking = 1;
-    nextDelayedMarking = aheader->arenaAddress() >> ArenaShift;
-}
-
-JS_ALWAYS_INLINE void
-ChunkBitmap::getMarkWordAndMask(const Cell *cell, uint32_t color,
-                                uintptr_t **wordp, uintptr_t *maskp)
-{
-    size_t bit = (cell->address() & ChunkMask) / Cell::CellSize + color;
-    JS_ASSERT(bit < ArenaBitmapBits * ArenasPerChunk);
-    *maskp = uintptr_t(1) << (bit % JS_BITS_PER_WORD);
-    *wordp = &bitmap[bit / JS_BITS_PER_WORD];
-}
-
-static void
-AssertValidColor(const void *thing, uint32_t color)
-{
-#ifdef DEBUG
-    ArenaHeader *aheader = reinterpret_cast<const js::gc::Cell *>(thing)->arenaHeader();
-    JS_ASSERT_IF(color, color < aheader->getThingSize() / Cell::CellSize);
-#endif
-}
-
-inline bool
-Cell::isMarked(uint32_t color) const
-{
-    AssertValidColor(this, color);
-    return chunk()->bitmap.isMarked(this, color);
-}
-
-bool
-Cell::markIfUnmarked(uint32_t color) const
-{
-    AssertValidColor(this, color);
-    return chunk()->bitmap.markIfUnmarked(this, color);
-}
-
-void
-Cell::unmark(uint32_t color) const
-{
-    JS_ASSERT(color != BLACK);
-    AssertValidColor(this, color);
-    chunk()->bitmap.unmark(this, color);
-}
-
-JSCompartment *
-Cell::compartment() const
-{
-    return arenaHeader()->compartment;
-}
-
 static inline JSGCTraceKind
 MapAllocToTraceKind(AllocKind thingKind)
 {
     static const JSGCTraceKind map[FINALIZE_LIMIT] = {
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT0 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT0_BACKGROUND */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT2 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT2_BACKGROUND */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -39,28 +39,28 @@
 
 #include "jsapi.h"
 #include "jsautooplen.h"
 #include "jsbool.h"
 #include "jsdate.h"
 #include "jsexn.h"
 #include "jsfriendapi.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinfer.h"
 #include "jsmath.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jscntxt.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jsiter.h"
 
 #include "frontend/TokenStream.h"
+#include "gc/Marking.h"
 #include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
 #ifdef JS_METHODJIT
 # include "assembler/assembler/MacroAssembler.h"
 #endif
 
 #include "jsatominlines.h"
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -38,22 +38,22 @@
  * ***** END LICENSE BLOCK ***** */
 
 /* Definitions related to javascript type inference. */
 
 #ifndef jsinfer_h___
 #define jsinfer_h___
 
 #include "jsalloc.h"
-#include "jscell.h"
 #include "jsfriendapi.h"
 #include "jsprvtd.h"
 
 #include "ds/LifoAlloc.h"
 #include "gc/Barrier.h"
+#include "gc/Heap.h"
 #include "js/HashTable.h"
 
 namespace JS {
 struct TypeInferenceSizes;
 }
 
 namespace js {
 namespace types {
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -37,19 +37,20 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* Inline members for javascript type inference. */
 
 #include "jsarray.h"
 #include "jsanalyze.h"
 #include "jscompartment.h"
-#include "jsgcmark.h"
 #include "jsinfer.h"
 #include "jsprf.h"
+
+#include "gc/Marking.h"
 #include "vm/GlobalObject.h"
 
 #include "vm/Stack-inl.h"
 
 #ifndef jsinferinlines_h___
 #define jsinferinlines_h___
 
 /////////////////////////////////////////////////////////////////////
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -55,29 +55,29 @@
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jspropertycache.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jslibmath.h"
 
+#include "gc/Marking.h"
 #include "frontend/BytecodeEmitter.h"
 #ifdef JS_METHODJIT
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Logging.h"
 #endif
 #include "vm/Debugger.h"
 
 #include "jsatominlines.h"
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -228,18 +228,17 @@ GetPropertyOperation(JSContext *cx, jsby
                     uint32_t length = argsobj->initialLength();
                     JS_ASSERT(length < INT32_MAX);
                     *vp = Int32Value(int32_t(length));
                     return true;
                 }
             }
 
             if (obj->isTypedArray()) {
-                JSObject *tarray = TypedArray::getTypedArray(obj);
-                *vp = Int32Value(TypedArray::getLength(tarray));
+                *vp = Int32Value(TypedArray::getLength(obj));
                 return true;
             }
         }
     }
 
     JSObject *obj = ValueToObject(cx, lval);
     if (!obj)
         return false;
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -49,33 +49,33 @@
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 #include "ds/Sort.h"
 #include "frontend/TokenStream.h"
+#include "gc/Marking.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/MethodGuard-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1224,21 +1224,33 @@ NumberValueToStringBuffer(JSContext *cx,
     JS_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize);
     return sb.appendInflated(cstr, cstrlen);
 }
 
 JS_PUBLIC_API(bool)
 ToNumberSlow(JSContext *cx, Value v, double *out)
 {
 #ifdef DEBUG
+    /*
+     * MSVC bizarrely miscompiles this, complaining about the first brace below
+     * being unmatched (!).  The error message points at both this opening brace
+     * and at the corresponding SkipRoot constructor.  The error seems to derive
+     * from the presence guard-object macros on the SkipRoot class/constructor,
+     * which seems well in the weeds for an unmatched-brace syntax error.
+     * Otherwise the problem is inscrutable, and I haven't found a workaround.
+     * So for now just disable it when compiling with MSVC -- not ideal, but at
+     * least Windows debug shell builds complete again.
+     */
+#ifndef _MSC_VER
     {
         SkipRoot skip(cx, &v);
         MaybeCheckStackRoots(cx);
     }
 #endif
+#endif
 
     JS_ASSERT(!v.isNumber());
     goto skip_int_double;
     for (;;) {
         if (v.isNumber()) {
             *out = v.toNumber();
             return true;
         }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -53,17 +53,16 @@
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsonparser.h"
 #include "jsopcode.h"
 #include "jsprobes.h"
@@ -76,16 +75,17 @@
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 #include "jsxml.h"
 
 #include "builtin/MapObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
+#include "gc/Marking.h"
 #include "js/MemoryMetrics.h"
 #include "vm/StringBuffer.h"
 #include "vm/Xdr.h"
 
 #include "jsarrayinlines.h"
 #include "jsatominlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
@@ -1658,19 +1658,17 @@ GetOwnPropertyDescriptor(JSContext *cx, 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
     AutoPropertyDescriptorRooter desc(cx);
     return GetOwnPropertyDescriptor(cx, obj, id, &desc) &&
            NewPropertyDescriptorObject(cx, &desc, vp);
 }
 
-}
-
-static bool
+bool
 GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp)
 {
     if (argc == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              method, "0", "s");
         return false;
     }
 
@@ -1684,16 +1682,18 @@ GetFirstArgumentAsObject(JSContext *cx, 
         JS_free(cx, bytes);
         return false;
     }
 
     *objp = &v.toObject();
     return true;
 }
 
+} /* namespace js */
+
 static JSBool
 obj_getOwnPropertyDescriptor(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedVarObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", obj.address()))
         return JS_FALSE;
     RootedVarId id(cx);
     if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), id.address()))
@@ -4320,20 +4320,20 @@ js_FindClassObject(JSContext *cx, JSObje
 bool
 JSObject::allocSlot(JSContext *cx, uint32_t *slotp)
 {
     uint32_t slot = slotSpan();
     JS_ASSERT(slot >= JSSLOT_FREE(getClass()));
 
     /*
      * If this object is in dictionary mode, try to pull a free slot from the
-     * property table's slot-number freelist.
+     * shape table's slot-number freelist.
      */
     if (inDictionaryMode()) {
-        PropertyTable &table = lastProperty()->table();
+        ShapeTable &table = lastProperty()->table();
         uint32_t last = table.freelist;
         if (last != SHAPE_INVALID_SLOT) {
 #ifdef DEBUG
             JS_ASSERT(last < slot);
             uint32_t next = getSlot(last).toPrivateUint32();
             JS_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot);
 #endif
 
@@ -6173,18 +6173,18 @@ JSObject::dump()
     if (obj->isDelegate()) fprintf(stderr, " delegate");
     if (obj->isSystem()) fprintf(stderr, " system");
     if (!obj->isExtensible()) fprintf(stderr, " not_extensible");
     if (obj->isIndexed()) fprintf(stderr, " indexed");
 
     if (obj->isNative()) {
         if (obj->inDictionaryMode())
             fprintf(stderr, " inDictionaryMode");
-        if (obj->hasPropertyTable())
-            fprintf(stderr, " hasPropertyTable");
+        if (obj->hasShapeTable())
+            fprintf(stderr, " hasShapeTable");
     }
     fprintf(stderr, "\n");
 
     if (obj->isDenseArray()) {
         unsigned slots = obj->getDenseArrayInitializedLength();
         fprintf(stderr, "elements\n");
         for (unsigned i = 0; i < slots; i++) {
             fprintf(stderr, " %3d: ", i);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -53,19 +53,19 @@
 #include "jsatom.h"
 #include "jsclass.h"
 #include "jsfriendapi.h"
 #include "jsinfer.h"
 #include "jshash.h"
 #include "jspubtd.h"
 #include "jsprvtd.h"
 #include "jslock.h"
-#include "jscell.h"
 
 #include "gc/Barrier.h"
+#include "gc/Heap.h"
 
 #include "vm/ObjectImpl.h"
 #include "vm/String.h"
 
 namespace js {
 
 class AutoPropDescArrayRooter;
 class ProxyHandler;
@@ -228,16 +228,17 @@ namespace js {
 extern JSBool
 DefaultValue(JSContext *cx, HandleObject obj, JSType hint, Value *vp);
 
 extern Class ArrayClass;
 extern Class ArrayBufferClass;
 extern Class BlockClass;
 extern Class BooleanClass;
 extern Class CallableObjectClass;
+extern Class DataViewClass;
 extern Class DateClass;
 extern Class ErrorClass;
 extern Class ElementIteratorClass;
 extern Class GeneratorClass;
 extern Class IteratorClass;
 extern Class JSONClass;
 extern Class MathClass;
 extern Class NumberClass;
@@ -254,16 +255,17 @@ extern Class WeakMapClass;
 extern Class WithClass;
 extern Class XMLFilterClass;
 
 class ArgumentsObject;
 class ArrayBufferObject;
 class BlockObject;
 class BooleanObject;
 class ClonedBlockObject;
+class DataViewObject;
 class DeclEnvObject;
 class ElementIteratorObject;
 class GlobalObject;
 class NestedScopeObject;
 class NewObjectCache;
 class NormalArgumentsObject;
 class NumberObject;
 class ScopeObject;
@@ -391,17 +393,17 @@ struct JSObject : public js::ObjectImpl
 
     bool shadowingShapeChange(JSContext *cx, const js::Shape &shape);
 
     /* Whether there may be indexed properties on this object. */
     inline bool isIndexed() const;
 
     inline uint32_t propertyCount() const;
 
-    inline bool hasPropertyTable() const;
+    inline bool hasShapeTable() const;
 
     inline size_t computedSizeOfThisSlotsElements() const;
 
     inline void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
                                     size_t *slotsSize, size_t *elementsSize,
                                     size_t *miscSize) const;
 
     static const uint32_t MAX_FIXED_SLOTS = 16;
@@ -910,16 +912,17 @@ struct JSObject : public js::ObjectImpl
      * 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 isDataView() const;
     inline bool isDate() const;
     inline bool isElementIterator() 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;
@@ -962,16 +965,17 @@ struct JSObject : public js::ObjectImpl
 
     inline js::ArgumentsObject &asArguments();
     inline js::ArrayBufferObject &asArrayBuffer();
     inline const js::ArgumentsObject &asArguments() const;
     inline js::BlockObject &asBlock();
     inline js::BooleanObject &asBoolean();
     inline js::CallObject &asCall();
     inline js::ClonedBlockObject &asClonedBlock();
+    inline js::DataViewObject &asDataView();
     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();
@@ -1422,16 +1426,19 @@ extern JSObject *
 NonNullObject(JSContext *cx, const Value &v);
 
 extern const char *
 InformalValueTypeName(const Value &v);
 
 inline void
 DestroyIdArray(FreeOp *fop, JSIdArray *ida);
 
+extern bool
+GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char *method, JSObject **objp);
+
 /* Helpers for throwing. These always return false. */
 extern bool
 Throw(JSContext *cx, jsid id, unsigned errorNumber);
 
 extern bool
 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber);
 
 }  /* namespace js */
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -43,33 +43,32 @@
 
 #include <new>
 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsbool.h"
 #include "jscntxt.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"
 
 #include "gc/Barrier.h"
+#include "gc/Marking.h"
 #include "js/TemplateLib.h"
-
 #include "vm/BooleanObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/NumberObject.h"
 #include "vm/RegExpStatics.h"
 #include "vm/StringObject.h"
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
@@ -786,16 +785,17 @@ inline bool JSObject::hasSpecialEquality
 }
 
 inline bool JSObject::isArguments() const { return isNormalArguments() || isStrictArguments(); }
 inline bool JSObject::isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); }
 inline bool JSObject::isBlock() const { return hasClass(&js::BlockClass); }
 inline bool JSObject::isBoolean() const { return hasClass(&js::BooleanClass); }
 inline bool JSObject::isCall() const { return hasClass(&js::CallClass); }
 inline bool JSObject::isClonedBlock() const { return isBlock() && !!getProto(); }
+inline bool JSObject::isDataView() const { return hasClass(&js::DataViewClass); }
 inline bool JSObject::isDate() const { return hasClass(&js::DateClass); }
 inline bool JSObject::isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
 inline bool JSObject::isElementIterator() const { return hasClass(&js::ElementIteratorClass); }
 inline bool JSObject::isError() const { return hasClass(&js::ErrorClass); }
 inline bool JSObject::isFunction() const { return hasClass(&js::FunctionClass); }
 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); }
@@ -807,17 +807,17 @@ inline bool JSObject::isObject() const {
 inline bool JSObject::isPrimitive() const { return isNumber() || isString() || isBoolean(); }
 inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); }
 inline bool JSObject::isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); }
 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::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
 inline bool JSObject::isString() const { return hasClass(&js::StringClass); }
-inline bool JSObject::isTypedArray() const { return IsFastTypedArrayClass(getClass()); }
+inline bool JSObject::isTypedArray() const { return IsTypedArrayClass(getClass()); }
 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::isXMLId() const
 {
     return hasClass(&js::QNameClass)
@@ -971,17 +971,17 @@ JSObject::nativeEmpty() const
 
 inline uint32_t
 JSObject::propertyCount() const
 {
     return lastProperty()->entryCount();
 }
 
 inline bool
-JSObject::hasPropertyTable() const
+JSObject::hasShapeTable() const
 {
     return lastProperty()->hasTable();
 }
 
 inline size_t
 JSObject::computedSizeOfThisSlotsElements() const
 {
     size_t n = sizeOfThis();
@@ -1299,41 +1299,42 @@ class AutoPropDescArrayRooter : private 
 
   private:
     PropDescArray descriptors;
     SkipRoot skip;
 };
 
 class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescriptor
 {
+    SkipRoot skip;
+
+    AutoPropertyDescriptorRooter *thisDuringConstruction() { return this; }
+
   public:
     AutoPropertyDescriptorRooter(JSContext *cx)
-      : AutoGCRooter(cx, DESCRIPTOR), skip(cx, this)
+      : AutoGCRooter(cx, DESCRIPTOR), skip(cx, thisDuringConstruction())
     {
         obj = NULL;
         attrs = 0;
         getter = (PropertyOp) NULL;
         setter = (StrictPropertyOp) NULL;
         value.setUndefined();
     }
 
     AutoPropertyDescriptorRooter(JSContext *cx, PropertyDescriptor *desc)
-      : AutoGCRooter(cx, DESCRIPTOR), skip(cx, this)
+      : AutoGCRooter(cx, DESCRIPTOR), skip(cx, thisDuringConstruction())
     {
         obj = desc->obj;
         attrs = desc->attrs;
         getter = desc->getter;
         setter = desc->setter;
         value = desc->value;
     }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
-
-  private:
-    SkipRoot skip;
 };
 
 inline void
 NewObjectCache::copyCachedToObject(JSObject *dst, JSObject *src)
 {
     js_memcpy(dst, src, dst->sizeOfThis());
 #ifdef JSGC_GENERATIONAL
     Shape::writeBarrierPost(dst->shape_, &dst->shape_);
--- a/js/src/jsonparser.h
+++ b/js/src/jsonparser.h
@@ -47,19 +47,16 @@
 #include "jscntxt.h"
 #include "jsstr.h"
 
 /*
  * NB: This class must only be used on the stack as it contains a js::Value.
  */
 class JSONParser
 {
-    JSONParser(const JSONParser &other) MOZ_DELETE;
-    void operator=(const JSONParser &other) MOZ_DELETE;
-
   public:
     enum ErrorHandling { RaiseError, NoError };
     enum ParsingMode { StrictJSON, LegacyJSON };
 
   private:
     /* Data members */
 
     JSContext * const cx;
@@ -78,32 +75,34 @@ class JSONParser
                  ArrayOpen, ArrayClose,
                  ObjectOpen, ObjectClose,
                  Colon, Comma,
                  OOM, Error };
 #ifdef DEBUG
     Token lastToken;
 #endif
 
+    JSONParser *thisDuringConstruction() { return this; }
+
   public:
     /* Public API */
 
     /*
      * Create a parser for the provided JSON data.  The parser will accept
      * certain legacy, non-JSON syntax if decodingMode is LegacyJSON.
      * Description of this syntax is deliberately omitted: new code should only
      * use strict JSON parsing.
      */
     JSONParser(JSContext *cx, const jschar *data, size_t length,
                ParsingMode parsingMode = StrictJSON,
                ErrorHandling errorHandling = RaiseError)
       : cx(cx),
         current(data, length),
         end(data + length, data, length),
-        root(cx, this),
+        root(cx, thisDuringConstruction()),
         parsingMode(parsingMode),
         errorHandling(errorHandling)
 #ifdef DEBUG
       , lastToken(Error)
 #endif
     {
         JS_ASSERT(current <= end);
     }
@@ -173,11 +172,15 @@ class JSONParser
     Token advancePropertyName();
     Token advancePropertyColon();
     Token advanceAfterProperty();
     Token advanceAfterObjectOpen();
     Token advanceAfterArrayElement();
 
     void error(const char *msg);
     bool errorReturn();
+
+  private:
+    JSONParser(const JSONParser &other) MOZ_DELETE;
+    void operator=(const JSONParser &other) MOZ_DELETE;
 };
 
 #endif /* jsonparser_h___ */
--- a/js/src/jsproto.tbl
+++ b/js/src/jsproto.tbl
@@ -89,12 +89,13 @@ JS_PROTO(Uint32Array,           30,     
 JS_PROTO(Float32Array,          31,     js_InitTypedArrayClasses)
 JS_PROTO(Float64Array,          32,     js_InitTypedArrayClasses)
 JS_PROTO(Uint8ClampedArray,     33,     js_InitTypedArrayClasses)
 JS_PROTO(Proxy,                 34,     js_InitProxyClass)
 JS_PROTO(AnyName,               35,     js_InitNullClass)
 JS_PROTO(WeakMap,               36,     js_InitWeakMapClass)
 JS_PROTO(Map,                   37,     js_InitMapClass)
 JS_PROTO(Set,                   38,     js_InitSetClass)
+JS_PROTO(DataView,              39,     js_InitTypedArrayClasses)
 
 #undef XML_INIT
 #undef NAMESPACE_INIT
 #undef QNAME_INIT
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -38,23 +38,23 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <string.h>
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsprvtd.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 
+#include "gc/Marking.h"
 #include "vm/MethodGuard.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -62,32 +62,32 @@
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 bool
-PropertyTable::init(JSRuntime *rt, Shape *lastProp)
+ShapeTable::init(JSRuntime *rt, Shape *lastProp)
 {
     /*
      * Either we're creating a table for a large scope that was populated
      * via property cache hit logic under JSOP_INITPROP, JSOP_SETNAME, or
      * JSOP_SETPROP; or else calloc failed at least once already. In any
      * event, let's try to grow, overallocating to hold at least twice the
      * current population.
      */
     uint32_t sizeLog2 = JS_CEILING_LOG2W(2 * entryCount);
     if (sizeLog2 < MIN_SIZE_LOG2)
         sizeLog2 = MIN_SIZE_LOG2;
 
     /*
      * Use rt->calloc_ for memory accounting and overpressure handling
-     * without OOM reporting. See PropertyTable::change.
+     * without OOM reporting. See ShapeTable::change.
      */
     entries = (Shape **) rt->calloc_(sizeOfEntries(JS_BIT(sizeLog2)));
     if (!entries)
         return false;
 
     hashShift = HASH_BITS - sizeLog2;
     for (Shape::Range r = lastProp->all(); !r.empty(); r.popFront()) {
         const Shape &shape = r.front();
@@ -149,17 +149,17 @@ Shape::hashify(JSContext *cx)
     JS_ASSERT(!hasTable());
 
     RootedVarShape self(cx, this);
 
     if (!ensureOwnBaseShape(cx))
         return false;
 
     JSRuntime *rt = cx->runtime;
-    PropertyTable *table = rt->new_<PropertyTable>(self->entryCount());
+    ShapeTable *table = rt->new_<ShapeTable>(self->entryCount());
     if (!table)
         return false;
 
     if (!table->init(rt, self)) {
         rt->free_(table);
         return false;
     }
 
@@ -170,17 +170,17 @@ Shape::hashify(JSContext *cx)
 /*
  * Double hashing needs the second hash code to be relatively prime to table
  * size, so we simply make hash2 odd.
  */
 #define HASH1(hash0,shift)      ((hash0) >> (shift))
 #define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1)
 
 Shape **
-PropertyTable::search(jsid id, bool adding)
+ShapeTable::search(jsid id, bool adding)
 {
     JSHashNumber hash0, hash1, hash2;
     int sizeLog2;
     Shape *stored, *shape, **spp, **firstRemoved;
     uint32_t sizeMask;
 
     JS_ASSERT(entries);
     JS_ASSERT(!JSID_IS_EMPTY(id));
@@ -248,17 +248,17 @@ PropertyTable::search(jsid id, bool addi
         }
     }
 
     /* NOTREACHED */
     return NULL;
 }
 
 bool
-PropertyTable::change(int log2Delta, JSContext *cx)
+ShapeTable::change(int log2Delta, JSContext *cx)
 {
     JS_ASSERT(entries);
 
     /*
      * Grow, shrink, or compress by changing this->entries.
      */
     int oldlog2 = HASH_BITS - hashShift;
     int newlog2 = oldlog2 + log2Delta;
@@ -286,17 +286,17 @@ PropertyTable::change(int log2Delta, JSC
     }
 
     /* Finally, free the old entries storage. */
     cx->free_(oldTable);
     return true;
 }
 
 bool
-PropertyTable::grow(JSContext *cx)
+ShapeTable::grow(JSContext *cx)
 {
     JS_ASSERT(needsToGrow());
 
     uint32_t size = capacity();
     int delta = removedCount < size >> 2;
 
     if (!change(delta, cx) && entryCount + removedCount == size - 1) {
         JS_ReportOutOfMemory(cx);
@@ -539,17 +539,17 @@ JSObject::addPropertyInternal(JSContext 
 {
     JS_ASSERT_IF(!allowDictionary, !inDictionaryMode());
 
     RootId idRoot(cx, &id);
     RootedVarObject self(cx, this);
 
     RootGetterSetter gsRoot(cx, attrs, &getter, &setter);
 
-    PropertyTable *table = NULL;
+    ShapeTable *table = NULL;
     if (!inDictionaryMode()) {
         bool stableSlot =
             (slot == SHAPE_INVALID_SLOT) ||
             lastProperty()->hasMissingSlot() ||
             (slot == lastProperty()->maybeSlot() + 1);
         JS_ASSERT_IF(!allowDictionary, stableSlot);
         if (allowDictionary &&
             (!stableSlot || lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT)) {
@@ -894,17 +894,17 @@ JSObject::removeProperty(JSContext *cx, 
     }
 
     /*
      * A dictionary-mode object owns mutable, unique shapes on a non-circular
      * doubly linked list, hashed by lastProperty()->table. So we can edit the
      * list and hash in place.
      */
     if (self->inDictionaryMode()) {
-        PropertyTable &table = self->lastProperty()->table();
+        ShapeTable &table = self->lastProperty()->table();
 
         if (SHAPE_HAD_COLLISION(*spp)) {
             *spp = SHAPE_REMOVED;
             ++table.removedCount;
             --table.entryCount;
         } else {
             *spp = NULL;
             --table.entryCount;
@@ -928,21 +928,21 @@ JSObject::removeProperty(JSContext *cx, 
         /* Hand off table from the old to new last property. */
         oldLastProp->handoffTableTo(self->lastProperty());
 
         /* Generate a new shape for the object, infallibly. */
         JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare));
 
         /* Consider shrinking table if its load factor is <= .25. */
         uint32_t size = table.capacity();
-        if (size > PropertyTable::MIN_SIZE && table.entryCount <= size >> 2)
+        if (size > ShapeTable::MIN_SIZE && table.entryCount <= size >> 2)
             (void) table.change(-1, cx);
     } else {
         /*
-         * Non-dictionary-mode property tables are shared immutables, so all we
+         * Non-dictionary-mode shape tables are shared immutables, so all we
          * need do is retract the last property and we'll either get or else
          * lazily make via a later hashify the exact table for the new property
          * lineage.
          */
         JS_ASSERT(shape == self->lastProperty());
         self->removeLastProperty(cx);
     }
 
@@ -1007,17 +1007,17 @@ JSObject::replaceWithNewEquivalentShape(
         RootObject selfRoot(cx, &self);
         RootShape oldRoot(cx, &oldShape);
         newShape = js_NewGCShape(cx);
         if (!newShape)
             return NULL;
         new (newShape) Shape(oldShape->base()->unowned(), 0);
     }
 
-    PropertyTable &table = self->lastProperty()->table();
+    ShapeTable &table = self->lastProperty()->table();
     Shape **spp = oldShape->isEmptyShape()
                   ? NULL
                   : table.search(oldShape->propidRef(), false);
 
     /*
      * Splice the new shape into the same position as the old shape, preserving
      * enumeration order (see bug 601399).
      */
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -108,20 +108,20 @@
  * 
  * 3. A property represented by a non-last Shape in a shape lineage has its
  *    attributes modified.
  * 
  * To find the Shape for a particular property of an object initially requires
  * a linear search. But if the number of searches starting at any particular
  * Shape in the property tree exceeds MAX_LINEAR_SEARCHES and the Shape's
  * lineage has (excluding the EmptyShape) at least MIN_ENTRIES, we create an
- * auxiliary hash table -- the PropertyTable -- that allows faster lookup.
- * Furthermore, a PropertyTable is always created for dictionary mode lists,
- * and it is attached to the last Shape in the lineage. Property tables for
- * property tree Shapes never change, but property tables for dictionary mode
+ * auxiliary hash table -- the ShapeTable -- that allows faster lookup.
+ * Furthermore, a ShapeTable is always created for dictionary mode lists,
+ * and it is attached to the last Shape in the lineage. Shape tables for
+ * property tree Shapes never change, but shape tables for dictionary mode
  * Shapes can grow and shrink.
  *
  * There used to be a long, math-heavy comment here explaining why property
  * trees are more space-efficient than alternatives.  This was removed in bug
  * 631138; see that bug for the full details.
  *
  * Because many Shapes have similar data, there is actually a secondary type
  * called a BaseShape that holds some of a Shape's data.  Many shapes can share
@@ -133,52 +133,52 @@ namespace js {
 /* Limit on the number of slotful properties in an object. */
 static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1;
 static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2;
 
 /*
  * Shapes use multiplicative hashing, but specialized to
  * minimize footprint.
  */
-struct PropertyTable {
+struct ShapeTable {
     static const uint32_t HASH_BITS     = tl::BitSize<HashNumber>::result;
     static const uint32_t MIN_ENTRIES   = 7;
     static const uint32_t MIN_SIZE_LOG2 = 4;
     static const uint32_t MIN_SIZE      = JS_BIT(MIN_SIZE_LOG2);
 
     int             hashShift;          /* multiplicative hash shift */
 
     uint32_t        entryCount;         /* number of entries in table */
     uint32_t        removedCount;       /* removed entry sentinels in table */
     uint32_t        freelist;           /* SHAPE_INVALID_SLOT or head of slot
                                            freelist in owning dictionary-mode
                                            object */
     js::Shape       **entries;          /* table of ptrs to shared tree nodes */
 
-    PropertyTable(uint32_t nentries)
+    ShapeTable(uint32_t nentries)
       : hashShift(HASH_BITS - MIN_SIZE_LOG2),
         entryCount(nentries),
         removedCount(0),
         freelist(SHAPE_INVALID_SLOT)
     {
         /* NB: entries is set by init, which must be called. */
     }
 
-    ~PropertyTable() {
+    ~ShapeTable() {
         js::UnwantedForeground::free_(entries);
     }
 
     /* By definition, hashShift = HASH_BITS - log2(capacity). */
     uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift); }
 
     /* Computes the size of the entries array for a given capacity. */
     static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); }
 
     /*
-     * This counts the PropertyTable object itself (which must be
+     * This counts the ShapeTable object itself (which must be
      * heap-allocated) and its |entries| array.
      */
     size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const {
         return mallocSizeOf(this) + mallocSizeOf(entries);
     }
 
     /* Whether we need to grow.  We want to do this if the load factor is >= 0.75 */
     bool needsToGrow() const {
@@ -221,17 +221,17 @@ class PropertyTree;
  * property. This information is split across the Shape and the BaseShape
  * at shape->base(). Both Shape and BaseShape can be either owned or unowned
  * by, respectively, the Object or Shape referring to them.
  *
  * Owned Shapes are used in dictionary objects, and form a doubly linked list
  * whose entries are all owned by that dictionary. Unowned Shapes are all in
  * the property tree.
  *
- * Owned BaseShapes are used for shapes which have property tables, including
+ * Owned BaseShapes are used for shapes which have shape tables, including
  * the last properties in all dictionaries. Unowned BaseShapes compactly store
  * information common to many shapes. In a given compartment there is a single
  * BaseShape for each combination of BaseShape information. This information
  * is cloned in owned BaseShapes so that information can be quickly looked up
  * for a given object or shape without regard to whether the base shape is
  * owned or not.
  *
  * All combinations of owned/unowned Shapes/BaseShapes are possible:
@@ -242,21 +242,21 @@ class PropertyTree;
  *     property to property as the object's last property changes.
  *
  * Owned Shape, Unowned BaseShape:
  *
  *     Property in a dictionary object other than the last one.
  *
  * Unowned Shape, Owned BaseShape:
  *
- *     Property in the property tree which has a property table.
+ *     Property in the property tree which has a shape table.
  *
  * Unowned Shape, Unowned BaseShape:
  *
- *     Property in the property tree which does not have a property table.
+ *     Property in the property tree which does not have a shape table.
  *
  * BaseShapes additionally encode some information about the referring object
  * itself. This includes the object's class, parent and various flags that may
  * be set for the object. Except for the class, this information is mutable and
  * may change when the object has an established property lineage. On such
  * changes the entire property lineage is not updated, but rather only the
  * last property (and its base shape). This works because only the object's
  * last property is used to query information about the object. Care must be
@@ -319,18 +319,18 @@ class BaseShape : public js::gc::Cell
         js::StrictPropertyOp rawSetter; /* setter hook for shape */
         JSObject        *setterObj;     /* user-defined callable "set" object or
                                            null if shape->hasSetterValue() */
     };
 
     /* For owned BaseShapes, the canonical unowned BaseShape. */
     HeapPtr<UnownedBaseShape> unowned_;
 
-    /* For owned BaseShapes, the shape's property table. */
-    PropertyTable       *table_;
+    /* For owned BaseShapes, the shape's shape table. */
+    ShapeTable       *table_;
 
   public:
     void finalize(FreeOp *fop);
 
     inline BaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags);
     inline BaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags,
                      uint8_t attrs, PropertyOp rawGetter, StrictPropertyOp rawSetter);
     inline BaseShape(const StackBaseShape &base);
@@ -353,18 +353,18 @@ class BaseShape : public js::gc::Cell
 
     bool hasGetterObject() const { return !!(flags & HAS_GETTER_OBJECT); }
     JSObject *getterObject() const { JS_ASSERT(hasGetterObject()); return getterObj; }
 
     bool hasSetterObject() const { return !!(flags & HAS_SETTER_OBJECT); }
     JSObject *setterObject() const { JS_ASSERT(hasSetterObject()); return setterObj; }
 
     bool hasTable() const { JS_ASSERT_IF(table_, isOwned()); return table_ != NULL; }
-    PropertyTable &table() const { JS_ASSERT(table_ && isOwned()); return *table_; }
-    void setTable(PropertyTable *table) { JS_ASSERT(isOwned()); table_ = table; }
+    ShapeTable &table() const { JS_ASSERT(table_ && isOwned()); return *table_; }
+    void setTable(ShapeTable *table) { JS_ASSERT(isOwned()); table_ = table; }
 
     uint32_t slotSpan() const { JS_ASSERT(isOwned()); return slotSpan_; }
     void setSlotSpan(uint32_t slotSpan) { JS_ASSERT(isOwned()); slotSpan_ = slotSpan; }
 
     /* Lookup base shapes from the compartment's baseShapes table. */
     static UnownedBaseShape *getUnowned(JSContext *cx, const StackBaseShape &base);
 
     /* Get the canonical base shape. */
@@ -545,17 +545,17 @@ struct Shape : public js::gc::Cell
             return true;
         return makeOwnBaseShape(cx);
     }
 
     bool makeOwnBaseShape(JSContext *cx);
 
   public:
     bool hasTable() const { return base()->hasTable(); }
-    js::PropertyTable &table() const { return base()->table(); }
+    js::ShapeTable &table() const { return base()->table(); }
 
     void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
                              size_t *propTableSize, size_t *kidsSize) const {
         *propTableSize = hasTable() ? table().sizeOfIncludingThis(mallocSizeOf) : 0;
         *kidsSize = !inDictionary() && kids.isHash()
                   ? kids.toHash()->sizeOfIncludingThis(mallocSizeOf)
                   : 0;
     }
@@ -847,23 +847,23 @@ struct Shape : public js::gc::Cell
 
         const js::Shape *shape = this;
         uint32_t count = 0;
         for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront())
             ++count;
         return count;
     }
 
-    bool isBigEnoughForAPropertyTable() const {
+    bool isBigEnoughForAShapeTable() const {
         JS_ASSERT(!hasTable());
         const js::Shape *shape = this;
         uint32_t count = 0;
         for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront()) {
             ++count;
-            if (count >= PropertyTable::MIN_ENTRIES)
+            if (count >= ShapeTable::MIN_ENTRIES)
                 return true;
         }
         return false;
     }
 
 #ifdef DEBUG
     void dump(JSContext *cx, FILE *fp) const;
     void dumpSubtree(JSContext *cx, int level, FILE *fp) const;
@@ -1068,17 +1068,17 @@ Shape::search(JSContext *cx, Shape *star
     *pspp = NULL;
 
     if (start->hasTable()) {
         Shape **spp = start->table().search(id, adding);
         return SHAPE_FETCH(spp);
     }
 
     if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) {
-        if (start->isBigEnoughForAPropertyTable()) {
+        if (start->isBigEnoughForAShapeTable()) {
             RootShape startRoot(cx, &start);
             RootId idRoot(cx, &id);
             if (start->hashify(cx)) {
                 Shape **spp = start->table().search(id, adding);
                 return SHAPE_FETCH(spp);
             }
         }
         /*
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -42,21 +42,21 @@
 
 #include <new>
 
 #include "jsarray.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
+#include "jsgc.h"
 #include "jsobj.h"
 #include "jsscope.h"
-#include "jsgc.h"
-#include "jsgcmark.h"
 
+#include "gc/Marking.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/ScopeObject.h"
 #include "vm/StringObject.h"
 
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
@@ -171,17 +171,17 @@ BaseShape::adoptUnowned(UnownedBaseShape
      * This is a base shape owned by a dictionary object, update it to reflect the
      * unowned base shape of a new last property.
      */
     JS_ASSERT(isOwned());
     DebugOnly<uint32_t> flags = getObjectFlags();
     JS_ASSERT((flags & other->getObjectFlags()) == flags);
 
     uint32_t span = slotSpan();
-    PropertyTable *table = &this->table();
+    ShapeTable *table = &this->table();
 
     *this = *other;
     setOwned(other);
     setTable(table);
     setSlotSpan(span);
 
     assertConsistency();
 }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -50,24 +50,24 @@
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 
+#include "gc/Marking.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
 #include "vm/Debugger.h"
 #include "vm/Xdr.h"
 
@@ -1784,56 +1784,56 @@ js::CloneScript(JSContext *cx, JSScript 
     if (!data)
         return NULL;
 
     /* Bindings */
 
     Bindings bindings(cx);
     BindingNames names(cx);
     if (!src->bindings.getLocalNameArray(cx, &names))
-        return false;
+        return NULL;
 
     for (unsigned i = 0; i < names.length(); ++i) {
         if (JSAtom *atom = names[i].maybeAtom) {
             if (!bindings.add(cx, RootedVarAtom(cx, atom), names[i].kind))
-                return false;
+                return NULL;
         } else {
             uint16_t _;
             if (!bindings.addDestructuring(cx, &_))
-                return false;
+                return NULL;
         }
     }
 
     if (!bindings.ensureShape(cx))
-        return false;
+        return NULL;
     bindings.makeImmutable();
 
     /* Objects */
 
     AutoObjectVector objects(cx);
     if (nobjects != 0) {
         HeapPtrObject *vector = src->objects()->vector;
         for (unsigned i = 0; i < nobjects; i++) {
             JSObject *clone = vector[i]->isStaticBlock()
                               ? CloneStaticBlockObject(cx, vector[i]->asStaticBlock(), objects, src)
                               : CloneInterpretedFunction(cx, vector[i]->toFunction());
             if (!clone || !objects.append(clone))
-                return false;
+                return NULL;
         }
     }
 
     /* RegExps */
 
     AutoObjectVector regexps(cx);
     for (unsigned i = 0; i < nregexps; i++) {
         HeapPtrObject *vector = src->regexps()->vector;
         for (unsigned i = 0; i < nregexps; i++) {
             JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->asRegExp());
             if (!clone || !regexps.append(clone))
-                return false;
+                return NULL;
         }
     }
 
     /* Now that all fallible allocation is complete, create the GC thing. */
 
     JSScript *dst = js_NewGCScript(cx);
     if (!dst) {
         Foreground::free_(data);
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -40,17 +40,16 @@
 #ifndef jsstr_h___
 #define jsstr_h___
 
 #include <ctype.h>
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jsprvtd.h"
 #include "jslock.h"
-#include "jscell.h"
 #include "jsutil.h"
 
 #include "js/HashTable.h"
 #include "vm/Unicode.h"
 
 namespace js {
 
 /* Implemented in jsstrinlines.h */
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -35,36 +35,36 @@
  * 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 <string.h>
 
 #include "mozilla/FloatingPoint.h"
-#include "mozilla/Util.h"
-
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
+#include "jscpucfg.h"
 #include "jsversion.h"
 #include "jsgc.h"
-#include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jstypedarray.h"
 
+#include "gc/Marking.h"
+#include "mozilla/Util.h"
 #include "vm/GlobalObject.h"
 #include "vm/NumericConversions.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jstypedarrayinlines.h"
 
@@ -133,39 +133,37 @@ ToClampedIndex(JSContext *cx, const Valu
  * ArrayBuffer
  *
  * This class holds the underlying raw buffer that the TypedArray classes
  * access.  It can be created explicitly and passed to a TypedArray, or
  * can be created implicitly by constructing a TypedArray with a size.
  */
 
 /**
- * Walks up the prototype chain to find the actual ArrayBuffer data.
- * This MAY return NULL. Callers should always use isArrayBuffer()
- * first.
+ * Walks up the prototype chain to find the actual ArrayBuffer data, if any.
  */
-JSObject *
-ArrayBufferObject::getArrayBuffer(JSObject *obj)
+static ArrayBufferObject *
+getArrayBuffer(JSObject *obj)
 {
     while (obj && !obj->isArrayBuffer())
         obj = obj->getProto();
-    return obj;
+    return obj ? &obj->asArrayBuffer() : NULL;
 }
 
 JSBool
 ArrayBufferObject::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    JSObject *bufobj = getArrayBuffer(obj);
-    if (!bufobj) {
-        vp->setInt32(0);
-        return true;
+    ArrayBufferObject *buffer = getArrayBuffer(obj);
+    if (!buffer) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_INCOMPATIBLE_PROTO, "ArrayBuffer", "byteLength", "object");
+        return false;
     }
 
-    ArrayBufferObject &arrayBuffer = bufobj->asArrayBuffer();
-    vp->setInt32(int32_t(arrayBuffer.byteLength()));
+    vp->setInt32(int32_t(buffer->byteLength()));
     return true;
 }
 
 JSBool
 ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -500,17 +498,25 @@ ArrayBufferObject::obj_getGeneric(JSCont
 
 JSBool
 ArrayBufferObject::obj_getProperty(JSContext *cx, JSObject *obj_,
                                    JSObject *receiver_, PropertyName *name_, Value *vp)
 {
     RootedVarObject obj(cx, obj_), receiver(cx, receiver_);
     RootedVarPropertyName name(cx, name_);
 
-    obj = getArrayBuffer(obj);
+    if (!(obj = getArrayBuffer(obj))) {
+        JSAutoByteString bs(cx, name);
+        if (!bs)
+            return false;
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_INCOMPATIBLE_PROTO, "ArrayBuffer", bs.ptr(), "object");
+        return false;
+    }
+
     if (name == cx->runtime->atomState.byteLengthAtom) {
         vp->setInt32(obj->asArrayBuffer().byteLength());
         return true;
     }
 
     RootedVarObject delegate(cx, DelegateObject(cx, obj));
     if (!delegate)
         return false;
@@ -782,106 +788,101 @@ ArrayBufferObject::obj_typeOf(JSContext 
 /*
  * TypedArray
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */
 
-JSObject *
-TypedArray::getTypedArray(JSObject *obj)
+static JSObject *
+getTypedArray(JSObject *obj)
 {
-    while (!obj->isTypedArray())
-        obj = obj->getProto();
-    return obj;
+    MOZ_ASSERT(obj);
+    do {
+        if (obj->isTypedArray())
+            return obj;
+    } while ((obj = obj->getProto()));
+    return NULL;
 }
 
 inline bool
 TypedArray::isArrayIndex(JSContext *cx, JSObject *obj, jsid id, uint32_t *ip)
 {
     uint32_t index;
     if (js_IdIsIndex(id, &index) && index < getLength(obj)) {
         if (ip)
             *ip = index;
         return true;
     }
 
     return false;
 }
 
-typedef Value (* TypedArrayPropertyGetter)(JSObject *tarray);
-
-template <TypedArrayPropertyGetter Get>
-class TypedArrayGetter {
-  public:
-    static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) {
-        do {
-            if (obj->isTypedArray()) {
-                JSObject *tarray = TypedArray::getTypedArray(obj);
-                if (tarray)
-                    *vp = Get(tarray);
-                return true;
-            }
-        } while ((obj = obj->getProto()) != NULL);
-        return true;
-    }
-};
+bool
+js::IsDataView(JSObject* obj)
+{
+    JS_ASSERT(obj);
+    return obj->isDataView();
+}
 
 /*
  * For now (until slots directly hold data)
  * slots data element points to the JSObject representing the ArrayBuffer.
  */
-inline Value
-getBufferValue(JSObject *tarray)
-{
-    JSObject *buffer = TypedArray::getBuffer(tarray);
-    return ObjectValue(*buffer);
-}
-
 JSBool
 TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getBufferValue>::get(cx, obj, id, vp);
-}
-
-inline Value
-getByteOffsetValue(JSObject *tarray)
-{
-    return Int32Value(TypedArray::getByteOffset(tarray));
+    if (!(obj = getTypedArray(obj))) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "buffer", "object");
+        return false;
+    }
+
+    JS_SET_RVAL(cx, vp, ObjectValue(*TypedArray::getBuffer(obj)));
+    return true;
 }
 
 JSBool
 TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getByteOffsetValue>::get(cx, obj, id, vp);
-}
-
-inline Value
-getByteLengthValue(JSObject *tarray)
-{
-    return Int32Value(TypedArray::getByteLength(tarray));
+    if (!(obj = getTypedArray(obj))) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "byteOffset", "object");
+        return false;
+    }
+
+    JS_SET_RVAL(cx, vp, Int32Value(TypedArray::getByteOffset(obj)));
+    return true;
 }
 
 JSBool
 TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getByteLengthValue>::get(cx, obj, id, vp);
-}
-
-inline Value
-getLengthValue(JSObject *tarray)
-{
-    return Int32Value(TypedArray::getLength(tarray));
+    if (!(obj = getTypedArray(obj))) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "byteLength", "object");
+        return false;
+    }
+
+    JS_SET_RVAL(cx, vp, Int32Value(TypedArray::getByteLength(obj)));
+    return true;
 }
 
 JSBool
 TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getLengthValue>::get(cx, obj, id, vp);
+    if (!(obj = getTypedArray(obj))) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_INCOMPATIBLE_PROTO, "TypedArray", "length", "object");
+        return false;
+    }
+
+    JS_SET_RVAL(cx, vp, Int32Value(TypedArray::getLength(obj)));
+    return true;
 }
 
 JSBool
 TypedArray::obj_lookupGeneric(JSContext *cx, JSObject *obj, jsid id,
                               JSObject **objp, JSProperty **propp)
 {
     JSObject *tarray = getTypedArray(obj);
     JS_ASSERT(tarray);
@@ -1085,17 +1086,17 @@ class TypedArrayTemplate
 
     static inline Class *protoClass()
     {
         return &TypedArray::protoClasses[ArrayTypeID()];
     }
 
     static inline Class *fastClass()
     {
-        return &TypedArray::fastClasses[ArrayTypeID()];
+        return &TypedArray::classes[ArrayTypeID()];
     }
 
     static void
     obj_trace(JSTracer *trc, JSObject *obj)
     {
         MarkSlot(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
     }
 
@@ -1191,44 +1192,54 @@ class TypedArrayTemplate
             vp->setUndefined();
             return true;
         }
 
         return proto->getElementIfPresent(cx, receiver, index, vp, present);
     }
 
     static bool
-    setElementTail(JSContext *cx, HandleObject tarray, uint32_t index, Value *vp, JSBool strict)
+    toDoubleForTypedArray(JSContext *cx, Value *vp, double *d)
+    {
+        if (vp->isDouble()) {
+            *d = vp->toDouble();
+        } else if (vp->isNull()) {
+            *d = 0.0;
+        } else if (vp->isPrimitive()) {
+            JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean());
+            if (vp->isString()) {
+                if (!ToNumber(cx, *vp, d))
+                    return false;
+            } else if (vp->isUndefined()) {
+                *d = js_NaN;
+            } else {
+                *d = double(vp->toBoolean());
+            }
+        } else {
+            // non-primitive assignments become NaN or 0 (for float/int arrays)
+            *d = js_NaN;
+        }
+
+        return true;
+    }
+
+    static bool
+    setElementTail(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp, JSBool strict)
     {
         JS_ASSERT(tarray);
         JS_ASSERT(index < getLength(tarray));
 
         if (vp->isInt32()) {
             setIndex(tarray, index, NativeType(vp->toInt32()));
             return true;
         }
 
         double d;
-        if (vp->isDouble()) {
-            d = vp->toDouble();
-        } else if (vp->isNull()) {
-            d = 0.0;
-        } else if (vp->isPrimitive()) {
-            JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean());
-            if (vp->isString()) {
-                JS_ALWAYS_TRUE(ToNumber(cx, *vp, &d));
-            } else if (vp->isUndefined()) {
-                d = js_NaN;
-            } else {
-                d = double(vp->toBoolean());
-            }
-        } else {
-            // non-primitive assignments become NaN or 0 (for float/int arrays)
-            d = js_NaN;
-        }
+        if (!toDoubleForTypedArray(cx, vp, &d))
+            return false;
 
         // If the array is an integer array, we only handle up to
         // 32-bit ints from this point on.  if we want to handle
         // 64-bit ints, we'll need some changes.
 
         // Assign based on characteristics of the destination type
         if (ArrayTypeIsFloatingPoint()) {
             setIndex(tarray, index, NativeType(d));
@@ -1349,17 +1360,17 @@ class TypedArrayTemplate
 
         rval->setBoolean(true);
         return true;
     }
 
     static JSBool
     obj_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
     {
-        JSObject *tarray = TypedArray::getTypedArray(obj);
+        JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         if (index < getLength(tarray)) {
             rval->setBoolean(false);
             return true;
         }
 
         rval->setBoolean(true);
@@ -1622,66 +1633,62 @@ class TypedArrayTemplate
         RootedVarObject obj(cx, NonGenericMethodGuard(cx, args, fun_set, fastClass(), &ok));
         if (!obj)
             return ok;
 
         RootedVarObject tarray(cx, getTypedArray(obj));
         if (!tarray)
             return true;
 
-        // these are the default values
-        int32_t off = 0;
-
+        // first arg must be either a typed array or a JS array
+        if (args.length() == 0 || !args[0].isObject()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
+            return false;
+        }
+
+        int32_t offset = 0;
         if (args.length() > 1) {
-            if (!ToInt32(cx, args[1], &off))
+            if (!ToInt32(cx, args[1], &offset))
                 return false;
 
-            if (off < 0 || uint32_t(off) > getLength(tarray)) {
+            if (offset < 0 || uint32_t(offset) > getLength(tarray)) {
                 // the given offset is bogus
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_TYPED_ARRAY_BAD_ARGS);
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_INDEX, "2");
                 return false;
             }
         }
 
-        uint32_t offset(off);
-
-        // first arg must be either a typed array or a JS array
-        if (args.length() == 0 || !args[0].isObject()) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_TYPED_ARRAY_BAD_ARGS);
+        if (!args[0].isObject()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
         RootedVarObject arg0(cx, args[0].toObjectOrNull());
-        if (arg0->isTypedArray()) {
-            JSObject *src = TypedArray::getTypedArray(arg0);
-            if (!src ||
-                getLength(src) > getLength(tarray) - offset)
-            {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_TYPED_ARRAY_BAD_ARGS);
+        RootedVarObject src(cx, getTypedArray(arg0));
+        if (src) {
+            if (getLength(src) > getLength(tarray) - offset) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
                 return false;
             }
 
             if (!copyFromTypedArray(cx, obj, src, offset))
                 return false;
         } else {
+            src = arg0;
             uint32_t len;
-            if (!js_GetLengthProperty(cx, arg0, &len))
+            if (!js_GetLengthProperty(cx, src, &len))
                 return false;
 
             // avoid overflow; we know that offset <= length
             if (len > getLength(tarray) - offset) {
-                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                     JSMSG_TYPED_ARRAY_BAD_ARGS);
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
                 return false;
             }
 
-            if (!copyFromArray(cx, obj, arg0, len, offset))
+            if (!copyFromArray(cx, obj, src, len, offset))
                 return false;
         }
 
         args.rval().setUndefined();
         return true;
     }
 
   public:
@@ -2140,39 +2147,578 @@ TypedArrayTemplate<float>::copyIndexToVa
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * confuse the engine into interpreting a double-typed jsval as an
      * object-typed jsval.
      *
      * This could be removed for platforms/compilers known to convert a 32-bit
      * non-canonical nan to a 64-bit canonical nan.
      */
-    if (JS_UNLIKELY(MOZ_DOUBLE_IS_NaN(dval)))
-        dval = js_NaN;
-
-    vp->setDouble(dval);
+    vp->setDouble(JS_CANONICALIZE_NAN(dval));
 }
 
 template<>
 void
 TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp)
 {
     double val = getIndex(tarray, index);
 
     /*
      * Doubles in typed arrays could be typed-punned arrays of integers. This
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * confuse the engine into interpreting a double-typed jsval as an
      * object-typed jsval.
      */
-    if (JS_UNLIKELY(MOZ_DOUBLE_IS_NaN(val)))
-        val = js_NaN;
-
-    vp->setDouble(val);
+    vp->setDouble(JS_CANONICALIZE_NAN(val));
+}
+
+JSBool
+DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    JSObject *bufobj;
+    if (!GetFirstArgumentAsObject(cx, args.length(), args.base(), "DataView constructor", &bufobj))
+        return false;
+
+    if (!bufobj->isArrayBuffer()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_EXPECTED_TYPE,
+                             "DataView", "ArrayBuffer", bufobj->getClass()->name);
+        return false;
+    }
+
+    RootedVar<ArrayBufferObject*> buffer(cx, &bufobj->asArrayBuffer());
+    uint32_t bufferLength = buffer->byteLength();
+    uint32_t byteOffset = 0;
+    uint32_t byteLength = bufferLength;
+
+    if (args.length() > 1) {
+        if (!ToUint32(cx, args[1], &byteOffset))
+            return false;
+        if (byteOffset > INT32_MAX) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                 JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+            return false;
+        }
+
+        if (args.length() > 2) {
+            if (!ToUint32(cx, args[2], &byteLength))
+                return false;
+            if (byteLength > INT32_MAX) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                     JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
+                return false;
+            }
+        } else {
+            if (byteOffset > bufferLength) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+                return false;
+            }
+
+            byteLength = bufferLength - byteOffset;
+        }
+    }
+
+    /* The sum of these cannot overflow a uint32_t */
+    JS_ASSERT(byteOffset <= INT32_MAX);
+    JS_ASSERT(byteLength <= INT32_MAX);
+
+    if (byteOffset + byteLength > bufferLength) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+        return false;
+    }
+
+    JSObject *obj = DataViewObject::create(cx, byteOffset, byteLength, buffer);
+    if (!obj)
+        return false;
+    args.rval().setObject(*obj);
+    return true;
+}
+
+JSBool
+DataViewObject::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
+{
+    obj = UnwrapObject(obj);
+    JS_ASSERT(obj->isDataView());
+    DataViewObject &view = obj->asDataView();
+    if (view.hasBuffer())
+        vp->setObject(view.arrayBuffer());
+    else
+        vp->setUndefined();
+    return true;
+}
+
+JSBool
+DataViewObject::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
+{
+    obj = UnwrapObject(obj);
+    JS_ASSERT(obj->isDataView());
+    DataViewObject &view = obj->asDataView();
+    vp->setInt32(view.byteOffset());
+    return true;
+}
+
+JSBool
+DataViewObject::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
+{
+    obj = UnwrapObject(obj);
+    JS_ASSERT(obj->isDataView());
+    DataViewObject &view = obj->asDataView();
+    vp->setInt32(view.byteLength());
+    return true;
+}
+
+bool
+DataViewObject::getDataPointer(JSContext *cx, CallArgs args, size_t typeSize, uint8_t **data)
+{
+    uint32_t offset;
+    JS_ASSERT(args.length() > 0);
+    if (!ToUint32(cx, args[0], &offset))
+        return false;
+    if (offset > UINT32_MAX - typeSize || offset + typeSize > byteLength()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+        return false;
+    }
+
+    *data = static_cast<uint8_t*>(dataPointer()) + offset;
+    return true;
+}
+
+static inline bool
+needToSwapBytes(bool littleEndian)
+{
+#if IS_LITTLE_ENDIAN
+    return !littleEndian;
+#else
+    return littleEndian;
+#endif
+}
+
+static inline uint8_t
+swapBytes(uint8_t x)
+{
+    return x;
+}
+
+static inline uint16_t
+swapBytes(uint16_t x)
+{
+    return ((x & 0xff) << 8) | (x >> 8);
+}
+
+static inline uint32_t
+swapBytes(uint32_t x)
+{
+    return ((x & 0xff) << 24) |
+           ((x & 0xff00) << 8) |
+           ((x & 0xff0000) >> 8) |
+           ((x & 0xff000000) >> 24);
+}
+
+static inline uint64_t
+swapBytes(uint64_t x)
+{
+    uint32_t a = x & UINT32_MAX;
+    uint32_t b = x >> 32;
+    return (uint64_t(swapBytes(a)) << 32) | swapBytes(b);
+}
+
+template <typename DataType> struct DataToRepType { typedef DataType result; };
+template <> struct DataToRepType<int8_t>   { typedef uint8_t result; };
+template <> struct DataToRepType<uint8_t>  { typedef uint8_t result; };
+template <> struct DataToRepType<int16_t>  { typedef uint16_t result; };
+template <> struct DataToRepType<uint16_t> { typedef uint16_t result; };
+template <> struct DataToRepType<int32_t>  { typedef uint32_t result; };
+template <> struct DataToRepType<uint32_t> { typedef uint32_t result; };
+template <> struct DataToRepType<float>    { typedef uint32_t result; };
+template <> struct DataToRepType<double>   { typedef uint64_t result; };
+
+template <typename DataType>
+struct DataViewIO
+{
+    typedef typename DataToRepType<DataType>::result ReadWriteType;
+
+    static void fromBuffer(DataType *dest, const uint8_t *unalignedBuffer, bool wantSwap)
+    {
+        JS_ASSERT((reinterpret_cast<uintptr_t>(dest) & (Min<size_t>(JS_ALIGN_OF_POINTER, sizeof(DataType)) - 1)) == 0);
+        memcpy((void *) dest, unalignedBuffer, sizeof(ReadWriteType));
+        if (wantSwap) {
+            ReadWriteType *rwDest = reinterpret_cast<ReadWriteType *>(dest);
+            *rwDest = swapBytes(*rwDest);
+        }
+    }
+
+    static void toBuffer(uint8_t *unalignedBuffer, const DataType *src, bool wantSwap)
+    {
+        JS_ASSERT((reinterpret_cast<uintptr_t>(src) & (Min<size_t>(JS_ALIGN_OF_POINTER, sizeof(DataType)) - 1)) == 0);
+        ReadWriteType temp = *reinterpret_cast<const ReadWriteType *>(src);
+        if (wantSwap)
+            temp = swapBytes(temp);
+        memcpy(unalignedBuffer, (void *) &temp, sizeof(ReadWriteType));
+    }
+};
+
+template<typename NativeType>
+bool
+DataViewObject::read(JSContext *cx, CallArgs &args, NativeType *val, const char *method)
+{
+    if (args.length() < 1) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_MORE_ARGS_NEEDED, method, "0", "s");
+        return false;
+    }
+
+    uint8_t *data;
+    if (!getDataPointer(cx, args, sizeof(NativeType), &data))
+        return false;
+
+    bool fromLittleEndian = args.length() >= 2 && js_ValueToBoolean(args[1]);
+    DataViewIO<NativeType>::fromBuffer(val, data, needToSwapBytes(fromLittleEndian));
+    return true;
+}
+
+template <typename NativeType>
+static inline bool
+WebIDLCast(JSContext *cx, const Value &value, NativeType *out)
+{
+    int32_t temp;
+    if (!ToInt32(cx, value, &temp))
+        return false;
+    // Technically, the behavior of assigning an out of range value to a signed
+    // variable is undefined. In practice, compilers seem to do what we want
+    // without issuing any warnings.
+    *out = static_cast<NativeType>(temp);
+    return true;
+}
+
+template <>
+inline bool
+WebIDLCast<float>(JSContext *cx, const Value &value, float *out)
+{
+    double temp;
+    if (!ToNumber(cx, value, &temp))
+        return false;
+    *out = static_cast<float>(temp);
+    return true;
+}
+
+template <>
+inline bool
+WebIDLCast<double>(JSContext *cx, const Value &value, double *out)
+{
+    return ToNumber(cx, value, out);
+}
+
+template<typename NativeType>
+bool
+DataViewObject::write(JSContext *cx, CallArgs &args, const char *method)
+{
+    if (args.length() < 2) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_MORE_ARGS_NEEDED, method, "1", "");
+        return false;
+    }
+
+    uint8_t *data;
+    if (!getDataPointer(cx, args, sizeof(NativeType), &data))
+        return false;
+
+    NativeType value;
+    if (!WebIDLCast(cx, args[1], &value))
+        return false;
+
+    bool toLittleEndian = args.length() >= 3 && js_ValueToBoolean(args[2]);
+    DataViewIO<NativeType>::toBuffer(data, &value, needToSwapBytes(toLittleEndian));
+    return true;
+}
+
+inline JSObject *
+NonGenericProtoSearchingMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok)
+{
+    const Value &thisv = args.thisv();
+    if (thisv.isObject()) {
+        JSObject *obj = thisv.toObjectOrNull();
+        while (obj) {
+            if (obj->getClass() == clasp) {
+                *ok = true;  /* quell gcc overwarning */
+                return obj;
+            }
+            obj = obj->getProto();
+        }
+    }
+
+    *ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp);
+    return NULL;
+}
+
+JSBool
+DataViewObject::fun_getInt8(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    bool ok;
+    JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getInt8, &DataViewClass, &ok);
+    if (!obj)
+        return ok;
+
+    int8_t val;
+    if (!obj->asDataView().read(cx, args, &val, "getInt8"))
+        return false;
+    args.rval().setInt32(val);
+    return true;
+}
+
+JSBool
+DataViewObject::fun_getUint8(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    bool ok;
+    JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getUint8, &DataViewClass, &ok);
+    if (!obj)
+        return ok;
+
+    uint8_t val;
+    if (!obj->asDataView().read(cx, args, &val, "getUint8"))
+        return false;
+    args.rval().setInt32(val);
+    return true;
+}
+
+JSBool
+DataViewObject::fun_getInt16(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    bool ok;
+    JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getInt16, &DataViewClass, &ok);
+    if (!obj)
+        return ok;
+
+    int16_t val;
+    if (!obj->asDataView().read(cx, args, &val, "getInt16"))
+        return false;
+    args.rval().setInt32(val);
+    return true;
+}
+
+JSBool
+DataViewObject::fun_getUint16(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    bool ok;
+    JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getUint16, &DataViewClass, &ok);
+    if (!obj)
+        return ok;
+
+    uint16_t val;
+    if (!obj->asDataView().read(cx, args, &val, "getUint16"))
+        return false;
+    args.rval().setInt32(val);
+    return true;
+}
+
+JSBool
+DataViewObject::fun_getInt32(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    bool ok;
+    JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getInt32, &DataViewClass, &ok);
+    if (!obj)
+        return ok;
+
+    int32_t val;
+    if (!obj->asDataView().read(cx, args, &val, "getInt32"))
+        return false;
+    args.rval().setInt32(val);
+    return true;
+}
+
+JSBool
+DataViewObject::fun_getUint32(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    bool ok;
+    JSObject *obj = NonGenericProtoSearchingMethodGuard(cx, args, fun_getUint32, &DataViewClass, &ok);
+    if (!obj)
+        return ok;
+
+    uint32_t val;
+    if (!obj->asDataView().read(cx, args, &val, "getUint32"))