Merge last green changeset on m-i to m-c
authorEd Morley <bmo@edmorley.co.uk>
Thu, 01 Sep 2011 08:41:18 +0100
changeset 77679 7d3d1c2c75f88ecaaf896fd6d5716f41b6c5707a
parent 77630 d772dfb96ba1bffd2d2e0ebfe2bfad4da7891e6d (current diff)
parent 77678 94a4a478d774833daef7aaf90f1695d003f4185f (diff)
child 77684 bd97d56b0785823388fcae28bcd409fb63e81faf
child 77700 63becbe85737890d364f39cf65188cbceca3c93b
child 77886 20189e7dcadae81c758ab72b6efd1b181b72561c
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last green changeset on m-i to m-c
js/src/jsinfer.cpp
js/src/jsinvoke.cpp
js/src/methodjit/Compiler.cpp
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -174,16 +174,17 @@
 @BINPATH@/components/htmlparser.xpt
 @BINPATH@/components/imglib2.xpt
 @BINPATH@/components/imgicon.xpt
 @BINPATH@/components/inspector.xpt
 @BINPATH@/components/intl.xpt
 @BINPATH@/components/jar.xpt
 @BINPATH@/components/jetpack.xpt
 @BINPATH@/components/jsdservice.xpt
+@BINPATH@/components/jsdebugger.xpt
 @BINPATH@/components/layout_base.xpt
 @BINPATH@/components/layout_forms.xpt
 #ifdef NS_PRINTING
 @BINPATH@/components/layout_printing.xpt
 #endif
 @BINPATH@/components/layout_xul_tree.xpt
 @BINPATH@/components/layout_xul.xpt
 @BINPATH@/components/locale.xpt
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/679689-1.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<img crossorigin>
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -88,8 +88,9 @@ load 610571-1.html
 load 604262-1.html
 load 628599-1.html
 load 637214-1.svg
 load 637214-2.svg
 load 642022-1.html
 load 646184.html
 load 658845-1.svg
 load 667336-1.html
+load 679689-1.html
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -1107,34 +1107,34 @@ nsAttrValue::ParseNonNegativeIntValue(co
 
   PRInt32 ec;
   PRBool strict;
   PRInt32 originalVal = StringToInteger(aString, &strict, &ec);
   if (NS_FAILED(ec) || originalVal < 0) {
     return PR_FALSE;
   }
 
-  SetIntValueAndType(originalVal, eInteger, nsnull);
+  SetIntValueAndType(originalVal, eInteger, strict ? nsnull : &aString);
 
   return PR_TRUE;
 }
 
 PRBool
 nsAttrValue::ParsePositiveIntValue(const nsAString& aString)
 {
   ResetIfSet();
 
   PRInt32 ec;
   PRBool strict;
   PRInt32 originalVal = StringToInteger(aString, &strict, &ec);
   if (NS_FAILED(ec) || originalVal <= 0) {
     return PR_FALSE;
   }
 
-  SetIntValueAndType(originalVal, eInteger, nsnull);
+  SetIntValueAndType(originalVal, eInteger, strict ? nsnull : &aString);
 
   return PR_TRUE;
 }
 
 void
 nsAttrValue::SetColorValue(nscolor aColor, const nsAString& aString)
 {
   nsStringBuffer* buf = GetStringBuffer(aString);
@@ -1245,20 +1245,24 @@ nsAttrValue::ParseIntMarginValue(const n
 void
 nsAttrValue::SetMiscAtomOrString(const nsAString* aValue)
 {
   NS_ASSERTION(GetMiscContainer(), "Must have MiscContainer!");
   NS_ASSERTION(!GetMiscContainer()->mStringBits,
                "Trying to re-set atom or string!");
   if (aValue) {
     PRUint32 len = aValue->Length();
-    // We're allowing eCSSStyleRule attributes to store empty strings as it
-    // can be beneficial to store an empty style attribute as a parsed rule.
+    // * We're allowing eCSSStyleRule attributes to store empty strings as it
+    //   can be beneficial to store an empty style attribute as a parsed rule.
+    // * We're allowing enumerated values because sometimes the empty
+    //   string corresponds to a particular enumerated value, especially
+    //   for enumerated values that are not limited enumerated.
     // Add other types as needed.
-    NS_ASSERTION(len || Type() == eCSSStyleRule, "Empty string?");
+    NS_ASSERTION(len || Type() == eCSSStyleRule || Type() == eEnum,
+                 "Empty string?");
     MiscContainer* cont = GetMiscContainer();
     if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
       nsIAtom* atom = NS_NewAtom(*aValue);
       if (atom) {
         cont->mStringBits = reinterpret_cast<PtrBits>(atom) | eAtomBase;
       }
     } else {
       nsStringBuffer* buf = GetStringBuffer(*aValue);
--- a/content/html/content/test/test_bug618948.html
+++ b/content/html/content/test/test_bug618948.html
@@ -69,17 +69,17 @@ i.oninput = function(event) {
 i.onchange = function(event) {
   eventHandler(event);
   i.onchange = null;
   synthesizeMouseAtCenter(b, {});
 };
 
 i.oninvalid = function(event) {
   eventHandler(event);
-  i.oninvad = null;
+  i.oninvalid = null;
   endTest();
 };
 
 SimpleTest.waitForExplicitFinish();
 
 SimpleTest.waitForFocus(beginTest);
 
 </script>
--- a/dom/interfaces/css/nsIDOMCSS2Properties.idl
+++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl
@@ -46,17 +46,17 @@
  * The nsIDOMCSS2Properties interface is a datatype for additional
  * reflection of data already provided in nsIDOMCSSStyleDeclaration in
  * the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[builtinclass, scriptable, uuid(519ae4fa-0fee-4aaa-bcb9-34b503236801)]
+[builtinclass, scriptable, uuid(79b66107-f9d2-42ac-bc68-b558d79037ec)]
 interface nsIDOMCSS2Properties : nsISupports
 {
            attribute DOMString        background;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundAttachment;
                                         // raises(DOMException) on setting
 
@@ -679,28 +679,16 @@ interface nsIDOMCSS2Properties : nsISupp
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozTransform;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozTransformOrigin;
                                         // raises(DOMException) on setting 
 
-           attribute DOMString        MozPerspective;
-                                        // raises(DOMException) on setting
-
-           attribute DOMString        MozPerspectiveOrigin;
-                                        // raises(DOMException) on setting
-
-           attribute DOMString        MozBackfaceVisibility;
-                                        // raises(DOMException) on setting
-
-           attribute DOMString        MozTransformStyle;
-                                        // raises(DOMException) on setting
-
            attribute DOMString        MozWindowShadow;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundSize;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozTextBlink;
                                         // raises(DOMException) on setting
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -622,17 +622,17 @@ TabParent::RecvGetWidgetNativeData(Windo
     if (document) {
       nsIPresShell* shell = document->GetShell();
       if (shell) {
         nsIViewManager* vm = shell->GetViewManager();
         nsCOMPtr<nsIWidget> widget;
         vm->GetRootWidget(getter_AddRefs(widget));
         if (widget) {
           *aValue = reinterpret_cast<WindowsHandle>(
-            widget->GetNativeData(NS_NATIVE_WINDOW));
+            widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
           return true;
         }
       }
     }
   }
   return false;
 }
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -712,42 +712,23 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
   nsresult rv = vm->GetRootWidget(getter_AddRefs(widget));            
   if (widget) {
     *pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
   } else {
     NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
   }
 
   return rv;
-#elif defined(MOZ_WIDGET_GTK2)
+#elif defined(MOZ_WIDGET_GTK2) || defined(MOZ_WIDGET_QT)
   // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
   nsIWidget* win = mObjectFrame->GetNearestWidget();
   if (!win)
     return NS_ERROR_FAILURE;
-  GdkWindow* gdkWindow = static_cast<GdkWindow*>(win->GetNativeData(NS_NATIVE_WINDOW));
-  if (!gdkWindow)
-    return NS_ERROR_FAILURE;
-  gdkWindow = gdk_window_get_toplevel(gdkWindow);
-#ifdef MOZ_X11
-  *static_cast<Window*>(value) = GDK_WINDOW_XID(gdkWindow);
-#endif
+  *static_cast<Window*>(value) = (long unsigned int)win->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW);
   return NS_OK;
-#elif defined(MOZ_WIDGET_QT)
-  // X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
-  nsIWidget* win = mObjectFrame->GetNearestWidget();
-  if (!win)
-    return NS_ERROR_FAILURE;
-  QWidget* widget = static_cast<QWidget*>(win->GetNativeData(NS_NATIVE_WINDOW));
-  if (!widget)
-    return NS_ERROR_FAILURE;
-#ifdef MOZ_X11
-  *static_cast<Window*>(value) = widget->handle();
-  return NS_OK;
-#endif
-  return NS_ERROR_FAILURE;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::SetEventModel(PRInt32 eventModel)
 {
 #ifdef XP_MACOSX
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -1039,16 +1039,24 @@ nsGeolocation::WindowOwnerStillExists()
   }
 
   return PR_TRUE;
 }
 
 bool
 nsGeolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
 {
+  if (Preferences::GetBool("geo.prompt.testing", PR_FALSE)) {
+    nsCOMPtr<nsIRunnable> ev =
+        new RequestAllowEvent(Preferences::GetBool("geo.prompt.testing.allow",
+                                                   PR_FALSE), request);
+    NS_DispatchToMainThread(ev);
+    return true;
+  }
+
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
     if (!window)
       return true;
 
     // because owner implements nsITabChild, we can assume that it is
     // the one and only TabChild.
     TabChild* child = GetTabChildFrom(window->GetDocShell());
@@ -1061,21 +1069,13 @@ nsGeolocation::RegisterRequestWithPrompt
 
     nsCString type = NS_LITERAL_CSTRING("geolocation");
     child->SendPContentPermissionRequestConstructor(request, type, IPC::URI(mURI));
     
     request->Sendprompt();
     return true;
   }
 
-  if (Preferences::GetBool("geo.prompt.testing", PR_FALSE)) {
-    nsCOMPtr<nsIRunnable> ev =
-      new RequestAllowEvent(Preferences::GetBool("geo.prompt.testing.allow",
-                                                 PR_FALSE), request);
-    NS_DispatchToMainThread(ev);
-    return true;
-  }
-
   nsCOMPtr<nsIRunnable> ev  = new RequestPromptEvent(request);
   NS_DispatchToMainThread(ev);
   return true;
 }
 
--- a/dom/system/nsDeviceMotion.cpp
+++ b/dom/system/nsDeviceMotion.cpp
@@ -34,16 +34,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDeviceMotion.h"
 
 #include "nsAutoPtr.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMWindow.h"
+#include "nsPIDOMWindow.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIServiceManager.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMDeviceOrientationEvent.h"
 #include "nsIDOMDeviceMotionEvent.h"
 #include "nsIServiceManager.h"
 #include "nsIPrefService.h"
@@ -227,36 +228,42 @@ nsDeviceMotion::DeviceMotionChanged(PRUi
     --i;
     nsRefPtr<nsDeviceMotionData> a = new nsDeviceMotionData(type, x, y, z);
     mListeners[i]->OnMotionChange(a);
   }
 
   for (PRUint32 i = mWindowListeners.Length(); i > 0 ; ) {
     --i;
 
+    // check to see if this window is in the background.  if
+    // it is, don't send any device motion to it.
+    nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(mWindowListeners[i]);
+    if (!pwindow || pwindow->GetOuterWindow()->IsBackground())
+      continue;
+
     nsCOMPtr<nsIDOMDocument> domdoc;
     mWindowListeners[i]->GetDocument(getter_AddRefs(domdoc));
 
     if (domdoc) {
       nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mWindowListeners[i]);
       if (type == nsIDeviceMotionData::TYPE_ACCELERATION)
         FireDOMMotionEvent(domdoc, target, x, y, z);
       else if (type == nsIDeviceMotionData::TYPE_ORIENTATION)
         FireDOMOrientationEvent(domdoc, target, x, y, z);
     }
   }
   return NS_OK;
 }
 
 void
 nsDeviceMotion::FireDOMOrientationEvent(nsIDOMDocument *domdoc,
-                                         nsIDOMEventTarget *target,
-                                         double alpha,
-                                         double beta,
-                                         double gamma)
+                                        nsIDOMEventTarget *target,
+                                        double alpha,
+                                        double beta,
+                                        double gamma)
 {
   nsCOMPtr<nsIDOMEvent> event;
   PRBool defaultActionEnabled = PR_TRUE;
   domdoc->CreateEvent(NS_LITERAL_STRING("DeviceOrientationEvent"), getter_AddRefs(event));
 
   nsCOMPtr<nsIDOMDeviceOrientationEvent> oe = do_QueryInterface(event);
 
   if (!oe) {
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -5,17 +5,17 @@
       android:installLocation="auto"
       android:versionCode="@ANDROID_VERSION_CODE@"
       android:versionName="@MOZ_APP_VERSION@"
 #ifdef MOZ_ANDROID_SHARED_ID
       android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
 #endif
       >
     <uses-sdk android:minSdkVersion="5"
-              android:targetSdkVersion="5"/>
+              android:targetSdkVersion="11"/>
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
 
--- a/gfx/2d/SourceSurfaceCG.cpp
+++ b/gfx/2d/SourceSurfaceCG.cpp
@@ -105,17 +105,17 @@ SourceSurfaceCG::InitFromData(unsigned c
 
     case A8:
       // XXX: why don't we set a colorspace here?
       bitsPerComponent = 8;
       bitsPerPixel = 8;
   };
 
   void *data = malloc(aStride * aSize.height);
-  memcpy(aData, data, aStride * aSize.height);
+  memcpy(data, aData, aStride * aSize.height);
 
   mFormat = aFormat;
 
   dataProvider = CGDataProviderCreateWithData (data,
                                                data,
 					       aSize.height * aStride,
 					       releaseCallback);
 
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -41,16 +41,17 @@
 
 #include "LayerManagerOGL.h"
 #include "ThebesLayerOGL.h"
 #include "ContainerLayerOGL.h"
 #include "ImageLayerOGL.h"
 #include "ColorLayerOGL.h"
 #include "CanvasLayerOGL.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/Preferences.h"
 
 #include "LayerManagerOGLShaders.h"
 
 #include "gfxContext.h"
 #include "nsIWidget.h"
 
 #include "GLContext.h"
 #include "GLContextProvider.h"
@@ -74,17 +75,16 @@ int LayerManagerOGLProgram::sCurrentProg
  */
 LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mBackBufferFBO(0)
   , mBackBufferTexture(0)
   , mBackBufferSize(-1, -1)
   , mHasBGRA(0)
-  , mRenderFPS(false)
 {
 }
 
 LayerManagerOGL::~LayerManagerOGL()
 {
   Destroy();
 }
 
@@ -329,17 +329,17 @@ LayerManagerOGL::Initialize(nsRefPtr<GLC
     0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
     /* Then quad texcoords */
     0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
     /* Then flipped quad texcoords */
     0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
   };
   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
 
-  nsCOMPtr<nsIConsoleService> 
+  nsCOMPtr<nsIConsoleService>
     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
 
   if (console) {
     nsString msg;
     msg +=
       NS_LITERAL_STRING("OpenGL LayerManager Initialized Succesfully.\nVersion: ");
     msg += NS_ConvertUTF8toUTF16(
       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
@@ -352,16 +352,18 @@ LayerManagerOGL::Initialize(nsRefPtr<GLC
     msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
     if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
       msg += NS_LITERAL_STRING("TEXTURE_2D");
     else
       msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
     console->LogStringMessage(msg.get());
   }
 
+  Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
+
   reporter.SetSuccessful();
   return true;
 }
 
 void
 LayerManagerOGL::SetClippingRegion(const nsIntRegion& aClippingRegion)
 {
   mClippingRegion = aClippingRegion;
@@ -533,16 +535,18 @@ LayerManagerOGL::RootLayer() const
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return nsnull;
   }
 
   return static_cast<LayerOGL*>(mRoot->ImplData());
 }
 
+PRBool LayerManagerOGL::sDrawFPS = PR_FALSE;
+
 /* This function tries to stick to portable C89 as much as possible
  * so that it can be easily copied into other applications */
 void
 LayerManagerOGL::FPSState::DrawFPS(GLContext* context, CopyProgram* copyprog)
 {
   fcount++;
 
   int rate = 30;
@@ -797,17 +801,17 @@ LayerManagerOGL::Render()
                            
   mWidget->DrawOver(this, rect);
 
   if (mTarget) {
     CopyToTarget();
     return;
   }
 
-  if (mRenderFPS) {
+  if (sDrawFPS) {
     mFPS.DrawFPS(mGLContext, GetCopy2DProgram());
   }
 
   if (mGLContext->IsDoubleBuffered()) {
     mGLContext->SwapBuffers();
     return;
   }
 
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -402,18 +402,16 @@ public:
    * Setup World transform matrix.
    * Transform will be ignored if it is not PreservesAxisAlignedRectangles
    * or has non integer scale
    */
   void SetWorldTransform(const gfxMatrix& aMatrix);
   gfxMatrix& GetWorldTransform(void);
   void WorldTransformRect(nsIntRect& aRect);
 
-  void SetRenderFPS(bool aRenderFPS) { mRenderFPS = aRenderFPS; };
-
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** 
    * Context target, NULL when drawing directly to our swap chain.
    */
@@ -500,17 +498,17 @@ private:
         : texture(0)
         , fps(0)
         , initialized(false)
         , fcount(0)
       {}
       void DrawFPS(GLContext*, CopyProgram*);
   } mFPS;
 
-  bool mRenderFPS;
+  static PRBool sDrawFPS;
 };
 
 /**
  * General information and tree management for OGL layers.
  */
 class LayerOGL
 {
 public:
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -431,16 +431,17 @@ static const char *sExtensionNames[] = {
     "GL_IMG_read_format",
     "GL_EXT_read_format_bgra",
     "GL_APPLE_client_storage",
     "GL_ARB_texture_non_power_of_two",
     "GL_ARB_pixel_buffer_object",
     "GL_ARB_ES2_compatibility",
     "GL_OES_texture_float",
     "GL_ARB_texture_float",
+    "GL_EXT_unpack_subimage",
     NULL
 };
 
 void
 GLContext::InitExtensions()
 {
     MakeCurrent();
     const GLubyte *extensions = fGetString(LOCAL_GL_EXTENSIONS);
@@ -1834,19 +1835,27 @@ GLContext::TexImage2D(GLenum target, GLi
                       GLint pixelsize, GLint border, GLenum format, 
                       GLenum type, const GLvoid *pixels)
 {
     fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 
                  NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
                         GetAddressAlignment((ptrdiff_t)stride)));
 
 #ifndef USE_GLES2
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, stride/pixelsize);
+    bool useUnpackRowLength = true;
 #else
-    if (stride != width * pixelsize) {
+    // A Khronos extension, GL_EXT_unpack_subimage, that restores support
+    // for GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_ROWS and GL_UNPACK_SKIP_PIXELS
+    // exists on Tegra 2 (and possibly other chipsets)
+    bool useUnpackRowLength = IsExtensionSupported(EXT_unpack_subimage);
+#endif
+
+    if (useUnpackRowLength)
+        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, stride/pixelsize);
+    else if (stride != width * pixelsize) {
         // Not using the whole row of texture data and GLES doesn't 
         // support GL_UNPACK_ROW_LENGTH. We need to upload each row
         // separately.
         fTexImage2D(target,
                     border,
                     internalformat,
                     width,
                     height,
@@ -1868,31 +1877,29 @@ GLContext::TexImage2D(GLenum target, GLi
                            row);
 
             row += stride;
         }
 
         fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
         return;
     }
-#endif
 
     fTexImage2D(target,
                 level,
                 internalformat,
                 width,
                 height,
                 border,
                 format,
                 type,
                 pixels);
 
-#ifndef USE_GLES2
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-#endif
+    if (useUnpackRowLength)
+        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
     fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
 }
 
 void
 GLContext::TexSubImage2D(GLenum target, GLint level, 
                          GLint xoffset, GLint yoffset, 
                          GLsizei width, GLsizei height, GLsizei stride,
                          GLint pixelsize, GLenum format, 
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -975,16 +975,17 @@ public:
         IMG_read_format,
         EXT_read_format_bgra,
         APPLE_client_storage,
         ARB_texture_non_power_of_two,
         ARB_pixel_buffer_object,
         ARB_ES2_compatibility,
         OES_texture_float,
         ARB_texture_float,
+        EXT_unpack_subimage,
         Extensions_Max
     };
 
     PRBool IsExtensionSupported(GLExtensions aKnownExtension) {
         return mAvailableExtensions[aKnownExtension];
     }
 
     // for unknown extensions
--- a/gfx/thebes/GLContextProviderEGL.cpp
+++ b/gfx/thebes/GLContextProviderEGL.cpp
@@ -130,16 +130,17 @@ public:
 
 #else
 
 #error "Platform not recognized"
 
 #endif
 
 #include "gfxUtils.h"
+#include "gfxFailure.h"
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "GLContextProvider.h"
 #include "nsDebug.h"
 #include "nsThreadUtils.h"
 #include "EGLUtils.h"
 
@@ -703,17 +704,23 @@ public:
 
     PRBool Init()
     {
         if (!OpenLibrary(GLES2_LIB)) {
             NS_WARNING("Couldn't load EGL LIB.");
             return PR_FALSE;
         }
 
-        MakeCurrent();
+        PRBool current = MakeCurrent();
+        if (!current) {
+            gfx::LogFailure(NS_LITERAL_CSTRING(
+                "Couldn't get device attachments for device."));
+            return PR_FALSE;
+        }
+
         PRBool ok = InitWithPrefix("gl", PR_TRUE);
 #if 0
         if (ok) {
             EGLint v;
             sEGLLibrary.fQueryContext(EGL_DISPLAY(), mContext, LOCAL_EGL_RENDER_BUFFER, &v);
             if (v == LOCAL_EGL_BACK_BUFFER)
                 mIsDoubleBuffered = PR_TRUE;
         }
new file mode 100644
--- /dev/null
+++ b/js/ductwork/Makefile.in
@@ -0,0 +1,49 @@
+# ***** 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 the Mozilla Browser code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Jason Orendorff <jorendorff@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH     = ../..
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
+
+include $(topsrcdir)/config/config.mk
+
+PARALLEL_DIRS += \
+  debugger \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/js/ductwork/debugger/IJSDebugger.idl
@@ -0,0 +1,52 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ *   Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * Do not use this interface. Instead, write:
+ *     Components.utils.import("resource://gre/modules/jsdebugger.jsm");
+ */
+[scriptable, uuid(2fc14cc6-4ed0-4bbf-a7dd-e535bf088eb5)]
+interface IJSDebugger : nsISupports
+{
+  /**
+   * Define the global Debugger constructor.
+   */
+  [implicit_jscontext]
+  void addClass();
+};
new file mode 100644
--- /dev/null
+++ b/js/ductwork/debugger/JSDebugger.cpp
@@ -0,0 +1,111 @@
+/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "JSDebugger.h"
+#include "nsIXPConnect.h"
+#include "nsThreadUtils.h"
+#include "jsapi.h"
+#include "jsobj.h"
+#include "jsgc.h"
+#include "jsfriendapi.h"
+#include "jsdbgapi.h"
+#include "mozilla/ModuleUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsMemory.h"
+
+#define JSDEBUGGER_CONTRACTID \
+  "@mozilla.org/jsdebugger;1"
+
+#define JSDEBUGGER_CID \
+{ 0x0365cbd5, 0xd46e, 0x4e94, { 0xa3, 0x9f, 0x83, 0xb6, 0x3c, 0xd1, 0xa9, 0x63 } }
+
+namespace mozilla {
+namespace jsdebugger {
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(JSDebugger)
+
+NS_IMPL_ISUPPORTS1(JSDebugger, IJSDebugger)
+
+JSDebugger::JSDebugger()
+{
+}
+
+JSDebugger::~JSDebugger()
+{
+}
+
+NS_IMETHODIMP
+JSDebugger::AddClass(JSContext *cx)
+{
+  nsresult rv;
+  nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
+
+  JSObject* global = JS_GetGlobalForScopeChain(cx);
+  if (!global) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (!JS_DefineDebuggerObject(cx, global)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+}
+}
+
+NS_DEFINE_NAMED_CID(JSDEBUGGER_CID);
+
+static const mozilla::Module::CIDEntry kJSDebuggerCIDs[] = {
+  { &kJSDEBUGGER_CID, false, NULL, mozilla::jsdebugger::JSDebuggerConstructor },
+  { NULL }
+};
+
+static const mozilla::Module::ContractIDEntry kJSDebuggerContracts[] = {
+  { JSDEBUGGER_CONTRACTID, &kJSDEBUGGER_CID },
+  { NULL }
+};
+
+static const mozilla::Module kJSDebuggerModule = {
+  mozilla::Module::kVersion,
+  kJSDebuggerCIDs,
+  kJSDebuggerContracts
+};
+
+NSMODULE_DEFN(jsdebugger) = &kJSDebuggerModule;
new file mode 100644
--- /dev/null
+++ b/js/ductwork/debugger/JSDebugger.h
@@ -0,0 +1,62 @@
+/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation <http://www.mozilla.org/>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef COMPONENTS_JSDEBUGGER_H
+#define COMPONENTS_JSDEBUGGER_H
+
+#include "IJSDebugger.h"
+
+namespace mozilla {
+namespace jsdebugger {
+
+class JSDebugger : public IJSDebugger
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_IJSDEBUGGER
+
+  JSDebugger();
+
+private:
+  ~JSDebugger();
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/js/ductwork/debugger/Makefile.in
@@ -0,0 +1,75 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Dave Camp <dcamp@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+relativesrcdir = js/ductwork/debugger
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = jsdebugger
+MODULE_NAME = jsdebugger
+GRE_MODULE = 1
+
+LIBRARY_NAME = jsdebugger
+XPIDL_MODULE = jsdebugger
+LIBXUL_LIBRARY = 1
+EXPORT_LIBRARY = 1
+IS_COMPONENT = 1
+
+CPPSRCS = \
+  JSDebugger.cpp \
+  $(NULL)
+
+EXTRA_DSO_LDOPTS += \
+  $(MOZ_COMPONENT_LIBS) \
+  $(MOZ_JS_LIBS) \
+  $(NULL)
+
+EXTRA_JS_MODULES = \
+  jsdebugger.jsm \
+  $(NULL)
+
+XPIDLSRCS = \
+  IJSDebugger.idl \
+  $(NULL)
+
+XPCSHELL_TESTS = tests
+
+include $(topsrcdir)/config/rules.mk
copy from toolkit/components/ctypes/ctypes.jsm
copy to js/ductwork/debugger/jsdebugger.jsm
--- a/toolkit/components/ctypes/ctypes.jsm
+++ b/js/ductwork/debugger/jsdebugger.jsm
@@ -11,46 +11,45 @@
  * 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 js-ctypes.
  *
  * The Initial Developer of the Original Code is
  * The Mozilla Foundation <http://www.mozilla.org/>.
- * Portions created by the Initial Developer are Copyright (C) 2009
+ * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *  Dan Witte <dwitte@mozilla.com>
+ *  Jason Orendorff <jorendorff@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-let EXPORTED_SYMBOLS = [ "ctypes" ];
+let EXPORTED_SYMBOLS = [ "Debugger" ];
 
 /*
- * This is the js module for ctypes. Import it like so:
- *   Components.utils.import("resource://gre/modules/ctypes.jsm");
+ * This is the js module for Debugger. Import it like so:
+ *   Components.utils.import("resource://gre/modules/jsdebugger.jsm");
  *
- * This will create a 'ctypes' object, which provides an interface to describe
- * and instantiate C types and call C functions from a dynamic library.
+ * This will create a 'Debugger' object, which provides an interface to debug
+ * JavaScript code running in other compartments in the same process, on the
+ * same thread.
  *
  * For documentation on the API, see:
- * https://developer.mozilla.org/en/js-ctypes/js-ctypes_reference
- *
+ *   https://wiki.mozilla.org/Debugger
  */
 
-// Initialize the ctypes object. You do not need to do this yourself.
-const init = Components.classes["@mozilla.org/jsctypes;1"].createInstance();
-init();
-
+// Initialize the Debugger object. You do not need to do this yourself.
+const init = Components.classes["@mozilla.org/jsdebugger;1"].createInstance(Components.interfaces.IJSDebugger);
+init.addClass();
new file mode 100644
--- /dev/null
+++ b/js/ductwork/debugger/tests/head_dbg.js
@@ -0,0 +1,17 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+function testGlobal(aName) {
+  let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
+    .createInstance(Ci.nsIPrincipal);
+
+  let sandbox = Cu.Sandbox(systemPrincipal);
+  Cu.evalInSandbox("this.__name = '" + aName + "'", sandbox);
+  return sandbox;
+}
new file mode 100644
--- /dev/null
+++ b/js/ductwork/debugger/tests/test_nativewrappers.js
@@ -0,0 +1,29 @@
+function run_test()
+{
+  Components.utils.import("resource://gre/modules/jsdebugger.jsm");
+  var g = testGlobal("test1");
+
+  var dbg = new Debugger();
+  dbg.addDebuggee(g);
+  dbg.onDebuggerStatement = function(aFrame) {
+    let args = aFrame["arguments"];
+    try {
+      args[0];
+      do_check_true(true);
+    } catch(ex) {
+      do_check_true(false);
+    }
+  };
+
+  g.eval("function stopMe(arg) {debugger;}");
+
+  g2 = testGlobal("test2");
+  g2.g = g;
+  g2.eval("(" + function createBadEvent() {
+    let parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
+    let doc = parser.parseFromString("<foo></foo>", "text/xml");
+    g.stopMe(doc.createEvent("MouseEvent"));
+  } + ")()");
+
+  dbg.enabled = false;
+}
new file mode 100644
--- /dev/null
+++ b/js/ductwork/debugger/tests/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head = head_dbg.js
+tail =
+
+[test_nativewrappers.js]
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -119,17 +119,16 @@ CPPSRCS		= \
 		jsgc.cpp \
 		jsgcmark.cpp \
 		jsgcchunk.cpp \
 		jsgcstats.cpp \
 		jscrashreport.cpp \
 		jshash.cpp \
 		jsinfer.cpp \
 		jsinterp.cpp \
-		jsinvoke.cpp \
 		jsiter.cpp \
 		jslock.cpp \
 		jslog2.cpp \
 		jsmath.cpp \
 		jsnativestack.cpp \
 		jsnum.cpp \
 		jsobj.cpp \
 		json.cpp \
--- a/js/src/gnuplot/gcTimer.gnu
+++ b/js/src/gnuplot/gcTimer.gnu
@@ -15,9 +15,10 @@ set style data linespoints
 plot 'gcTimer.dat' using 2 title columnheader(2), \
 '' u 3 title columnheader(3) with points, \
 '' u 4 title columnheader(4), \
 '' u 5 title columnheader(5), \
 '' u 6 title columnheader(6) with points, \
 '' u 7 title columnheader(7) with points, \
 '' u 8 title columnheader(8) with points, \
 '' u 9 title columnheader(9) with points, \
-'' u 10 title columnheader(10) with points
+'' u 10 title columnheader(10) with points, \
+'' u 11 title columnheader(11) with points
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug683470.js
@@ -0,0 +1,15 @@
+// |jit-test| debug
+
+f = (function() {
+  function b() {
+    "use strict";
+    Object.defineProperty(this, "x", ({}));
+  }
+  for each(let d in [0, 0]) {
+    try {
+      b(d);
+    } catch (e) {}
+  }
+})
+trap(f, 54, undefined);
+f()
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -303,28 +303,28 @@ ScriptAnalysis::analyzeBytecode(JSContex
      * Populate arg and local slots which can escape and be accessed in ways
      * other than through ARG* and LOCAL* opcodes (though arguments can still
      * be indirectly read but not written through 'arguments' properties).
      * All escaping locals are treated as having possible use-before-defs.
      */
 
     PodZero(escapedSlots, numSlots);
 
-    if (script->usesEval || script->usesArguments || script->compartment->debugMode()) {
+    if (script->usesEval || script->usesArguments || script->compartment()->debugMode()) {
         for (unsigned i = 0; i < nargs; i++)
             escapedSlots[ArgSlot(i)] = true;
     } else {
         for (unsigned i = 0; i < script->nClosedArgs; i++) {
             unsigned arg = script->getClosedArg(i);
             JS_ASSERT(arg < nargs);
             escapedSlots[ArgSlot(arg)] = true;
         }
     }
 
-    if (script->usesEval || script->compartment->debugMode()) {
+    if (script->usesEval || script->compartment()->debugMode()) {
         for (unsigned i = 0; i < script->nfixed; i++) {
             escapedSlots[LocalSlot(script, i)] = true;
             setLocal(i, LOCAL_USE_BEFORE_DEF);
         }
     } else {
         for (uint32 i = 0; i < script->nClosedVars; i++) {
             unsigned local = script->getClosedVar(i);
             escapedSlots[LocalSlot(script, local)] = true;
@@ -607,17 +607,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
              * Note that there is no problem with code which is skipped by a thrown
              * exception but is not caught by a later handler in the same function:
              * no more code will execute, and it does not matter what is defined.
              */
             isInlineable = canTrackVars = false;
             JSTryNote *tn = script->trynotes()->vector;
             JSTryNote *tnlimit = tn + script->trynotes()->length;
             for (; tn < tnlimit; tn++) {
-                unsigned startOffset = script->main - script->code + tn->start;
+                unsigned startOffset = script->mainOffset + tn->start;
                 if (startOffset == offset + 1) {
                     unsigned catchOffset = startOffset + tn->length;
 
                     /* This will overestimate try block code, for multiple catch/finally. */
                     if (catchOffset > forwardCatch)
                         forwardCatch = catchOffset;
 
                     if (tn->kind != JSTRY_ITER) {
@@ -889,17 +889,17 @@ ScriptAnalysis::analyzeLifetimes(JSConte
         if (loop && code->jumpTarget && offset != loop->entry && offset > loop->lastBlock)
             loop->lastBlock = offset;
 
         if (code->exceptionEntry) {
             DebugOnly<bool> found = false;
             JSTryNote *tn = script->trynotes()->vector;
             JSTryNote *tnlimit = tn + script->trynotes()->length;
             for (; tn < tnlimit; tn++) {
-                unsigned startOffset = script->main - script->code + tn->start;
+                unsigned startOffset = script->mainOffset + tn->start;
                 if (startOffset + tn->length == offset) {
                     /*
                      * Extend all live variables at exception entry to the start of
                      * the try block.
                      */
                     for (unsigned i = 0; i < numSlots; i++) {
                         if (lifetimes[i].lifetime)
                             ensureVariable(lifetimes[i], startOffset - 1);
@@ -1669,17 +1669,17 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
             }
             break;
           }
 
           case JSOP_TRY: { 
             JSTryNote *tn = script->trynotes()->vector;
             JSTryNote *tnlimit = tn + script->trynotes()->length;
             for (; tn < tnlimit; tn++) {
-                unsigned startOffset = script->main - script->code + tn->start;
+                unsigned startOffset = script->mainOffset + tn->start;
                 if (startOffset == offset + 1) {
                     unsigned catchOffset = startOffset + tn->length;
 
                     if (tn->kind != JSTRY_ITER)
                         checkBranchTarget(cx, catchOffset, branchTargets, values, stackDepth);
                 }
             }
             break;
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -947,25 +947,25 @@ class ScriptAnalysis
      * True if there are any LOCAL opcodes aliasing values on the stack (above
      * script->nfixed).
      */
     bool localsAliasStack() { return localsAliasStack_; }
 
     /* Accessors for bytecode information. */
 
     Bytecode& getCode(uint32 offset) {
-        JS_ASSERT(script->compartment->activeAnalysis);
+        JS_ASSERT(script->compartment()->activeAnalysis);
         JS_ASSERT(offset < script->length);
         JS_ASSERT(codeArray[offset]);
         return *codeArray[offset];
     }
     Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script->code); }
 
     Bytecode* maybeCode(uint32 offset) {
-        JS_ASSERT(script->compartment->activeAnalysis);
+        JS_ASSERT(script->compartment()->activeAnalysis);
         JS_ASSERT(offset < script->length);
         return codeArray[offset];
     }
     Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script->code); }
 
     bool jumpTarget(uint32 offset) {
         JS_ASSERT(offset < script->length);
         return codeArray[offset] && codeArray[offset]->jumpTarget;
@@ -1143,32 +1143,32 @@ class ScriptAnalysis
     /*
      * Escaping slots include all slots that can be accessed in ways other than
      * through the corresponding LOCAL/ARG opcode. This includes all closed
      * slots in the script, all slots in scripts which use eval or are in debug
      * mode, and slots which are aliased by NAME or similar opcodes in the
      * containing script (which does not imply the variable is closed).
      */
     bool slotEscapes(uint32 slot) {
-        JS_ASSERT(script->compartment->activeAnalysis);
+        JS_ASSERT(script->compartment()->activeAnalysis);
         if (slot >= numSlots)
             return true;
         return escapedSlots[slot];
     }
 
     /*
      * Whether we distinguish different writes of this variable while doing
      * SSA analysis. Escaping locals can be written in other scripts, and the
      * presence of NAME opcodes, switch or try blocks keeps us from tracking
      * variable values at each point.
      */
     bool trackSlot(uint32 slot) { return !slotEscapes(slot) && canTrackVars; }
 
     const LifetimeVariable & liveness(uint32 slot) {
-        JS_ASSERT(script->compartment->activeAnalysis);
+        JS_ASSERT(script->compartment()->activeAnalysis);
         JS_ASSERT(!slotEscapes(slot));
         return lifetimes[slot];
     }
 
     void printSSA(JSContext *cx);
     void printTypes(JSContext *cx);
 
     void clearAllocations();
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1206,17 +1206,17 @@ JSClass js_dummy_class = {
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
 {
     CHECK_REQUEST(cx);
 
     JSObject *scriptObject = target->u.object;
     if (!scriptObject) {
-        SwitchToCompartment sc(cx, target->compartment);
+        SwitchToCompartment sc(cx, target->compartment());
         scriptObject = JS_NewGlobalObject(cx, &js_dummy_class);
         if (!scriptObject)
             return NULL;
     }
     return JS_EnterCrossCompartmentCall(cx, scriptObject);
 }
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
@@ -1256,17 +1256,17 @@ JSAutoEnterCompartment::enterAndIgnoreEr
 }
 
 namespace JS {
 
 bool
 AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
 {
     JS_ASSERT(!call);
-    if (cx->compartment == target->compartment) {
+    if (cx->compartment == target->compartment()) {
         call = reinterpret_cast<JSCrossCompartmentCall*>(1);
         return true;
     }
     call = JS_EnterCrossCompartmentCallScript(cx, target);
     return call != NULL;
 }
 
 bool
@@ -2190,29 +2190,32 @@ JS_TraceRuntime(JSTracer *trc)
 {
     TraceRuntime(trc);
 }
 
 JS_PUBLIC_API(void)
 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
 {
     JS_ASSERT(thing);
-    MarkKind(trc, thing, kind);
+    JS_ASSERT(kind <= JSTRACE_LAST);
+    MarkKind(trc, thing, JSGCTraceKind(kind));
 }
 
 #ifdef DEBUG
 
 #ifdef HAVE_XPCONNECT
 #include "dump_xpc.h"
 #endif
 
 JS_PUBLIC_API(void)
-JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
+JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kindIndex,
                        JSBool details)
 {
+    JS_ASSERT(kindIndex <= JSTRACE_LAST);
+    JSGCTraceKind kind = JSGCTraceKind(kindIndex);
     const char *name;
     size_t n;
 
     if (bufsize == 0)
         return;
 
     switch (kind) {
       case JSTRACE_OBJECT:
@@ -2235,29 +2238,33 @@ JS_PrintTraceThingInfo(char *buf, size_t
       }
 
       case JSTRACE_STRING:
         name = ((JSString *)thing)->isDependent()
                ? "substring"
                : "string";
         break;
 
+      case JSTRACE_SCRIPT:
+        name = "script";
+        break;
+
       case JSTRACE_SHAPE:
         name = "shape";
         break;
 
+      case JSTRACE_TYPE_OBJECT:
+        name = "type_object";
+        break;
+
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_XML:
         name = "xml";
         break;
 #endif
-      default:
-        JS_ASSERT(0);
-        return;
-        break;
     }
 
     n = strlen(name);
     if (n > bufsize - 1)
         n = bufsize - 1;
     memcpy(buf, name, n + 1);
     buf += n;
     bufsize -= n;
@@ -2294,35 +2301,37 @@ JS_PrintTraceThingInfo(char *buf, size_t
             JSString *str = (JSString *)thing;
             if (str->isLinear())
                 PutEscapedString(buf, bufsize, &str->asLinear(), 0);
             else
                 JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
             break;
           }
 
-          case JSTRACE_SHAPE:
+          case JSTRACE_SCRIPT:
           {
-            JS_snprintf(buf, bufsize, "<shape>");
+            JSScript *script = static_cast<JSScript *>(thing);
+            JS_snprintf(buf, bufsize, "%s:%u", script->filename, unsigned(script->lineno));
             break;
           }
 
+          case JSTRACE_SHAPE:
+          case JSTRACE_TYPE_OBJECT:
+            break;
+
 #if JS_HAS_XML_SUPPORT
           case JSTRACE_XML:
           {
             extern const char *js_xml_class_str[];
             JSXML *xml = (JSXML *)thing;
 
             JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
             break;
           }
 #endif
-          default:
-            JS_ASSERT(0);
-            break;
         }
     }
     buf[bufsize - 1] = '\0';
 }
 
 typedef struct JSHeapDumpNode JSHeapDumpNode;
 
 struct JSHeapDumpNode {
@@ -3201,17 +3210,16 @@ LookupResult(JSContext *cx, JSObject *ob
         vp->setUndefined();
         return JS_TRUE;
     }
 
     if (obj2->isNative()) {
         Shape *shape = (Shape *) prop;
 
         if (shape->isMethod()) {
-            AutoShapeRooter root(cx, shape);
             vp->setObject(shape->methodObject());
             return !!obj2->methodReadBarrier(cx, *shape, vp);
         }
 
         /* Peek at the native property's slot value, without doing a Get. */
         if (obj2->containsSlot(shape->slot)) {
             *vp = obj2->nativeGetSlot(shape->slot);
             return true;
@@ -4738,17 +4746,16 @@ CompileUCFunctionForPrincipalsCommon(JSC
         funAtom = NULL;
     } else {
         funAtom = js_Atomize(cx, name, strlen(name));
         if (!funAtom)
             return NULL;
     }
 
     Bindings bindings(cx);
-    AutoBindingsRooter root(cx, bindings);
     for (uintN i = 0; i < nargs; i++) {
         uint16 dummy;
         JSAtom *argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]));
         if (!argAtom || !bindings.addArgument(cx, argAtom, &dummy))
             return NULL;
     }
 
     JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
@@ -4837,18 +4844,18 @@ JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     JSPrinter *jp;
     JSString *str;
 
     CHECK_REQUEST(cx);
 #ifdef DEBUG
-    if (cx->compartment != script->compartment)
-        CompartmentChecker::fail(cx->compartment, script->compartment);
+    if (cx->compartment != script->compartment())
+        CompartmentChecker::fail(cx->compartment, script->compartment());
 #endif
     jp = js_NewPrinter(cx, name, NULL,
                        indent & ~JS_DONT_PRETTY_PRINT,
                        !(indent & JS_DONT_PRETTY_PRINT),
                        false, false);
     if (!jp)
         return NULL;
     if (js_DecompileScript(jp, script))
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1596,26 +1596,35 @@ extern JS_PUBLIC_API(void)
 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
 
 /*
  * JS_CallTracer API and related macros for implementors of JSTraceOp, to
  * enumerate all references to traceable things reachable via a property or
  * other strong ref identified for debugging purposes by name or index or
  * a naming callback.
  *
- * By definition references to traceable things include non-null pointers
- * to JSObject, JSString and jsdouble and corresponding jsvals.
- *
  * See the JSTraceOp typedef in jspubtd.h.
  */
 
-/* Trace kinds to pass to JS_Tracing. */
-#define JSTRACE_OBJECT  0
-#define JSTRACE_STRING  1
-#define JSTRACE_SHAPE   2
+typedef enum {
+    JSTRACE_OBJECT,
+    JSTRACE_STRING,
+    JSTRACE_SCRIPT,
+
+    /*
+     * Trace kinds internal to the engine. JSTraceCallback implementation can
+     * only call JS_TraceChildren on them.
+     */ 
+#if JS_HAS_XML_SUPPORT
+    JSTRACE_XML,
+#endif
+    JSTRACE_SHAPE,
+    JSTRACE_TYPE_OBJECT,
+    JSTRACE_LAST = JSTRACE_TYPE_OBJECT
+} JSGCTraceKind;
 
 /*
  * Use the following macros to check if a particular jsval is a traceable
  * thing and to extract the thing and its kind to pass to JS_CallTracer.
  */
 static JS_ALWAYS_INLINE JSBool
 JSVAL_IS_TRACEABLE(jsval v)
 {
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -640,38 +640,35 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
 #define TEMP_SIZE_LIMIT_LOG2    (TEMP_SIZE_START_LOG2 + NUM_TEMP_FREELISTS)
 
 #define TEMP_SIZE_START         JS_BIT(TEMP_SIZE_START_LOG2)
 #define TEMP_SIZE_LIMIT         JS_BIT(TEMP_SIZE_LIMIT_LOG2)
 
 JS_STATIC_ASSERT(TEMP_SIZE_START >= sizeof(JSHashTable));
 
 void
-js_InitAtomMap(JSContext *cx, JSAtomMap *map, AtomIndexMap *indices)
+js_InitAtomMap(JSContext *cx, AtomIndexMap *indices, JSAtom **atoms)
 {
-    /* Map length must already be initialized. */
-    JS_ASSERT(indices->count() == map->length);
-
     if (indices->isMap()) {
         typedef AtomIndexMap::WordMap WordMap;
         const WordMap &wm = indices->asMap();
         for (WordMap::Range r = wm.all(); !r.empty(); r.popFront()) {
             JSAtom *atom = r.front().key;
             jsatomid index = r.front().value;
-            JS_ASSERT(index < map->length);
-            map->vector[index] = atom;
+            JS_ASSERT(index < indices->count());
+            atoms[index] = atom;
         }
     } else {
         for (const AtomIndexMap::InlineElem *it = indices->asInline(), *end = indices->inlineEnd();
              it != end; ++it) {
             JSAtom *atom = it->key;
             if (!atom)
                 continue;
-            JS_ASSERT(it->value < map->length);
-            map->vector[it->value] = atom;
+            JS_ASSERT(it->value < indices->count());
+            atoms[it->value] = atom;
         }
     }
 }
 
 namespace js {
 
 bool
 IndexToIdSlow(JSContext *cx, uint32 index, jsid *idp)
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -157,21 +157,16 @@ struct DefaultHasher<jsid>
 
 /*
  * Return a printable, lossless char[] representation of a string-type atom.
  * The lifetime of the result matches the lifetime of bytes.
  */
 extern const char *
 js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes);
 
-struct JSAtomMap {
-    JSAtom **vector;    /* array of ptrs to indexed atoms */
-    uint32 length;      /* count of (to-be-)indexed atoms */
-};
-
 namespace js {
 
 typedef TaggedPointerEntry<JSAtom> AtomStateEntry;
 
 struct AtomHasher
 {
     struct Lookup
     {
@@ -537,11 +532,11 @@ js_InternNonIntElementId(JSContext *cx, 
                          jsid *idp, js::Value *vp);
 
 /*
  * 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
-js_InitAtomMap(JSContext *cx, JSAtomMap *map, js::AtomIndexMap *indices);
+js_InitAtomMap(JSContext *cx, js::AtomIndexMap *indices, JSAtom **atoms);
 
 #endif /* jsatom_h___ */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -109,16 +109,19 @@ ThreadData::ThreadData()
     maxCodeCacheBytes(DEFAULT_JIT_CACHE_SIZE),
 #endif
     waiveGCQuota(false),
     dtoaState(NULL),
     nativeStackBase(GetNativeStackBase()),
     pendingProxyOperation(NULL),
     interpreterFrames(NULL)
 {
+#ifdef DEBUG
+    noGCOrAllocationCheck = 0;
+#endif
 }
 
 ThreadData::~ThreadData()
 {
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
 }
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -204,16 +204,20 @@ struct ThreadData {
     /* Base address of the native stack for the current thread. */
     jsuword             *nativeStackBase;
 
     /* List of currently pending operations on proxies. */
     PendingProxyOperation *pendingProxyOperation;
 
     ConservativeGCThreadData conservativeGC;
 
+#ifdef DEBUG
+    size_t              noGCOrAllocationCheck;
+#endif
+
     ThreadData();
     ~ThreadData();
 
     bool init();
 
     void mark(JSTracer *trc) {
         stackSpace.mark(trc);
     }
@@ -1390,17 +1394,17 @@ class AutoCheckRequestDepth {
 # define CHECK_REQUEST_THREAD(cx)   ((void) 0)
 #endif
 
 static inline JSAtom **
 FrameAtomBase(JSContext *cx, js::StackFrame *fp)
 {
     return fp->hasImacropc()
            ? cx->runtime->atomState.commonAtomsStart()
-           : fp->script()->atomMap.vector;
+           : fp->script()->atoms;
 }
 
 struct AutoResolving {
   public:
     enum Kind {
         LOOKUP,
         WATCH
     };
@@ -1473,35 +1477,32 @@ class AutoGCRooter {
      * memory corruption.
      */
     ptrdiff_t tag;
 
     JSContext * const context;
 
     enum {
         JSVAL =        -1, /* js::AutoValueRooter */
-        SHAPE =        -2, /* js::AutoShapeRooter */
+        VALARRAY =     -2, /* js::AutoValueArrayRooter */
         PARSER =       -3, /* js::Parser */
-        SCRIPT =       -4, /* js::AutoScriptRooter */
+        SHAPEVECTOR =  -4, /* js::AutoShapeVector */
         ENUMERATOR =   -5, /* js::AutoEnumStateRooter */
         IDARRAY =      -6, /* js::AutoIdArray */
         DESCRIPTORS =  -7, /* js::AutoPropDescArrayRooter */
         NAMESPACES =   -8, /* js::AutoNamespaceArray */
         XML =          -9, /* js::AutoXMLRooter */
         OBJECT =      -10, /* js::AutoObjectRooter */
         ID =          -11, /* js::AutoIdRooter */
         VALVECTOR =   -12, /* js::AutoValueVector */
         DESCRIPTOR =  -13, /* js::AutoPropertyDescriptorRooter */
         STRING =      -14, /* js::AutoStringRooter */
         IDVECTOR =    -15, /* js::AutoIdVector */
-        BINDINGS =    -16, /* js::Bindings */
-        SHAPEVECTOR = -17, /* js::AutoShapeVector */
-        OBJVECTOR =   -18, /* js::AutoObjectVector */
-        TYPE =        -19, /* js::types::AutoTypeRooter */
-        VALARRAY =    -20  /* js::AutoValueArrayRooter */
+        OBJVECTOR =   -16, /* js::AutoObjectVector */
+        TYPE =        -17  /* js::types::AutoTypeRooter */
     };
 
     private:
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida);
     void operator=(AutoGCRooter &ida);
 };
 
@@ -1662,53 +1663,16 @@ class AutoArrayRooter : private AutoGCRo
     Value *array;
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
   private:
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-class AutoShapeRooter : private AutoGCRooter {
-  public:
-    AutoShapeRooter(JSContext *cx, const js::Shape *shape
-                    JS_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, SHAPE), shape(shape)
-    {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    friend void AutoGCRooter::trace(JSTracer *trc);
-    friend void MarkRuntime(JSTracer *trc);
-
-  private:
-    const js::Shape * const shape;
-    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-class AutoScriptRooter : private AutoGCRooter {
-  public:
-    AutoScriptRooter(JSContext *cx, JSScript *script
-                     JS_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, SCRIPT), script(script)
-    {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    void setScript(JSScript *script) {
-        this->script = script;
-    }
-
-    friend void AutoGCRooter::trace(JSTracer *trc);
-
-  private:
-    JSScript *script;
-    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 class AutoIdRooter : private AutoGCRooter
 {
   public:
     explicit AutoIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0)
                           JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, ID), id_(id)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
@@ -1823,32 +1787,16 @@ class AutoXMLRooter : private AutoGCRoot
     friend void MarkRuntime(JSTracer *trc);
 
   private:
     JSXML * const xml;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 #endif /* JS_HAS_XML_SUPPORT */
 
-class AutoBindingsRooter : private AutoGCRooter {
-  public:
-    AutoBindingsRooter(JSContext *cx, Bindings &bindings
-                       JS_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, BINDINGS), bindings(bindings)
-    {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    friend void AutoGCRooter::trace(JSTracer *trc);
-
-  private:
-    Bindings &bindings;
-    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 class AutoLockGC {
   public:
     explicit AutoLockGC(JSRuntime *rt
                         JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : rt(rt)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
         JS_LOCK_GC(rt);
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -205,17 +205,17 @@ class CompartmentChecker
                 if (JSID_IS_OBJECT(ida->vector[i]))
                     check(ida->vector[i]);
             }
         }
     }
 
     void check(JSScript *script) {
         if (script) {
-            check(script->compartment);
+            check(script->compartment());
             if (script->u.object)
                 check(script->u.object);
         }
     }
 
     void check(StackFrame *fp) {
         check(&fp->scopeChain());
     }
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -95,19 +95,17 @@ JSCompartment::JSCompartment(JSRuntime *
     emptyWithShape(NULL),
     initialRegExpShape(NULL),
     initialStringShape(NULL),
     debugModeBits(rt->debugMode ? DebugFromC : 0),
     mathCache(NULL),
     breakpointSites(rt),
     watchpointMap(NULL)
 {
-    JS_INIT_CLIST(&scripts);
-
-    PodArrayZero(scriptsToGC);
+    PodArrayZero(evalCache);
 }
 
 JSCompartment::~JSCompartment()
 {
 #if ENABLE_YARR_JIT
     Foreground::delete_(regExpAllocator);
 #endif
 
@@ -118,18 +116,18 @@ JSCompartment::~JSCompartment()
 #ifdef JS_TRACER
     Foreground::delete_(traceMonitor_);
 #endif
 
     Foreground::delete_(mathCache);
     Foreground::delete_(watchpointMap);
 
 #ifdef DEBUG
-    for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
-        JS_ASSERT(!scriptsToGC[i]);
+    for (size_t i = 0; i != JS_ARRAY_LENGTH(evalCache); ++i)
+        JS_ASSERT(!evalCache[i]);
 #endif
 }
 
 bool
 JSCompartment::init(JSContext *cx)
 {
     for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
         arenas[i].init();
@@ -487,61 +485,43 @@ void
 JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
 {
     JS_ASSERT(trc->context->runtime->gcCurrentCompartment);
 
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront())
         MarkValue(trc, e.front().key, "cross-compartment wrapper");
 }
 
-struct MarkSingletonObjectOp
-{
-    JSTracer *trc;
-    MarkSingletonObjectOp(JSTracer *trc) : trc(trc) {}
-    void operator()(Cell *cell) {
-        JSObject *object = static_cast<JSObject *>(cell);
-        if (!object->isNewborn() && object->hasSingletonType())
-            MarkObject(trc, *object, "mark_types_singleton");
-    }
-};
-
-struct MarkTypeObjectOp
-{
-    JSTracer *trc;
-    MarkTypeObjectOp(JSTracer *trc) : trc(trc) {}
-    void operator()(Cell *cell) {
-        types::TypeObject *object = static_cast<types::TypeObject *>(cell);
-        MarkTypeObject(trc, object, "mark_types_scan");
-    }
-};
-
 void
 JSCompartment::markTypes(JSTracer *trc)
 {
     /*
      * Mark all scripts, type objects and singleton JS objects in the
      * compartment. These can be referred to directly by type sets, which we
      * cannot modify while code which depends on these type sets is active.
      */
     JS_ASSERT(activeAnalysis);
 
-    for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
-        JSScript *script = reinterpret_cast<JSScript *>(cursor);
-        js_TraceScript(trc, script, NULL);
+    for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
+        MarkScript(trc, script, "mark_types_script");
     }
 
-    MarkSingletonObjectOp objectCellOp(trc);
     for (unsigned thingKind = FINALIZE_OBJECT0;
          thingKind <= FINALIZE_FUNCTION_AND_OBJECT_LAST;
          thingKind++) {
-        gc::ForEachArenaAndCell(this, (FinalizeKind) thingKind, EmptyArenaOp, objectCellOp);
+        for (CellIterUnderGC i(this, FinalizeKind(thingKind)); !i.done(); i.next()) {
+            JSObject *object = i.get<JSObject>();
+            if (!object->isNewborn() && object->hasSingletonType())
+                MarkObject(trc, *object, "mark_types_singleton");
+        }
     }
 
-    MarkTypeObjectOp typeCellOp(trc);
-    gc::ForEachArenaAndCell(this, FINALIZE_TYPE_OBJECT, EmptyArenaOp, typeCellOp);
+    for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next())
+        MarkTypeObject(trc, i.get<types::TypeObject>(), "mark_types_scan");
 }
 
 void
 JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
 {
     /* Remove dead wrappers from the table. */
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
         JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) &&
@@ -579,18 +559,18 @@ JSCompartment::sweep(JSContext *cx, uint
         traceMonitor()->sweep(cx);
 #endif
 
 # if defined JS_METHODJIT && defined JS_POLYIC
     /*
      * Purge all PICs in the compartment. These can reference type data and
      * need to know which types are pending collection.
      */
-    for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
-        JSScript *script = reinterpret_cast<JSScript *>(cursor);
+    for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
         if (script->hasJITCode())
             mjit::ic::PurgePICs(cx, script);
     }
 # endif
 
     bool discardScripts = !active && (releaseInterval != 0 || hasDebugModeCodeToDrop);
 
 #if defined JS_METHODJIT && defined JS_MONOIC
@@ -601,18 +581,18 @@ JSCompartment::sweep(JSContext *cx, uint
      * Initialize counter so that the first pool will be destroyed, and eventually drive
      * the amount of JIT code in never-used compartments to zero. Don't discard anything
      * for compartments which currently have active stack frames.
      */
     uint32 counter = 1;
     if (discardScripts)
         hasDebugModeCodeToDrop = false;
 
-    for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
-        JSScript *script = reinterpret_cast<JSScript *>(cursor);
+    for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
         if (script->hasJITCode()) {
             mjit::ic::SweepCallICs(cx, script, discardScripts);
             if (discardScripts) {
                 ScriptTryDestroyCode(cx, script, true, releaseInterval, counter);
                 ScriptTryDestroyCode(cx, script, false, releaseInterval, counter);
             }
         }
     }
@@ -631,19 +611,18 @@ JSCompartment::sweep(JSContext *cx, uint
          * Sweep analysis information and everything depending on it from the
          * compartment, including all remaining mjit code if inference is
          * enabled in the compartment.
          */
         if (types.inferenceEnabled) {
 #ifdef JS_METHODJIT
             mjit::ClearAllFrames(this);
 #endif
-
-            for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
-                JSScript *script = reinterpret_cast<JSScript *>(cursor);
+            for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
+                JSScript *script = i.get<JSScript>();
                 if (script->types) {
                     types::TypeScript::Sweep(cx, script);
 
                     /*
                      * On each 1/8 lifetime, release observed types for all scripts.
                      * This is always safe to do when there are no frames for the
                      * compartment on the stack.
                      */
@@ -652,67 +631,73 @@ JSCompartment::sweep(JSContext *cx, uint
                         script->types = NULL;
                     }
                 }
             }
         }
 
         types.sweep(cx);
 
-        for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
-            JSScript *script = reinterpret_cast<JSScript *>(cursor);
+        for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
+            JSScript *script = i.get<JSScript>();
             if (script->types)
                 script->types->analysis = NULL;
         }
 
         /* Reset the analysis pool, releasing all analysis and intermediate type data. */
         JS_FinishArenaPool(&oldPool);
-
-        /*
-         * Destroy eval'ed scripts, now that any type inference information referring
-         * to eval scripts has been removed.
-         */
-        js_DestroyScriptsToGC(cx, this);
     }
 
     active = false;
 }
 
 void
 JSCompartment::purge(JSContext *cx)
 {
     freeLists.purge();
     dtoaCache.purge();
 
+    /*
+     * Clear the hash and reset all evalHashLink to null before the GC. This
+     * way MarkChildren(trc, JSScript *) can assume that JSScript::u.object is
+     * not null when we have script owned by an object and not from the eval
+     * cache.
+     */
+    for (size_t i = 0; i != JS_ARRAY_LENGTH(evalCache); ++i) {
+        for (JSScript **listHeadp = &evalCache[i]; *listHeadp; ) {
+            JSScript *script = *listHeadp;
+            JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
+            *listHeadp = NULL;
+            listHeadp = &script->u.evalHashLink;
+        }
+    }
+
     nativeIterCache.purge();
     toSourceCache.destroyIfConstructed();
 
 #ifdef JS_TRACER
     /*
      * If we are about to regenerate shapes, we have to flush the JIT cache,
      * which will eventually abort any current recording.
      */
     if (cx->runtime->gcRegenShapes)
         if (hasTraceMonitor())
             traceMonitor()->needFlush = JS_TRUE;
 #endif
 
-#ifdef JS_METHODJIT
-    for (JSScript *script = (JSScript *)scripts.next;
-         &script->links != &scripts;
-         script = (JSScript *)script->links.next) {
-        if (script->hasJITCode()) {
-# if defined JS_MONOIC
-            /*
-             * MICs do not refer to data which can be GC'ed and do not generate stubs
-             * which might need to be discarded, but are sensitive to shape regeneration.
-             */
-            if (cx->runtime->gcRegenShapes)
+#if defined JS_METHODJIT && defined JS_MONOIC
+    /*
+     * MICs do not refer to data which can be GC'ed and do not generate stubs
+     * which might need to be discarded, but are sensitive to shape regeneration.
+     */
+    if (cx->runtime->gcRegenShapes) {
+        for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
+            JSScript *script = i.get<JSScript>();
+            if (script->hasJITCode())
                 mjit::ic::PurgeMICs(cx, script);
-# endif
         }
     }
 #endif
 }
 
 MathCache *
 JSCompartment::allocMathCache(JSContext *cx)
 {
@@ -756,17 +741,17 @@ JSCompartment::incBackEdgeCount(jsbyteco
     return 1;  /* oom not reported by backEdgeTable, so ignore. */
 }
 
 bool
 JSCompartment::hasScriptsOnStack(JSContext *cx)
 {
     for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) {
         JSScript *script = i.fp()->maybeScript();
-        if (script && script->compartment == this)
+        if (script && script->compartment() == this)
             return true;
     }
     return false;
 }
 
 bool
 JSCompartment::setDebugModeFromC(JSContext *cx, bool b)
 {
@@ -813,22 +798,22 @@ JSCompartment::updateForDebugMode(JSCont
 
     if (enabled) {
         JS_ASSERT(!hasScriptsOnStack(cx));
     } else if (hasScriptsOnStack(cx)) {
         hasDebugModeCodeToDrop = true;
         return;
     }
 
-    // Discard JIT code for any scripts that change debugMode. This assumes
-    // that 'comp' is in the same thread as 'cx'.
-    for (JSScript *script = (JSScript *) scripts.next;
-         &script->links != &scripts;
-         script = (JSScript *) script->links.next)
-    {
+    /*
+     * Discard JIT code for any scripts that change debugMode. This assumes
+     * that 'comp' is in the same thread as 'cx'.
+     */
+    for (gc::CellIter i(cx, this, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
         if (script->debugMode != enabled) {
             mjit::ReleaseScriptCode(cx, script);
             script->debugMode = enabled;
         }
     }
     hasDebugModeCodeToDrop = false;
 #endif
 }
@@ -900,17 +885,17 @@ JSCompartment::getOrCreateBreakpointSite
 
     return site;
 }
 
 void
 JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script,
                                   JSObject *handler)
 {
-    JS_ASSERT_IF(script, script->compartment == this);
+    JS_ASSERT_IF(script, script->compartment() == this);
 
     for (BreakpointSiteMap::Enum e(breakpointSites); !e.empty(); e.popFront()) {
         BreakpointSite *site = e.front().value;
         if (!script || site->script == script) {
             Breakpoint *nextbp;
             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
                 nextbp = bp->nextInSite();
                 if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -293,20 +293,21 @@ struct TraceMonitor {
 namespace mjit {
 class JaegerCompartment;
 }
 }
 
 /* Defined in jsapi.cpp */
 extern JSClass js_dummy_class;
 
-/* Number of potentially reusable scriptsToGC to search for the eval cache. */
 #ifndef JS_EVAL_CACHE_SHIFT
 # define JS_EVAL_CACHE_SHIFT        6
 #endif
+
+/* Number of buckets in the hash of eval scripts. */
 #define JS_EVAL_CACHE_SIZE          JS_BIT(JS_EVAL_CACHE_SHIFT)
 
 namespace js {
 
 class NativeIterCache {
     static const size_t SIZE = size_t(1) << 8;
     
     /* Cached native iterators. */
@@ -421,17 +422,17 @@ struct JS_FRIEND_API(JSCompartment) {
      * Trace-tree JIT recorder/interpreter state.  It's created lazily because
      * many compartments don't end up needing it.
      */
     js::TraceMonitor             *traceMonitor_;
 #endif
 
   public:
     /* Hashed lists of scripts created by eval to garbage-collect. */
-    JSScript                     *scriptsToGC[JS_EVAL_CACHE_SIZE];
+    JSScript                     *evalCache[JS_EVAL_CACHE_SIZE];
 
     void                         *data;
     bool                         active;  // GC flag, whether there are active frames
     bool                         hasDebugModeCodeToDrop;
     js::WrapperMap               crossCompartmentWrappers;
 
 #ifdef JS_METHODJIT
   private:
@@ -502,18 +503,16 @@ struct JS_FRIEND_API(JSCompartment) {
     const js::Shape              *initialStringShape;
 
   private:
     enum { DebugFromC = 1, DebugFromJS = 2 };
 
     uintN                        debugModeBits;  // see debugMode() below
 
   public:
-    JSCList                      scripts;        // scripts in this compartment
-
     js::NativeIterCache          nativeIterCache;
 
     typedef js::Maybe<js::ToSourceCache> LazyToSourceCache;
     LazyToSourceCache            toSourceCache;
 
     js::ScriptFilenameTable      scriptFilenameTable;
 
     JSCompartment(JSRuntime *rt);
@@ -535,16 +534,17 @@ struct JS_FRIEND_API(JSCompartment) {
 
     void markTypes(JSTracer *trc);
     void sweep(JSContext *cx, uint32 releaseInterval);
     void purge(JSContext *cx);
     void finishArenaLists();
     void finalizeObjectArenaLists(JSContext *cx);
     void finalizeStringArenaLists(JSContext *cx);
     void finalizeShapeArenaLists(JSContext *cx);
+    void finalizeScriptArenaLists(JSContext *cx);
     bool arenaListsAreEmpty();
 
     void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
     void reduceGCTriggerBytes(uint32 amount);
 
     js::DtoaCache dtoaCache;
 
   private:
@@ -628,17 +628,16 @@ struct JS_FRIEND_API(JSCompartment) {
 
   private:
     void sweepBreakpoints(JSContext *cx);
 
   public:
     js::WatchpointMap *watchpointMap;
 };
 
-#define JS_SCRIPTS_TO_GC(cx)    ((cx)->compartment->scriptsToGC)
 #define JS_PROPERTY_TREE(cx)    ((cx)->compartment->propertyTree)
 
 /*
  * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current
  * thread, regardless of whether cx is the context in which that trace is
  * executing. cx must be a context on the current thread.
  */
 static inline bool
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -177,17 +177,17 @@ JS_SetSingleStepMode(JSContext *cx, JSSc
 
     return script->setStepModeFlag(cx, singleStep);
 }
 
 jsbytecode *
 js_UntrapScriptCode(JSContext *cx, JSScript *script)
 {
     jsbytecode *code = script->code;
-    BreakpointSiteMap &sites = script->compartment->breakpointSites;
+    BreakpointSiteMap &sites = script->compartment()->breakpointSites;
     for (BreakpointSiteMap::Range r = sites.all(); !r.empty(); r.popFront()) {
         BreakpointSite *site = r.front().value;
         if (site->script == script && size_t(site->pc - script->code) < script->length) {
             if (code == script->code) {
                 size_t nbytes = script->length * sizeof(jsbytecode);
                 jssrcnote *notes = script->notes();
                 jssrcnote *sn;
                 for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
@@ -207,48 +207,48 @@ js_UntrapScriptCode(JSContext *cx, JSScr
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handler, jsval closure)
 {
     if (!CheckDebugMode(cx))
         return false;
 
-    BreakpointSite *site = script->compartment->getOrCreateBreakpointSite(cx, script, pc, NULL);
+    BreakpointSite *site = script->compartment()->getOrCreateBreakpointSite(cx, script, pc, NULL);
     if (!site)
         return false;
     site->setTrap(cx, handler, Valueify(closure));
     return true;
 }
 
 JS_PUBLIC_API(JSOp)
 JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
-    BreakpointSite *site = script->compartment->getBreakpointSite(pc);
+    BreakpointSite *site = script->compartment()->getBreakpointSite(pc);
     return site ? site->realOpcode : JSOp(*pc);
 }
 
 JS_PUBLIC_API(void)
 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
              JSTrapHandler *handlerp, jsval *closurep)
 {
-    if (BreakpointSite *site = script->compartment->getBreakpointSite(pc)) {
+    if (BreakpointSite *site = script->compartment()->getBreakpointSite(pc)) {
         site->clearTrap(cx, NULL, handlerp, Valueify(closurep));
     } else {
         if (handlerp)
             *handlerp = NULL;
         if (closurep)
             *closurep = JSVAL_VOID;
     }
 }
 
 JS_PUBLIC_API(void)
 JS_ClearScriptTraps(JSContext *cx, JSScript *script)
 {
-    script->compartment->clearTraps(cx, script);
+    script->compartment()->clearTraps(cx, script);
 }
 
 JS_PUBLIC_API(void)
 JS_ClearAllTrapsForCompartment(JSContext *cx)
 {
     cx->compartment->clearTraps(cx, NULL);
 }
 
@@ -1084,19 +1084,19 @@ JS_GetScriptTotalSize(JSContext *cx, JSS
     JSObjectArray *objarray;
     JSPrincipals *principals;
 
     nbytes = sizeof *script;
     if (script->u.object)
         nbytes += JS_GetObjectTotalSize(cx, script->u.object);
 
     nbytes += script->length * sizeof script->code[0];
-    nbytes += script->atomMap.length * sizeof script->atomMap.vector[0];
-    for (size_t i = 0; i < script->atomMap.length; i++)
-        nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
+    nbytes += script->natoms * sizeof script->atoms[0];
+    for (size_t i = 0; i < script->natoms; i++)
+        nbytes += GetAtomTotalSize(cx, script->atoms[i]);
 
     if (script->filename)
         nbytes += strlen(script->filename) + 1;
 
     notes = script->notes();
     for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
         continue;
     nbytes += (sn - notes + 1) * sizeof *sn;
@@ -2173,18 +2173,23 @@ JS_DumpBytecode(JSContext *cx, JSScript 
 
     fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
     js_Disassemble(cx, script, true, &sprinter);
     fputs(sprinter.base, stdout);
     fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename, script->lineno);
 #endif
 }
 
+static void
+DumpBytecodeScriptCallback(JSContext *cx, void *data, void *thing,
+                           JSGCTraceKind traceKind, size_t thingSize)
+{
+    JS_ASSERT(traceKind == JSTRACE_SCRIPT);
+    JS_ASSERT(!data);
+    JSScript *script = static_cast<JSScript *>(thing);
+    JS_DumpBytecode(cx, script);
+}
+
 JS_PUBLIC_API(void)
 JS_DumpCompartmentBytecode(JSContext *cx)
 {
-    for (JSScript *script = (JSScript *) JS_LIST_HEAD(&cx->compartment->scripts);
-         script != (JSScript *) &cx->compartment->scripts;
-         script = (JSScript *) JS_NEXT_LINK((JSCList *)script))
-    {
-        JS_DumpBytecode(cx, script);
-    }
+    IterateCells(cx, cx->compartment, gc::FINALIZE_SCRIPT, NULL, DumpBytecodeScriptCallback);
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -202,17 +202,16 @@ ArgumentsObject::create(JSContext *cx, u
     JS_STATIC_ASSERT(StrictArgumentsObject::RESERVED_SLOTS == 2);
     JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!obj)
         return NULL;
 
     EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx);
     if (!emptyArgumentsShape)
         return NULL;
-    AutoShapeRooter shapeRoot(cx, emptyArgumentsShape);
 
     ArgumentsData *data = (ArgumentsData *)
         cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
     SetValueRangeToUndefined(data->slots, argc);
 
     /* Can't fail from here on, so initialize everything in argsobj. */
@@ -1168,30 +1167,16 @@ call_resolve(JSContext *cx, JSObject *ob
     /* Control flow reaches here only if id was not resolved. */
     return true;
 }
 
 static void
 call_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isCall());
-    if (StackFrame *fp = obj->maybeCallObjStackFrame()) {
-        /*
-         * FIXME: Hide copies of stack values rooted by fp from the Cycle
-         * Collector, which currently lacks a non-stub Unlink implementation
-         * for JS objects (including Call objects), so is unable to collect
-         * cycles involving Call objects whose frames are active without this
-         * hiding hack.
-         */
-        uintN first = JSObject::CALL_RESERVED_SLOTS;
-        uintN count = fp->script()->bindings.countArgsAndVars();
-
-        JS_ASSERT(obj->numSlots() >= first + count);
-        obj->clearSlotRange(first, count);
-    }
 
     MaybeMarkGenerator(trc, obj);
 }
 
 JS_PUBLIC_DATA(Class) js_CallClass = {
     "Call",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
@@ -1641,19 +1626,16 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
     JSScript *script = fun->u.i.script;
     if (!js_XDRScript(xdr, &script))
         return false;
     fun->u.i.script = script;
 
     if (xdr->mode == JSXDR_DECODE) {
         *objp = fun;
         fun->u.i.script->setOwnerObject(fun);
-#ifdef CHECK_SCRIPT_OWNER
-        fun->script()->owner = NULL;
-#endif
         if (!fun->u.i.script->typeSetFunction(cx, fun))
             return false;
         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
     }
 
     return true;
 }
@@ -1714,52 +1696,39 @@ fun_trace(JSTracer *trc, JSObject *obj)
                            obj->getFlatClosureUpvars(), "upvars");
         }
         return;
     }
 
     if (fun->atom)
         MarkString(trc, fun->atom, "atom");
 
-    if (fun->isInterpreted() && fun->script())
-        js_TraceScript(trc, fun->script(), obj);
+    if (fun->isInterpreted() && fun->script()) {
+        CheckScriptOwner(fun->script(), obj);
+        MarkScript(trc, fun->script(), "script");
+    }
 }
 
 static void
 fun_finalize(JSContext *cx, JSObject *obj)
 {
-    /* Ignore newborn function objects. */
-    JSFunction *fun = obj->getFunctionPrivate();
-    if (!fun)
-        return;
-
-    /* Cloned function objects may be flat closures with upvars to free. */
-    if (fun != obj) {
-        if (fun->isFlatClosure() && fun->script()->bindings.hasUpvars())
-            cx->free_((void *) obj->getFlatClosureUpvars());
-        return;
-    }
-
-    /*
-     * Null-check fun->script() because the parser sets interpreted very early.
-     */
-    if (fun->isInterpreted() && fun->script())
-        js_DestroyScriptFromGC(cx, fun->script(), obj);
+    obj->finalizeUpvarsIfFlatClosure();
 }
 
 /*
  * Reserve two slots in all function objects for XPConnect.  Note that this
  * does not bloat every instance, only those on which reserved slots are set,
  * and those on which ad-hoc properties are defined.
  */
 JS_PUBLIC_DATA(Class) js_FunctionClass = {
     js_Function_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Function) |
+    JSCLASS_CONCURRENT_FINALIZER,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     fun_enumerate,
     (JSResolveOp)fun_resolve,
     ConvertStub,
     fun_finalize,
@@ -2189,18 +2158,16 @@ Function(JSContext *cx, uintN argc, Valu
     /* Block this call if security callbacks forbid it. */
     GlobalObject *global = call.callee().getGlobal();
     if (!global->isRuntimeCodeGenEnabled(cx)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
         return false;
     }
 
     Bindings bindings(cx);
-    AutoBindingsRooter root(cx, bindings);
-
     uintN lineno;
     const char *filename = CurrentScriptFileAndLine(cx, &lineno);
 
     Value *argv = call.argv();
     uintN n = argc ? argc - 1 : 0;
     if (n > 0) {
         /*
          * Collect the function-argument arguments into one string, separated
@@ -2420,19 +2387,16 @@ js_InitFunctionClass(JSContext *cx, JSOb
     fun->flags |= JSFUN_PROTOTYPE;
 
     JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT);
     if (!script)
         return NULL;
     script->noScriptRval = true;
     script->code[0] = JSOP_STOP;
     script->code[1] = SRC_NULL;
-#ifdef CHECK_SCRIPT_OWNER
-    script->owner = NULL;
-#endif
     fun->u.i.script = script;
     fun->getType(cx)->functionScript = script;
     script->hasFunction = true;
     script->where.fun = fun;
     script->setOwnerObject(fun);
     js_CallNewScriptHook(cx, script, fun);
 
     if (obj->isGlobal()) {
@@ -2541,33 +2505,30 @@ js_CloneFunctionObject(JSContext *cx, JS
         cfun->nargs = fun->nargs;
         cfun->flags = fun->flags;
         cfun->u = fun->getFunctionPrivate()->u;
         cfun->atom = fun->atom;
         clone->setPrivate(cfun);
         if (cfun->isInterpreted()) {
             JSScript *script = cfun->script();
             JS_ASSERT(script);
-            JS_ASSERT(script->compartment == fun->compartment());
-            JS_ASSERT(script->compartment != cx->compartment);
+            JS_ASSERT(script->compartment() == fun->compartment());
+            JS_ASSERT(script->compartment() != cx->compartment);
             JS_OPT_ASSERT(script->ownerObject == fun);
 
             cfun->u.i.script = NULL;
             JSScript *cscript = js_CloneScript(cx, script);
             if (!cscript)
                 return NULL;
 
             cfun->u.i.script = cscript;
             if (!cfun->u.i.script->typeSetFunction(cx, cfun))
                 return NULL;
 
             cfun->script()->setOwnerObject(cfun);
-#ifdef CHECK_SCRIPT_OWNER
-            cfun->script()->owner = NULL;
-#endif
             js_CallNewScriptHook(cx, cfun->script(), cfun);
             Debugger::onNewScript(cx, cfun->script(), cfun, Debugger::NewHeldScript);
         }
     }
     return clone;
 }
 
 #ifdef JS_TRACER
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -101,31 +101,16 @@
 #endif
 #ifdef JS_VALGRIND
 # include <valgrind/memcheck.h>
 #endif
 
 using namespace js;
 using namespace js::gc;
 
-/*
- * Check that JSTRACE_XML follows JSTRACE_OBJECT and JSTRACE_STRING.
- */
-JS_STATIC_ASSERT(JSTRACE_OBJECT      == 0);
-JS_STATIC_ASSERT(JSTRACE_STRING      == 1);
-JS_STATIC_ASSERT(JSTRACE_SHAPE       == 2);
-JS_STATIC_ASSERT(JSTRACE_TYPE_OBJECT == 3);
-JS_STATIC_ASSERT(JSTRACE_XML         == 4);
-
-/*
- * JS_IS_VALID_TRACE_KIND assumes that JSTRACE_TYPE_OBJECT is the last non-xml
- * trace kind when JS_HAS_XML_SUPPORT is false.
- */
-JS_STATIC_ASSERT(JSTRACE_TYPE_OBJECT + 1 == JSTRACE_XML);
-
 namespace js {
 namespace gc {
 
 /* This array should be const, but that doesn't link right under GCC. */
 FinalizeKind slotsToThingKind[] = {
     /* 0 */  FINALIZE_OBJECT0,  FINALIZE_OBJECT2,  FINALIZE_OBJECT2,  FINALIZE_OBJECT4,
     /* 4 */  FINALIZE_OBJECT4,  FINALIZE_OBJECT8,  FINALIZE_OBJECT8,  FINALIZE_OBJECT8,
     /* 8 */  FINALIZE_OBJECT8,  FINALIZE_OBJECT12, FINALIZE_OBJECT12, FINALIZE_OBJECT12,
@@ -144,16 +129,17 @@ const uint8 GCThingSizeMap[] = {
     sizeof(JSObject_Slots4),    /* FINALIZE_OBJECT4_BACKGROUND  */
     sizeof(JSObject_Slots8),    /* FINALIZE_OBJECT8             */
     sizeof(JSObject_Slots8),    /* FINALIZE_OBJECT8_BACKGROUND  */
     sizeof(JSObject_Slots12),   /* FINALIZE_OBJECT12            */
     sizeof(JSObject_Slots12),   /* FINALIZE_OBJECT12_BACKGROUND */
     sizeof(JSObject_Slots16),   /* FINALIZE_OBJECT16            */
     sizeof(JSObject_Slots16),   /* FINALIZE_OBJECT16_BACKGROUND */
     sizeof(JSFunction),         /* FINALIZE_FUNCTION            */
+    sizeof(JSScript),           /* FINALIZE_SCRIPT              */
     sizeof(Shape),              /* FINALIZE_SHAPE               */
     sizeof(types::TypeObject),  /* FINALIZE_TYPE_OBJECT         */
 #if JS_HAS_XML_SUPPORT
     sizeof(JSXML),              /* FINALIZE_XML                 */
 #endif
     sizeof(JSShortString),      /* FINALIZE_SHORT_STRING        */
     sizeof(JSString),           /* FINALIZE_STRING              */
     sizeof(JSExternalString),   /* FINALIZE_EXTERNAL_STRING     */
@@ -193,16 +179,20 @@ ArenaHeader::checkSynchronizedWithFreeLi
     JS_ASSERT(firstSpan.isSameNonEmptySpan(list));
 }
 #endif
 
 template<typename T>
 inline bool
 Arena::finalize(JSContext *cx)
 {
+    /* Enforce requirements on size of T. */
+    JS_STATIC_ASSERT(sizeof(T) % Cell::CellSize == 0);
+    JS_STATIC_ASSERT(sizeof(T) <= 255);
+
     JS_ASSERT(aheader.allocated());
     JS_ASSERT(!aheader.getMarkingDelay()->link);
 
     uintptr_t thing = thingsStart(sizeof(T));
     uintptr_t lastByte = thingsEnd() - 1;
 
     FreeSpan nextFree(aheader.getFirstFreeSpan());
     nextFree.checkSpan();
@@ -782,16 +772,19 @@ MarkIfGCThingWord(JSTracer *trc, jsuword
         test = MarkArenaPtrConservatively<JSExternalString>(trc, aheader, addr);
         break;
       case FINALIZE_SHORT_STRING:
         test = MarkArenaPtrConservatively<JSShortString>(trc, aheader, addr);
         break;
       case FINALIZE_FUNCTION:
         test = MarkArenaPtrConservatively<JSFunction>(trc, aheader, addr);
         break;
+      case FINALIZE_SCRIPT:
+        test = MarkArenaPtrConservatively<JSScript>(trc, aheader, addr);
+        break;
       case FINALIZE_SHAPE:
         test = MarkArenaPtrConservatively<Shape>(trc, aheader, addr);
         break;
       case FINALIZE_TYPE_OBJECT:
         test = MarkArenaPtrConservatively<types::TypeObject>(trc, aheader, addr);
         break;
 #if JS_HAS_XML_SUPPORT
       case FINALIZE_XML:
@@ -1248,28 +1241,35 @@ ArenaList::finalizeLater(JSContext *cx)
 {
     JS_ASSERT_IF(head,
                  head->getThingKind() == FINALIZE_OBJECT0_BACKGROUND  ||
                  head->getThingKind() == FINALIZE_OBJECT2_BACKGROUND  ||
                  head->getThingKind() == FINALIZE_OBJECT4_BACKGROUND  ||
                  head->getThingKind() == FINALIZE_OBJECT8_BACKGROUND  ||
                  head->getThingKind() == FINALIZE_OBJECT12_BACKGROUND ||
                  head->getThingKind() == FINALIZE_OBJECT16_BACKGROUND ||
+                 head->getThingKind() == FINALIZE_FUNCTION            ||
                  head->getThingKind() == FINALIZE_SHORT_STRING        ||
                  head->getThingKind() == FINALIZE_STRING);
     JS_ASSERT(!cx->runtime->gcHelperThread.sweeping);
 
     /*
      * The state can be just-finished if we have not allocated any GC things
      * from the arena list after the previous background finalization.
      */
     JS_ASSERT(backgroundFinalizeState == BFS_DONE ||
               backgroundFinalizeState == BFS_JUST_FINISHED);
 
-    if (head && cx->gcBackgroundFree && cx->gcBackgroundFree->finalizeVector.append(head)) {
+    if (head && cx->gcBackgroundFree) {
+        /*
+         * To ensure the finalization order even during the background GC we
+         * must use infallibleAppend so arenas scheduled for background
+         * finalization would not be finalized now if the append fails.
+         */
+        cx->gcBackgroundFree->finalizeVector.infallibleAppend(head);
         head = NULL;
         cursor = &head;
         backgroundFinalizeState = BFS_RUN;
     } else {
         JS_ASSERT_IF(!head, cursor == &head);
         backgroundFinalizeState = BFS_DONE;
         finalizeNow<T>(cx);
     }
@@ -1300,16 +1300,19 @@ ArenaList::backgroundFinalize(JSContext 
         FinalizeArenas<JSObject_Slots8>(cx, &listHead);
         break;
       case FINALIZE_OBJECT12_BACKGROUND:
         FinalizeArenas<JSObject_Slots12>(cx, &listHead);
         break;
       case FINALIZE_OBJECT16_BACKGROUND:
         FinalizeArenas<JSObject_Slots16>(cx, &listHead);
         break;
+      case FINALIZE_FUNCTION:
+        FinalizeArenas<JSFunction>(cx, &listHead);
+        break;
       case FINALIZE_STRING:
         FinalizeArenas<JSString>(cx, &listHead);
         break;
       case FINALIZE_SHORT_STRING:
         FinalizeArenas<JSShortString>(cx, &listHead);
         break;
     }
 
@@ -1458,16 +1461,18 @@ RefillFinalizableFreeList(JSContext *cx,
       case FINALIZE_STRING:
         return RefillTypedFreeList<JSString>(cx, thingKind);
       case FINALIZE_EXTERNAL_STRING:
         return RefillTypedFreeList<JSExternalString>(cx, thingKind);
       case FINALIZE_SHORT_STRING:
         return RefillTypedFreeList<JSShortString>(cx, thingKind);
       case FINALIZE_FUNCTION:
         return RefillTypedFreeList<JSFunction>(cx, thingKind);
+      case FINALIZE_SCRIPT:
+        return RefillTypedFreeList<JSScript>(cx, thingKind);
       case FINALIZE_SHAPE:
         return RefillTypedFreeList<Shape>(cx, thingKind);
       case FINALIZE_TYPE_OBJECT:
         return RefillTypedFreeList<types::TypeObject>(cx, thingKind);
 #if JS_HAS_XML_SUPPORT
       case FINALIZE_XML:
         return RefillTypedFreeList<JSXML>(cx, thingKind);
 #endif
@@ -1475,17 +1480,17 @@ RefillFinalizableFreeList(JSContext *cx,
         JS_NOT_REACHED("bad finalize kind");
         return 0;
     }
 }
 
 } /* namespace gc */
 } /* namespace js */
 
-uint32
+JSGCTraceKind
 js_GetGCThingTraceKind(void *thing)
 {
     return GetGCThingTraceKind(thing);
 }
 
 JSBool
 js_LockGCThingRT(JSRuntime *rt, void *thing)
 {
@@ -1573,17 +1578,17 @@ GCMarker::delayMarkingChildren(const voi
 #ifdef DEBUG
     markLaterArenas++;
 #endif
 }
 
 static void
 MarkDelayedChildren(JSTracer *trc, ArenaHeader *aheader)
 {
-    unsigned traceKind = GetFinalizableTraceKind(aheader->getThingKind());
+    JSGCTraceKind traceKind = GetFinalizableTraceKind(aheader->getThingKind());
     size_t thingSize = aheader->getThingSize();
     Arena *a = aheader->getArena();
     uintptr_t end = a->thingsEnd();
     for (uintptr_t thing = a->thingsStart(thingSize); thing != end; thing += thingSize) {
         Cell *t = reinterpret_cast<Cell *>(thing);
         if (t->isMarked())
             JS_TraceChildren(trc, t, traceKind);
     }
@@ -1670,18 +1675,18 @@ gc_lock_traversal(const GCLocks::Entry &
 void
 js_TraceStackFrame(JSTracer *trc, StackFrame *fp)
 {
     MarkObject(trc, fp->scopeChain(), "scope chain");
     if (fp->isDummyFrame())
         return;
     if (fp->hasArgsObj())
         MarkObject(trc, fp->argsObj(), "arguments");
-    js_TraceScript(trc, fp->script(), NULL);
-    fp->script()->compartment->active = true;
+    MarkScript(trc, fp->script(), "script");
+    fp->script()->compartment()->active = true;
     MarkValue(trc, fp->returnValue(), "rval");
 }
 
 void
 AutoIdArray::trace(JSTracer *trc)
 {
     JS_ASSERT(tag == IDARRAY);
     gc::MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
@@ -1696,29 +1701,20 @@ AutoEnumStateRooter::trace(JSTracer *trc
 inline void
 AutoGCRooter::trace(JSTracer *trc)
 {
     switch (tag) {
       case JSVAL:
         MarkValue(trc, static_cast<AutoValueRooter *>(this)->val, "js::AutoValueRooter.val");
         return;
 
-      case SHAPE:
-        MarkShape(trc, static_cast<AutoShapeRooter *>(this)->shape, "js::AutoShapeRooter.val");
-        return;
-
       case PARSER:
         static_cast<Parser *>(this)->trace(trc);
         return;
 
-      case SCRIPT:
-        if (JSScript *script = static_cast<AutoScriptRooter *>(this)->script)
-            js_TraceScript(trc, script, NULL);
-        return;
-
       case ENUMERATOR:
         static_cast<AutoEnumStateRooter *>(this)->trace(trc);
         return;
 
       case IDARRAY: {
         JSIdArray *ida = static_cast<AutoIdArray *>(this)->idArray;
         MarkIdRange(trc, ida->length, ida->vector, "js::AutoIdArray.idArray");
         return;
@@ -1788,33 +1784,22 @@ AutoGCRooter::trace(JSTracer *trc)
       }
 
       case SHAPEVECTOR: {
         AutoShapeVector::VectorImpl &vector = static_cast<js::AutoShapeVector *>(this)->vector;
         MarkShapeRange(trc, vector.length(), vector.begin(), "js::AutoShapeVector.vector");
         return;
       }
 
-      case BINDINGS: {
-        static_cast<js::AutoBindingsRooter *>(this)->bindings.trace(trc);
-        return;
-      }
-
       case OBJVECTOR: {
         AutoObjectVector::VectorImpl &vector = static_cast<AutoObjectVector *>(this)->vector;
         MarkObjectRange(trc, vector.length(), vector.begin(), "js::AutoObjectVector.vector");
         return;
       }
 
-      case TYPE: {
-        types::TypeObject *type = static_cast<types::AutoTypeRooter *>(this)->type;
-        MarkTypeObject(trc, type, "js::AutoTypeRooter");
-        return;
-      }
-
       case VALARRAY: {
         AutoValueArray *array = static_cast<AutoValueArray *>(this);
         MarkValueRange(trc, array->length(), array->start(), "js::AutoValueArray");
         return;
       }
     }
 
     JS_ASSERT(tag >= 0);
@@ -1984,50 +1969,45 @@ MaybeGC(JSContext *cx)
             rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN;
         }
     }
 }
 
 } /* namespace js */
 
 void
-js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp)
-{
-    JSScript **listp, *script;
-
-    for (size_t i = 0; i != JS_ARRAY_LENGTH(comp->scriptsToGC); ++i) {
-        listp = &comp->scriptsToGC[i];
-        while ((script = *listp) != NULL) {
-            *listp = script->u.nextToGC;
-            script->u.nextToGC = NULL;
-            js_DestroyCachedScript(cx, script);
-        }
-    }
-}
-
-void
 JSCompartment::finalizeObjectArenaLists(JSContext *cx)
 {
     arenas[FINALIZE_OBJECT0]. finalizeNow<JSObject>(cx);
     arenas[FINALIZE_OBJECT2]. finalizeNow<JSObject_Slots2>(cx);
     arenas[FINALIZE_OBJECT4]. finalizeNow<JSObject_Slots4>(cx);
     arenas[FINALIZE_OBJECT8]. finalizeNow<JSObject_Slots8>(cx);
     arenas[FINALIZE_OBJECT12].finalizeNow<JSObject_Slots12>(cx);
     arenas[FINALIZE_OBJECT16].finalizeNow<JSObject_Slots16>(cx);
-    arenas[FINALIZE_FUNCTION].finalizeNow<JSFunction>(cx);
 
 #ifdef JS_THREADSAFE
     arenas[FINALIZE_OBJECT0_BACKGROUND]. finalizeLater<JSObject>(cx);
     arenas[FINALIZE_OBJECT2_BACKGROUND]. finalizeLater<JSObject_Slots2>(cx);
     arenas[FINALIZE_OBJECT4_BACKGROUND]. finalizeLater<JSObject_Slots4>(cx);
     arenas[FINALIZE_OBJECT8_BACKGROUND]. finalizeLater<JSObject_Slots8>(cx);
     arenas[FINALIZE_OBJECT12_BACKGROUND].finalizeLater<JSObject_Slots12>(cx);
     arenas[FINALIZE_OBJECT16_BACKGROUND].finalizeLater<JSObject_Slots16>(cx);
 #endif
 
+    /*
+     * We must finalize Function instances after finalizing any other objects
+     * even if we use the background finalization for the latter. See comments
+     * in JSObject::finalizeUpvarsIfFlatClosure.
+     */
+#ifdef JS_THREADSAFE
+    arenas[FINALIZE_FUNCTION].finalizeLater<JSFunction>(cx);
+#else
+    arenas[FINALIZE_FUNCTION].finalizeNow<JSFunction>(cx);
+#endif
+
 #if JS_HAS_XML_SUPPORT
     arenas[FINALIZE_XML].finalizeNow<JSXML>(cx);
 #endif
 }
 
 void
 JSCompartment::finalizeStringArenaLists(JSContext *cx)
 {
@@ -2043,16 +2023,22 @@ JSCompartment::finalizeStringArenaLists(
 
 void
 JSCompartment::finalizeShapeArenaLists(JSContext *cx)
 {
     arenas[FINALIZE_TYPE_OBJECT].finalizeNow<types::TypeObject>(cx);
     arenas[FINALIZE_SHAPE].finalizeNow<Shape>(cx);
 }
 
+void
+JSCompartment::finalizeScriptArenaLists(JSContext *cx)
+{
+    arenas[FINALIZE_SCRIPT].finalizeNow<JSScript>(cx);
+}
+
 #ifdef JS_THREADSAFE
 
 namespace js {
 
 bool
 GCHelperThread::init(JSRuntime *rt)
 {
     if (!(wakeup = PR_NewCondVar(rt->gcLock)))
@@ -2112,16 +2098,25 @@ GCHelperThread::threadLoop(JSRuntime *rt
             AutoUnlockGC unlock(rt);
             doSweep();
         }
         sweeping = false;
         PR_NotifyAllCondVar(sweepingDone);
     }
 }
 
+bool
+GCHelperThread::prepareForBackgroundSweep(JSContext *context) {
+    size_t maxArenaLists = MAX_BACKGROUND_FINALIZE_KINDS * context->runtime->compartments.length();
+    if (!finalizeVector.reserve(maxArenaLists))
+        return false;
+    cx = context;
+    return true;
+}
+
 void
 GCHelperThread::startBackgroundSweep(JSRuntime *rt, JSGCInvocationKind gckind)
 {
     /* The caller takes the GC lock. */
     JS_ASSERT(!sweeping);
     lastGCKind = gckind;
     sweeping = true;
     PR_NotifyCondVar(wakeup);
@@ -2155,16 +2150,21 @@ GCHelperThread::replenishAndFreeLater(vo
     } while (false);
     Foreground::free_(ptr);
 }
 
 void
 GCHelperThread::doSweep()
 {
     JS_ASSERT(cx);
+
+    /*
+     * We must finalize in the insert order, see comments in
+     * finalizeObjectArenaLists.
+     */
     for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
         ArenaList::backgroundFinalize(cx, *i);
     finalizeVector.resize(0);
     ExpireGCChunks(cx->runtime, lastGCKind);
     cx = NULL;
 
     if (freeCursor) {
         void **array = freeCursorEnd - FREE_ARRAY_LENGTH;
@@ -2371,16 +2371,18 @@ MarkAndSweep(JSContext *cx, JSCompartmen
      */
     if (comp) {
         Probes::GCStartSweepPhase(comp);
         comp->sweep(cx, 0);
         comp->finalizeObjectArenaLists(cx);
         GCTIMESTAMP(sweepObjectEnd);
         comp->finalizeStringArenaLists(cx);
         GCTIMESTAMP(sweepStringEnd);
+        comp->finalizeScriptArenaLists(cx);
+        GCTIMESTAMP(sweepScriptEnd);
         comp->finalizeShapeArenaLists(cx);
         GCTIMESTAMP(sweepShapeEnd);
         Probes::GCEndSweepPhase(comp);
     } else {
         /*
          * Some sweeping is not compartment-specific. Start a NULL-compartment
          * phase to demarcate all of that. (The compartment sweeps will nest
          * within.)
@@ -2397,16 +2399,22 @@ MarkAndSweep(JSContext *cx, JSCompartmen
         GCTIMESTAMP(sweepObjectEnd);
 
         for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++)
             (*c)->finalizeStringArenaLists(cx);
 
         GCTIMESTAMP(sweepStringEnd);
 
         for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
+            (*c)->finalizeScriptArenaLists(cx);
+        }
+
+        GCTIMESTAMP(sweepScriptEnd);
+
+        for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
             (*c)->finalizeShapeArenaLists(cx);
             Probes::GCEndSweepPhase(*c);
         }
 
         GCTIMESTAMP(sweepShapeEnd);
     }
 
 #ifdef DEBUG
@@ -2548,16 +2556,17 @@ class AutoGCSession {
  * contains the rendezvous algorithm by which we stop the world for GC.
  *
  * This thread becomes the GC thread. Wait for all other threads to quiesce.
  * Then set rt->gcRunning and return.
  */
 AutoGCSession::AutoGCSession(JSContext *cx)
   : context(cx)
 {
+    JS_ASSERT(!JS_THREAD_DATA(cx)->noGCOrAllocationCheck);
     JSRuntime *rt = cx->runtime;
 
 #ifdef JS_THREADSAFE
     if (rt->gcThread && rt->gcThread != cx->thread())
         LetOtherGCFinish(cx);
 #endif
 
     JS_ASSERT(!rt->gcRunning);
@@ -2674,18 +2683,18 @@ GCCycle(JSContext *cx, JSCompartment *co
 #ifdef JS_THREADSAFE
         /*
          * As we about to purge caches and clear the mark bits we must wait
          * for any background finalization to finish.
          */
         JS_ASSERT(!cx->gcBackgroundFree);
         rt->gcHelperThread.waitBackgroundSweepEnd(rt);
         if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
-            cx->gcBackgroundFree = &rt->gcHelperThread;
-            cx->gcBackgroundFree->setContext(cx);
+            if (rt->gcHelperThread.prepareForBackgroundSweep(cx))
+                cx->gcBackgroundFree = &rt->gcHelperThread;
         }
 #endif
         MarkAndSweep(cx, comp, gckind  GCTIMER_ARG);
     }
 
 #ifdef JS_THREADSAFE
     if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
         JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
@@ -2843,34 +2852,34 @@ TraceRuntime(JSTracer *trc)
     MarkRuntime(trc);
 }
 
 struct IterateArenaCallbackOp
 {
     JSContext *cx;
     void *data;
     IterateArenaCallback callback;
-    size_t traceKind;
+    JSGCTraceKind traceKind;
     size_t thingSize;
     IterateArenaCallbackOp(JSContext *cx, void *data, IterateArenaCallback callback,
-                           size_t traceKind, size_t thingSize)
+                           JSGCTraceKind traceKind, size_t thingSize)
         : cx(cx), data(data), callback(callback), traceKind(traceKind), thingSize(thingSize)
     {}
     void operator()(Arena *arena) { (*callback)(cx, data, arena, traceKind, thingSize); }
 };
 
 struct IterateCellCallbackOp
 {
     JSContext *cx;
     void *data;
     IterateCellCallback callback;
-    size_t traceKind;
+    JSGCTraceKind traceKind;
     size_t thingSize;
     IterateCellCallbackOp(JSContext *cx, void *data, IterateCellCallback callback,
-                          size_t traceKind, size_t thingSize)
+                          JSGCTraceKind traceKind, size_t thingSize)
         : cx(cx), data(data), callback(callback), traceKind(traceKind), thingSize(thingSize)
     {}
     void operator()(Cell *cell) { (*callback)(cx, data, cell, traceKind, thingSize); }
 };
 
 void
 IterateCompartmentsArenasCells(JSContext *cx, void *data,
                                IterateCompartmentCallback compartmentCallback,
@@ -2891,17 +2900,17 @@ IterateCompartmentsArenasCells(JSContext
     AutoUnlockGC unlock(rt);
 
     AutoCopyFreeListToArenas copy(rt);
     for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
         JSCompartment *compartment = *c;
         (*compartmentCallback)(cx, data, compartment);
 
         for (unsigned thingKind = 0; thingKind < FINALIZE_LIMIT; thingKind++) {
-            size_t traceKind = GetFinalizableTraceKind(thingKind);
+            JSGCTraceKind traceKind = GetFinalizableTraceKind(thingKind);
             size_t thingSize = GCThingSizeMap[thingKind];
             IterateArenaCallbackOp arenaOp(cx, data, arenaCallback, traceKind, thingSize);
             IterateCellCallbackOp cellOp(cx, data, cellCallback, traceKind, thingSize);
 
             ForEachArenaAndCell(compartment, (FinalizeKind) thingKind, arenaOp, cellOp);
         }
     }
 }
@@ -2922,21 +2931,28 @@ IterateCells(JSContext *cx, JSCompartmen
     AutoGCSession gcsession(cx);
 #ifdef JS_THREADSAFE
     rt->gcHelperThread.waitBackgroundSweepEnd(rt, false);
 #endif
     AutoUnlockGC unlock(rt);
 
     AutoCopyFreeListToArenas copy(rt);
 
-    size_t traceKind = GetFinalizableTraceKind(thingKind);
+    JSGCTraceKind traceKind = GetFinalizableTraceKind(thingKind);
     size_t thingSize = GCThingSizeMap[thingKind];
-    IterateCellCallbackOp cellOp(cx, data, cellCallback, traceKind, thingSize);
-
-    ForEachArenaAndCell(compartment, thingKind, EmptyArenaOp, cellOp);
+
+    if (compartment) {
+        for (CellIterUnderGC i(compartment, thingKind); !i.done(); i.next())
+            cellCallback(cx, data, i.getCell(), traceKind, thingSize);
+    } else {
+        for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
+            for (CellIterUnderGC i(*c, thingKind); !i.done(); i.next())
+                cellCallback(cx, data, i.getCell(), traceKind, thingSize);
+        }
+    }
 }
 
 namespace gc {
 
 JSCompartment *
 NewCompartment(JSContext *cx, JSPrincipals *principals)
 {
     JSRuntime *rt = cx->runtime;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -92,27 +92,34 @@ enum FinalizeKind {
     FINALIZE_OBJECT8_BACKGROUND,
     FINALIZE_OBJECT12,
     FINALIZE_OBJECT12_BACKGROUND,
     FINALIZE_OBJECT16,
     FINALIZE_OBJECT16_BACKGROUND,
     FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
     FINALIZE_FUNCTION,
     FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
+    FINALIZE_SCRIPT,
     FINALIZE_SHAPE,
     FINALIZE_TYPE_OBJECT,
 #if JS_HAS_XML_SUPPORT
     FINALIZE_XML,
 #endif
     FINALIZE_SHORT_STRING,
     FINALIZE_STRING,
     FINALIZE_EXTERNAL_STRING,
     FINALIZE_LIMIT
 };
 
+/*
+ * This must be an upper bound, but we do not need the least upper bound, so
+ * we just exclude non-background objects.
+ */
+const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - (FINALIZE_OBJECT_LAST + 1) / 2;
+
 extern JS_FRIEND_DATA(const uint8) GCThingSizeMap[];
 
 const size_t ArenaShift = 12;
 const size_t ArenaSize = size_t(1) << ArenaShift;
 const size_t ArenaMask = ArenaSize - 1;
 
 /*
  * The mark bitmap has one bit per each GC cell. For multi-cell GC things this
@@ -751,73 +758,64 @@ Cell::unmark(uint32 color) const
 }
 
 JSCompartment *
 Cell::compartment() const
 {
     return arenaHeader()->compartment;
 }
 
-#define JSTRACE_TYPE_OBJECT 3
-#define JSTRACE_XML         4
-
-/*
- * One past the maximum trace kind.
- */
-#define JSTRACE_LIMIT       5
-
 /*
  * Lower limit after which we limit the heap growth
  */
 const size_t GC_ALLOCATION_THRESHOLD = 30 * 1024 * 1024;
 
 /*
  * A GC is triggered once the number of newly allocated arenas is
  * GC_HEAP_GROWTH_FACTOR times the number of live arenas after the last GC
  * starting after the lower limit of GC_ALLOCATION_THRESHOLD.
  */
 const float GC_HEAP_GROWTH_FACTOR = 3.0f;
 
 /* Perform a Full GC every 20 seconds if MaybeGC is called */
 static const int64 GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
 
-static inline size_t
+static inline JSGCTraceKind
 GetFinalizableTraceKind(size_t thingKind)
 {
-    JS_STATIC_ASSERT(JSExternalString::TYPE_LIMIT == 8);
-
-    static const uint8 map[FINALIZE_LIMIT] = {
+    static const JSGCTraceKind map[FINALIZE_LIMIT] = {
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT0 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT0_BACKGROUND */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT2 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT2_BACKGROUND */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT4 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT4_BACKGROUND */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT8 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT8_BACKGROUND */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT12 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT12_BACKGROUND */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT16 */
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT16_BACKGROUND */
         JSTRACE_OBJECT,     /* FINALIZE_FUNCTION */
+        JSTRACE_SCRIPT,     /* FINALIZE_SCRIPT */
         JSTRACE_SHAPE,      /* FINALIZE_SHAPE */
         JSTRACE_TYPE_OBJECT,/* FINALIZE_TYPE_OBJECT */
 #if JS_HAS_XML_SUPPORT      /* FINALIZE_XML */
         JSTRACE_XML,
 #endif
         JSTRACE_STRING,     /* FINALIZE_SHORT_STRING */
         JSTRACE_STRING,     /* FINALIZE_STRING */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING */
     };
 
     JS_ASSERT(thingKind < FINALIZE_LIMIT);
     return map[thingKind];
 }
 
-inline uint32
+inline JSGCTraceKind
 GetGCThingTraceKind(const void *thing);
 
 static inline JSRuntime *
 GetGCThingRuntime(void *thing)
 {
     return reinterpret_cast<Cell *>(thing)->chunk()->info.runtime;
 }
 
@@ -876,16 +874,20 @@ class ArenaList {
     template<typename T>
     inline void finalizeLater(JSContext *cx);
 
     static void backgroundFinalize(JSContext *cx, ArenaHeader *listHead);
 
     bool willBeFinalizedLater() const {
         return backgroundFinalizeState == BFS_RUN;
     }
+
+    bool doneBackgroundFinalize() const {
+        return backgroundFinalizeState == BFS_DONE;
+    }
 #endif
 
 #ifdef DEBUG
     bool markedThingsInArenaList() {
 # ifdef JS_THREADSAFE
         /* The background finalization must have stopped at this point. */
         JS_ASSERT(backgroundFinalizeState == BFS_DONE ||
                   backgroundFinalizeState == BFS_JUST_FINISHED);
@@ -961,41 +963,68 @@ struct FreeLists {
     }
 
     /*
      * Temporarily copy the free list heads to the arenas so the code can see
      * the proper value in ArenaHeader::freeList when accessing the latter
      * outside the GC.
      */
     void copyToArenas() {
-        for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) {
-            FreeSpan *list = &lists[i];
-            if (!list->isEmpty()) {
-                ArenaHeader *aheader = list->arenaHeader();
-                JS_ASSERT(!aheader->hasFreeThings());
-                aheader->setFirstFreeSpan(list);
-            }
+        for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i)
+            copyToArena(FinalizeKind(i));
+    }
+
+    void copyToArena(FinalizeKind thingKind) {
+        FreeSpan *list = &lists[thingKind];
+        if (!list->isEmpty()) {
+            ArenaHeader *aheader = list->arenaHeader();
+            JS_ASSERT(!aheader->hasFreeThings());
+            aheader->setFirstFreeSpan(list);
         }
     }
 
     /*
      * Clear the free lists in arenas that were temporarily set there using
      * copyToArenas.
      */
     void clearInArenas() {
-        for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) {
-            FreeSpan *list = &lists[i];
-            if (!list->isEmpty()) {
-                ArenaHeader *aheader = list->arenaHeader();
-                JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
-                aheader->setAsFullyUsed();
-            }
+        for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) 
+            clearInArena(FinalizeKind(i));
+    }
+
+
+    void clearInArena(FinalizeKind thingKind) {
+        FreeSpan *list = &lists[thingKind];
+        if (!list->isEmpty()) {
+            ArenaHeader *aheader = list->arenaHeader();
+            JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
+            aheader->setAsFullyUsed();
         }
     }
 
+    /*
+     * Check that the free list is either empty or were synchronized with the
+     * arena using copyToArena().
+     */
+    bool isSynchronizedWithArena(FinalizeKind thingKind) {
+        FreeSpan *list = &lists[thingKind];
+        if (list->isEmpty())
+            return true;
+        ArenaHeader *aheader = list->arenaHeader();
+        if (aheader->hasFreeThings()) {
+            /*
+             * If the arena has a free list, it must be the same as one in
+             * lists.
+             */ 
+            JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
+            return true;
+        }
+        return false;
+    }
+
     JS_ALWAYS_INLINE void *getNext(unsigned thingKind, size_t thingSize) {
         return lists[thingKind].allocate(thingSize);
     }
 
     void *populate(ArenaHeader *aheader, unsigned thingKind, size_t thingSize) {
         FreeSpan *list = &lists[thingKind];
         *list = aheader->getFirstFreeSpan();
         aheader->setAsFullyUsed();
@@ -1074,17 +1103,17 @@ class AutoIdVector;
 
 } /* namespace js */
 
 #ifdef DEBUG
 extern bool
 CheckAllocation(JSContext *cx);
 #endif
 
-extern JS_FRIEND_API(uint32)
+extern JS_FRIEND_API(JSGCTraceKind)
 js_GetGCThingTraceKind(void *thing);
 
 extern JSBool
 js_InitGC(JSRuntime *rt, uint32 maxbytes);
 
 extern void
 js_FinishGC(JSRuntime *rt);
 
@@ -1189,20 +1218,16 @@ extern void
 js_WaitForGC(JSRuntime *rt);
 
 #else /* !JS_THREADSAFE */
 
 # define js_WaitForGC(rt)    ((void) 0)
 
 #endif
 
-extern void
-js_DestroyScriptsToGC(JSContext *cx, JSCompartment *comp);
-
-
 namespace js {
 
 #ifdef JS_THREADSAFE
 
 /*
  * During the finalization we do not free immediately. Rather we add the
  * corresponding pointers to a buffer which we later release on a separated
  * thread.
@@ -1268,17 +1293,17 @@ class GCHelperThread {
     void freeLater(void *ptr) {
         JS_ASSERT(!sweeping);
         if (freeCursor != freeCursorEnd)
             *freeCursor++ = ptr;
         else
             replenishAndFreeLater(ptr);
     }
 
-    void setContext(JSContext *context) { cx = context; }
+    bool prepareForBackgroundSweep(JSContext *context);
 };
 
 #endif /* JS_THREADSAFE */
 
 struct GCChunkHasher {
     typedef gc::Chunk *Lookup;
 
     /*
@@ -1469,53 +1494,50 @@ struct GCMarker : public JSTracer {
             delayMarkingChildren(xml);
     }
 };
 
 void
 MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end);
 
 typedef void (*IterateCompartmentCallback)(JSContext *cx, void *data, JSCompartment *compartment);
-typedef void (*IterateArenaCallback)(JSContext *cx, void *data, gc::Arena *arena, size_t traceKind,
-                                     size_t thingSize);
-typedef void (*IterateCellCallback)(JSContext *cx, void *data, void *thing, size_t traceKind,
-                                    size_t thingSize);
+typedef void (*IterateArenaCallback)(JSContext *cx, void *data, gc::Arena *arena,
+                                     JSGCTraceKind traceKind, size_t thingSize);
+typedef void (*IterateCellCallback)(JSContext *cx, void *data, void *thing,
+                                    JSGCTraceKind traceKind, size_t thingSize);
 
 /*
  * This function calls |compartmentCallback| on every compartment,
  * |arenaCallback| on every in-use arena, and |cellCallback| on every in-use
  * cell in the GC heap.
  */
 extern JS_FRIEND_API(void)
 IterateCompartmentsArenasCells(JSContext *cx, void *data,
                                IterateCompartmentCallback compartmentCallback,
                                IterateArenaCallback arenaCallback,
                                IterateCellCallback cellCallback);
 
-/* Invoke cellCallback on every in-use object of the specified thing kind. */
-void
+/*
+ * Invoke cellCallback on every in-use object of the specified thing kind for
+ * the given compartment or for all compartments if it is null.
+ */
+extern JS_FRIEND_API(void)
 IterateCells(JSContext *cx, JSCompartment *compartment, gc::FinalizeKind thingKind,
              void *data, IterateCellCallback cellCallback);
 
 } /* namespace js */
 
 extern void
 js_FinalizeStringRT(JSRuntime *rt, JSString *str);
 
 /*
  * Macro to test if a traversal is the marking phase of the GC.
  */
 #define IS_GC_MARKING_TRACER(trc) ((trc)->callback == NULL)
 
-#if JS_HAS_XML_SUPPORT
-# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) < JSTRACE_LIMIT)
-#else
-# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_TYPE_OBJECT)
-#endif
-
 namespace js {
 namespace gc {
 
 JSCompartment *
 NewCompartment(JSContext *cx, JSPrincipals *principals);
 
 /* Tries to run a GC no matter what (used for GC zeal). */
 void
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -107,17 +107,17 @@ JSAtom::isStatic(const void *ptr)
 }
 
 namespace js {
 
 struct Shape;
 
 namespace gc {
 
-inline uint32
+inline JSGCTraceKind
 GetGCThingTraceKind(const void *thing)
 {
     JS_ASSERT(thing);
     if (JSAtom::isStatic(thing))
         return JSTRACE_STRING;
     const Cell *cell = reinterpret_cast<const Cell *>(thing);
     return GetFinalizableTraceKind(cell->arenaHeader()->getThingKind());
 }
@@ -251,16 +251,128 @@ ForEachArenaAndCell(JSCompartment *compa
             } else {
                 Cell *t = reinterpret_cast<Cell *>(thing);
                 cellOp(t);
             }
         }
     }
 }
 
+class CellIterImpl
+{
+    size_t thingSize;
+    ArenaHeader *aheader;
+    FreeSpan firstSpan;
+    const FreeSpan *span;
+    uintptr_t thing;
+    Cell *cell;
+
+  protected:
+    CellIterImpl() {
+    }
+
+    void init(JSCompartment *comp, FinalizeKind thingKind) {
+        thingSize = GCThingSizeMap[thingKind];
+        aheader = comp->arenas[thingKind].getHead();
+        firstSpan.initAsEmpty();
+        span = &firstSpan;
+        thing = span->first;
+        next();
+    }
+
+  public:
+    bool done() const {
+        return !cell;
+    }
+
+    template<typename T> T *get() const {
+        JS_ASSERT(!done());
+        return static_cast<T *>(cell);
+    }
+
+    Cell *getCell() const {
+        JS_ASSERT(!done());
+        return cell;
+    }
+
+    void next() {
+        for (;;) {
+            if (thing != span->first)
+                break;
+            if (JS_LIKELY(span->hasNext())) {
+                thing = span->last + thingSize;
+                span = span->nextSpan();
+                break;
+            }
+            if (!aheader) {
+                cell = NULL;
+                return;
+            }
+            firstSpan = aheader->getFirstFreeSpan();
+            span = &firstSpan;
+            thing = aheader->getArena()->thingsStart(thingSize);
+            aheader = aheader->next;
+        }
+        cell = reinterpret_cast<Cell *>(thing);
+        thing += thingSize;
+    }
+};
+
+class CellIterUnderGC : public CellIterImpl {
+
+  public:
+    CellIterUnderGC(JSCompartment *comp, FinalizeKind thingKind) {
+        JS_ASSERT(comp->rt->gcRunning);
+        JS_ASSERT(comp->freeLists.lists[thingKind].isEmpty());
+        init(comp, thingKind);
+    }
+};
+
+/*
+ * When using the iterator outside the GC the caller must ensure that no GC or
+ * allocations of GC things are possible and that the background finalization
+ * for the given thing kind is not enabled or is done.
+ */
+class CellIter: public CellIterImpl
+{
+    FreeLists *lists;
+    FinalizeKind thingKind;
+#ifdef DEBUG
+    size_t *counter;
+#endif
+  public:
+    CellIter(JSContext *cx, JSCompartment *comp, FinalizeKind thingKind)
+      : lists(&comp->freeLists),
+        thingKind(thingKind) {
+#ifdef JS_THREADSAFE
+        JS_ASSERT(comp->arenas[thingKind].doneBackgroundFinalize());
+#endif
+        if (lists->isSynchronizedWithArena(thingKind)) {
+            lists = NULL;
+        } else {
+            JS_ASSERT(!comp->rt->gcRunning);
+            lists->copyToArena(thingKind);
+        }
+#ifdef DEBUG
+        counter = &JS_THREAD_DATA(cx)->noGCOrAllocationCheck;
+        ++*counter;
+#endif
+        init(comp, thingKind);
+    }
+
+    ~CellIter() {
+#ifdef DEBUG
+        JS_ASSERT(*counter > 0);
+        --*counter;
+#endif
+        if (lists)
+            lists->clearInArena(thingKind);
+    }
+};
+
 /* Signatures for ArenaOp and CellOp above. */
 
 inline void EmptyArenaOp(Arena *arena) {}
 inline void EmptyCellOp(Cell *t) {}
 
 } /* namespace gc */
 } /* namespace js */
 
@@ -278,16 +390,17 @@ NewGCThing(JSContext *cx, unsigned thing
     JS_ASSERT(thingKind < js::gc::FINALIZE_LIMIT);
     JS_ASSERT(thingSize == js::gc::GCThingSizeMap[thingKind]);
 #ifdef JS_THREADSAFE
     JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
                  (thingKind == js::gc::FINALIZE_STRING) ||
                  (thingKind == js::gc::FINALIZE_SHORT_STRING));
 #endif
     JS_ASSERT(!cx->runtime->gcRunning);
+    JS_ASSERT(!JS_THREAD_DATA(cx)->noGCOrAllocationCheck);
 
 #ifdef JS_GC_ZEAL
     if (cx->runtime->needZealousGC())
         js::gc::RunDebugGC(cx);
 #endif
 
     void *t = cx->compartment->freeLists.getNext(thingKind, thingSize);
     return static_cast<T *>(t ? t : js::gc::RefillFinalizableFreeList(cx, thingKind));
@@ -328,16 +441,22 @@ js_NewGCFunction(JSContext *cx)
     JSFunction *fun = NewGCThing<JSFunction>(cx, js::gc::FINALIZE_FUNCTION, sizeof(JSFunction));
     if (fun) {
         fun->capacity = JSObject::FUN_CLASS_RESERVED_SLOTS;
         fun->lastProp = NULL; /* Stops fun from being scanned until initializated. */
     }
     return fun;
 }
 
+inline JSScript *
+js_NewGCScript(JSContext *cx)
+{
+    return NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
+}
+
 inline js::Shape *
 js_NewGCShape(JSContext *cx)
 {
     return NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
 }
 
 #if JS_HAS_XML_SUPPORT
 extern JSXML *
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -41,16 +41,17 @@
 #include "jsprf.h"
 #include "jsscope.h"
 #include "jsstr.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.
  *
  * 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
@@ -87,33 +88,35 @@ PushMarkStack(GCMarker *gcmarker, JSXML 
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSObject *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSFunction *thing);
 
 static inline void
+PushMarkStack(GCMarker *gcmarker, JSScript *thing);
+
+static inline void
 PushMarkStack(GCMarker *gcmarker, const Shape *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSShortString *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSString *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing);
 
 template<typename T>
 static inline void
 CheckMarkedThing(JSTracer *trc, T *thing)
 {
     JS_ASSERT(thing);
-    JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing)));
     JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
     JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
 
     JS_ASSERT(!JSAtom::isStatic(thing));
     JS_ASSERT(thing->isAligned());
 
     JS_ASSERT(thing->compartment());
     JS_ASSERT(thing->compartment()->rt == trc->context->runtime);
@@ -190,16 +193,25 @@ MarkObjectWithPrinter(JSTracer *trc, JSO
 {
     JS_ASSERT(trc);
     JS_ASSERT(&obj);
     JS_SET_TRACING_DETAILS(trc, printer, arg, index);
     Mark(trc, &obj);
 }
 
 void
+MarkScript(JSTracer *trc, JSScript *script, const char *name)
+{
+    JS_ASSERT(trc);
+    JS_ASSERT(script);
+    JS_SET_TRACING_NAME(trc, name);
+    Mark(trc, script);
+}
+
+void
 MarkShape(JSTracer *trc, const Shape *shape, const char *name)
 {
     JS_ASSERT(trc);
     JS_ASSERT(shape);
     JS_SET_TRACING_NAME(trc, name);
     Mark(trc, shape);
 }
 
@@ -218,17 +230,17 @@ MarkTypeObject(JSTracer *trc, types::Typ
      * only used for marking tracers; for tracers with a callback, if we
      * reenter through JS_TraceChildren then MarkChildren will *not* skip these
      * members, and we don't need to handle them here.
      */
     if (IS_GC_MARKING_TRACER(trc)) {
         if (type->singleton)
             MarkObject(trc, *type->singleton, "type_singleton");
         if (type->functionScript)
-            js_TraceScript(trc, type->functionScript, NULL);
+            MarkScript(trc, type->functionScript, "functionScript");
     }
 }
 
 #if JS_HAS_XML_SUPPORT
 void
 MarkXML(JSTracer *trc, JSXML *xml, const char *name)
 {
     JS_ASSERT(trc);
@@ -282,31 +294,46 @@ void
 PushMarkStack(GCMarker *gcmarker, JSShortString *thing)
 {
     JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
                      thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
 
     (void) thing->markIfUnmarked(gcmarker->getMarkColor());
 }
 
+void
+PushMarkStack(GCMarker *gcmarker, JSScript *thing)
+{
+    JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
+                 thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+
+    /*
+     * We mark scripts directly rather than pushing on the stack as they can
+     * refer to other scripts only indirectly (like via nested functions) and
+     * we cannot get to deep recursion.
+     */
+    if (thing->markIfUnmarked(gcmarker->getMarkColor()))
+        MarkChildren(gcmarker, thing);
+}
+
 static void
 ScanShape(GCMarker *gcmarker, const Shape *shape);
 
 void
 PushMarkStack(GCMarker *gcmarker, const Shape *thing)
 {
     JS_OPT_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
                      thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
 
     /* We mark shapes directly rather than pushing on the stack. */
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         ScanShape(gcmarker, thing);
 }
 
-void
+static void
 MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
 {
     for (uint32 i = 0; i < len; i++) {
         if (JSAtom *atom = vec[i]) {
             JS_SET_TRACING_INDEX(trc, name, i);
             if (!atom->isStaticAtom())
                 Mark(trc, atom);
         }
@@ -365,40 +392,41 @@ MarkIdRange(JSTracer *trc, jsid *beg, js
 
 void
 MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
 {
     MarkIdRange(trc, vec, vec + len, name);
 }
 
 void
-MarkKind(JSTracer *trc, void *thing, uint32 kind)
+MarkKind(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
     JS_ASSERT(thing);
     JS_ASSERT(kind == GetGCThingTraceKind(thing));
     switch (kind) {
-        case JSTRACE_OBJECT:
-            Mark(trc, reinterpret_cast<JSObject *>(thing));
-            break;
-        case JSTRACE_STRING:
-            MarkString(trc, reinterpret_cast<JSString *>(thing));
-            break;
-        case JSTRACE_SHAPE:
-            Mark(trc, reinterpret_cast<Shape *>(thing));
-            break;
-        case JSTRACE_TYPE_OBJECT:
-            Mark(trc, reinterpret_cast<types::TypeObject *>(thing));
-            break;
+      case JSTRACE_OBJECT:
+        Mark(trc, reinterpret_cast<JSObject *>(thing));
+        break;
+      case JSTRACE_STRING:
+        MarkString(trc, reinterpret_cast<JSString *>(thing));
+        break;
+      case JSTRACE_SCRIPT:
+        Mark(trc, static_cast<JSScript *>(thing));
+        break;
+      case JSTRACE_SHAPE:
+        Mark(trc, reinterpret_cast<Shape *>(thing));
+        break;
+      case JSTRACE_TYPE_OBJECT:
+        Mark(trc, reinterpret_cast<types::TypeObject *>(thing));
+        break;
 #if JS_HAS_XML_SUPPORT
-        case JSTRACE_XML:
-            Mark(trc, reinterpret_cast<JSXML *>(thing));
-            break;
+      case JSTRACE_XML:
+        Mark(trc, static_cast<JSXML *>(thing));
+        break;
 #endif
-        default:
-            JS_ASSERT(false);
     }
 }
 
 /* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
 void
 MarkValueRaw(JSTracer *trc, const js::Value &v)
 {
     if (v.isMarkable()) {
@@ -457,17 +485,17 @@ MarkShapeRange(JSTracer *trc, const Shap
 void
 MarkShapeRange(JSTracer *trc, size_t len, const Shape **vec, const char *name)
 {
     MarkShapeRange(trc, vec, vec + len, name);
 }
 
 /* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */
 void
-MarkGCThing(JSTracer *trc, void *thing, uint32 kind)
+MarkGCThing(JSTracer *trc, void *thing, JSGCTraceKind kind)
 {
     if (!thing)
         return;
 
     MarkKind(trc, thing, kind);
 }
 
 void
@@ -488,17 +516,17 @@ MarkGCThing(JSTracer *trc, void *thing, 
 void
 MarkGCThing(JSTracer *trc, void *thing, const char *name, size_t index)
 {
     JS_SET_TRACING_INDEX(trc, name, index);
     MarkGCThing(trc, thing);
 }
 
 void
-Mark(JSTracer *trc, void *thing, uint32 kind, const char *name)
+Mark(JSTracer *trc, void *thing, JSGCTraceKind kind, const char *name)
 {
     JS_ASSERT(thing);
     JS_SET_TRACING_NAME(trc, name);
     MarkKind(trc, thing, kind);
 }
 
 void
 MarkRoot(JSTracer *trc, JSObject *thing, const char *name)
@@ -508,16 +536,22 @@ MarkRoot(JSTracer *trc, JSObject *thing,
 
 void
 MarkRoot(JSTracer *trc, JSString *thing, const char *name)
 {
     MarkString(trc, thing, name);
 }
 
 void
+MarkRoot(JSTracer *trc, JSScript *thing, const char *name)
+{
+    MarkScript(trc, thing, name);
+}
+
+void
 MarkRoot(JSTracer *trc, const Shape *thing, const char *name)
 {
     MarkShape(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, types::TypeObject *thing, const char *name)
 {
@@ -563,29 +597,24 @@ PrintPropertyMethod(JSTracer *trc, char 
     if (n < bufsize)
         JS_snprintf(buf + n, bufsize - n, " method");
 }
 
 static inline void
 ScanValue(GCMarker *gcmarker, const Value &v)
 {
     if (v.isMarkable()) {
-        switch (v.gcKind()) {
-          case JSTRACE_STRING: {
+        JSGCTraceKind kind = v.gcKind();
+        if (kind == JSTRACE_STRING) {
             JSString *str = (JSString *)v.toGCThing();
             if (!str->isStaticAtom())
                 PushMarkStack(gcmarker, str);
-            break;
-          }
-          case JSTRACE_OBJECT:
+        } else {
+            JS_ASSERT(kind == JSTRACE_OBJECT);
             PushMarkStack(gcmarker, (JSObject *)v.toGCThing());
-            break;
-          case JSTRACE_XML:
-            PushMarkStack(gcmarker, (JSXML *)v.toGCThing());
-            break;
         }
     }
 }
 
 static void
 ScanShape(GCMarker *gcmarker, const Shape *shape)
 {
 restart:
@@ -787,16 +816,62 @@ MarkChildren(JSTracer *trc, JSString *st
         MarkString(trc, str->asDependent().base(), "base");
     } else if (str->isRope()) {
         JSRope &rope = str->asRope();
         MarkString(trc, rope.leftChild(), "left child");
         MarkString(trc, rope.rightChild(), "right child");
     }
 }
 
+
+void
+MarkChildren(JSTracer *trc, JSScript *script)
+{
+    CheckScript(script, NULL);
+
+#ifdef JS_CRASH_DIAGNOSTICS
+    JSRuntime *rt = trc->context->runtime;
+    JS_OPT_ASSERT_IF(rt->gcCheckCompartment, script->compartment() == rt->gcCheckCompartment);
+#endif
+    
+    MarkAtomRange(trc, script->natoms, script->atoms, "atoms");
+
+    if (JSScript::isValidOffset(script->objectsOffset)) {
+        JSObjectArray *objarray = script->objects();
+        MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
+    }
+
+    if (JSScript::isValidOffset(script->regexpsOffset)) {
+        JSObjectArray *objarray = script->regexps();
+        MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
+    }
+
+    if (JSScript::isValidOffset(script->constOffset)) {
+        JSConstArray *constarray = script->consts();
+        MarkValueRange(trc, constarray->length, constarray->vector, "consts");
+    }
+
+    if (!script->isCachedEval && script->u.object)
+        MarkObject(trc, *script->u.object, "object");
+    if (script->hasFunction)
+        MarkObject(trc, *script->function(), "script_fun");
+
+    if (IS_GC_MARKING_TRACER(trc) && script->filename)
+        js_MarkScriptFilename(script->filename);
+
+    script->bindings.trace(trc);
+
+#ifdef JS_METHODJIT
+    if (script->jitNormal)
+        script->jitNormal->trace(trc);
+    if (script->jitCtor)
+        script->jitCtor->trace(trc);
+#endif
+}
+
 void
 MarkChildren(JSTracer *trc, const Shape *shape)
 {
 restart:
     MarkId(trc, shape->propid, "propid");
 
     if (shape->hasGetterValue() && shape->getter())
         MarkObjectWithPrinter(trc, *shape->getterObject(), PrintPropertyGetterOrSetter, shape, 0);
@@ -833,17 +908,17 @@ ScanTypeObject(GCMarker *gcmarker, types
                 PushMarkStack(gcmarker, type->emptyShapes[i]);
         }
     }
 
     if (type->proto)
         PushMarkStack(gcmarker, type->proto);
 
     if (type->newScript) {
-        js_TraceScript(gcmarker, type->newScript->script, NULL);
+        PushMarkStack(gcmarker, type->newScript->script);
         PushMarkStack(gcmarker, type->newScript->shape);
     }
 
     /*
      * Don't need to trace singleton or functionScript, an object with this
      * type must have already been traced and it will also hold a reference
      * on the script (singleton and functionScript types cannot be the newType
      * of another object). Attempts to mark type objects directly must use
@@ -873,22 +948,22 @@ MarkChildren(JSTracer *trc, types::TypeO
 
     if (type->proto)
         MarkObject(trc, *type->proto, "type_proto");
 
     if (type->singleton)
         MarkObject(trc, *type->singleton, "type_singleton");
 
     if (type->newScript) {
-        js_TraceScript(trc, type->newScript->script, NULL);
+        MarkScript(trc, type->newScript->script, "type_new_script");
         MarkShape(trc, type->newScript->shape, "type_new_shape");
     }
 
     if (type->functionScript)
-        js_TraceScript(trc, type->functionScript, NULL);
+        MarkScript(trc, type->functionScript, "functionScript");
 }
 
 #ifdef JS_HAS_XML_SUPPORT
 void
 MarkChildren(JSTracer *trc, JSXML *xml)
 {
     js_TraceXML(trc, xml);
 }
@@ -931,38 +1006,45 @@ GCMarker::drainMarkStack()
     }
 
     rt->gcCheckCompartment = NULL;
 }
 
 } /* namespace js */
 
 JS_PUBLIC_API(void)
-JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
+JS_TraceChildren(JSTracer *trc, void *thing, uint32 kindIndex)
 {
+    JS_ASSERT(kindIndex <= JSTRACE_LAST);
+    JSGCTraceKind kind = JSGCTraceKind(kindIndex);
     switch (kind) {
-      case JSTRACE_OBJECT:
-	MarkChildren(trc, (JSObject *)thing);
+      default:
+        JS_ASSERT(kind == JSTRACE_OBJECT);
+	MarkChildren(trc, static_cast<JSObject *>(thing));
         break;
 
       case JSTRACE_STRING:
-	MarkChildren(trc, (JSString *)thing);
+	MarkChildren(trc, static_cast<JSString *>(thing));
+        break;
+
+      case JSTRACE_SCRIPT:
+	MarkChildren(trc, static_cast<JSScript *>(thing));
         break;
 
       case JSTRACE_SHAPE:
-	MarkChildren(trc, (js::Shape *)thing);
+	MarkChildren(trc, static_cast<Shape *>(thing));
         break;
 
       case JSTRACE_TYPE_OBJECT:
         MarkChildren(trc, (types::TypeObject *)thing);
         break;
 
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_XML:
-        MarkChildren(trc, (JSXML *)thing);
+        MarkChildren(trc, static_cast<JSXML *>(thing));
         break;
 #endif
     }
 }
 
 inline void
 JSObject::scanSlots(GCMarker *gcmarker)
 {
--- a/js/src/jsgcmark.h
+++ b/js/src/jsgcmark.h
@@ -69,28 +69,28 @@ MarkObject(JSTracer *trc, JSObject &obj,
 void
 MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name);
 
 void
 MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
 		      const void *arg, size_t index);
 
 void
+MarkScript(JSTracer *trc, JSScript *script, const char *name);
+
+void
 MarkShape(JSTracer *trc, const Shape *shape, const char *name);
 
 void
 MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name);
 
 void
 MarkXML(JSTracer *trc, JSXML *xml, const char *name);
 
 void
-MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name);
-
-void
 MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name);
 
 void
 MarkXMLRange(JSTracer *trc, size_t len, JSXML **vec, const char *name);
 
 void
 MarkId(JSTracer *trc, jsid id);
 
@@ -99,17 +99,17 @@ MarkId(JSTracer *trc, jsid id, const cha
 
 void
 MarkIdRange(JSTracer *trc, jsid *beg, jsid *end, const char *name);
 
 void
 MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
 
 void
-MarkKind(JSTracer *trc, void *thing, uint32 kind);
+MarkKind(JSTracer *trc, void *thing, JSGCTraceKind kind);
 
 void
 MarkValueRaw(JSTracer *trc, const js::Value &v);
 
 void
 MarkValue(JSTracer *trc, const js::Value &v, const char *name);
 
 /*
@@ -149,16 +149,19 @@ Mark(JSTracer *trc, void *thing, uint32 
 
 void
 MarkRoot(JSTracer *trc, JSObject *thing, const char *name);
 
 void
 MarkRoot(JSTracer *trc, JSString *thing, const char *name);
 
 void
+MarkRoot(JSTracer *trc, JSScript *thing, const char *name);
+
+void
 MarkRoot(JSTracer *trc, const Shape *thing, const char *name);
 
 void
 MarkRoot(JSTracer *trc, types::TypeObject *thing, const char *name);
 
 void
 MarkRoot(JSTracer *trc, JSXML *thing, const char *name);
 
@@ -167,14 +170,17 @@ MarkChildren(JSTracer *trc, JSObject *ob
 
 void
 MarkChildren(JSTracer *trc, JSString *str);
 
 void
 MarkChildren(JSTracer *trc, const Shape *shape);
 
 void
+MarkChildren(JSTracer *trc, JSScript *script);
+
+void
 MarkChildren(JSTracer *trc, JSXML *xml);
 
 }
 }
 
 #endif
--- a/js/src/jsgcstats.cpp
+++ b/js/src/jsgcstats.cpp
@@ -150,39 +150,44 @@ GCMarker::dumpConservativeRoots()
 
     conservativeStats.dump(fp);
 
     for (void **thingp = conservativeRoots.begin(); thingp != conservativeRoots.end(); ++thingp) {
         void *thing = thingp;
         fprintf(fp, "  %p: ", thing);
         
         switch (GetGCThingTraceKind(thing)) {
-          default:
-            JS_NOT_REACHED("Unknown trace kind");
-
           case JSTRACE_OBJECT: {
             JSObject *obj = (JSObject *) thing;
             fprintf(fp, "object %s", obj->getClass()->name);
             break;
           }
-          case JSTRACE_SHAPE: {
-            fprintf(fp, "shape");
-            break;
-          }
           case JSTRACE_STRING: {
             JSString *str = (JSString *) thing;
             if (str->isLinear()) {
                 char buf[50];
                 PutEscapedString(buf, sizeof buf, &str->asLinear(), '"');
                 fprintf(fp, "string %s", buf);
             } else {
                 fprintf(fp, "rope: length %d", (int)str->length());
             }
             break;
           }
+          case JSTRACE_SCRIPT: {
+            fprintf(fp, "shape");
+            break;
+          }
+          case JSTRACE_SHAPE: {
+            fprintf(fp, "shape");
+            break;
+          }
+          case JSTRACE_TYPE_OBJECT: {
+            fprintf(fp, "type_object");
+            break;
+          }
 # if JS_HAS_XML_SUPPORT
           case JSTRACE_XML: {
             JSXML *xml = (JSXML *) thing;
             fprintf(fp, "xml %u", (unsigned)xml->xml_class);
             break;
           }
 # endif
         }
@@ -253,33 +258,35 @@ GCTimer::finish(bool lastGC)
     if (startMark > 0) {
         double appTime = TIMEDIFF(getFirstEnter(), enter);
         double gcTime = TIMEDIFF(enter, end);
         double waitTime = TIMEDIFF(enter, startMark);
         double markTime = TIMEDIFF(startMark, startSweep);
         double sweepTime = TIMEDIFF(startSweep, sweepDestroyEnd);
         double sweepObjTime = TIMEDIFF(startSweep, sweepObjectEnd);
         double sweepStringTime = TIMEDIFF(sweepObjectEnd, sweepStringEnd);
-        double sweepShapeTime = TIMEDIFF(sweepStringEnd, sweepShapeEnd);
+        double sweepScriptTime = TIMEDIFF(sweepStringEnd, sweepScriptEnd);
+        double sweepShapeTime = TIMEDIFF(sweepScriptEnd, sweepShapeEnd);
         double destroyTime = TIMEDIFF(sweepShapeEnd, sweepDestroyEnd);
         double endTime = TIMEDIFF(sweepDestroyEnd, end);
 
 #if defined(JSGC_TESTPILOT)
         GCData &data = rt->gcData;
         size_t oldLimit = (data.start + data.count) % GCData::INFO_LIMIT;
         data.count += 1;
 
         JSGCInfo &info = data.info[oldLimit];
         info.appTime = appTime;
         info.gcTime = gcTime;
         info.waitTime = waitTime;
         info.markTime = markTime;
         info.sweepTime = sweepTime;
         info.sweepObjTime = sweepObjTime;
         info.sweepStringTime = sweepStringTime;
+        info.sweepScriptTime = sweepScriptTime;
         info.sweepShapeTime = sweepShapeTime;
         info.destroyTime = destroyTime;
         info.endTime = endTime;
         info.isCompartmental = isCompartmental;
 #endif
 
 #if defined(MOZ_GCTIMER)
         static FILE *gcFile;
@@ -292,30 +299,30 @@ GCTimer::finish(bool lastGC)
             } else if (!strcmp(gcTimerStatPath, "stderr")) {
                 gcFile = stderr;
                 fullFormat = false;
             } else {
                 gcFile = fopen(gcTimerStatPath, "a");
                 JS_ASSERT(gcFile);
                 fullFormat = true;
                 fprintf(gcFile, "     AppTime,  Total,   Wait,   Mark,  Sweep, FinObj,"
-                        " FinStr, SwShapes, Destroy,    End, +Chu, -Chu, T, Reason\n");
+                        " FinStr, SwScripts, SwShapes, Destroy,    End, +Chu, -Chu, T, Reason\n");
             }
         }
 
         if (!fullFormat) {
             fprintf(stderr, "%f %f %f\n",
                     TIMEDIFF(enter, end),
                     TIMEDIFF(startMark, startSweep),
                     TIMEDIFF(startSweep, sweepDestroyEnd));
         } else {
-            /*               App   , Tot  , Wai  , Mar  , Swe  , FiO  , FiS  , SwS  , Des   , End */
-            fprintf(gcFile, "%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %8.1f,  %6.1f, %6.1f, ",
+            /*               App   , Tot  , Wai  , Mar  , Swe  , FiO  , FiS  , SwScr , SwS  , Des   , End */
+            fprintf(gcFile, "%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %8.1f,  %6.1f, %6.1f, ",
                     appTime, gcTime, waitTime, markTime, sweepTime, sweepObjTime, sweepStringTime,
-                    sweepShapeTime, destroyTime, endTime);
+                    sweepScriptTime, sweepShapeTime, destroyTime, endTime);
             fprintf(gcFile, "%4d, %4d,", newChunkCount, destroyChunkCount);
             fprintf(gcFile, " %s, %s\n", isCompartmental ? "C" : "G", gcReasons[gcReason]);
         }
         fflush(gcFile);
         
         if (lastGC && gcFile != stdout && gcFile != stderr)
             fclose(gcFile);
 #endif
--- a/js/src/jsgcstats.h
+++ b/js/src/jsgcstats.h
@@ -44,17 +44,18 @@
 #endif
 
 #ifdef JSGC_TESTPILOT
 JS_BEGIN_EXTERN_C
 
 struct JSGCInfo
 {
     double appTime, gcTime, waitTime, markTime, sweepTime;
-    double sweepObjTime, sweepStringTime, sweepShapeTime, destroyTime, endTime;
+    double sweepObjTime, sweepStringTime, sweepScriptTime, sweepShapeTime;
+    double destroyTime, endTime;
     bool isCompartmental;
 };
 
 extern JS_PUBLIC_API(void)
 JS_SetGCInfoEnabled(JSRuntime *rt, bool enabled);
 
 extern JS_PUBLIC_API(bool)
 JS_GetGCInfoEnabled(JSRuntime *rt);
@@ -129,16 +130,17 @@ struct GCTimer
 {
     JSRuntime *rt;
 
     uint64 enter;
     uint64 startMark;
     uint64 startSweep;
     uint64 sweepObjectEnd;
     uint64 sweepStringEnd;
+    uint64 sweepScriptEnd;
     uint64 sweepShapeEnd;
     uint64 sweepDestroyEnd;
     uint64 end;
 
     bool isCompartmental;
     bool enabled; /* Disabled timers should cause no PRMJ calls. */
 
     GCTimer(JSRuntime *rt, JSCompartment *comp);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2058,26 +2058,24 @@ TypeCompartment::nukeTypes(JSContext *cx
     }
 
 #ifdef JS_METHODJIT
 
     JSCompartment *compartment = cx->compartment;
     mjit::ExpandInlineFrames(compartment);
 
     /* Throw away all JIT code in the compartment, but leave everything else alone. */
-    for (JSCList *cursor = compartment->scripts.next;
-         cursor != &compartment->scripts;
-         cursor = cursor->next) {
-        JSScript *script = reinterpret_cast<JSScript *>(cursor);
+
+    for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
         if (script->hasJITCode()) {
             mjit::Recompiler recompiler(cx, script);
             recompiler.recompile();
         }
     }
-
 #endif /* JS_METHODJIT */
 
 }
 
 void
 TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
 {
 #ifdef JS_METHODJIT
@@ -2135,80 +2133,56 @@ TypeCompartment::monitorBytecode(JSConte
 
     cx->compartment->types.addPendingRecompile(cx, script);
 
     /* Trigger recompilation of any inline callers. */
     if (script->hasFunction && !script->function()->hasLazyType())
         ObjectStateChange(cx, script->function()->type(), false, true);
 }
 
-/*
- * State for keeping track of which property type sets contain an object we are
- * scrubbing from all properties in the compartment. We make a list of
- * properties to update and fix them afterwards, as adding types can't be done
- * with the GC locked (as is done in IterateCells), and can potentially make
- * new type objects as well.
- */
-struct MarkSetsUnknownState
-{
-    TypeObject *target;
-    Vector<TypeSet *> pending;
-
-    MarkSetsUnknownState(JSContext *cx, TypeObject *target)
-        : target(target), pending(cx)
-    {}
-};
-
-static void
-MarkObjectSetsUnknownCallback(JSContext *cx, void *data, void *thing,
-                              size_t traceKind, size_t thingSize)
-{
-    MarkSetsUnknownState *state = (MarkSetsUnknownState *) data;
-    TypeObject *object = (TypeObject *) thing;
-
-    unsigned count = object->getPropertyCount();
-    for (unsigned i = 0; i < count; i++) {
-        Property *prop = object->getProperty(i);
-        if (prop && prop->types.hasType(Type::ObjectType(state->target))) {
-            if (!state->pending.append(&prop->types))
-                cx->compartment->types.setPendingNukeTypes(cx);
-        }
-    }
-}
-
 void
 TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
 {
     JS_ASSERT(this == &cx->compartment->types);
     JS_ASSERT(!(target->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
     JS_ASSERT(!target->singleton);
     JS_ASSERT(target->unknownProperties());
     target->flags |= OBJECT_FLAG_SETS_MARKED_UNKNOWN;
 
     AutoEnterTypeInference enter(cx);
 
     /*
      * Mark both persistent and transient type sets which contain obj as having
      * a generic object type. It is not sufficient to mark just the persistent
      * sets, as analysis of individual opcodes can pull type objects from
      * static information (like initializer objects at various offsets).
+     * 
+     * We make a list of properties to update and fix them afterwards, as adding
+     * types can't be done while iterating over cells as it can potentially make
+     * new type objects as well or trigger GC.
      */
-
-    MarkSetsUnknownState state(cx, target);
-
-    IterateCells(cx, cx->compartment, gc::FINALIZE_TYPE_OBJECT,
-                 (void *) &state, MarkObjectSetsUnknownCallback);
-
-    for (unsigned i = 0; i < state.pending.length(); i++)
-        state.pending[i]->addType(cx, Type::AnyObjectType());
-
-    for (JSCList *cursor = cx->compartment->scripts.next;
-         cursor != &cx->compartment->scripts;
-         cursor = cursor->next) {
-        JSScript *script = reinterpret_cast<JSScript *>(cursor);
+    Vector<TypeSet *> pending(cx);
+    for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
+        TypeObject *object = i.get<TypeObject>();
+
+        unsigned count = object->getPropertyCount();
+        for (unsigned i = 0; i < count; i++) {
+            Property *prop = object->getProperty(i);
+            if (prop && prop->types.hasType(Type::ObjectType(target))) {
+                if (!pending.append(&prop->types))
+                    cx->compartment->types.setPendingNukeTypes(cx);
+            }
+        }
+    }
+
+    for (unsigned i = 0; i < pending.length(); i++)
+        pending[i]->addType(cx, Type::AnyObjectType());
+
+    for (gc::CellIter i(cx, cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
         if (script->types) {
             unsigned count = TypeScript::NumTypeSets(script);
             TypeSet *typeArray = script->types->typeArray();
             for (unsigned i = 0; i < count; i++) {
                 if (typeArray[i].hasType(Type::ObjectType(target)))
                     typeArray[i].addType(cx, Type::AnyObjectType());
             }
         }
@@ -2301,42 +2275,49 @@ ScriptAnalysis::addSingletonTypeBarrier(
     TypeBarrier *barrier =
         ArenaNew<TypeBarrier>(cx->compartment->pool, target, Type::UndefinedType(),
                               singleton, singletonId);
 
     barrier->next = code.typeBarriers;
     code.typeBarriers = barrier;
 }
 
+static void
+PrintScriptTypeCallback(JSContext *cx, void *data, void *thing,
+                        JSGCTraceKind traceKind, size_t thingSize)
+{
+    JS_ASSERT(!data);
+    JS_ASSERT(traceKind == JSTRACE_SCRIPT);
+    JSScript *script = static_cast<JSScript *>(thing);
+    if (script->hasAnalysis() && script->analysis()->ranInference())
+        script->analysis()->printTypes(cx);
+}
+
 #ifdef DEBUG
 static void
 PrintObjectCallback(JSContext *cx, void *data, void *thing,
-                    size_t traceKind, size_t thingSize)
+                    JSGCTraceKind traceKind, size_t thingSize)
 {
+    JS_ASSERT(traceKind == JSTRACE_OBJECT);
     TypeObject *object = (TypeObject *) thing;
     object->print(cx);
 }
 #endif
 
 void
 TypeCompartment::print(JSContext *cx, bool force)
 {
     JSCompartment *compartment = this->compartment();
 
-    if (JS_CLIST_IS_EMPTY(&compartment->scripts))
-        return;
-
     if (!force && !InferSpewActive(ISpewResult))
         return;
 
-    for (JSScript *script = (JSScript *)compartment->scripts.next;
-         &script->links != &compartment->scripts;
-         script = (JSScript *)script->links.next) {
-        if (script->hasAnalysis() && script->analysis()->ranInference())
-            script->analysis()->printTypes(cx);
+    {
+        AutoUnlockGC unlock(cx->runtime);
+        IterateCells(cx, compartment, gc::FINALIZE_SCRIPT, cx, PrintScriptTypeCallback);
     }
 
 #ifdef DEBUG
     {
         AutoUnlockGC unlock(cx->runtime);
         IterateCells(cx, compartment, gc::FINALIZE_TYPE_OBJECT, NULL, PrintObjectCallback);
     }
 #endif
@@ -4471,17 +4452,17 @@ CheckNewScriptProperties(JSContext *cx, 
 /////////////////////////////////////////////////////////////////////
 // Printing
 /////////////////////////////////////////////////////////////////////
 
 void
 ScriptAnalysis::printTypes(JSContext *cx)
 {
     AutoEnterAnalysis enter(cx);
-    TypeCompartment *compartment = &script->compartment->types;
+    TypeCompartment *compartment = &script->compartment()->types;
 
     /*
      * Check if there are warnings for used values with unknown types, and build
      * statistics about the size of type sets found for stack values.
      */
     for (unsigned offset = 0; offset < script->length; offset++) {
         if (!maybeCode(offset))
             continue;
@@ -5009,17 +4990,16 @@ JSScript::typeSetFunction(JSContext *cx,
     if (singleton) {
         if (!fun->setSingletonType(cx))
             return false;
     } else {
         TypeObject *type = cx->compartment->types.newTypeObject(cx, this,
                                                                 JSProto_Function, fun->getProto());
         if (!type)
             return false;
-        AutoTypeRooter root(cx, type);
 
         fun->setType(type);
         type->functionScript = this;
     }
 
     return true;
 }
 
@@ -5529,17 +5509,17 @@ TypeCompartment::~TypeCompartment()
 
     if (allocationSiteTable)
         Foreground::delete_(allocationSiteTable);
 }
 
 /* static */ void
 TypeScript::Sweep(JSContext *cx, JSScript *script)
 {
-    JSCompartment *compartment = script->compartment;
+    JSCompartment *compartment = script->compartment();
     JS_ASSERT(compartment->types.inferenceEnabled);
 
     unsigned num = NumTypeSets(script);
     TypeSet *typeArray = script->types->typeArray();
 
     if (script->isAboutToBeFinalized(cx)) {
         /* Release all memory associated with the persistent type sets. */
         for (unsigned i = 0; i < num; i++)
@@ -5615,17 +5595,17 @@ TypeObject::dynamicSize()
 }
 
 static void
 GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats)
 {
     if (!script->types)
         return;
 
-    if (!script->compartment->types.inferenceEnabled) {
+    if (!script->compartment()->types.inferenceEnabled) {
         stats->scripts += sizeof(TypeScript);
         return;
     }
 
     unsigned count = TypeScript::NumTypeSets(script);
     stats->scripts += sizeof(TypeScript) + count * sizeof(TypeSet);
 
     TypeResult *result = script->types->dynamicList;
@@ -5651,22 +5631,18 @@ JS_GetTypeInferenceMemoryStats(JSContext
      * by being copied to the replacement pool. This memory will be counted too
      * and deducted from the amount of temporary data.
      */
     stats->temporary += ArenaAllocatedSize(compartment->pool);
 
     /* Pending arrays are cleared on GC along with the analysis pool. */
     stats->temporary += sizeof(TypeCompartment::PendingWork) * compartment->types.pendingCapacity;
 
-    for (JSCList *cursor = compartment->scripts.next;
-         cursor != &compartment->scripts;
-         cursor = cursor->next) {
-        JSScript *script = reinterpret_cast<JSScript *>(cursor);
-        GetScriptMemoryStats(script, stats);
-    }
+    for (gc::CellIter i(cx, compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next())
+        GetScriptMemoryStats(i.get<JSScript>(), stats);
 
     if (compartment->types.allocationSiteTable)
         stats->tables += compartment->types.allocationSiteTable->allocatedSize();
 
     if (compartment->types.arrayTypeTable)
         stats->tables += compartment->types.arrayTypeTable->allocatedSize();
 
     if (compartment->types.objectTypeTable) {
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1211,33 +1211,16 @@ TypeObject::setFlagsFromKey(JSContext *c
               | OBJECT_FLAG_NON_PACKED_ARRAY;
         break;
     }
 
     if (!hasAllFlags(flags))
         setFlags(cx, flags);
 }
 
-class AutoTypeRooter : private AutoGCRooter {
-  public:
-    AutoTypeRooter(JSContext *cx, TypeObject *type
-                   JS_GUARD_OBJECT_NOTIFIER_PARAM)
-      : AutoGCRooter(cx, TYPE), type(type)
-    {
-        JS_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    friend void AutoGCRooter::trace(JSTracer *trc);
-    friend void MarkRuntime(JSTracer *trc);
-
-  private:
-    TypeObject *type;
-    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 } } /* namespace js::types */
 
 inline bool
 JSScript::isAboutToBeFinalized(JSContext *cx)
 {
     return isCachedEval ||
         (u.object && IsAboutToBeFinalized(cx, u.object)) ||
         (hasFunction && IsAboutToBeFinalized(cx, function()));
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -105,19 +105,16 @@
 #if defined(JS_METHODJIT) && defined(JS_MONOIC)
 #include "methodjit/MonoIC.h"
 #endif
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
-/* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */
-#if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___
-
 JSObject *
 js::GetScopeChain(JSContext *cx)
 {
     /*
      * Note: we don't need to expand inline frames here, because frames are
      * only inlined when the caller and callee share the same scope chain.
      */
     StackFrame *fp = js_GetTopStackFrame(cx, FRAME_EXPAND_NONE);
@@ -912,17 +909,16 @@ ExecuteKernel(JSContext *cx, JSScript *s
 
     if (script->isEmpty()) {
         if (result)
             result->setUndefined();
         return true;
     }
 
     LeaveTrace(cx);
-    AutoScriptRooter root(cx, script);
 
     ExecuteFrameGuard efg;
     if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
         return false;
 
     /* Give strict mode eval its own fresh lexical environment. */
     StackFrame *fp = efg.fp();
     if (fp->isStrictEvalFrame() && !CreateEvalCallObject(cx, fp))
@@ -1317,17 +1313,17 @@ ValueToId(JSContext *cx, const Value &v,
 }
 
 } /* namespace js */
 
 /*
  * Enter the new with scope using an object at sp[-1] and associate the depth
  * of the with block with sp + stackIndex.
  */
-JS_STATIC_INTERPRET JS_REQUIRES_STACK JSBool
+JS_REQUIRES_STACK JSBool
 js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen)
 {
     StackFrame *fp = cx->fp();
     Value *sp = cx->regs().sp;
     JS_ASSERT(stackIndex < 0);
     JS_ASSERT(fp->base() <= sp + stackIndex);
 
     JSObject *obj;
@@ -1352,17 +1348,17 @@ js_EnterWith(JSContext *cx, jsint stackI
                                          sp + stackIndex - fp->base());
     if (!withobj)
         return JS_FALSE;
 
     fp->setScopeChainNoCallObj(*withobj);
     return JS_TRUE;
 }
 
-JS_STATIC_INTERPRET JS_REQUIRES_STACK void
+JS_REQUIRES_STACK void
 js_LeaveWith(JSContext *cx)
 {
     JSObject *withobj;
 
     withobj = &cx->fp()->scopeChain();
     JS_ASSERT(withobj->getClass() == &js_WithClass);
     JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
     JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
@@ -1408,17 +1404,17 @@ js_UnwindScope(JSContext *cx, jsint stac
             js_LeaveWith(cx);
         }
     }
 
     cx->regs().sp = fp->base() + stackDepth;
     return normalUnwind;
 }
 
-JS_STATIC_INTERPRET JSBool
+JSBool
 js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, Value *vp, Value *vp2)
 {
     if (cs->format & JOF_POST) {
         double d;
         if (!ToNumber(cx, *vp, &d))
             return JS_FALSE;
         vp->setNumber(d);
         (cs->format & JOF_INC) ? ++d : --d;
@@ -1470,20 +1466,16 @@ js::FindUpvarFrame(JSContext *cx, uintN 
         JS_ASSERT(fp && fp->isScriptFrame());
         if (fp->script()->staticLevel == targetLevel)
             break;
         fp = fp->prev();
     }
     return fp;
 }
 
-#endif /* !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___ */
-
-#ifndef  jsinvoke_cpp___
-
 #define PUSH_COPY(v)             do { *regs.sp++ = v; assertSameCompartment(cx, regs.sp[-1]); } while (0)
 #define PUSH_COPY_SKIP_CHECK(v)  *regs.sp++ = v
 #define PUSH_NULL()              regs.sp++->setNull()
 #define PUSH_UNDEFINED()         regs.sp++->setUndefined()
 #define PUSH_BOOLEAN(b)          regs.sp++->setBoolean(b)
 #define PUSH_DOUBLE(d)           regs.sp++->setDouble(d)
 #define PUSH_INT32(i)            regs.sp++->setInt32(i)
 #define PUSH_STRING(s)           do { regs.sp++->setString(s); assertSameCompartment(cx, regs.sp[-1]); } while (0)
@@ -1858,24 +1850,23 @@ Interpret(JSContext *cx, StackFrame *ent
 
 #define ENABLE_INTERRUPTS() (interruptEnabler.enableInterrupts())
 
 #define LOAD_ATOM(PCOFF, atom)                                                \
     JS_BEGIN_MACRO                                                            \
         JS_ASSERT(regs.fp()->hasImacropc()                                    \
                   ? atoms == rt->atomState.commonAtomsStart() &&              \
                     GET_INDEX(regs.pc + PCOFF) < js_common_atom_count         \
-                  : (size_t)(atoms - script->atomMap.vector) <                \
-                    (size_t)(script->atomMap.length -                         \
-                             GET_INDEX(regs.pc + PCOFF)));                    \
+                  : (size_t)(atoms - script->atoms) <                         \
+                    (size_t)(script->natoms - GET_INDEX(regs.pc + PCOFF)));   \
         atom = atoms[GET_INDEX(regs.pc + PCOFF)];                             \
     JS_END_MACRO
 
 #define GET_FULL_INDEX(PCOFF)                                                 \
-    (atoms - script->atomMap.vector + GET_INDEX(regs.pc + (PCOFF)))
+    (atoms - script->atoms + GET_INDEX(regs.pc + (PCOFF)))
 
 #define LOAD_OBJECT(PCOFF, obj)                                               \
     (obj = script->getObject(GET_FULL_INDEX(PCOFF)))
 
 #define LOAD_FUNCTION(PCOFF)                                                  \
     (fun = script->getFunction(GET_FULL_INDEX(PCOFF)))
 
 #define LOAD_DOUBLE(PCOFF, dbl)                                               \
@@ -2037,17 +2028,17 @@ Interpret(JSContext *cx, StackFrame *ent
 
     /*
      * Initialize the index segment register used by LOAD_ATOM and
      * GET_FULL_INDEX macros below. As a register we use a pointer based on
      * the atom map to turn frequently executed LOAD_ATOM into simple array
      * access. For less frequent object and regexp loads we have to recover
      * the segment from atoms pointer first.
      */
-    JSAtom **atoms = script->atomMap.vector;
+    JSAtom **atoms = script->atoms;
 
 #if JS_HAS_GENERATORS
     if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
         JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
         JS_ASSERT((size_t) (regs.sp - regs.fp()->base()) <= StackDepth(script));
 
         /*
          * To support generator_throw and to catch ignored exceptions,
@@ -2445,17 +2436,17 @@ BEGIN_CASE(JSOP_STOP)
         JS_ASSERT(op == JSOP_STOP);
         JS_ASSERT((uintN)(regs.sp - regs.fp()->slots()) <= script->nslots);
         jsbytecode *imacpc = regs.fp()->imacropc();
         regs.pc = imacpc + js_CodeSpec[*imacpc].length;
         if (js_CodeSpec[*imacpc].format & JOF_DECOMPOSE)
             regs.pc += GetDecomposeLength(imacpc, js_CodeSpec[*imacpc].length);
         regs.fp()->clearImacropc();
         LEAVE_ON_SAFE_POINT();
-        atoms = script->atomMap.vector;
+        atoms = script->atoms;
         op = JSOp(*regs.pc);
         DO_OP();
     }
 #endif
 
     interpReturnOK = true;
     if (entryFrame != regs.fp())
   inline_return:
@@ -4361,31 +4352,31 @@ BEGIN_CASE(JSOP_INT8)
 END_CASE(JSOP_INT8)
 
 BEGIN_CASE(JSOP_INT32)
     PUSH_INT32(GET_INT32(regs.pc));
 END_CASE(JSOP_INT32)
 
 BEGIN_CASE(JSOP_INDEXBASE)
     /*
-     * Here atoms can exceed script->atomMap.length as we use atoms as a
+     * Here atoms can exceed script->natoms as we use atoms as a
      * segment register for object literals as well.
      */
     atoms += GET_INDEXBASE(regs.pc);
 END_CASE(JSOP_INDEXBASE)
 
 BEGIN_CASE(JSOP_INDEXBASE1)
 BEGIN_CASE(JSOP_INDEXBASE2)
 BEGIN_CASE(JSOP_INDEXBASE3)
     atoms += (op - JSOP_INDEXBASE1 + 1) << 16;
 END_CASE(JSOP_INDEXBASE3)
 
 BEGIN_CASE(JSOP_RESETBASE0)
 BEGIN_CASE(JSOP_RESETBASE)
-    atoms = script->atomMap.vector;
+    atoms = script->atoms;
 END_CASE(JSOP_RESETBASE)
 
 BEGIN_CASE(JSOP_DOUBLE)
 {
     JS_ASSERT(!regs.fp()->hasImacropc());
     double dbl;
     LOAD_DOUBLE(0, dbl);
     PUSH_DOUBLE(dbl);
@@ -4537,17 +4528,17 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
     off = JUMP_OFFSET_LEN;
 
   do_lookup_switch:
     /*
      * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if any atom
      * index in it would exceed 64K limit.
      */
     JS_ASSERT(!regs.fp()->hasImacropc());
-    JS_ASSERT(atoms == script->atomMap.vector);
+    JS_ASSERT(atoms == script->atoms);
     jsbytecode *pc2 = regs.pc;
 
     Value lval = regs.sp[-1];
     regs.sp--;
 
     if (!lval.isPrimitive())
         goto end_lookup_switch;
 
@@ -5501,26 +5492,26 @@ BEGIN_CASE(JSOP_SHARPINIT)
 }
 END_CASE(JSOP_SHARPINIT)
 
 #endif /* JS_HAS_SHARP_VARS */
 
 {
 BEGIN_CASE(JSOP_GOSUB)
     PUSH_BOOLEAN(false);
-    jsint i = (regs.pc - script->main) + JSOP_GOSUB_LENGTH;
+    jsint i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH;
     PUSH_INT32(i);
     len = GET_JUMP_OFFSET(regs.pc);
 END_VARLEN_CASE
 }
 
 {
 BEGIN_CASE(JSOP_GOSUBX)
     PUSH_BOOLEAN(false);
-    jsint i = (regs.pc - script->main) + JSOP_GOSUBX_LENGTH;
+    jsint i = (regs.pc - script->code) + JSOP_GOSUBX_LENGTH;
     len = GET_JUMPX_OFFSET(regs.pc);
     PUSH_INT32(i);
 END_VARLEN_CASE
 }
 
 {
 BEGIN_CASE(JSOP_RETSUB)
     /* Pop [exception or hole, retsub pc-index]. */
@@ -5535,17 +5526,17 @@ BEGIN_CASE(JSOP_RETSUB)
          * be necessary, but it seems clearer.  And it points out a FIXME:
          * 350509, due to Igor Bukanov.
          */
         cx->setPendingException(rval);
         goto error;
     }
     JS_ASSERT(rval.isInt32());
     len = rval.toInt32();
-    regs.pc = script->main;
+    regs.pc = script->code;
 END_VARLEN_CASE
 }
 
 BEGIN_CASE(JSOP_EXCEPTION)
     PUSH_COPY(cx->getPendingException());
     cx->clearPendingException();
 #if defined(JS_TRACER) && defined(JS_METHODJIT)
     if (interpMode == JSINTERP_PROFILE) {
@@ -6164,17 +6155,17 @@ END_CASE(JSOP_ARRAYPUSH)
         /* This is an error, not a catchable exception, quit the frame ASAP. */
         interpReturnOK = JS_FALSE;
     } else {
         JSThrowHook handler;
         JSTryNote *tn, *tnlimit;
         uint32 offset;
 
         /* Restore atoms local in case we will resume. */
-        atoms = script->atomMap.vector;
+        atoms = script->atoms;
 
         /* Call debugger throw hook if set. */
         if (cx->debugHooks->throwHook || !cx->compartment->getDebuggees().empty()) {
             Value rval;
             JSTrapStatus st = Debugger::onExceptionUnwind(cx, &rval);
             if (st == JSTRAP_CONTINUE) {
                 handler = cx->debugHooks->throwHook;
                 if (handler)
@@ -6199,17 +6190,17 @@ END_CASE(JSOP_ARRAYPUSH)
         }
 
         /*
          * Look for a try block in script that can catch this exception.
          */
         if (!JSScript::isValidOffset(script->trynotesOffset))
             goto no_catch;
 
-        offset = (uint32)(regs.pc - script->main);
+        offset = (uint32)(regs.pc - script->main());
         tn = script->trynotes()->vector;
         tnlimit = tn + script->trynotes()->length;
         do {
             if (offset - tn->start >= tn->length)
                 continue;
 
             /*
              * We have a note that covers the exception pc but we must check
@@ -6233,17 +6224,17 @@ END_CASE(JSOP_ARRAYPUSH)
             if (tn->stackDepth > regs.sp - regs.fp()->base())
                 continue;
 
             /*
              * Set pc to the first bytecode after the the try note to point
              * to the beginning of catch or finally or to [enditer] closing
              * the for-in loop.
              */
-            regs.pc = (script)->main + tn->start + tn->length;
+            regs.pc = (script)->main() + tn->start + tn->length;
 
             JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
             JS_ASSERT(regs.sp == regs.fp()->base() + tn->stackDepth);
             if (!ok) {
                 /*
                  * Restart the handler search with updated pc and stack depth
                  * to properly notify the debugger.
                  */
@@ -6366,10 +6357,8 @@ END_CASE(JSOP_ARRAYPUSH)
         JSAutoByteString printable;
         if (js_AtomToPrintableString(cx, atomNotDefined, &printable))
             js_ReportIsNotDefined(cx, printable.ptr());
     }
     goto error;
 }
 
 } /* namespace js */
-
-#endif /* !defined jsinvoke_cpp___ */
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -357,56 +357,31 @@ class InterpreterFrames {
   private:
     JSContext *context;
     FrameRegs *regs;
     const InterruptEnablerBase &enabler;
 };
 
 } /* namespace js */
 
-/*
- * JS_LONE_INTERPRET indicates that the compiler should see just the code for
- * the js_Interpret function when compiling jsinterp.cpp. The rest of the code
- * from the file should be visible only when compiling jsinvoke.cpp. It allows
- * platform builds to optimize selectively js_Interpret when the granularity
- * of the optimizations with the given compiler is a compilation unit.
- *
- * JS_STATIC_INTERPRET is the modifier for functions defined in jsinterp.cpp
- * that only js_Interpret calls. When JS_LONE_INTERPRET is true all such
- * functions are declared below.
- */
-#ifndef JS_LONE_INTERPRET
-# ifdef _MSC_VER
-#  define JS_LONE_INTERPRET 0
-# else
-#  define JS_LONE_INTERPRET 1
-# endif
-#endif
-
-#if !JS_LONE_INTERPRET
-# define JS_STATIC_INTERPRET    static
-#else
-# define JS_STATIC_INTERPRET
-
 extern JS_REQUIRES_STACK JSBool
 js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen);
 
 extern JS_REQUIRES_STACK void
 js_LeaveWith(JSContext *cx);
 
 /*
  * Find the results of incrementing or decrementing *vp. For pre-increments,
  * both *vp and *vp2 will contain the result on return. For post-increments,
  * vp will contain the original value converted to a number and vp2 will get
  * the result. Both vp and vp2 must be roots.
  */
 extern JSBool
 js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, js::Value *vp, js::Value *vp2);
 
-#endif /* JS_LONE_INTERPRET */
 /*
  * Unwind block and scope chains to match the given depth. The function sets
  * fp->sp on return to stackDepth.
  */
 extern JS_REQUIRES_STACK JSBool
 js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind);
 
 extern JSBool
deleted file mode 100644
--- a/js/src/jsinvoke.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla SpiderMonkey JavaScript 1.8 code, released
- * March 4, 2008.
- *
- * The Initial Developer of the Original Code is
- *   Igor Bukanov <igor@mir2.org>
- *
- * Contributor(s):
- *   Brendan Eich <brendan@mozilla.org
- *
- * 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 ***** */
-
-#define jsinvoke_cpp___
-
-#include "jsinterp.cpp"
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -979,17 +979,17 @@ EvalCacheHash(JSContext *cx, JSLinearStr
     if (n > 100)
         n = 100;
     uint32 h;
     for (h = 0; n; s++, n--)
         h = JS_ROTATE_LEFT32(h, 4) ^ *s;
 
     h *= JS_GOLDEN_RATIO;
     h >>= 32 - JS_EVAL_CACHE_SHIFT;
-    return &JS_SCRIPTS_TO_GC(cx)[h];
+    return &cx->compartment->evalCache[h];
 }
 
 static JS_ALWAYS_INLINE JSScript *
 EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN staticLevel,
                 JSPrincipals *principals, JSObject &scopeobj, JSScript **bucket)
 {
     /*
      * Cache local eval scripts indexed by source qualified by scope.
@@ -1027,17 +1027,17 @@ EvalCacheLookup(JSContext *cx, JSLinearS
              */
             JSFunction *fun = script->getCallerFunction();
 
             if (fun == caller->fun()) {
                 /*
                  * Get the source string passed for safekeeping in the
                  * atom map by the prior eval to Compiler::compileScript.
                  */
-                JSAtom *src = script->atomMap.vector[0];
+                JSAtom *src = script->atoms[0];
 
                 if (src == str || EqualStrings(src, str)) {
                     /*
                      * Source matches, qualify by comparing scopeobj to the
                      * COMPILE_N_GO-memoized parent of the first literal
                      * function or regexp object if any. If none, then this
                      * script has no compiled-in dependencies on the prior
                      * eval's scopeobj.
@@ -1051,41 +1051,41 @@ EvalCacheLookup(JSContext *cx, JSLinearS
                             i = 0;
                         } else {
                             i = -1;
                         }
                     }
                     if (i < 0 ||
                         objarray->vector[i]->getParent() == &scopeobj) {
                         JS_ASSERT(staticLevel == script->staticLevel);
-                        *scriptp = script->u.nextToGC;
-                        script->u.nextToGC = NULL;
+                        *scriptp = script->u.evalHashLink;
+                        script->u.evalHashLink = NULL;
                         return script;
                     }
                 }
             }
         }
 
         if (++count == EVAL_CACHE_CHAIN_LIMIT)
             return NULL;
-        scriptp = &script->u.nextToGC;
+        scriptp = &script->u.evalHashLink;
     }
     return NULL;
 }
 
 /*
  * There are two things we want to do with each script executed in EvalKernel:
  *  1. notify jsdbgapi about script creation/destruction
  *  2. add the script to the eval cache when EvalKernel is finished
  *
  * NB: Although the eval cache keeps a script alive wrt to the JS engine, from
  * a jsdbgapi user's perspective, we want each eval() to create and destroy a
  * script. This hides implementation details and means we don't have to deal
  * with calls to JS_GetScriptObject for scripts in the eval cache (currently,
- * script->u.object aliases script->u.nextToGC).
+ * script->u.object aliases script->u.evalHashLink).
  */
 class EvalScriptGuard
 {
     JSContext *cx_;
     JSLinearString *str_;
     JSScript **bucket_;
     JSScript *script_;
 
@@ -1097,21 +1097,18 @@ class EvalScriptGuard
         bucket_ = EvalCacheHash(cx, str);
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             js_CallDestroyScriptHook(cx_, script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
-            script_->u.nextToGC = *bucket_;
+            script_->u.evalHashLink = *bucket_;
             *bucket_ = script_;
-#ifdef CHECK_SCRIPT_OWNER
-            script_->owner = NULL;
-#endif
         }
     }
 
     void lookupInEvalCache(StackFrame *caller, uintN staticLevel,
                            JSPrincipals *principals, JSObject &scopeobj) {
         if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
                                               principals, scopeobj, bucket_)) {
             js_CallNewScriptHook(cx_, found, NULL);
@@ -5573,22 +5570,18 @@ js_NativeGetInline(JSContext *cx, JSObje
         return true;
 
     if (JS_UNLIKELY(shape->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER)) {
         JS_ASSERT(shape->methodObject() == vp->toObject());
         return true;
     }
 
     sample = cx->runtime->propertyRemovals;
-    {
-        AutoShapeRooter tvr(cx, shape);
-        AutoObjectRooter tvr2(cx, pobj);
-        if (!shape->get(cx, receiver, obj, pobj, vp))
-            return false;
-    }
+    if (!shape->get(cx, receiver, obj, pobj, vp))
+        return false;
 
     if (pobj->containsSlot(slot) &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
          pobj->nativeContains(*shape))) {
         if (!pobj->methodWriteBarrier(cx, *shape, *vp))
             return false;
         pobj->nativeSetSlot(slot, *vp);
     }
@@ -5641,24 +5634,21 @@ js_NativeSet(JSContext *cx, JSObject *ob
          * not writable, so attempting to set such a property should do nothing
          * or throw if we're in strict mode.
          */
         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
             return js_ReportGetterOnlyAssignment(cx);
     }
 
     sample = cx->runtime->propertyRemovals;
-    {
-        AutoShapeRooter tvr(cx, shape);
-        if (!shape->set(cx, obj, strict, vp))
-            return false;
-
-        JS_ASSERT_IF(!obj->inDictionaryMode(), shape->slot == slot);
-        slot = shape->slot;
-    }
+    if (!shape->set(cx, obj, strict, vp))
+        return false;
+    
+    JS_ASSERT_IF(!obj->inDictionaryMode(), shape->slot == slot);
+    slot = shape->slot;
 
     if (obj->containsSlot(slot) &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
          obj->nativeContains(*shape))) {
         if (!added) {
             AbortRecordingIfUnexpectedGlobalWrite(cx, obj, slot);
             if (!obj->methodWriteBarrier(cx, *shape, *vp))
                 return false;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1127,16 +1127,19 @@ struct JSObject : js::gc::Cell {
     inline JSFunction *getFunctionPrivate() const;
 
     inline js::Value *getFlatClosureUpvars() const;
     inline js::Value getFlatClosureUpvar(uint32 i) const;
     inline const js::Value &getFlatClosureUpvar(uint32 i);
     inline void setFlatClosureUpvar(uint32 i, const js::Value &v);
     inline void setFlatClosureUpvars(js::Value *upvars);
 
+    /* See comments in fun_finalize. */
+    inline void finalizeUpvarsIfFlatClosure();
+
     inline bool hasMethodObj(const JSObject& obj) const;
     inline void setMethodObj(JSObject& obj);
 
     inline bool initBoundFunction(JSContext *cx, const js::Value &thisArg,
                                   const js::Value *args, uintN argslen);
 
     inline JSObject *getBoundFunctionTarget() const;
     inline const js::Value &getBoundFunctionThis() const;
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -650,16 +650,47 @@ JSObject::getFlatClosureUpvars() const
 #ifdef DEBUG
     JSFunction *fun = getFunctionPrivate();
     JS_ASSERT(fun->isFlatClosure());
     JS_ASSERT(fun->script()->bindings.countUpvars() == fun->script()->upvars()->length);
 #endif
     return (js::Value *) getFixedSlot(JSSLOT_FLAT_CLOSURE_UPVARS).toPrivate();
 }
 
+inline void
+JSObject::finalizeUpvarsIfFlatClosure()
+{
+    /*
+     * Cloned function objects may be flat closures with upvars to free.
+     *
+     * We do not record in the closure objects any flags. Rather we use flags
+     * stored in the compiled JSFunction that we get via getFunctionPrivate()
+     * to distinguish between closure types. Then during finalization we must
+     * ensure that the compiled JSFunction always finalized after the closures
+     * so we can safely access it here. Currently the GC ensures that through
+     * finalizing JSFunction instances after finalizing any other objects even
+     * during the background finalization.
+     *
+     * But we must not access JSScript here that is stored in JSFunction. The
+     * script can be finalized before the function or closure instances. So we
+     * just check if JSSLOT_FLAT_CLOSURE_UPVARS holds a private value encoded
+     * as a double. We must also ignore newborn closures that do not have the
+     * private pointer set.
+     *
+     * FIXME bug 648320 - allocate upvars on the GC heap to avoid doing it
+     * here explicitly.
+     */
+    JSFunction *fun = getFunctionPrivate();
+    if (fun && fun != this && fun->isFlatClosure()) {
+        const js::Value &v = getSlot(JSSLOT_FLAT_CLOSURE_UPVARS);
+        if (v.isDouble())
+            js::Foreground::free_(v.toPrivate());
+    }
+}
+
 inline js::Value
 JSObject::getFlatClosureUpvar(uint32 i) const
 {
     JS_ASSERT(i < getFunctionPrivate()->script()->bindings.countUpvars());
     return getFlatClosureUpvars()[i];
 }
 
 inline const js::Value &
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -253,33 +253,31 @@ public:
           , assertionBefore(false)
 #endif
     {
         jsbytecode *newCode = js_UntrapScriptCode(cx, script);
         if (newCode == script->code) {
             // No change needed
             newPC = origPC;
         } else {
-            script->main += newCode - script->code;
             *pc = newPC = origPC + (newCode - script->code);
             script->code = newCode;
 #ifdef DEBUG
             assertionBefore = cx->stackIterAssertionEnabled;
             cx->stackIterAssertionEnabled = false;
 #endif
         }
     }
     ~AutoScriptUntrapper()
     {
         ptrdiff_t delta = newPC - origPC;
         if (delta) {
             jsbytecode *oldCode = script->code - delta;
             cx->free_(script->code);
             script->code = oldCode;
-            script->main -= delta;
 #ifdef DEBUG
             cx->stackIterAssertionEnabled = assertionBefore;
 #endif
         }
     }
 };
 
 #ifdef DEBUG
@@ -308,17 +306,17 @@ js_DisassembleAtPC(JSContext *cx, JSScri
     }
     if (lines)
         SprintCString(sp, "----");
     SprintCString(sp, "  --\n");
 
     next = script->code;
     end = next + script->length;
     while (next < end) {
-        if (next == script->main)
+        if (next == script->main())
             SprintCString(sp, "main:\n");
         if (pc != NULL) {
             if (pc == next)
                 SprintCString(sp, "--> ");
             else
                 SprintCString(sp, "    ");
         }
         len = js_Disassemble1(cx, script, next,
@@ -2018,18 +2016,18 @@ Decompile(SprintStack *ss, jsbytecode *p
 
 #define LOAD_REGEXP(PCOFF)                                                    \
     GET_REGEXP_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
 
 #define GET_SOURCE_NOTE_ATOM(sn, atom)                                        \
     JS_BEGIN_MACRO                                                            \
         jsatomid atomIndex_ = (jsatomid) js_GetSrcNoteOffset((sn), 0);        \
                                                                               \
-        LOCAL_ASSERT(atomIndex_ < jp->script->atomMap.length);                \
-        (atom) = jp->script->atomMap.vector[atomIndex_];                      \
+        LOCAL_ASSERT(atomIndex_ < jp->script->natoms);                        \
+        (atom) = jp->script->atoms[atomIndex_];                               \
     JS_END_MACRO
 
 /*
  * Get atom from jp->script's atom map, quote/escape its string appropriately
  * into rval, and select fmt from the quoted and unquoted alternatives.
  */
 #define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval)                              \
     JS_BEGIN_MACRO                                                            \
@@ -4105,18 +4103,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                     jp->script = inner;
                     jp->fun = fun;
                     jp->localNames = innerLocalNames;
 
                     /*
                      * Decompile only the main bytecode, to avoid tripping over
                      * new prolog ops that have stack effects.
                      */
-                    ok = Decompile(&ss2, inner->main,
-                                   inner->length - (inner->main - inner->code),
+                    ok = Decompile(&ss2, inner->main(), inner->length - inner->mainOffset,
                                    JSOP_NOP)
                          != NULL;
                     jp->script = outer;
                     jp->fun = outerfun;
                     jp->localNames = outerLocalNames;
                     if (!ok) {
                         JS_ARENA_RELEASE(&cx->tempPool, mark);
                         return NULL;
@@ -4992,17 +4989,17 @@ js_DecompileFunction(JSPrinter *jp)
     } else {
         JSScript *script = fun->script();
 #if JS_HAS_DESTRUCTURING
         SprintStack ss;
         void *mark;
 #endif
 
         /* Print the parameters. */
-        pc = script->main;
+        pc = script->main();
         AutoScriptUntrapper untrapper(jp->sprinter.context, script, &pc);
         endpc = pc + script->length;
         ok = JS_TRUE;
 
 #if JS_HAS_DESTRUCTURING
         ss.printer = NULL;
         jp->script = script;
         mark = JS_ARENA_MARK(&jp->sprinter.context->tempPool);
@@ -5101,17 +5098,17 @@ js_DecompileValueGenerator(JSContext *cx
     if (!cx->hasfp() || !cx->fp()->isScriptFrame())
         goto do_fallback;
 
     fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL);
     script = fp->script();
     pc = fp->hasImacropc() ? fp->imacropc() : cx->regs().pc;
     JS_ASSERT(script->code <= pc && pc < script->code + script->length);
 
-    if (pc < script->main)
+    if (pc < script->main())
         goto do_fallback;
     
     if (spindex != JSDVG_IGNORE_STACK) {
         jsbytecode **pcstack;
 
         /*
          * Prepare computing pcstack containing pointers to opcodes that
          * populated interpreter's stack with its current content.
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -966,17 +966,17 @@ Compiler::compileScript(JSContext *cx, J
 
 #ifdef DEBUG
     bool savedCallerFun;
     savedCallerFun = false;
 #endif
     if (tcflags & TCF_COMPILE_N_GO) {
         if (source) {
             /*
-             * Save eval program source in script->atomMap.vector[0] for the
+             * Save eval program source in script->atoms[0] for the
              * eval cache (see EvalCacheLookup in jsobj.cpp).
              */
             JSAtom *atom = js_AtomizeString(cx, source);
             jsatomid _;
             if (!atom || !cg.makeAtomIndex(atom, &_))
                 goto out;
         }
 
@@ -1109,35 +1109,27 @@ Compiler::compileScript(JSContext *cx, J
     JS_ASSERT(cg.version() == version);
 
     script = JSScript::NewScriptFromCG(cx, &cg);
     if (!script)
         goto out;
 
     JS_ASSERT(script->savedCallerFun == savedCallerFun);
 
-    {
-        AutoScriptRooter root(cx, script);
-        if (!defineGlobals(cx, globalScope, script))
-            goto late_error;
-    }
+    if (!defineGlobals(cx, globalScope, script))
+        script = NULL;
 
   out:
     JS_FinishArenaPool(&codePool);
     JS_FinishArenaPool(&notePool);
     Probes::compileScriptEnd(cx, script, filename, lineno);
     return script;
 
   too_many_slots:
     parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS);
-    /* Fall through. */
-
-  late_error:
-    if (script && !script->u.object)
-        js_DestroyScript(cx, script, 7);
     script = NULL;
     goto out;
 }
 
 bool
 Compiler::defineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript *script)
 {
     if (!globalScope.defs.length())
@@ -2471,17 +2463,17 @@ Parser::setFunctionKinds(JSFunctionBox *
 
         JS_ASSERT(fun->kind() == JSFUN_INTERPRETED);
 
         if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) {
             /* nothing to do */
         } else if (funbox->inAnyDynamicScope()) {
             JS_ASSERT(!fun->isNullClosure());
         } else {
-            uintN hasUpvars = false;
+            bool hasUpvars = false;
             bool canFlatten = true;
 
             if (pn->pn_type == TOK_UPVARS) {
                 AtomDefnMapPtr upvars = pn->pn_names;
                 JS_ASSERT(!upvars->empty());
 
                 /*
                  * For each lexical dependency from this closure to an outer
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -87,17 +87,16 @@ typedef struct JSParseNode          JSPa
 typedef struct JSProperty           JSProperty;
 typedef struct JSScript             JSScript;
 typedef struct JSSharpObjectMap     JSSharpObjectMap;
 typedef struct JSThread             JSThread;
 typedef struct JSTreeContext        JSTreeContext;
 typedef struct JSTryNote            JSTryNote;
 
 /* Friend "Advanced API" typedefs. */
-typedef struct JSAtomMap            JSAtomMap;
 typedef struct JSAtomState          JSAtomState;
 typedef struct JSCodeSpec           JSCodeSpec;
 typedef struct JSPrinter            JSPrinter;
 typedef struct JSStackHeader        JSStackHeader;
 typedef struct JSSubString          JSSubString;
 typedef struct JSNativeTraceInfo    JSNativeTraceInfo;
 typedef struct JSSpecializedNative  JSSpecializedNative;
 typedef struct JSXML                JSXML;
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -286,40 +286,40 @@ Bindings::makeImmutable()
 
 void
 Bindings::trace(JSTracer *trc)
 {
     if (lastBinding)
         MarkShape(trc, lastBinding, "shape");
 }
 
-} /* namespace js */
+#ifdef JS_CRASH_DIAGNOSTICS
 
-static void
+void
 CheckScript(JSScript *script, JSScript *prev)
 {
-#ifdef JS_CRASH_DIAGNOSTICS
-    if (script->cookie1 != JS_SCRIPT_COOKIE || script->cookie2 != JS_SCRIPT_COOKIE) {
+    if (script->cookie1[0] != JS_SCRIPT_COOKIE || script->cookie2[0] != JS_SCRIPT_COOKIE) {
         crash::StackBuffer<sizeof(JSScript), 0x87> buf1(script);
         crash::StackBuffer<sizeof(JSScript), 0x88> buf2(prev);
         JS_OPT_ASSERT(false);
     }
-#endif
 }
 
-static void
+void
 CheckScriptOwner(JSScript *script, JSObject *owner)
 {
-#ifdef JS_CRASH_DIAGNOSTICS
     JS_OPT_ASSERT(script->ownerObject == owner);
     if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT)
-        JS_OPT_ASSERT(script->compartment == owner->compartment());
-#endif
+        JS_OPT_ASSERT(script->compartment() == owner->compartment());
 }
 
+#endif /* JS_CRASH_DIAGNOSTICS */
+
+} /* namespace js */
+
 #if JS_HAS_XDR
 
 enum ScriptBits {
     NoScriptRval,
     SavedCallerFun,
     HasSharps,
     StrictModeCode,
     UsesEval,
@@ -377,17 +377,16 @@ js_XDRScript(JSXDRState *xdr, JSScript *
         JS_ASSERT((paddingUpvars >> 16) == 0);
         nupvars = paddingUpvars & 0xFFFF;
     }
     JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT);
     JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT);
     JS_ASSERT(nupvars != Bindings::BINDING_COUNT_LIMIT);
 
     Bindings bindings(cx);
-    AutoBindingsRooter rooter(cx, bindings);
     uint32 nameCount = nargs + nvars + nupvars;
     if (nameCount > 0) {
         struct AutoMark {
           JSArenaPool * const pool;
           void * const mark;
           AutoMark(JSArenaPool *pool) : pool(pool), mark(JS_ARENA_MARK(pool)) { }
           ~AutoMark() {
             JS_ARENA_RELEASE(pool, mark);
@@ -467,23 +466,23 @@ js_XDRScript(JSXDRState *xdr, JSScript *
     }
 
     if (xdr->mode == JSXDR_ENCODE)
         length = script->length;
     if (!JS_XDRUint32(xdr, &length))
         return JS_FALSE;
 
     if (xdr->mode == JSXDR_ENCODE) {
-        prologLength = script->main - script->code;
+        prologLength = script->mainOffset;
         JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
         version = (uint32)script->getVersion() | (script->nfixed << 16);
         lineno = (uint32)script->lineno;
         nslots = (uint32)script->nslots;
         nslots = (uint32)((script->staticLevel << 16) | script->nslots);
-        natoms = (uint32)script->atomMap.length;
+        natoms = script->natoms;
 
         notes = script->notes();
         nsrcnotes = script->numNotes();
 
         if (JSScript::isValidOffset(script->objectsOffset))
             nobjects = script->objects()->length;
         if (JSScript::isValidOffset(script->upvarsOffset))
             JS_ASSERT(script->bindings.countUpvars() == script->upvars()->length);
@@ -539,40 +538,37 @@ js_XDRScript(JSXDRState *xdr, JSScript *
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &encodedClosedCount))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &nTypeSets))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &scriptBits))
         return JS_FALSE;
 
-    AutoScriptRooter tvr(cx, NULL);
-
     if (xdr->mode == JSXDR_DECODE) {
         nClosedArgs = encodedClosedCount >> 16;
         nClosedVars = encodedClosedCount & 0xFFFF;
 
         /* Note: version is packed into the 32b space with another 16b value. */
         JSVersion version_ = JSVersion(version & JS_BITMASK(16));
         JS_ASSERT((version_ & VersionFlags::FULL_MASK) == uintN(version_));
         script = JSScript::NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars,
                                      nregexps, ntrynotes, nconsts, 0, nClosedArgs,
                                      nClosedVars, nTypeSets, version_);
         if (!script)
             return JS_FALSE;
 
         script->bindings.transfer(cx, &bindings);
-
-        script->main += prologLength;
+        JS_ASSERT(!script->mainOffset);
+        script->mainOffset = prologLength;
         script->nfixed = uint16(version >> 16);
 
         /* If we know nsrcnotes, we allocated space for notes in script. */
         notes = script->notes();
         *scriptp = script;
-        tvr.setScript(script);
 
         if (scriptBits & (1 << NoScriptRval))
             script->noScriptRval = true;
         if (scriptBits & (1 << SavedCallerFun))
             script->savedCallerFun = true;
         if (scriptBits & (1 << HasSharps))
             script->hasSharps = true;
         if (scriptBits & (1 << StrictModeCode))
@@ -652,17 +648,17 @@ js_XDRScript(JSXDRState *xdr, JSScript *
 
     if (xdr->mode == JSXDR_DECODE) {
         script->lineno = (uintN)lineno;
         script->nslots = (uint16)nslots;
         script->staticLevel = (uint16)(nslots >> 16);
     }
 
     for (i = 0; i != natoms; ++i) {
-        if (!js_XDRAtom(xdr, &script->atomMap.vector[i]))
+        if (!js_XDRAtom(xdr, &script->atoms[i]))
             goto error;
     }
 
     /*
      * Here looping from 0-to-length to xdr objects is essential. It ensures
      * that block objects from the script->objects array will be written and
      * restored in the outer-to-inner order. js_XDRBlockObject relies on this
      * to restore the parent chain.
@@ -739,20 +735,18 @@ js_XDRScript(JSXDRState *xdr, JSScript *
         if (!JS_XDRValue(xdr, Jsvalify(&script->consts()->vector[i])))
             goto error;
     }
 
     xdr->script = oldscript;
     return JS_TRUE;
 
   error:
-    if (xdr->mode == JSXDR_DECODE) {
-        js_DestroyScript(cx, script, 1);
+    if (xdr->mode == JSXDR_DECODE)
         *scriptp = NULL;
-    }
     xdr->script = oldscript;
     return JS_FALSE;
 }
 
 #endif /* JS_HAS_XDR */
 
 bool
 JSPCCounters::init(JSContext *cx, size_t numBytecodes)
@@ -770,43 +764,37 @@ JSPCCounters::destroy(JSContext *cx)
 {
     if (counts) {
         cx->free_(counts);
         counts = NULL;
     }
 }
 
 static void
-script_finalize(JSContext *cx, JSObject *obj)
-{
-    JSScript *script = (JSScript *) obj->getPrivate();
-    if (script)
-        js_DestroyScriptFromGC(cx, script, obj);
-}
-
-static void
 script_trace(JSTracer *trc, JSObject *obj)
 {
     JSScript *script = (JSScript *) obj->getPrivate();
-    if (script)
-        js_TraceScript(trc, script, obj);
+    if (script) {
+        CheckScriptOwner(script, obj);
+        MarkScript(trc, script, "script");
+    }
 }
 
 Class js_ScriptClass = {
     "Script",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
-    script_finalize,
+    NULL,                 /* finalize */
     NULL,                 /* reserved0   */
     NULL,                 /* checkAccess */
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     NULL,                 /* hasInstance */
     script_trace
 };
@@ -872,18 +860,18 @@ js_SweepScriptFilenames(JSCompartment *c
  *
  * JSScript
  * JSObjectArray    script objects' descriptor if JSScript.objectsOffset != 0,
  *                    use script->objects() to access it.
  * JSObjectArray    script regexps' descriptor if JSScript.regexpsOffset != 0,
  *                    use script->regexps() to access it.
  * JSTryNoteArray   script try notes' descriptor if JSScript.tryNotesOffset
  *                    != 0, use script->trynotes() to access it.
- * JSAtom *a[]      array of JSScript.atomMap.length atoms pointed by
- *                    JSScript.atomMap.vector if any.
+ * JSAtom *a[]      array of JSScript.natoms atoms pointed by
+ *                    JSScript.atoms if any.
  * JSObject *o[]    array of script->objects()->length objects if any
  *                    pointed by script->objects()->vector.
  * JSObject *r[]    array of script->regexps()->length regexps if any
  *                    pointed by script->regexps()->vector.
  * JSTryNote t[]    array of script->trynotes()->length try notes if any
  *                    pointed by script->trynotes()->vector.
  * jsbytecode b[]   script bytecode pointed by JSScript.code.
  * jssrcnote  s[]   script source notes, use script->notes() to access it
@@ -920,211 +908,208 @@ JS_STATIC_ASSERT(sizeof(JSObjectArray) +
 JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255);
 
 JSScript *
 JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
                     uint32 nobjects, uint32 nupvars, uint32 nregexps,
                     uint32 ntrynotes, uint32 nconsts, uint32 nglobals,
                     uint16 nClosedArgs, uint16 nClosedVars, uint32 nTypeSets, JSVersion version)
 {
-    size_t size, vectorSize;
-    JSScript *script;
-    uint8 *cursor;
-    unsigned constPadding = 0;
-
-    uint32 totalClosed = nClosedArgs + nClosedVars;
-
-    size = sizeof(JSScript) +
-           sizeof(JSAtom *) * natoms;
-
+    size_t size = sizeof(JSAtom *) * natoms;
     if (nobjects != 0)
         size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
     if (nupvars != 0)
         size += sizeof(JSUpvarArray) + nupvars * sizeof(uint32);
     if (nregexps != 0)
         size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
     if (ntrynotes != 0)
         size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
     if (nglobals != 0)
         size += sizeof(GlobalSlotArray) + nglobals * sizeof(GlobalSlotArray::Entry);
+    uint32 totalClosed = nClosedArgs + nClosedVars;
     if (totalClosed != 0)
         size += totalClosed * sizeof(uint32);
 
-    if (nconsts != 0) {
-        size += sizeof(JSConstArray);
+    /*
+     * To esnure jsval alignment for the const array we place it immediately
+     * after JSSomethingArray structs as their sizes all divide sizeof(jsval).
+     * This works as long as the data itself is allocated with proper
+     * alignment which we ensure below.
+     */
+    JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(jsval) == 0);
+    JS_STATIC_ASSERT(sizeof(JSUpvarArray) % sizeof(jsval) == 0);
+    JS_STATIC_ASSERT(sizeof(JSTryNoteArray) % sizeof(jsval) == 0);
+    JS_STATIC_ASSERT(sizeof(GlobalSlotArray) % sizeof(jsval) == 0);
+    JS_STATIC_ASSERT(sizeof(JSConstArray) % sizeof(jsval) == 0);
+    if (nconsts != 0)
+        size += sizeof(JSConstArray) + nconsts * sizeof(Value);
+
+    size += length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote);
+
+    uint8 *data = NULL;
+#if JS_SCRIPT_INLINE_DATA_LIMIT
+    if (size <= JS_SCRIPT_INLINE_DATA_LIMIT) {
         /*
-         * Calculate padding assuming that consts go after the other arrays,
-         * but before the bytecode and source notes.
+         * Check that if inlineData is big enough to store const values, we
+         * can do that without any special alignment requirements given that
+         * the script as a GC thing is always aligned on Cell::CellSize.
          */
-        constPadding = (8 - (size % 8)) % 8;
-        size += constPadding + nconsts * sizeof(Value);
+        JS_STATIC_ASSERT(Cell::CellSize % sizeof(Value) == 0);
+        JS_STATIC_ASSERT(JS_SCRIPT_INLINE_DATA_LIMIT < sizeof(Value) ||
+                         offsetof(JSScript, inlineData) % sizeof(Value) == 0);
+    } else
+#endif
+    {
+        /*
+         * We assume that calloc aligns on sizeof(Value) if the size we ask to
+         * allocate divides sizeof(Value).
+         */
+        JS_STATIC_ASSERT(sizeof(Value) == sizeof(jsdouble));
+        data = static_cast<uint8 *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
+        if (!data)
+            return NULL;
     }
 
-    size += length * sizeof(jsbytecode) +
-            nsrcnotes * sizeof(jssrcnote);
-
-    script = (JSScript *) cx->malloc_(size);
-    if (!script)
+    JSScript *script = js_NewGCScript(cx);
+    if (!script) {
+        Foreground::free_(data);
         return NULL;
+    }
 
     PodZero(script);
 #ifdef JS_CRASH_DIAGNOSTICS
-    script->cookie1 = script->cookie2 = JS_SCRIPT_COOKIE;
+    script->cookie1[0] = script->cookie2[0] = JS_SCRIPT_COOKIE;
     script->ownerObject = JS_NEW_SCRIPT;
 #endif
+#if JS_SCRIPT_INLINE_DATA_LIMIT
+    if (!data)
+        data = script->inlineData;
+#endif
+    script->data  = data;
     script->length = length;
     script->version = version;
     new (&script->bindings) Bindings(cx);
 
     if (cx->hasRunOption(JSOPTION_PCCOUNT))
         (void) script->pcCounters.init(cx, length);
 
-    uint8 *scriptEnd = reinterpret_cast<uint8 *>(script + 1);
-
-    cursor = scriptEnd;
+    uint8 *cursor = data;
     if (nobjects != 0) {
-        script->objectsOffset = (uint8)(cursor - scriptEnd);
+        script->objectsOffset = (uint8)(cursor - data);
         cursor += sizeof(JSObjectArray);
     } else {
         script->objectsOffset = JSScript::INVALID_OFFSET;
     }
     if (nupvars != 0) {
-        script->upvarsOffset = (uint8)(cursor - scriptEnd);
+        script->upvarsOffset = (uint8)(cursor - data);
         cursor += sizeof(JSUpvarArray);
     } else {
         script->upvarsOffset = JSScript::INVALID_OFFSET;
     }
     if (nregexps != 0) {
-        script->regexpsOffset = (uint8)(cursor - scriptEnd);
+        script->regexpsOffset = (uint8)(cursor - data);
         cursor += sizeof(JSObjectArray);
     } else {
         script->regexpsOffset = JSScript::INVALID_OFFSET;
     }
     if (ntrynotes != 0) {
-        script->trynotesOffset = (uint8)(cursor - scriptEnd);
+        script->trynotesOffset = (uint8)(cursor - data);
         cursor += sizeof(JSTryNoteArray);
     } else {
         script->trynotesOffset = JSScript::INVALID_OFFSET;
     }
     if (nglobals != 0) {
-        script->globalsOffset = (uint8)(cursor - scriptEnd);
+        script->globalsOffset = (uint8)(cursor - data);
         cursor += sizeof(GlobalSlotArray);
     } else {
         script->globalsOffset = JSScript::INVALID_OFFSET;
     }
-    JS_ASSERT(cursor - scriptEnd < 0xFF);
+    JS_ASSERT(cursor - data < 0xFF);
     if (nconsts != 0) {
-        script->constOffset = (uint8)(cursor - scriptEnd);
+        script->constOffset = (uint8)(cursor - data);
         cursor += sizeof(JSConstArray);
     } else {
         script->constOffset = JSScript::INVALID_OFFSET;
     }
 
     JS_STATIC_ASSERT(sizeof(JSObjectArray) +
                      sizeof(JSUpvarArray) +
                      sizeof(JSObjectArray) +
                      sizeof(JSTryNoteArray) +
                      sizeof(GlobalSlotArray) < 0xFF);
 
-    if (natoms != 0) {
-        script->atomMap.length = natoms;
-        script->atomMap.vector = (JSAtom **)cursor;
-        vectorSize = natoms * sizeof(script->atomMap.vector[0]);
 
-        /*
-         * Clear object map's vector so the GC tracing can run when not yet
-         * all atoms are copied to the array.
-         */
-        memset(cursor, 0, vectorSize);
-        cursor += vectorSize;
+    if (nconsts != 0) {
+        JS_ASSERT(reinterpret_cast<jsuword>(cursor) % sizeof(jsval) == 0);
+        script->consts()->length = nconsts;
+        script->consts()->vector = reinterpret_cast<Value *>(cursor);
+        cursor += nconsts * sizeof(script->consts()->vector[0]);
+    }
+
+    if (natoms != 0) {
+        script->natoms = natoms;
+        script->atoms = reinterpret_cast<JSAtom **>(cursor);
+        cursor += natoms * sizeof(script->atoms[0]);
     }
 
     if (nobjects != 0) {
         script->objects()->length = nobjects;
-        script->objects()->vector = (JSObject **)cursor;
-        vectorSize = nobjects * sizeof(script->objects()->vector[0]);
-        memset(cursor, 0, vectorSize);
-        cursor += vectorSize;
+        script->objects()->vector = reinterpret_cast<JSObject **>(cursor);
+        cursor += nobjects * sizeof(script->objects()->vector[0]);
     }
 
     if (nregexps != 0) {
         script->regexps()->length = nregexps;
-        script->regexps()->vector = (JSObject **)cursor;
-        vectorSize = nregexps * sizeof(script->regexps()->vector[0]);
-        memset(cursor, 0, vectorSize);
-        cursor += vectorSize;
+        script->regexps()->vector = reinterpret_cast<JSObject **>(cursor);
+        cursor += nregexps * sizeof(script->regexps()->vector[0]);
     }
 
     if (ntrynotes != 0) {
         script->trynotes()->length = ntrynotes;
-        script->trynotes()->vector = (JSTryNote *)cursor;
-        vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
+        script->trynotes()->vector = reinterpret_cast<JSTryNote *>(cursor);
+        size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
 #ifdef DEBUG
         memset(cursor, 0, vectorSize);
 #endif
         cursor += vectorSize;
     }
 
     if (nglobals != 0) {
         script->globals()->length = nglobals;
-        script->globals()->vector = (GlobalSlotArray::Entry *)cursor;
-        vectorSize = nglobals * sizeof(script->globals()->vector[0]);
-        cursor += vectorSize;
+        script->globals()->vector = reinterpret_cast<GlobalSlotArray::Entry *>(cursor);
+        cursor += nglobals * sizeof(script->globals()->vector[0]);
     }
 
     if (totalClosed != 0) {
         script->nClosedArgs = nClosedArgs;
         script->nClosedVars = nClosedVars;
-        script->closedSlots = (uint32 *)cursor;
+        script->closedSlots = reinterpret_cast<uint32 *>(cursor);
         cursor += totalClosed * sizeof(uint32);
     }
 
     JS_ASSERT(nTypeSets <= UINT16_MAX);
     script->nTypeSets = uint16(nTypeSets);
 
     /*
      * NB: We allocate the vector of uint32 upvar cookies after all vectors of
      * pointers, to avoid misalignment on 64-bit platforms. See bug 514645.
      */
     if (nupvars != 0) {
         script->upvars()->length = nupvars;
         script->upvars()->vector = reinterpret_cast<UpvarCookie *>(cursor);
-        vectorSize = nupvars * sizeof(script->upvars()->vector[0]);
-        memset(cursor, 0, vectorSize);
-        cursor += vectorSize;
+        cursor += nupvars * sizeof(script->upvars()->vector[0]);
     }
 
-    /* Must go after other arrays; see constPadding definition. */
-    if (nconsts != 0) {
-        cursor += constPadding;
-        script->consts()->length = nconsts;
-        script->consts()->vector = (Value *)cursor;
-        JS_ASSERT((size_t)cursor % sizeof(double) == 0);
-        vectorSize = nconsts * sizeof(script->consts()->vector[0]);
-        memset(cursor, 0, vectorSize);
-        cursor += vectorSize;
-    }
-
-    script->code = script->main = (jsbytecode *)cursor;
-    JS_ASSERT(cursor +
-              length * sizeof(jsbytecode) +
-              nsrcnotes * sizeof(jssrcnote) ==
-              (uint8 *)script + size);
-
-    script->compartment = cx->compartment;
-#ifdef CHECK_SCRIPT_OWNER
-    script->owner = cx->thread();
-#endif
+    script->code = (jsbytecode *)cursor;
+    JS_ASSERT(cursor + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) == data + size);
 
 #ifdef DEBUG
     script->id_ = ++cx->compartment->types.scriptCount;
 #endif
 
-    JS_APPEND_LINK(&script->links, &cx->compartment->scripts);
-
     JS_ASSERT(script->getVersion() == version);
     return script;
 }
 
 JSScript *
 JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
 {
     uint32 mainLength, prologLength, nsrcnotes, nfixed;
@@ -1154,50 +1139,49 @@ JSScript::NewScriptFromCG(JSContext *cx,
                        upvarIndexCount, cg->regexpList.length,
                        cg->ntrynotes, cg->constList.length(),
                        cg->globalUses.length(), nClosedArgs, nClosedVars,
                        cg->typesetCount, cg->version());
     if (!script)
         return NULL;
 
     cg->bindings.makeImmutable();
-    AutoShapeRooter shapeRoot(cx, cg->bindings.lastShape());
 
-    /* Now that we have script, error control flow must go to label bad. */
-    script->main += prologLength;
+    JS_ASSERT(script->mainOffset == 0);
+    script->mainOffset = prologLength;
     memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
-    memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
+    memcpy(script->main(), CG_BASE(cg), mainLength * sizeof(jsbytecode));
     nfixed = cg->inFunction()
              ? cg->bindings.countVars()
              : cg->sharpSlots();
     JS_ASSERT(nfixed < SLOTNO_LIMIT);
     script->nfixed = (uint16) nfixed;
-    js_InitAtomMap(cx, &script->atomMap, cg->atomIndices.getMap());
+    js_InitAtomMap(cx, cg->atomIndices.getMap(), script->atoms);
 
     filename = cg->parser->tokenStream.getFilename();
     if (filename) {
         script->filename = SaveScriptFilename(cx, filename);
         if (!script->filename)
-            goto bad;
+            return NULL;
     }
     script->lineno = cg->firstLine;
     if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) {
         ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET, "script");
-        goto bad;
+        return NULL;
     }
     script->nslots = script->nfixed + cg->maxStackDepth;
     script->staticLevel = uint16(cg->staticLevel);
     script->principals = cg->parser->principals;
     if (script->principals)
         JSPRINCIPALS_HOLD(cx, script->principals);
 
     script->sourceMap = (jschar *) cg->parser->tokenStream.releaseSourceMap();
 
     if (!js_FinishTakingSrcNotes(cx, cg, script->notes()))
-        goto bad;
+        return NULL;
     if (cg->ntrynotes != 0)
         js_FinishTakingTryNotes(cg, script->trynotes());
     if (cg->objectList.length != 0)
         cg->objectList.finish(script->objects());
     if (cg->regexpList.length != 0)
         cg->regexpList.finish(script->regexps());
     if (cg->constList.length() != 0)
         cg->constList.finish(script->consts());
@@ -1261,66 +1245,62 @@ JSScript::NewScriptFromCG(JSContext *cx,
         JS_ASSERT(fun->isInterpreted());
         JS_ASSERT(!fun->script());
 #ifdef DEBUG
         if (JSScript::isValidOffset(script->upvarsOffset))
             JS_ASSERT(script->upvars()->length == script->bindings.countUpvars());
         else
             JS_ASSERT(script->bindings.countUpvars() == 0);
 #endif
-#ifdef CHECK_SCRIPT_OWNER
-        script->owner = NULL;
-#endif
         if (cg->flags & TCF_FUN_HEAVYWEIGHT)
             fun->flags |= JSFUN_HEAVYWEIGHT;
 
         /* Watch for scripts whose functions will not be cloned. These are singletons. */
         bool singleton =
             cx->typeInferenceEnabled() && cg->parent && cg->parent->compiling() &&
             cg->parent->asCodeGenerator()->checkSingletonContext();
 
         if (!script->typeSetFunction(cx, fun, singleton))
-            goto bad;
+            return NULL;
 
         fun->u.i.script = script;
         script->setOwnerObject(fun);
     } else {
         /*
          * Initialize script->object, if necessary, so that the debugger has a
          * valid holder object.
          */
         if ((cg->flags & TCF_NEED_SCRIPT_OBJECT) && !js_NewScriptObject(cx, script))
-            goto bad;
+            return NULL;
     }
 
     /* Tell the debugger about this compiled script. */
     js_CallNewScriptHook(cx, script, fun);
     if (!cg->parent) {
         Debugger::onNewScript(cx, script,
                               fun ? fun : (script->u.object ? script->u.object : cg->scopeChain()),
                               (fun || script->u.object)
                               ? Debugger::NewHeldScript
                               : Debugger::NewNonHeldScript);
     }
 
     return script;
-
-bad:
-    if (!script->u.object)
-        js_DestroyScript(cx, script, 2);
-    return NULL;
 }
 
 size_t
-JSScript::totalSize()
+JSScript::dataSize()
 {
-    return code +
-           length * sizeof(jsbytecode) +
-           numNotes() * sizeof(jssrcnote) -
-           (uint8 *) this;
+#if JS_SCRIPT_INLINE_DATA_LIMIT
+    if (data == inlineData)
+        return 0;
+#endif
+
+    uint8 *dataEnd = code + length * sizeof(jsbytecode) + numNotes() * sizeof(jssrcnote);
+    JS_ASSERT(dataEnd >= data);
+    return dataEnd - data;
 }
 
 void
 JSScript::setOwnerObject(JSObject *owner)
 {
 #ifdef JS_CRASH_DIAGNOSTICS
     CheckScriptOwner(this, JS_NEW_SCRIPT);
     ownerObject = owner;
@@ -1339,229 +1319,92 @@ JSScript::numNotes()
     for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
         continue;
     return sn - notes_ + 1;    /* +1 for the terminator */
 }
 
 JS_FRIEND_API(void)
 js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
 {
-    JSNewScriptHook hook;
-
-    hook = cx->debugHooks->newScriptHook;
-    if (hook) {
+    JS_ASSERT(!script->callDestroyHook);
+    if (JSNewScriptHook hook = cx->debugHooks->newScriptHook) {
         AutoKeepAtoms keep(cx->runtime);
         hook(cx, script->filename, script->lineno, script, fun,
              cx->debugHooks->newScriptHookData);
     }
+    script->callDestroyHook = true;
 }
 
 void
 js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
 {
-    JSDestroyScriptHook hook;
+    if (!script->callDestroyHook)
+        return;
 
-    hook = cx->debugHooks->destroyScriptHook;
-    if (hook)
+    if (JSDestroyScriptHook hook = cx->debugHooks->destroyScriptHook)
         hook(cx, script, cx->debugHooks->destroyScriptHookData);
+    script->callDestroyHook = false;
     Debugger::onDestroyScript(script);
     JS_ClearScriptTraps(cx, script);
 }
 
-static void
-DestroyScript(JSContext *cx, JSScript *script, JSObject *owner, uint32 caller)
+void
+JSScript::finalize(JSContext *cx)
 {
-    CheckScript(script, NULL);
-    CheckScriptOwner(script, owner);
-
-    if (script->principals)
-        JSPRINCIPALS_DROP(cx, script->principals);
-
-    GSNCache *gsnCache = GetGSNCache(cx);
-    if (gsnCache->code == script->code)
-        gsnCache->purge();
+    CheckScript(this, NULL);
 
-    /*
-     * Worry about purging the property cache and any compiled traces related
-     * to its bytecode if this script is being destroyed from JS_DestroyScript
-     * or equivalent according to a mandatory "New/Destroy" protocol.
-     *
-     * The GC purges all property caches when regenerating shapes upon shape
-     * generator overflow, so no need in that event to purge just the entries
-     * for this script.
-     *
-     * The GC purges trace-JITted code on every GC activation, not just when
-     * regenerating shapes, so we don't have to purge fragments if the GC is
-     * currently running.
-     *
-     * JS_THREADSAFE note: The code below purges only the current thread's
-     * property cache, so a script not owned by a function or object, which
-     * hands off lifetime management for that script to the GC, must be used by
-     * only one thread over its lifetime.
-     *
-     * This should be an API-compatible change, since a script is never safe
-     * against premature GC if shared among threads without a rooted object
-     * wrapping it to protect the script's mapped atoms against GC. We use
-     * script->owner to enforce this requirement via assertions.
-     */
-#ifdef CHECK_SCRIPT_OWNER
-    JS_ASSERT_IF(cx->runtime->gcRunning, !script->owner);
-#endif
+    js_CallDestroyScriptHook(cx, this);
 
-    /* FIXME: bug 506341; would like to do this only if regenerating shapes. */
-    if (!cx->runtime->gcRunning) {
-        JS_PROPERTY_CACHE(cx).purgeForScript(cx, script);
-
-#ifdef CHECK_SCRIPT_OWNER
-        JS_ASSERT(script->owner == cx->thread());
-#endif
-    }
+    if (principals)
+        JSPRINCIPALS_DROP(cx, principals);
 
 #ifdef JS_TRACER
-    if (script->compartment->hasTraceMonitor())
-        PurgeScriptFragments(script->compartment->traceMonitor(), script);
-#endif
-
-    if (script->types)
-        script->types->destroy();
-
-#ifdef JS_METHODJIT
-    mjit::ReleaseScriptCode(cx, script);
+    if (compartment()->hasTraceMonitor())
+        PurgeScriptFragments(compartment()->traceMonitor(), this);
 #endif
 
-    JS_REMOVE_LINK(&script->links);
-
-    script->pcCounters.destroy(cx);
-
-    if (script->sourceMap)
-        cx->free_(script->sourceMap);
-
-    JS_POISON(script, 0xdb, sizeof(JSScript));
-    *(uint32 *)script = caller;
-    cx->free_(script);
-}
-
-void
-js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller)
-{
-    JS_ASSERT(!cx->runtime->gcRunning);
-    js_CallDestroyScriptHook(cx, script);
-    DestroyScript(cx, script, JS_NEW_SCRIPT, caller);
-}
-
-void
-js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner)
-{
-    JS_ASSERT(cx->runtime->gcRunning);
+    if (types)
+        types->destroy();
 
 #ifdef JS_METHODJIT
-    /* Keep the hook from trying to recompile while the GC is running. */
-    mjit::ReleaseScriptCode(cx, script);
+    mjit::ReleaseScriptCode(cx, this);
 #endif
 
-    js_CallDestroyScriptHook(cx, script);
-    DestroyScript(cx, script, owner, 100);
-}
-
-void
-js_DestroyCachedScript(JSContext *cx, JSScript *script)
-{
-    JS_ASSERT(cx->runtime->gcRunning);
-    DestroyScript(cx, script, JS_CACHED_SCRIPT, 101);
-}
-
-void
-js_TraceScript(JSTracer *trc, JSScript *script, JSObject *owner)
-{
-    JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
+    pcCounters.destroy(cx);
 
-    CheckScript(script, NULL);
-    if (owner)
-        CheckScriptOwner(script, owner);
-
-    JSRuntime *rt = trc->context->runtime;
-
-    /*
-     * During per-compartment GCs we may attempt to trace scripts that are out
-     * of the target compartment. Ignore such attempts, marking the children is
-     * wasted work and if we mark external type objects they will not get
-     * unmarked at the end of the GC cycle.
-     */
-    if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != script->compartment)
-        return;
-
-#ifdef JS_CRASH_DIAGNOSTICS
-    JS_OPT_ASSERT_IF(rt->gcCheckCompartment, script->compartment == rt->gcCheckCompartment);
-#endif
+    if (sourceMap)
+        cx->free_(sourceMap);
 
-    JSAtomMap *map = &script->atomMap;
-    MarkAtomRange(trc, map->length, map->vector, "atomMap");
-
-    if (JSScript::isValidOffset(script->objectsOffset)) {
-        JSObjectArray *objarray = script->objects();
-        MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
-    }
-
-    if (JSScript::isValidOffset(script->regexpsOffset)) {
-        JSObjectArray *objarray = script->regexps();
-        MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
-    }
-
-    if (JSScript::isValidOffset(script->constOffset)) {
-        JSConstArray *constarray = script->consts();
-        MarkValueRange(trc, constarray->length, constarray->vector, "consts");
+#if JS_SCRIPT_INLINE_DATA_LIMIT
+    if (data != inlineData)
+#endif
+    {
+        JS_POISON(data, 0xdb, dataSize());
+        cx->free_(data);
     }
-
-    /*
-     * Mark the object keeping this script alive. The script can be traced
-     * separately if, e.g. we are GC'ing while type inference code is active,
-     * and we need to make sure both the script and the object survive the GC.
-     */
-    if (!script->isCachedEval && script->u.object)
-        MarkObject(trc, *script->u.object, "object");
-    if (script->hasFunction)
-        MarkObject(trc, *script->function(), "script_fun");
-
-    if (IS_GC_MARKING_TRACER(trc) && script->filename)
-        js_MarkScriptFilename(script->filename);
-
-    script->bindings.trace(trc);
-
-#ifdef JS_METHODJIT
-    if (script->jitNormal)
-        script->jitNormal->trace(trc);
-    if (script->jitCtor)
-        script->jitCtor->trace(trc);
-#endif
 }
 
 JSObject *
 js_NewScriptObject(JSContext *cx, JSScript *script)
 {
-    AutoScriptRooter root(cx, script);
-
     JS_ASSERT(!script->u.object);
 
     JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
     if (!obj)
         return NULL;
     obj->setPrivate(script);
     script->u.object = obj;
     script->setOwnerObject(obj);
 
     /*
      * Clear the object's type/proto, to avoid entraining stuff. Once we no longer use the parent
      * for security checks, then we can clear the parent, too.
      */
     obj->clearType();
 
-#ifdef CHECK_SCRIPT_OWNER
-    script->owner = NULL;
-#endif
-
     return obj;
 }
 
 namespace js {
 
 static const uint32 GSN_CACHE_THRESHOLD = 100;
 static const uint32 GSN_CACHE_MAP_INIT_SIZE = 20;
 
@@ -1701,17 +1544,17 @@ js_LineNumberToPC(JSScript *script, uint
     best = -1;
     lineno = script->lineno;
     bestdiff = SN_LINE_LIMIT;
     for (sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
         /*
          * Exact-match only if offset is not in the prolog; otherwise use
          * nearest greater-or-equal line number match.
          */
-        if (lineno == target && script->code + offset >= script->main)
+        if (lineno == target && offset >= ptrdiff_t(script->mainOffset))
             goto out;
         if (lineno >= target) {
             diff = lineno - target;
             if (diff < bestdiff) {
                 bestdiff = diff;
                 best = offset;
             }
         }
@@ -1833,18 +1676,17 @@ public:
 private:
     JSXDRState *const xdr;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 JSScript *
 js_CloneScript(JSContext *cx, JSScript *script)
 {
-    JS_ASSERT(cx->compartment != script->compartment);
-    JS_ASSERT(script->compartment);
+    JS_ASSERT(cx->compartment != script->compartment());
 
     // serialize script
     AutoJSXDRState w(JS_XDRNewMem(cx, JSXDR_ENCODE));
     if (!w)
         return NULL;
 
     // we don't want gecko to transcribe our principals for us
     DisablePrincipalsTranscoding disable(cx);
@@ -1874,17 +1716,17 @@ js_CloneScript(JSContext *cx, JSScript *
     XDRScriptState rstate(r);
     rstate.filename = script->filename;
     rstate.filenameSaved = true;
 
     if (!js_XDRScript(r, &script))
         return NULL;
 
     // set the proper principals for the script
-    script->principals = script->compartment->principals;
+    script->principals = script->compartment()->principals;
     if (script->principals)
         JSPRINCIPALS_HOLD(cx, script->principals);
 
     return script;
 }
 
 void
 JSScript::copyClosedSlotsTo(JSScript *other)
@@ -1937,12 +1779,12 @@ JSScript::setStepModeFlag(JSContext *cx,
 bool
 JSScript::changeStepModeCount(JSContext *cx, int delta)
 {
     assertSameCompartment(cx, this);
     JS_ASSERT_IF(delta > 0, cx->compartment->debugMode());
 
     uint32 count = stepMode & stepCountMask;
     JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
-    return tryNewStepMode(cx, 
+    return tryNewStepMode(cx,
                           (stepMode & stepFlagMask) |
                           ((count + delta) & stepCountMask));
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=4 sw=4 et tw=79 ft=cpp:
  *
  * ***** 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
@@ -357,20 +357,16 @@ class Bindings {
     void trace(JSTracer *trc);
 };
 
 } /* namespace js */
 
 #define JS_OBJECT_ARRAY_SIZE(length)                                          \
     (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
 
-#if defined DEBUG && defined JS_THREADSAFE
-# define CHECK_SCRIPT_OWNER 1
-#endif
-
 #ifdef JS_METHODJIT
 namespace JSC {
     class ExecutablePool;
 }
 
 #define JS_UNJITTABLE_SCRIPT (reinterpret_cast<void*>(1))
 
 enum JITScriptStatus {
@@ -427,17 +423,17 @@ class JSPCCounters {
     }
 };
 
 static const uint32 JS_SCRIPT_COOKIE = 0xc00cee;
 
 static JSObject * const JS_NEW_SCRIPT = (JSObject *)0x12345678;
 static JSObject * const JS_CACHED_SCRIPT = (JSObject *)0x12341234;
 
-struct JSScript {
+struct JSScript : public js::gc::Cell {
     /*
      * Two successively less primitive ways to make a new JSScript.  The first
      * does *not* call a non-null cx->runtime->newScriptHook -- only the second,
      * NewScriptFromCG, calls this optional debugger hook.
      *
      * The NewScript function can't know whether the script it creates belongs
      * to a function, or is top-level or eval code, but the debugger wants access
      * to the newly made script's function, if any -- so callers of NewScript
@@ -447,63 +443,64 @@ struct JSScript {
     static JSScript *NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
                                uint32 nobjects, uint32 nupvars, uint32 nregexps,
                                uint32 ntrynotes, uint32 nconsts, uint32 nglobals,
                                uint16 nClosedArgs, uint16 nClosedVars, uint32 nTypeSets,
                                JSVersion version);
 
     static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
 
-    /* FIXME: bug 586181 */
-    JSCList         links;      /* Links for compartment script list */
+#ifdef JS_CRASH_DIAGNOSTICS
+    /*
+     * Make sure that the cookie size does not affect the GC alignment
+     * requirements.
+     */
+    uint32          cookie1[Cell::CellSize / sizeof(uint32)];
+#endif
     jsbytecode      *code;      /* bytecodes and their immediate operands */
-    uint32          length;     /* length of code vector */
+    uint8           *data;      /* pointer to variable-length data array */
 
-#ifdef JS_CRASH_DIAGNOSTICS
-    uint32          cookie1;
-#endif
-
+    uint32          length;     /* length of code vector */
   private:
-    size_t          useCount_;  /* Number of times the script has been called
-                                 * or has had backedges taken. Reset if the
-                                 * script's JIT code is forcibly discarded. */
-
     uint16          version;    /* JS version under which script was compiled */
 
   public:
     uint16          nfixed;     /* number of slots besides stack operands in
                                    slot array */
-    uint16          nTypeSets;  /* number of type sets used in this script for
-                                   dynamic type monitoring */
-
-    /*
-     * When non-zero, compile script in single-step mode. The top bit is set and
-     * cleared by setStepMode, as used by JSD. The lower bits are a count,
-     * adjusted by changeStepModeCount, used by the Debugger object. Only
-     * when the bit is clear and the count is zero may we compile the script
-     * without single-step support.
-     */
-    uint32          stepMode;
-
     /*
      * Offsets to various array structures from the end of this script, or
      * JSScript::INVALID_OFFSET if the array has length 0.
      */
-  public:
     uint8           objectsOffset;  /* offset to the array of nested function,
                                        block, scope, xml and one-time regexps
                                        objects */
     uint8           upvarsOffset;   /* offset of the array of display ("up")
                                        closure vars */
     uint8           regexpsOffset;  /* offset to the array of to-be-cloned
                                        regexps  */
     uint8           trynotesOffset; /* offset to the array of try notes */
     uint8           globalsOffset;  /* offset to the array of global slots */
     uint8           constOffset;    /* offset to the array of constants */
 
+    uint16          nTypeSets;      /* number of type sets used in this script for
+                                       dynamic type monitoring */
+
+    /*
+     * When non-zero, compile script in single-step mode. The top bit is set and
+     * cleared by setStepMode, as used by JSD. The lower bits are a count,
+     * adjusted by changeStepModeCount, used by the Debugger object. Only
+     * when the bit is clear and the count is zero may we compile the script
+     * without single-step support.
+     */
+    uint32          stepMode;
+
+    uint32          lineno;     /* base line number of script */
+
+    uint32          mainOffset; /* offset of main entry point from code, after
+                                   predef'ing prolog */
     bool            noScriptRval:1; /* no need for result value of last
                                        expression statement */
     bool            savedCallerFun:1; /* can call getCallerFunction() */
     bool            hasSharps:1;      /* script uses sharp variables */
     bool            strictModeCode:1; /* code is in strict mode */
     bool            compileAndGo:1;   /* script was compiled with TCF_COMPILE_N_GO */
     bool            usesEval:1;       /* script uses eval() */
     bool            usesArguments:1;  /* script uses arguments */
@@ -519,97 +516,107 @@ struct JSScript {
     bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
     bool            usedLazyArgs:1;   /* script has used lazy arguments at some point */
     bool            createdArgs:1;    /* script has had arguments objects created */
     bool            uninlineable:1;   /* script is considered uninlineable by analysis */
 #ifdef JS_METHODJIT
     bool            debugMode:1;      /* script was compiled in debug mode */
     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
 #endif
+    bool            callDestroyHook:1;/* need to call destroy hook */
 
-    jsbytecode      *main;      /* main entry point, after predef'ing prolog */
-    JSAtomMap       atomMap;    /* maps immediate index to literal struct */
-    JSCompartment   *compartment; /* compartment the script was compiled for */
-    const char      *filename;  /* source filename or null */
-    uint32          lineno;     /* base line number of script */
+    uint32          natoms;     /* length of atoms array */
     uint16          nslots;     /* vars plus maximum stack depth */
     uint16          staticLevel;/* static level for display maintenance */
+
     uint16          nClosedArgs; /* number of args which are closed over. */
     uint16          nClosedVars; /* number of vars which are closed over. */
+
+    /*
+     * To ensure sizeof(JSScript) % gc::Cell::CellSize  == 0 on we must pad
+     * the script with 4 bytes. We use them to store tiny scripts like empty
+     * scripts.
+     */
+#define JS_SCRIPT_INLINE_DATA_LIMIT 4
+    uint8           inlineData[JS_SCRIPT_INLINE_DATA_LIMIT];
+
+    const char      *filename;  /* source filename or null */
+    JSAtom          **atoms;    /* maps immediate index to literal struct */
+  private:
+    size_t          useCount;  /* Number of times the script has been called
+                                 * or has had backedges taken. Reset if the
+                                 * script's JIT code is forcibly discarded. */
+  public:
     js::Bindings    bindings;   /* names of top-level variables in this script
                                    (and arguments if this is a function script) */
     JSPrincipals    *principals;/* principals for this script */
     jschar          *sourceMap; /* source map file or null */
 
-#ifdef JS_CRASH_DIAGNOSTICS
-    JSObject        *ownerObject;
-#endif
-
-    void setOwnerObject(JSObject *owner);
-
     union {
         /*
          * A script object of class js_ScriptClass, to ensure the script is GC'd.
          * - All scripts returned by JSAPI functions (JS_CompileScript,
          *   JS_CompileFile, etc.) have these objects.
          * - Function scripts never have script objects; such scripts are owned
          *   by their function objects.
          * - Temporary scripts created by obj_eval, JS_EvaluateScript, and
          *   similar functions never have these objects; such scripts are
          *   explicitly destroyed by the code that created them.
          */
         JSObject    *object;
-        JSScript    *nextToGC;  /* next to GC in rt->scriptsToGC list */
+
+        /* Hash table chaining for JSCompartment::evalCache. */
+        JSScript    *evalHashLink;
     } u;
 
-#ifdef CHECK_SCRIPT_OWNER
-    JSThread        *owner;     /* for thread-safe life-cycle assertions */
-#endif
-
     uint32          *closedSlots; /* vector of closed slots; args first, then vars. */
 
     /* array of execution counters for every JSOp in the script, by runmode */
     JSPCCounters    pcCounters;
 
-#ifdef JS_CRASH_DIAGNOSTICS
-    uint32          cookie2;
-#endif
-
-  public:
-
     union {
         /* Function this script is the body for, if there is one. */
         JSFunction *fun;
 
         /* Global object for this script, if compileAndGo. */
         js::GlobalObject *global;
     } where;
 
     inline JSFunction *function() const {
         JS_ASSERT(hasFunction);
         return where.fun;
     }
 
+#ifdef JS_CRASH_DIAGNOSTICS
+    JSObject        *ownerObject;
+
+    /* All diagnostic fields must be multiples of Cell::CellSize. */
+    uint32          cookie2[sizeof(JSObject *) == 4 ? 1 : 2];
+#endif
+
+    void setOwnerObject(JSObject *owner);
+
     /*
      * Associates this script with a specific function, constructing a new type
      * object for the function.
      */
     bool typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton = false);
 
     inline bool hasGlobal() const;
     inline js::GlobalObject *global() const;
 
     inline bool hasClearedGlobal() const;
 
 #ifdef DEBUG
     /*
      * Unique identifier within the compartment for this script, used for
      * printing analysis information.
      */
-    unsigned id_;
+    uint32 id_;
+    uint32 idpad;
     unsigned id() { return id_; }
 #else
     unsigned id() { return 0; }
 #endif
 
     /* Persistent type information retained across GCs. */
     js::types::TypeScript *types;
 
@@ -634,90 +641,96 @@ struct JSScript {
     // quickly test whether there is JIT code; a NULL value means no
     // compilation has been attempted. A JS_UNJITTABLE_SCRIPT value means
     // compilation failed. Any value is the arity-check entry point.
     void *jitArityCheckNormal;
     void *jitArityCheckCtor;
 
     js::mjit::JITScript *jitNormal;   /* Extra JIT info for normal scripts */
     js::mjit::JITScript *jitCtor;     /* Extra JIT info for constructors */
+#endif
 
+#ifdef JS_METHODJIT
     bool hasJITCode() {
         return jitNormal || jitCtor;
     }
 
     // These methods are implemented in MethodJIT.h.
     inline void **nativeMap(bool constructing);
     inline void *maybeNativeCodeForPC(bool constructing, jsbytecode *pc);
     inline void *nativeCodeForPC(bool constructing, jsbytecode *pc);
 
     js::mjit::JITScript *getJIT(bool constructing) {
         return constructing ? jitCtor : jitNormal;
     }
 
-    size_t useCount() const  { return useCount_; }
-    size_t incUseCount() { return ++useCount_; }
-    size_t *addressOfUseCount() { return &useCount_; }
-    void resetUseCount() { useCount_ = 0; }
+    size_t getUseCount() const  { return useCount; }
+    size_t incUseCount() { return ++useCount; }
+    size_t *addressOfUseCount() { return &useCount; }
+    void resetUseCount() { useCount = 0; }
 
     JITScriptStatus getJITStatus(bool constructing) {
         void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;
         if (addr == NULL)
             return JITScript_None;
         if (addr == JS_UNJITTABLE_SCRIPT)
             return JITScript_Invalid;
         return JITScript_Valid;
     }
 
     // This method is implemented in MethodJIT.h.
     JS_FRIEND_API(size_t) jitDataSize();/* Size of the JITScript and all sections */
 #endif
 
-    JS_FRIEND_API(size_t) totalSize();  /* Size of the JSScript and all sections */
+    jsbytecode *main() {
+        return code + mainOffset;
+    }
+
+    JS_FRIEND_API(size_t) dataSize();   /* Size of all data sections */
     uint32 numNotes();                  /* Number of srcnote slots in the srcnotes section */
 
     /* Script notes are allocated right after the code. */
     jssrcnote *notes() { return (jssrcnote *)(code + length); }
 
     static const uint8 INVALID_OFFSET = 0xFF;
     static bool isValidOffset(uint8 offset) { return offset != INVALID_OFFSET; }
 
     JSObjectArray *objects() {
         JS_ASSERT(isValidOffset(objectsOffset));
-        return reinterpret_cast<JSObjectArray *>(uintptr_t(this + 1) + objectsOffset);
+        return reinterpret_cast<JSObjectArray *>(data + objectsOffset);
     }
 
     JSUpvarArray *upvars() {
         JS_ASSERT(isValidOffset(upvarsOffset));
-        return reinterpret_cast<JSUpvarArray *>(uintptr_t(this + 1) + upvarsOffset);
+        return reinterpret_cast<JSUpvarArray *>(data + upvarsOffset);
     }
 
     JSObjectArray *regexps() {
         JS_ASSERT(isValidOffset(regexpsOffset));
-        return reinterpret_cast<JSObjectArray *>(uintptr_t(this + 1) + regexpsOffset);
+        return reinterpret_cast<JSObjectArray *>(data + regexpsOffset);
     }
 
     JSTryNoteArray *trynotes() {
         JS_ASSERT(isValidOffset(trynotesOffset));
-        return reinterpret_cast<JSTryNoteArray *>(uintptr_t(this + 1) + trynotesOffset);
+        return reinterpret_cast<JSTryNoteArray *>(data + trynotesOffset);
     }
 
     js::GlobalSlotArray *globals() {
         JS_ASSERT(isValidOffset(globalsOffset));
-        return reinterpret_cast<js::GlobalSlotArray *>(uintptr_t(this + 1) + globalsOffset);
+        return reinterpret_cast<js::GlobalSlotArray *>(data + globalsOffset);
     }
 
     JSConstArray *consts() {
         JS_ASSERT(isValidOffset(constOffset));
-        return reinterpret_cast<JSConstArray *>(uintptr_t(this + 1) + constOffset);
+        return reinterpret_cast<JSConstArray *>(data + constOffset);
     }
 
     JSAtom *getAtom(size_t index) {
-        JS_ASSERT(index < atomMap.length);
-        return atomMap.vector[index];
+        JS_ASSERT(index < natoms);
+        return atoms[index];
     }
 
     JSObject *getObject(size_t index) {
         JSObjectArray *arr = objects();
         JS_ASSERT(index < arr->length);
         return arr->vector[index];
     }
 
@@ -797,21 +810,24 @@ struct JSScript {
      */
     bool changeStepModeCount(JSContext *cx, int delta);
 
     bool stepModeEnabled() { return !!stepMode; }
 
 #ifdef DEBUG
     uint32 stepModeCount() { return stepMode & stepCountMask; }
 #endif
+
+    void finalize(JSContext *cx);
 };
 
+JS_STATIC_ASSERT(sizeof(JSScript) % js::gc::Cell::CellSize == 0);
+
 #define SHARP_NSLOTS            2       /* [#array, #depth] slots if the script
                                            uses sharp variables */
-
 static JS_INLINE uintN
 StackDepth(JSScript *script)
 {
     return script->nslots - script->nfixed;
 }
 
 /*
  * If pc_ does not point within script_'s bytecode, then it must point into an
@@ -847,37 +863,41 @@ js_SweepScriptFilenames(JSCompartment *c
  * of any owning function (the fun parameter) or script object (null fun).
  */
 extern JS_FRIEND_API(void)
 js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun);
 
 extern void
 js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
 
-/*
- * The function must be used only outside the GC for a script that was run
- * only on the current thread.
- */
-extern void
-js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller);
+namespace js {
+
+#ifdef JS_CRASH_DIAGNOSTICS
 
-extern void
-js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner);
+void
+CheckScriptOwner(JSScript *script, JSObject *owner);
+
+void
+CheckScript(JSScript *script, JSScript *prev);
+
+#else
 
-/*
- * Script objects may be cached and reused, in which case their JSD-visible
- * lifetimes may be shorter than their actual lifetimes. Destroy one such
- * script for real as part of a GC pass. From JSD's point of view, the script
- * is already dead.
- */
-extern void
-js_DestroyCachedScript(JSContext *cx, JSScript *script);
+inline void
+CheckScriptOwner(JSScript *script, JSObject *owner)
+{
+}
 
-extern void
-js_TraceScript(JSTracer *trc, JSScript *script, JSObject *owner);
+inline void
+CheckScript(JSScript *script, JSScript *prev)
+{
+}
+
+#endif /* !JS_CRASH_DIAGNOSTICS */
+
+} /* namespace js */
 
 extern JSObject *
 js_NewScriptObject(JSContext *cx, JSScript *script);
 
 /*
  * To perturb as little code as possible, we introduce a js_GetSrcNote lookup
  * cache without adding an explicit cx parameter.  Thus js_GetSrcNote becomes
  * a macro that uses cx from its calls' lexical environments.
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -8092,17 +8092,17 @@ TraceRecorder::updateAtoms()
              ? 0
              : script->consts()->vector;
     strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::updateAtoms(JSScript *script)
 {
-    atoms = script->atomMap.vector;
+    atoms = script->atoms;
     consts = JSScript::isValidOffset(script->constOffset) ? script->consts()->vector : 0;
     strictModeCode_ins = w.name(w.immi(script->strictModeCode), "strict");
 }
 
 /*
  * Generate LIR to compute the scope chain.
  */
 JS_REQUIRES_STACK LIns*
@@ -14511,17 +14511,17 @@ TraceRecorder::record_JSOP_STRICTNE()
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_OBJECT()
 {
     StackFrame* const fp = cx->fp();
     JSScript* script = fp->script();
-    unsigned index = atoms - script->atomMap.vector + GET_INDEX(cx->regs().pc);
+    unsigned index = atoms - script->atoms + GET_INDEX(cx->regs().pc);
 
     JSObject* obj;
     obj = script->getObject(index);
     stack(0, w.immpObjGC(obj));
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
@@ -15439,17 +15439,17 @@ TraceRecorder::record_JSOP_DEFVAR()
 {
     return ARECORD_STOP;
 }
 
 jsatomid
 TraceRecorder::getFullIndex(ptrdiff_t pcoff)
 {
     jsatomid index = GET_INDEX(cx->regs().pc + pcoff);
-    index += atoms - cx->fp()->script()->atomMap.vector;
+    index += atoms - cx->fp()->script()->atoms;
     return index;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_LAMBDA()
 {
     JSFunction* fun;
     fun = cx->fp()->script()->getFunction(getFullIndex());
@@ -15826,17 +15826,17 @@ TraceRecorder::record_JSOP_RETRVAL()
     return ARECORD_STOP;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_REGEXP()
 {
     StackFrame* const fp = cx->fp();
     JSScript* script = fp->script();
-    unsigned index = atoms - script->atomMap.vector + GET_INDEX(cx->regs().pc);
+    unsigned index = atoms - script->atoms + GET_INDEX(cx->regs().pc);
 
     LIns* proto_ins;
     CHECK_STATUS_A(getClassPrototype(JSProto_RegExp, proto_ins));
 
     LIns* args[] = {
         proto_ins,
         w.immpObjGC(script->getRegExp(index)),
         cx_ins
@@ -16974,17 +16974,17 @@ PCWithinLoop(StackFrame *fp, jsbytecode 
 }
 
 LoopProfile::ProfileAction
 LoopProfile::profileOperation(JSContext* cx, JSOp op)
 {
     TraceMonitor* tm = JS_TRACE_MONITOR_FROM_CONTEXT(cx);
 
     JS_ASSERT(tm == traceMonitor);
-    JS_ASSERT(entryScript->compartment->traceMonitor() == tm);
+    JS_ASSERT(entryScript->compartment()->traceMonitor() == tm);
 
     if (profiled) {
         stopProfiling(cx);
         return ProfComplete;
     }
 
     jsbytecode *pc = cx->regs().pc;
     StackFrame *fp = cx->fp();
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -560,19 +560,19 @@ class Value
 #endif
 
     JS_ALWAYS_INLINE
     bool isMarkable() const {
         return JSVAL_IS_TRACEABLE_IMPL(data);
     }
 
     JS_ALWAYS_INLINE
-    int32 gcKind() const {
+    JSGCTraceKind gcKind() const {
         JS_ASSERT(isMarkable());
-        return JSVAL_TRACE_KIND_IMPL(data);
+        return JSGCTraceKind(JSVAL_TRACE_KIND_IMPL(data));
     }
 
     JS_ALWAYS_INLINE
     JSWhyMagic whyMagic() const {
         JS_ASSERT(isMagic());
         return data.s.payload.why;
     }
 
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -714,20 +714,18 @@ JS_XDRScriptObject(JSXDRState *xdr, JSOb
     if (!JS_XDRCStringOrNull(xdr, (char **) &state.filename))
         return false;
 
     if (!js_XDRScript(xdr, &script))
         return false;
 
     if (xdr->mode == JSXDR_DECODE) {
         *scriptObjp = js_NewScriptObject(xdr->cx, script);
-        if (!*scriptObjp) {
-            js_DestroyScript(xdr->cx, script, 8);
+        if (!*scriptObjp)
             return false;
-        }
         js_CallNewScriptHook(xdr->cx, script, NULL);
         Debugger::onNewScript(xdr->cx, script, *scriptObjp, Debugger::NewHeldScript);
     }
 
     return true;
 }
 
 #define CLASS_REGISTRY_MIN      8
--- a/js/src/methodjit/BaseCompiler.h
+++ b/js/src/methodjit/BaseCompiler.h
@@ -143,17 +143,17 @@ class LinkerHelper : public JSC::LinkBuf
     bool verifyRange(JITScript *jit) {
         return verifyRange(JSC::JITCode(jit->code.m_code.executableAddress(), jit->code.m_size));
     }
 
     JSC::ExecutablePool *init(JSContext *cx) {
         // The pool is incref'd after this call, so it's necessary to release()
         // on any failure.
         JSScript *script = cx->fp()->script();
-        JSC::ExecutableAllocator *allocator = script->compartment->jaegerCompartment()->execAlloc();
+        JSC::ExecutableAllocator *allocator = script->compartment()->jaegerCompartment()->execAlloc();
         JSC::ExecutablePool *pool;
         m_code = executableAllocAndCopy(masm, allocator, &pool);
         if (!m_code) {
             js_ReportOutOfMemory(cx);
             return NULL;
         }
         m_size = masm.size();   // must come after call to executableAllocAndCopy()!
         return pool;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -137,17 +137,17 @@ mjit::Compiler::Compiler(JSContext *cx, 
     pcLengths(NULL)
 {
     /* :FIXME: bug 637856 disabling traceJit if inference is enabled */
     if (cx->typeInferenceEnabled())
         addTraceHints = false;
 
     /* Once a script starts getting really hot we will inline calls in it. */
     if (!debugMode() && cx->typeInferenceEnabled() && globalObj &&
-        (outerScript->useCount() >= USES_BEFORE_INLINING ||
+        (outerScript->getUseCount() >= USES_BEFORE_INLINING ||
          cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS))) {
         inlining_ = true;
     }
 }
 
 CompileStatus
 mjit::Compiler::compile()
 {
@@ -860,17 +860,17 @@ mjit::Compiler::finishThisUp(JITScript *
 
     size_t codeSize = masm.size() +
                       stubcc.size() +
                       (masm.numDoubles() * sizeof(double)) +
                       (stubcc.masm.numDoubles() * sizeof(double)) +
                       jumpTableOffsets.length() * sizeof(void *);
 
     JSC::ExecutablePool *execPool;
-    uint8 *result = (uint8 *)script->compartment->jaegerCompartment()->execAlloc()->
+    uint8 *result = (uint8 *)script->compartment()->jaegerCompartment()->execAlloc()->
                     alloc(codeSize, &execPool, JSC::METHOD_CODE);
     if (!result) {
         js_ReportOutOfMemory(cx);
         return Compile_Error;
     }
     JS_ASSERT(execPool);
     JSC::ExecutableAllocator::makeWritable(result, codeSize);
     masm.executableCopy(result);
@@ -2817,17 +2817,17 @@ mjit::Compiler::labelOf(jsbytecode *pc, 
 
 uint32
 mjit::Compiler::fullAtomIndex(jsbytecode *pc)
 {
     return GET_SLOTNO(pc);
 
     /* If we ever enable INDEXBASE garbage, use this below. */
 #if 0
-    return GET_SLOTNO(pc) + (atoms - script->atomMap.vector);
+    return GET_SLOTNO(pc) + (atoms - script->atoms);
 #endif
 }
 
 bool
 mjit::Compiler::knownJump(jsbytecode *pc)
 {
     return pc < PC;
 }
@@ -5497,17 +5497,17 @@ mjit::Compiler::iter(uintN flags)
     frame.pinReg(reg);
     RegisterID ioreg = frame.allocReg();  /* Will hold iterator JSObject */
     RegisterID nireg = frame.allocReg();  /* Will hold NativeIterator */
     RegisterID T1 = frame.allocReg();
     RegisterID T2 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Fetch the most recent iterator. */
-    masm.loadPtr(&script->compartment->nativeIterCache.last, ioreg);
+    masm.loadPtr(&script->compartment()->nativeIterCache.last, ioreg);
 
     /* Test for NULL. */
     Jump nullIterator = masm.branchTest32(Assembler::Zero, ioreg, ioreg);
     stubcc.linkExit(nullIterator, Uses(1));
 
     /* Get NativeIterator from iter obj. */
     masm.loadObjPrivate(ioreg, nireg);
 
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -82,17 +82,17 @@ static jsbytecode *
 FindExceptionHandler(JSContext *cx)
 {
     StackFrame *fp = cx->fp();
     JSScript *script = fp->script();
 
 top:
     if (cx->isExceptionPending() && JSScript::isValidOffset(script->trynotesOffset)) {
         // The PC is updated before every stub call, so we can use it here.
-        unsigned offset = cx->regs().pc - script->main;
+        unsigned offset = cx->regs().pc - script->main();
 
         JSTryNoteArray *tnarray = script->trynotes();
         for (unsigned i = 0; i < tnarray->length; ++i) {
             JSTryNote *tn = &tnarray->vector[i];
 
             // The following if condition actually tests two separate conditions:
             //   (1) offset - tn->start >= tn->length
             //       means the PC is not in the range of this try note, so we
@@ -108,17 +108,17 @@ top:
             //       exception, in which case this would not be the right handler.
             //       But the first ops of exception handlers generated by our
             //       bytecode compiler cannot throw, so this is not possible.
             if (offset - tn->start > tn->length)
                 continue;
             if (tn->stackDepth > cx->regs().sp - fp->base())
                 continue;
 
-            jsbytecode *pc = script->main + tn->start + tn->length;
+            jsbytecode *pc = script->main() + tn->start + tn->length;
             cx->regs().pc = pc;
             JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
             JS_ASSERT(cx->regs().sp == fp->base() + tn->stackDepth);
 
             switch (tn->kind) {
                 case JSTRY_CATCH:
                   JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENTERBLOCK);
 
@@ -176,21 +176,22 @@ top:
  */
 static void
 InlineReturn(VMFrame &f)
 {
     JS_ASSERT(f.fp() != f.entryfp);
     JS_ASSERT(!js_IsActiveWithOrBlock(f.cx, &f.fp()->scopeChain(), 0));
     f.cx->stack.popInlineFrame(f.regs);
 
-    JS_ASSERT(*f.regs.pc == JSOP_CALL ||
-              *f.regs.pc == JSOP_NEW ||
-              *f.regs.pc == JSOP_EVAL ||
-              *f.regs.pc == JSOP_FUNCALL ||
-              *f.regs.pc == JSOP_FUNAPPLY);
+    DebugOnly<JSOp> op = js_GetOpcode(f.cx, f.fp()->script(), f.regs.pc);
+    JS_ASSERT(op == JSOP_CALL ||
+              op == JSOP_NEW ||
+              op == JSOP_EVAL ||
+              op == JSOP_FUNCALL ||
+              op == JSOP_FUNAPPLY);
     f.regs.pc += JSOP_CALL_LENGTH;
 }
 
 void JS_FASTCALL
 stubs::SlowCall(VMFrame &f, uint32 argc)
 {
     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
     if (!InvokeKernel(f.cx, args))
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -127,25 +127,25 @@ StackFrame::methodjitStaticAsserts()
 #ifdef JS_METHODJIT_PROFILE_STUBS
 static const size_t STUB_CALLS_FOR_OP_COUNT = 255;
 static uint32 StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
 #endif
 
 extern "C" void JS_FASTCALL
 PushActiveVMFrame(VMFrame &f)
 {
-    f.entryfp->script()->compartment->jaegerCompartment()->pushActiveFrame(&f);
+    f.entryfp->script()->compartment()->jaegerCompartment()->pushActiveFrame(&f);
     f.entryfp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
     f.regs.clearInlined();
 }
 
 extern "C" void JS_FASTCALL
 PopActiveVMFrame(VMFrame &f)
 {
-    f.entryfp->script()->compartment->jaegerCompartment()->popActiveFrame();
+    f.entryfp->script()->compartment()->jaegerCompartment()->popActiveFrame();
 }
 
 extern "C" void JS_FASTCALL
 SetVMFrameRegs(VMFrame &f)
 {
     f.oldregs = &f.cx->stack.regs();
 
     /* Restored on exit from EnterMethodJIT. */
--- a/js/src/methodjit/Retcon.cpp
+++ b/js/src/methodjit/Retcon.cpp
@@ -432,17 +432,17 @@ Recompiler::recompile(bool resetUses)
      *    code.
      * 2) If an address corresponds to a call site registered by |callSite| during
      *    the last compilation, patch it to go to the interpoline.
      * 3) Purge the old compiled state.
      */
 
     // Find all JIT'd stack frames to account for return addresses that will
     // need to be patched after recompilation.
-    for (VMFrame *f = script->compartment->jaegerCompartment()->activeFrame();
+    for (VMFrame *f = script->compartment()->jaegerCompartment()->activeFrame();
          f != NULL;
          f = f->previous) {
 
         // Scan all frames owned by this VMFrame.
         StackFrame *end = f->entryfp->prev();
         StackFrame *next = NULL;
         for (StackFrame *fp = f->fp(); fp != end; fp = fp->prev()) {
             if (fp->script() != script) {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1930,17 +1930,17 @@ SrcNotes(JSContext *cx, JSScript *script
                 Sprint(sp, " first case offset %u", caseOff);
             UpdateSwitchTableBounds(cx, script, offset,
                                     &switchTableStart, &switchTableEnd);
             break;
           }
           case SRC_CATCH:
             delta = (uintN) js_GetSrcNoteOffset(sn, 0);
             if (delta) {
-                if (script->main[offset] == JSOP_LEAVEBLOCK)
+                if (script->main()[offset] == JSOP_LEAVEBLOCK)
                     Sprint(sp, " stack depth %u", delta);
                 else
                     Sprint(sp, " guard delta %u", delta);
             }
             break;
           default:;
         }
         Sprint(sp, "\n");
@@ -3803,16 +3803,21 @@ Parent(JSContext *cx, uintN argc, jsval 
  */
 static char *
 MakeAbsolutePathname(JSContext *cx, const char *from, const char *leaf)
 {
     size_t dirlen;
     char *dir;
     const char *slash = NULL, *cp;
 
+    if (*leaf == '/') {
+        /* We were given an absolute pathname. */
+        return JS_strdup(cx, leaf);
+    }
+
     cp = from;
     while (*cp) {
         if (*cp == '/') {
             slash = cp;
         }
 
         ++cp;
     }
@@ -3902,53 +3907,59 @@ Parse(JSContext *cx, uintN argc, jsval *
     return JS_TRUE;
 }
 
 struct FreeOnReturn {
     JSContext *cx;
     const char *ptr;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
-    FreeOnReturn(JSContext *cx, const char *ptr JS_GUARD_OBJECT_NOTIFIER_PARAM)
+    FreeOnReturn(JSContext *cx, const char *ptr = NULL JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : cx(cx), ptr(ptr) {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
+    void init(const char *ptr) {
+        JS_ASSERT(!this->ptr);
+        this->ptr = ptr;
+    }
+
     ~FreeOnReturn() {
         JS_free(cx, (void*)ptr);
     }
 };
 
 static JSBool
 Snarf(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str;
-    const char *pathname;
 
     if (!argc)
         return JS_FALSE;
 
     str = JS_ValueToString(cx, JS_ARGV(cx, vp)[0]);
     if (!str)
         return JS_FALSE;
     JSAutoByteString filename(cx, str);
     if (!filename)
         return JS_FALSE;
 
     /* Get the currently executing script's name. */
     JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
     JSScript *script = JS_GetFrameScript(cx, fp);
     JS_ASSERT(fp && script->filename);
+    const char *pathname = filename.ptr();
 #ifdef XP_UNIX
-    pathname = MakeAbsolutePathname(cx, script->filename, filename.ptr());
-    if (!pathname)
-        return JS_FALSE;
-    FreeOnReturn pnGuard(cx, pathname);
-#else
-    pathname = filename.ptr();
+    FreeOnReturn pnGuard(cx);
+    if (pathname[0] != '/') {
+        pathname = MakeAbsolutePathname(cx, script->filename, pathname);
+        if (!pathname)
+            return JS_FALSE;
+        pnGuard.init(pathname);
+    }
 #endif
 
     if (argc > 1) {
         JSString *opt = JS_ValueToString(cx, JS_ARGV(cx, vp)[1]);
         if (!opt)
             return JS_FALSE;
         JSBool match;
         if (!JS_StringEqualsAscii(cx, opt, "binary", &match))
@@ -4050,31 +4061,36 @@ MJitCodeStats(JSContext *cx, uintN argc,
     }
     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(n));
 #else
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
 #endif
     return true;
 }
 
+#ifdef JS_METHODJIT
+
+static void
+SumJitDataSizeCallabck(JSContext *cx, void *data, void *thing,
+                       JSGCTraceKind traceKind, size_t thingSize)
+{
+    size_t *sump = static_cast<size_t *>(data);
+    JS_ASSERT(traceKind == JSTRACE_SCRIPT);
+    JSScript *script = static_cast<JSScript *>(thing);
+    *sump += script->jitDataSize();
+}
+
+#endif
+
 JSBool
 MJitDataStats(JSContext *cx, uintN argc, jsval *vp)
 {
 #ifdef JS_METHODJIT
-    JSRuntime *rt = cx->runtime;
-    AutoLockGC lock(rt);
     size_t n = 0;
-    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
-        for (JSScript *script = (JSScript *)(*c)->scripts.next;
-             &script->links != &(*c)->scripts;
-             script = (JSScript *)script->links.next)
-        {
-            n += script->jitDataSize(); 
-        }
-    }
+    IterateCells(cx, NULL, gc::FINALIZE_TYPE_OBJECT, &n, SumJitDataSizeCallabck);
     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(n));
 #else
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
 #endif
     return true;
 }
 
 JSBool
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -232,17 +232,17 @@ BreakpointSite::clearTrap(JSContext *cx,
 
 void
 BreakpointSite::destroyIfEmpty(JSRuntime *rt, BreakpointSiteMap::Enum *e)
 {
     if (JS_CLIST_IS_EMPTY(&breakpoints) && !trapHandler) {
         if (e)
             e->removeFront();
         else
-            script->compartment->breakpointSites.remove(pc);
+            script->compartment()->breakpointSites.remove(pc);
         rt->delete_(this);
     }
 }
 
 Breakpoint *
 BreakpointSite::firstBreakpoint() const
 {
     if (JS_CLIST_IS_EMPTY(&breakpoints))
@@ -474,17 +474,17 @@ Debugger::slowPathOnLeaveFrame(JSContext
     }
 
     /*
      * If this is an eval frame, then from the debugger's perspective the
      * script is about to be destroyed. Remove any breakpoints in it.
      */
     if (fp->isEvalFrame()) {
         JSScript *script = fp->script();
-        script->compartment->clearBreakpointsIn(cx, NULL, script, NULL);
+        script->compartment()->clearBreakpointsIn(cx, NULL, script, NULL);
     }
 }
 
 bool
 Debugger::wrapDebuggeeValue(JSContext *cx, Value *vp)
 {
     assertSameCompartment(cx, object);
 
@@ -832,17 +832,17 @@ Debugger::slowPathOnNewScript(JSContext 
     if (script->compileAndGo) {
         global = obj->getGlobal();
         if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
             if (!AddNewScriptRecipients(debuggers, &triggered))
                 return;
         }
     } else {
         global = NULL;
-        GlobalObjectSet &debuggees = script->compartment->getDebuggees();
+        GlobalObjectSet &debuggees = script->compartment()->getDebuggees();
         for (GlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
             if (!AddNewScriptRecipients(r.front()->getDebuggers(), &triggered))
                 return;
         }
     }
 
     /*
      * Deliver the event to each debugger, checking again as in
@@ -1893,18 +1893,18 @@ Debugger::newDebuggerScript(JSContext *c
 
     return scriptobj;
 }
 
 JSObject *
 Debugger::wrapHeldScript(JSContext *cx, JSScript *script, JSObject *obj)
 {
     assertSameCompartment(cx, object);
-    JS_ASSERT(cx->compartment != script->compartment);
-    JS_ASSERT(script->compartment == obj->compartment());
+    JS_ASSERT(cx->compartment != script->compartment());
+    JS_ASSERT(script->compartment() == obj->compartment());
 
     ScriptWeakMap::AddPtr p = heldScripts.lookupForAdd(obj);
     if (!p) {
         JSObject *scriptobj = newDebuggerScript(cx, script, obj);
 
         /* The allocation may have caused a GC, which can remove table entries. */
         if (!scriptobj || !heldScripts.relookupOrAdd(p, obj, scriptobj))
             return NULL;
@@ -1926,17 +1926,17 @@ Debugger::wrapJSAPIScript(JSContext *cx,
     JS_ASSERT(obj->isScript());
     return wrapHeldScript(cx, obj->getScript(), obj);
 }
 
 JSObject *
 Debugger::wrapNonHeldScript(JSContext *cx, JSScript *script)
 {
     assertSameCompartment(cx, object);
-    JS_ASSERT(cx->compartment != script->compartment);
+    JS_ASSERT(cx->compartment != script->compartment());
 
     ScriptMap::AddPtr p = nonHeldScripts.lookupForAdd(script);
     if (!p) {
         JSObject *scriptobj = newDebuggerScript(cx, script, NULL);
 
         /* The allocation may have caused a GC, which can remove table entries. */
         if (!scriptobj || !nonHeldScripts.relookupOrAdd(p, script, scriptobj))
             return NULL;
@@ -1945,17 +1945,17 @@ Debugger::wrapNonHeldScript(JSContext *c
     JS_ASSERT(GetScriptReferent(p->value) == script);
     return p->value;
 }
 
 void
 Debugger::slowPathOnDestroyScript(JSScript *script)
 {
     /* Find all debuggers that might have Debugger.Script referring to this script. */
-    js::GlobalObjectSet *debuggees = &script->compartment->getDebuggees();
+    js::GlobalObjectSet *debuggees = &script->compartment()->getDebuggees();
     for (GlobalObjectSet::Range r = debuggees->all(); !r.empty(); r.popFront()) {
         GlobalObject::DebuggerVector *debuggers = r.front()->getDebuggers();
         for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++)
             (*p)->destroyNonHeldScript(script);
     }
 }
 
 void
@@ -2390,17 +2390,17 @@ DebuggerScript_setBreakpoint(JSContext *
     size_t offset;
     if (!ScriptOffset(cx, script, args[0], &offset))
         return false;
 
     JSObject *handler = NonNullObject(cx, args[1]);
     if (!handler)
         return false;
 
-    JSCompartment *comp = script->compartment;
+    JSCompartment *comp = script->compartment();
     jsbytecode *pc = script->code + offset;
     BreakpointSite *site = comp->getOrCreateBreakpointSite(cx, script, pc, holder);
     if (!site)
         return false;
     if (site->inc(cx)) {
         if (cx->runtime->new_<Breakpoint>(dbg, site, handler)) {
             args.rval().setUndefined();
             return true;
@@ -2425,17 +2425,17 @@ DebuggerScript_getBreakpoints(JSContext 
         pc = script->code + offset;
     } else {
         pc = NULL;
     }
 
     JSObject *arr = NewDenseEmptyArray(cx);
     if (!arr)
         return false;
-    JSCompartment *comp = script->compartment;
+    JSCompartment *comp = script->compartment();
     for (BreakpointSiteMap::Range r = comp->breakpointSites.all(); !r.empty(); r.popFront()) {
         BreakpointSite *site = r.front().value;
         if (site->script == script && (!pc || site->pc == pc)) {
             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = bp->nextInSite()) {
                 if (bp->debugger == dbg &&
                     !js_NewbornArrayPush(cx, arr, ObjectValue(*bp->getHandler())))
                 {
                     return false;
@@ -2453,27 +2453,27 @@ DebuggerScript_clearBreakpoint(JSContext
     REQUIRE_ARGC("Debugger.Script.clearBreakpoint", 1);
     THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "clearBreakpoint", args, obj, script);
     Debugger *dbg = Debugger::fromChildJSObject(obj);
 
     JSObject *handler = NonNullObject(cx, args[0]);
     if (!handler)
         return false;
 
-    script->compartment->clearBreakpointsIn(cx, dbg, script, handler);
+    script->compartment()->clearBreakpointsIn(cx, dbg, script, handler);
     args.rval().setUndefined();
     return true;
 }
 
 static JSBool
 DebuggerScript_clearAllBreakpoints(JSContext *cx, uintN argc, Value *vp)
 {
     THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "clearBreakpoint", args, obj, script);
     Debugger *dbg = Debugger::fromChildJSObject(obj);
-    script->compartment->clearBreakpointsIn(cx, dbg, script, NULL);
+    script->compartment()->clearBreakpointsIn(cx, dbg, script, NULL);
     args.rval().setUndefined();
     return true;
 }
 
 static JSBool
 DebuggerScript_construct(JSContext *cx, uintN argc, Value *vp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR, "Debugger.Script");
@@ -2876,18 +2876,17 @@ EvaluateInScope(JSContext *cx, JSObject 
                                                TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_OBJECT,
                                                chars, length,
                                                filename, lineno, cx->findVersion(),
                                                NULL, UpvarCookie::UPVAR_LEVEL_LIMIT);
 
     if (!script)
         return false;
 
-    bool ok = ExecuteKernel(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
-    return ok;
+    return ExecuteKernel(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
 }
 
 }
 
 enum EvalBindingsMode { WithoutBindings, WithBindings };
 
 static JSBool
 DebuggerFrameEval(JSContext *cx, uintN argc, Value *vp, EvalBindingsMode mode)
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -563,24 +563,24 @@ Debugger::onExceptionUnwind(JSContext *c
            ? JSTRAP_CONTINUE
            : dispatchHook(cx, vp, OnExceptionUnwind);
 }
 
 void
 Debugger::onNewScript(JSContext *cx, JSScript *script, JSObject *obj, NewScriptKind kind)
 {
     JS_ASSERT_IF(kind == NewHeldScript || script->compileAndGo, obj);
-    if (!script->compartment->getDebuggees().empty())
+    if (!script->compartment()->getDebuggees().empty())
         slowPathOnNewScript(cx, script, obj, kind);
 }
 
 void
 Debugger::onDestroyScript(JSScript *script)
 {
-    if (!script->compartment->getDebuggees().empty())
+    if (!script->compartment()->getDebuggees().empty())
         slowPathOnDestroyScript(script);
 }
 
 extern JSBool
 EvaluateInScope(JSContext *cx, JSObject *scobj, StackFrame *fp, const jschar *chars,
                 uintN length, const char *filename, uintN lineno, Value *rval);
 
 }
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -579,26 +579,26 @@ ContextStack::currentScript(jsbytecode *
         return NULL;
 
 #ifdef JS_METHODJIT
     mjit::CallSite *inlined = regs->inlined();
     if (inlined) {
         JS_ASSERT(inlined->inlineIndex < fp->jit()->nInlineFrames);
         mjit::InlineFrame *frame = &fp->jit()->inlineFrames()[inlined->inlineIndex];
         JSScript *script = frame->fun->script();
-        if (script->compartment != cx_->compartment)
+        if (script->compartment() != cx_->compartment)
             return NULL;
         if (ppc)
             *ppc = script->code + inlined->pcOffset;
         return script;
     }
 #endif
 
     JSScript *script = fp->script();
-    if (script->compartment != cx_->compartment)
+    if (script->compartment() != cx_->compartment)
         return NULL;
 
     if (ppc)
         *ppc = fp->pcQuadratic(*this);
     return script;
 }
 
 inline JSObject *
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -887,17 +887,17 @@ class StackFrame
     /*
      * Frame compartment
      *
      * A stack frame's compartment is the frame's containing context's
      * compartment when the frame was pushed.
      */
 
     JSCompartment *compartment() const {
-        JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment);
+        JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment());
         return scopeChain().compartment();
     }
 
     /*
      * Imacropc
      *
      * A frame's IMacro pc is the bytecode address when an imacro started
      * executing (guaranteed non-null). An imacro does not push a frame, so
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -840,21 +840,25 @@ nsXPConnect::Traverse(void *p, nsCycleCo
             else
             {
                 JS_snprintf(name, sizeof(name), "JS Object (%s)",
                             clazz->name);
             }
         }
         else
         {
-            static const char trace_types[JSTRACE_LIMIT][7] = {
+            static const char trace_types[][11] = {
                 "Object",
                 "String",
-                "Xml"
+                "Script",
+                "Xml",
+                "Shape",
+                "TypeObject",
             };
+            JS_STATIC_ASSERT(JS_ARRAY_LENGTH(trace_types) == JSTRACE_LAST + 1);
             JS_snprintf(name, sizeof(name), "JS %s", trace_types[traceKind]);
         }
 
         if(traceKind == JSTRACE_OBJECT) {
             JSObject *global = static_cast<JSObject*>(p), *parent;
             while((parent = global->getParent()))
                 global = parent;
             char fullname[100];
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -221,17 +221,17 @@ DyingProtoKiller(JSDHashTable *table, JS
     delete proto;
     return JS_DHASH_REMOVE;
 }
 
 static JSDHashOperator
 DetachedWrappedNativeProtoMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
                                  uint32 number, void *arg)
 {
-    XPCWrappedNativeProto* proto = 
+    XPCWrappedNativeProto* proto =
         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
 
     proto->Mark();
     return JS_DHASH_NEXT;
 }
 
 // GCCallback calls are chained
 static JSBool
@@ -505,17 +505,17 @@ NoteJSHolder(JSDHashTable *table, JSDHas
 // static
 void
 XPCJSRuntime::SuspectWrappedNative(JSContext *cx, XPCWrappedNative *wrapper,
                                    nsCycleCollectionTraversalCallback &cb)
 {
     if(!wrapper->IsValid() || wrapper->IsWrapperExpired())
         return;
 
-    NS_ASSERTION(NS_IsMainThread() || NS_IsCycleCollectorThread(), 
+    NS_ASSERTION(NS_IsMainThread() || NS_IsCycleCollectorThread(),
                  "Suspecting wrapped natives from non-CC thread");
 
     // Only suspect wrappedJSObjects that are in a compartment that
     // participates in cycle collection.
     JSObject* obj = wrapper->GetFlatJSObjectPreserveColor();
     if(!xpc::ParticipatesInCycleCollection(cx, obj))
         return;
 
@@ -846,17 +846,17 @@ JSBool XPCJSRuntime::GCCallback(JSContex
             // Skip this part if XPConnect is shutting down. We get into
             // bad locking problems with the thread iteration otherwise.
             if(!self->GetXPConnect()->IsShuttingDown())
             {
                 Mutex* threadLock = XPCPerThreadData::GetLock();
                 if(threadLock)
                 {
                     // Do the marking...
-                    
+
                     { // scoped lock
                         MutexAutoLock lock(*threadLock);
 
                         XPCPerThreadData* iterp = nsnull;
                         XPCPerThreadData* thread;
 
                         while(nsnull != (thread =
                                  XPCPerThreadData::IterateThreads(&iterp)))
@@ -865,17 +865,17 @@ JSBool XPCJSRuntime::GCCallback(JSContex
                             while(ccxp)
                             {
                                 // Deal with the strictness of callcontext that
                                 // complains if you ask for a tearoff when
                                 // it is in a state where the tearoff could not
                                 // possibly be valid.
                                 if(ccxp->CanGetTearOff())
                                 {
-                                    XPCWrappedNativeTearOff* to = 
+                                    XPCWrappedNativeTearOff* to =
                                         ccxp->GetTearOff();
                                     if(to)
                                         to->Mark();
                                 }
                                 ccxp = ccxp->GetPrevCallContext();
                             }
                         }
                     }
@@ -1037,17 +1037,17 @@ WrappedJSShutdownMarker(JSDHashTable *ta
     wrapper->SystemIsBeingShutDown(rt);
     return JS_DHASH_NEXT;
 }
 
 static JSDHashOperator
 DetachedWrappedNativeProtoShutdownMarker(JSDHashTable *table, JSDHashEntryHdr *hdr,
                                          uint32 number, void *arg)
 {
-    XPCWrappedNativeProto* proto = 
+    XPCWrappedNativeProto* proto =
         (XPCWrappedNativeProto*)((JSDHashEntryStub*)hdr)->key;
 
     proto->SystemIsBeingShutDown((JSContext*)arg);
     return JS_DHASH_NEXT;
 }
 
 void XPCJSRuntime::SystemIsBeingShutDown(JSContext* cx)
 {
@@ -1245,53 +1245,16 @@ XPCJSRuntime::~XPCJSRuntime()
 #endif
     }
 
     XPCPerThreadData::ShutDown();
 }
 
 namespace {
 
-PRInt64
-GetCompartmentScriptsSize(JSCompartment *c)
-{
-    PRInt64 n = 0;
-    for(JSScript *script = (JSScript *)c->scripts.next;
-        &script->links != &c->scripts;
-        script = (JSScript *)script->links.next)
-    {
-        n += script->totalSize();
-    }
-    return n;
-}
-
-#ifdef JS_METHODJIT
-
-void
-GetCompartmentMjitCodeStats(JSCompartment *c, size_t& method, size_t& regexp,
-        size_t& unused)
-{
-    c->getMjitCodeStats(method, regexp, unused);
-}
-
-PRInt64
-GetCompartmentMjitDataSize(JSCompartment *c)
-{
-    PRInt64 n = 0;
-    for(JSScript *script = (JSScript *)c->scripts.next;
-        &script->links != &c->scripts;
-        script = (JSScript *)script->links.next)
-    {
-        n += script->jitDataSize();
-    }
-    return n;
-}
-
-#endif  // JS_METHODJIT
-
 #ifdef JS_TRACER
 
 PRInt64
 GetCompartmentTjitCodeSize(JSCompartment *c)
 {
     if(c->hasTraceMonitor())
     {
         size_t total, frag_size, free_size;
@@ -1333,84 +1296,95 @@ CompartmentCallback(JSContext *cx, void 
     // Append a new CompartmentStats to the vector.
     IterateData *data = static_cast<IterateData *>(vdata);
     CompartmentStats compartmentStats(cx, compartment);
     CompartmentStats *curr =
         data->compartmentStatsVector.AppendElement(compartmentStats);
     data->currCompartmentStats = curr;
 
     // Get the compartment-level numbers.
-    curr->scripts = GetCompartmentScriptsSize(compartment);
 #ifdef JS_METHODJIT
     size_t method, regexp, unused;
-    GetCompartmentMjitCodeStats(compartment, method, regexp, unused);
+    compartment->getMjitCodeStats(method, regexp, unused);
     curr->mjitCodeMethod = method;
     curr->mjitCodeRegexp = regexp;
     curr->mjitCodeUnused = unused;
-    curr->mjitData = GetCompartmentMjitDataSize(compartment);
 #endif
 #ifdef JS_TRACER
     curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
     curr->tjitDataAllocatorsMain = GetCompartmentTjitDataAllocatorsMainSize(compartment);
     curr->tjitDataAllocatorsReserve = GetCompartmentTjitDataAllocatorsReserveSize(compartment);
     curr->tjitDataNonAllocators = GetCompartmentTjitDataTraceMonitorSize(compartment);
 #endif
     JS_GetTypeInferenceMemoryStats(cx, compartment, &curr->typeInferenceMemory);
 }
 
 void
 ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
-              size_t traceKind, size_t thingSize)
+              JSGCTraceKind traceKind, size_t thingSize)
 {
     IterateData *data = static_cast<IterateData *>(vdata);
     data->currCompartmentStats->gcHeapArenaHeaders +=
         sizeof(js::gc::ArenaHeader);
     data->currCompartmentStats->gcHeapArenaPadding +=
         arena->thingsStartOffset(thingSize) - sizeof(js::gc::ArenaHeader);
     // We don't call the callback on unused things.  So we compute the
     // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
     // We do this by setting arenaUnused to maxArenaUnused here, and then
     // subtracting thingSize for every used cell, in CellCallback().
     data->currCompartmentStats->gcHeapArenaUnused += arena->thingsSpan(thingSize);
 }
 
 void
-CellCallback(JSContext *cx, void *vdata, void *thing, size_t traceKind,
+CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
              size_t thingSize)
 {
     IterateData *data = static_cast<IterateData *>(vdata);
     CompartmentStats *curr = data->currCompartmentStats;
-    if(traceKind == JSTRACE_OBJECT)
-    {
-        curr->gcHeapObjects += thingSize;
-        JSObject *obj = static_cast<JSObject *>(thing);
-        curr->objectSlots += JS_ObjectCountDynamicSlots(obj) * sizeof(js::Value);
-    }
-    else if(traceKind == JSTRACE_STRING)
-    {
-        curr->gcHeapStrings += thingSize;
-        JSString *str = static_cast<JSString *>(thing);
-        curr->stringChars += str->charsHeapSize();
-    }
-    else if(traceKind == JSTRACE_SHAPE)
+    curr->gcHeapKinds[traceKind] += thingSize;
+    switch (traceKind)
     {
-        curr->gcHeapShapes += thingSize;
-        js::Shape *shape = static_cast<js::Shape *>(thing);
-        if(shape->hasTable())
-            curr->propertyTables += shape->getTable()->sizeOf();
-    }
-    else if(traceKind == JSTRACE_TYPE_OBJECT)
-    {
-        js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
-        JS_GetTypeInferenceObjectStats(obj, &curr->typeInferenceMemory);
-    }
-    else
-    {
-        JS_ASSERT(traceKind == JSTRACE_XML);
-        curr->gcHeapXml += thingSize;
+        case JSTRACE_OBJECT:
+        {
+            JSObject *obj = static_cast<JSObject *>(thing);
+            curr->objectSlots += JS_ObjectCountDynamicSlots(obj) * sizeof(js::Value);
+            break;
+        }
+        case JSTRACE_STRING:
+        {
+            JSString *str = static_cast<JSString *>(thing);
+            curr->stringChars += str->charsHeapSize();
+            break;
+        }
+        case JSTRACE_SHAPE:
+        {
+            js::Shape *shape = static_cast<js::Shape *>(thing);
+            if(shape->hasTable())
+                curr->propertyTables += shape->getTable()->sizeOf();
+            break;
+        }
+        case JSTRACE_SCRIPT:
+        {
+            JSScript *script = static_cast<JSScript *>(thing);
+            curr->scriptData += script->dataSize();
+#ifdef JS_METHODJIT
+            curr->mjitData += script->jitDataSize();
+#endif
+            break;
+        }
+        case JSTRACE_TYPE_OBJECT:
+        {
+            js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
+            JS_GetTypeInferenceObjectStats(obj, &curr->typeInferenceMemory);
+            break;
+        }
+        case JSTRACE_XML:
+        {
+            break;
+        }
     }
     // Yes, this is a subtraction:  see ArenaCallback() for details.
     curr->gcHeapArenaUnused -= thingSize;
 }
 
 template <int N>
 inline void
 ReportMemory(const nsACString &path, PRInt32 kind, PRInt32 units,
@@ -1665,33 +1639,34 @@ CollectCompartmentStatsForRuntime(JSRunt
     data->gcHeapArenaUnused = 0;
 
     for(PRUint32 index = 0;
         index < data->compartmentStatsVector.Length();
         index++)
     {
         CompartmentStats &stats = data->compartmentStatsVector[index];
 
-        data->gcHeapChunkDirtyUnused -=
-            stats.gcHeapArenaHeaders + stats.gcHeapArenaPadding +
-            stats.gcHeapArenaUnused +
-            stats.gcHeapObjects + stats.gcHeapStrings +
-            stats.gcHeapShapes + stats.gcHeapXml;
-        
+        PRInt64 used = stats.gcHeapArenaHeaders +
+                       stats.gcHeapArenaPadding +
+                       stats.gcHeapArenaUnused;
+        for (size_t i = 0; i != JS_ARRAY_LENGTH(stats.gcHeapKinds); ++i)
+            used += stats.gcHeapKinds[i];
+
+        data->gcHeapChunkDirtyUnused -= used;
         data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
     }
 
     size_t numDirtyChunks = (data->gcHeapChunkTotal -
                              data->gcHeapChunkCleanUnused) /
                             js::GC_CHUNK_SIZE;
     PRInt64 perChunkAdmin =
         sizeof(js::gc::Chunk) - (sizeof(js::gc::Arena) * js::gc::ArenasPerChunk);
     data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
     data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
-    
+
     // Why 10000x?  100x because it's a percentage, and another 100x
     // because nsIMemoryReporter requires that for percentage amounts so
     // they can be fractional.
     data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
                                     data->gcHeapChunkDirtyUnused +
                                     data->gcHeapArenaUnused) * 10000 /
                                    data->gcHeapChunkTotal;
 
@@ -1723,42 +1698,57 @@ ReportCompartmentStats(const Compartment
                                               "gc-heap/arena-unused"),
                        JS_GC_HEAP_KIND, stats.gcHeapArenaUnused,
     "Memory on the compartment's garbage-collected JavaScript heap, within "
     "arenas, that could be holding useful data but currently isn't.",
                        callback, closure);
 
     ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
                                               "gc-heap/objects"),
-                       JS_GC_HEAP_KIND, stats.gcHeapObjects,
+                       JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_OBJECT],
     "Memory on the compartment's garbage-collected JavaScript heap that holds "
     "objects.",
                        callback, closure);
 
     ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
                                               "gc-heap/strings"),
-                       JS_GC_HEAP_KIND, stats.gcHeapStrings,
+                       JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_STRING],
     "Memory on the compartment's garbage-collected JavaScript heap that holds "
     "string headers.  String headers contain various pieces of information "
     "about a string, but do not contain (except in the case of very short "
     "strings) the string characters;  characters in longer strings are counted "
     "under 'gc-heap/string-chars' instead.",
                        callback, closure);
 
     ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/scripts"),
+                       JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_SCRIPT],
+    "Memory on the compartment's garbage-collected JavaScript heap that holds "
+    "JSScript instances. A JSScript is created for each user-defined function "
+    "in a script. One is also created for the top-level code in a script.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
                                               "gc-heap/shapes"),
-                       JS_GC_HEAP_KIND, stats.gcHeapShapes,
+                       JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_SHAPE],
     "Memory on the compartment's garbage-collected JavaScript heap that holds "
     "shapes. A shape is an internal data structure that makes JavaScript "
     "property accesses fast.",
                        callback, closure);
 
     ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/shapes"),
+                       JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_TYPE_OBJECT],
+    "Memory on the compartment's garbage-collected JavaScript heap that holds "
+    "type inference information.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
                                               "gc-heap/xml"),
-                       JS_GC_HEAP_KIND, stats.gcHeapXml,
+                       JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_XML],
     "Memory on the compartment's garbage-collected JavaScript heap that holds "
     "E4X XML objects.",
                        callback, closure);
 
     ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
                                               "object-slots"),
                        nsIMemoryReporter::KIND_HEAP, stats.objectSlots,
     "Memory allocated for the compartment's non-fixed object slot arrays, "
@@ -1790,21 +1780,28 @@ ReportCompartmentStats(const Compartment
                                               "object-empty-shapes"),
                        nsIMemoryReporter::KIND_HEAP,
                        stats.typeInferenceMemory.emptyShapes,
     "Arrays attached to prototype JS objects managing shape information.",
                        callback, closure);
 
     ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
                                               "scripts"),
-                       nsIMemoryReporter::KIND_HEAP, stats.scripts,
+                       nsIMemoryReporter::KIND_HEAP,
+                       stats.gcHeapKinds[JSTRACE_SCRIPT],
     "Memory allocated for the compartment's JSScripts.  A JSScript is created "
     "for each user-defined function in a script.  One is also created for "
-    "the top-level code in a script.  Each JSScript includes byte-code and "
-    "various other things.",
+    "the top-level code in a script.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "script-data"),
+                       nsIMemoryReporter::KIND_HEAP, stats.scriptData,
+    "Memory allocated for JSScript bytecode and various variable-length "
+    "tables.",
                        callback, closure);
 
 #ifdef JS_METHODJIT
     ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
                                               "mjit-code/method"),
                        nsIMemoryReporter::KIND_NONHEAP, stats.mjitCodeMethod,
     "Memory used by the method JIT to hold the compartment's generated code.",
                        callback, closure);
--- a/js/src/xpconnect/src/xpcpublic.h
+++ b/js/src/xpconnect/src/xpcpublic.h
@@ -197,26 +197,23 @@ struct CompartmentStats
 {
     CompartmentStats(JSContext *cx, JSCompartment *c);
 
     nsCString name;
     PRInt64 gcHeapArenaHeaders;
     PRInt64 gcHeapArenaPadding;
     PRInt64 gcHeapArenaUnused;
 
-    PRInt64 gcHeapObjects;
-    PRInt64 gcHeapStrings;
-    PRInt64 gcHeapShapes;
-    PRInt64 gcHeapXml;
+    PRInt64 gcHeapKinds[JSTRACE_LAST + 1];
 
     PRInt64 objectSlots;
     PRInt64 stringChars;
     PRInt64 propertyTables;
+    PRInt64 scriptData;
 
-    PRInt64 scripts;
 #ifdef JS_METHODJIT
     PRInt64 mjitCodeMethod;
     PRInt64 mjitCodeRegexp;
     PRInt64 mjitCodeUnused;
     PRInt64 mjitData;
 #endif
 #ifdef JS_TRACER
     PRInt64 tjitCode;
--- a/layout/mathml/nsMathMLmactionFrame.cpp
+++ b/layout/mathml/nsMathMLmactionFrame.cpp
@@ -377,17 +377,17 @@ ShowStatus(nsPresContext* aPresContext, 
 NS_IMETHODIMP
 nsMathMLmactionFrame::MouseListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
   if (eventType.EqualsLiteral("mouseover")) {
     mOwner->MouseOver();
   }
-  else if (eventType.EqualsLiteral("mouseclick")) {
+  else if (eventType.EqualsLiteral("click")) {
     mOwner->MouseClick();
   }
   else if (eventType.EqualsLiteral("mouseout")) {
     mOwner->MouseOut();
   }
   else {
     NS_ABORT();
   }
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -346,16 +346,22 @@ nsCSSProps::LookupProperty(const nsACStr
                             *alias_end = gAliases + NS_ARRAY_LENGTH(gAliases);
          alias < alias_end; ++alias) {
       if (aProperty.LowerCaseEqualsASCII(alias->name)) {
         res = alias->id;
         break;
       }
     }
   }
+  
+  if (res == eCSSProperty_perspective || res == eCSSProperty_perspective_origin || 
+      res == eCSSProperty_backface_visibility || res == eCSSProperty_transform_style) {
+    return eCSSProperty_UNKNOWN;
+  }
+
   return res;
 }
 
 nsCSSProperty
 nsCSSProps::LookupProperty(const nsAString& aProperty)
 {
   // This is faster than converting and calling
   // LookupProperty(nsACString&).  The table will do its own
@@ -367,16 +373,22 @@ nsCSSProps::LookupProperty(const nsAStri
                             *alias_end = gAliases + NS_ARRAY_LENGTH(gAliases);
          alias < alias_end; ++alias) {
       if (aProperty.LowerCaseEqualsASCII(alias->name)) {
         res = alias->id;
         break;
       }
     }
   }
+  
+  if (res == eCSSProperty_perspective || res == eCSSProperty_perspective_origin || 
+      res == eCSSProperty_backface_visibility || res == eCSSProperty_transform_style) {
+    return eCSSProperty_UNKNOWN;
+  }
+
   return res;
 }
 
 nsCSSFontDesc
 nsCSSProps::LookupFontDesc(const nsACString& aFontDesc)
 {
   NS_ABORT_IF_FALSE(gFontDescTable, "no lookup table, needs addref");
   return nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
--- a/layout/style/nsDOMCSSDeclaration.h
+++ b/layout/style/nsDOMCSSDeclaration.h
@@ -62,16 +62,25 @@ class nsDOMCSSDeclaration : public nsICS
 {
 public:
   // Only implement QueryInterface; subclasses have the responsibility
   // of implementing AddRef/Release.
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
 
   NS_DECL_NSICSSDECLARATION
 
+  NS_IMETHOD GetMozPerspective(nsAString_internal&);
+  NS_IMETHOD SetMozPerspective(const nsAString_internal&);
+  NS_IMETHOD GetMozPerspectiveOrigin(nsAString_internal&);
+  NS_IMETHOD SetMozPerspectiveOrigin(const nsAString_internal&);
+  NS_IMETHOD GetMozBackfaceVisibility(nsAString_internal&);
+  NS_IMETHOD SetMozBackfaceVisibility(const nsAString_internal&);
+  NS_IMETHOD GetMozTransformStyle(nsAString_internal&);
+  NS_IMETHOD SetMozTransformStyle(const nsAString_internal&);
+
   // Require subclasses to implement |GetParentRule|.
   //NS_DECL_NSIDOMCSSSTYLEDECLARATION
   NS_IMETHOD GetCssText(nsAString & aCssText);
   NS_IMETHOD SetCssText(const nsAString & aCssText);
   NS_IMETHOD GetPropertyValue(const nsAString & propertyName,
                               nsAString & _retval);
   NS_IMETHOD GetPropertyCSSValue(const nsAString & propertyName,
                                  nsIDOMCSSValue **_retval);
--- a/layout/style/test/ListCSSProperties.cpp
+++ b/layout/style/test/ListCSSProperties.cpp
@@ -188,16 +188,24 @@ print_array(const char *aName,
         const PropertyInfo *p = aProps + i;
 
         if (is_inaccessible(p->propName))
             // inaccessible properties never have DOM props, so don't
             // worry about incrementing j.  The assertion below will
             // catch if they do.
             continue;
 
+        if (strcmp(p->propName, "-moz-perspective") == 0 ||
+            strcmp(p->propName, "-moz-perspective-origin") == 0 ||
+            strcmp(p->propName, "-moz-backface-visibility") == 0 ||
+            strcmp(p->propName, "-moz-transform-style") == 0) {
+            ++j;
+            continue;
+        }
+
         if (first)
             first = 0;
         else
             printf(",\n");
 
         printf("\t{ name: \"%s\", prop: ", p->propName);
         if (j >= aDOMPropsLength || strcmp(p->propName, aDOMProps[j]) != 0)
             printf("null");
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -976,67 +976,16 @@ var gCSSProperties = {
 			"-moz-calc(20px + 50%) -moz-calc(50% - 10px)",
 			"-moz-calc(-20px) -moz-calc(-50%)",
 			"-moz-calc(-20%) -moz-calc(-50%)"
 		],
 		invalid_values: ["red", "auto", "none", "0.5 0.5", "40px #0000ff",
 						 "border", "center red", "right diagonal",
 						 "#00ffff bottom"]
 	},
-    "-moz-perspective-origin": {
-        domProp: "MozPerspectiveOrigin",
-        inherited: false,
-        type: CSS_TYPE_LONGHAND,
-        /* no subproperties */
-        prerequisites: { "width": "10px", "height": "10px", "display": "block"},
-        initial_values: [ "50% 50%", "center", "center center" ],
-        other_values: [ "25% 25%", "5px 5px", "20% 3em", "0 0", "0in 1in",
-                        "top", "bottom","top left", "top right",
-                        "top center", "center left", "center right",
-                        "bottom left", "bottom right", "bottom center",
-                        "20% center", "5px center", "13in bottom",
-                        "left 50px", "right 13%", "center 40px",
-                        "-moz-calc(20px)",
-                        "-moz-calc(20px) 10px",
-                        "10px -moz-calc(20px)",
-                        "-moz-calc(20px) 25%",
-                        "25% -moz-calc(20px)",
-                        "-moz-calc(20px) -moz-calc(20px)",
-                        "-moz-calc(20px + 1em) -moz-calc(20px / 2)",
-                        "-moz-calc(20px + 50%) -moz-calc(50% - 10px)",
-                        "-moz-calc(-20px) -moz-calc(-50%)",
-                        "-moz-calc(-20%) -moz-calc(-50%)" ],
-        invalid_values: [ "red", "auto", "none", "0.5 0.5", "40px #0000ff",
-                          "border", "center red", "right diagonal",
-                          "#00ffff bottom"]
-    },
-    "-moz-perspective": {
-		domProp: "MozPerspective",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none", "0" ],
-		other_values: [ "1000px", "500.2px", "-100px", "-27.2em" ],
-		invalid_values: [ "pants", "200" ]
-	},
-    "-moz-backface-visibility": {
-        domProp: "MozBackfaceVisibility",
-        inherited: false,
-        type: CSS_TYPE_LONGHAND,
-        initial_values: [ "visible" ],
-        other_values: [ "hidden" ],
-        invalid_values: [ "collapse" ]
-    },
-	"-moz-transform-style": {
-		domProp: "MozTransformStyle",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "flat" ],
-		other_values: [ "preserve-3d" ],
-		invalid_values: []
-	},
 	"-moz-user-focus": {
 		domProp: "MozUserFocus",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "none" ],
 		other_values: [ "normal", "ignore", "select-all", "select-before", "select-after", "select-same", "select-menu" ],
 		invalid_values: []
 	},
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -75,19 +75,16 @@ var supported_properties = {
     "-moz-outline-radius-topleft": [ test_radius_transition ],
     "-moz-outline-radius-topright": [ test_radius_transition ],
     "-moz-text-decoration-color": [ test_color_transition,
                                     test_border_color_transition ],
     "-moz-transform": [ test_transform_transition ],
     "-moz-transform-origin": [ test_length_pair_transition,
                                test_length_percent_pair_transition,
                                test_length_percent_pair_unclamped ],
-    "-moz-perspective-origin": [ test_length_pair_transition,
-                                 test_length_percent_pair_transition,
-                                 test_length_percent_pair_unclamped ],
     "background-color": [ test_color_transition ],
     "background-position": [ test_background_position_transition,
                              // FIXME: We don't currently test clamping,
                              // since background-position uses calc() as
                              // an intermediate form.
                              /* test_length_percent_pair_unclamped */ ],
     "background-size": [ test_background_size_transition,
                          // FIXME: We don't currently test clamping,
@@ -188,17 +185,16 @@ var supported_properties = {
                       test_length_percent_calc_transition,
                       test_length_clamped, test_percent_clamped ],
     "padding-right": [ test_length_transition, test_percent_transition,
                        test_length_percent_calc_transition,
                        test_length_clamped, test_percent_clamped ],
     "padding-top": [ test_length_transition, test_percent_transition,
                      test_length_percent_calc_transition,
                      test_length_clamped, test_percent_clamped ],
-    "-moz-perspective": [ test_length_transition ],
     "right": [ test_length_transition, test_percent_transition,
                test_length_percent_calc_transition,
                test_length_unclamped, test_percent_unclamped ],
     "stop-color": [ test_color_transition ],
     "stop-opacity" : [ test_float_zeroToOne_transition,
                        // opacity is clamped in computed style
                        // (not parsing/interpolation)
                        test_float_zeroToOne_clamped ],
--- a/memory/mozalloc/Makefile.in
+++ b/memory/mozalloc/Makefile.in
@@ -80,30 +80,41 @@ CPPSRCS 		=			\
 	mozalloc_oom.cpp			\
 	$(NULL)
 
 ifdef WRAP_STL_INCLUDES #{
 ifdef GNU_CXX #{
 EXPORTS_mozilla	+= throw_gcc.h
 else
 ifdef _MSC_VER #{
-EXPORTS_mozilla	+= throw_msvc.h
-ifdef MOZ_MSVC_STL_WRAP__Throw #{
-EXPORTS_mozilla	+= msvc_throw_wrapper.h
-CPPSRCS		+= msvc_throw_wrapper.cpp
+
+ifeq ($(MOZ_MSVC_STL_WRAP__RAISE),1) #{
+BUILD_MSVC_WRAPPERS = 1
 else
-ifdef MOZ_MSVC_STL_WRAP__RAISE #{
-EXPORTS_mozilla	+= msvc_raise_wrappers.h
-CPPSRCS		+= msvc_raise_wrappers.cpp
-else
-$(error Unknown STL wrapper tactic for MSVC)
+ifeq ($(MOZ_MSVC_STL_WRAP__Throw),1) #{
+BUILD_MSVC_WRAPPERS = 1
 endif #}
 endif #}
+
+ifdef BUILD_MSVC_WRAPPERS #{
+EXPORTS_mozilla		+=			\
+	msvc_raise_wrappers.h			\
+	msvc_throw_wrapper.h			\
+	throw_msvc.h				\
+	$(NULL)
+
+CPPSRCS			+= 			\
+	msvc_raise_wrappers.cpp			\
+	msvc_throw_wrapper.cpp			\
+	$(NULL)
+endif #}
+
 endif #}
 endif #}
+
 endif #}
 
 ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
 SDK_LIBRARY = $(IMPORT_LIBRARY)
 else
 SDK_LIBRARY = $(SHARED_LIBRARY)
 endif
 
--- a/memory/mozalloc/msvc_raise_wrappers.cpp
+++ b/memory/mozalloc/msvc_raise_wrappers.cpp
@@ -39,16 +39,18 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include <stdio.h>
 
 #if defined(XP_WIN) || defined(XP_OS2)
 #  define MOZALLOC_EXPORT __declspec(dllexport)
 #endif
 
+#include "mozalloc_abort.h"
+
 #define MOZALLOC_DONT_WRAP_RAISE_FUNCTIONS
 #include "mozilla/throw_msvc.h"
 
 __declspec(noreturn) static void abort_from_exception(const char* const which,
                                                       const char* const what);
 static void
 abort_from_exception(const char* const which,  const char* const what)
 {
--- a/mobile/app/mobile.js
+++ b/mobile/app/mobile.js
@@ -395,17 +395,17 @@ pref("javascript.options.mem.high_water_
 pref("javascript.options.gc_on_memory_pressure", false);
 
 pref("dom.max_chrome_script_run_time", 0); // disable slow script dialog for chrome
 pref("dom.max_script_run_time", 20);
 
 // JS error console
 pref("devtools.errorconsole.enabled", false);
 
-pref("browser.ui.layout.tablet", 0); // on: 1, off: 0, auto: -1
+pref("browser.ui.layout.tablet", -1); // on: 1, off: 0, auto: -1
 
 // kinetic tweakables
 pref("browser.ui.kinetic.updateInterval", 16);
 pref("browser.ui.kinetic.exponentialC", 1400);
 pref("browser.ui.kinetic.polynomialC", 100);
 pref("browser.ui.kinetic.swipeLength", 160);
 
 // zooming
--- a/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
+++ b/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
@@ -453,19 +453,20 @@ static int GetColorTableSize(BITMAPINFOH
   case 16:
   case 32:
     // If we have BI_BITFIELDS compression, we would normally need 3 DWORDS for
     // the bitfields mask which would be stored in the color table; However, 
     // we instead force the bitmap to request data of type BI_RGB so the color
     // table should be of size 0.  
     // Setting aHeader->biCompression = BI_RGB forces the later call to 
     // GetDIBits to return to us BI_RGB data.
-    if (aHeader->biCompression == BI_BITFIELDS)
+    if (aHeader->biCompression == BI_BITFIELDS) {
       aHeader->biCompression = BI_RGB;
-      colorTableSize = 0;
+    }
+    colorTableSize = 0;
     break;
   case 24:
     colorTableSize = 0;
     break;
   }
 
   if (colorTableSize < 0)
     NS_WARNING("Unable to figure out the color table size for this bitmap");
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..32bfc5e8f97422fc2f7a7d45c24d4a5bc3302523
GIT binary patch
literal 160
zc${<cUBCbV3P8*QrWF_%fe;A(|Nqa(wF1cCU|?X<U|?`yVd&rx;$UP5Xi!j6b#Zla
zSs@@8;N_|s8l|YTL`zF+N!O%RleAQptqNVWYa!RFt6p5;+g5NzU0Kw$`rQhxZ8tp`
z?&qy^+MP9t<Nnqlr+u%MFx=l8G~w5(B@F-H1~uGUHA(3IuM-VlS50F0_cmz3|65BK
E0J3g6q5uE@
--- a/modules/libpr0n/test/reftest/bmp/bmp-1bpp/reftest.list
+++ b/modules/libpr0n/test/reftest/bmp/bmp-1bpp/reftest.list
@@ -12,9 +12,10 @@
 == bmp-size-9x9-1bpp.bmp   bmp-size-9x9-1bpp.png
 == bmp-size-15x15-1bpp.bmp bmp-size-15x15-1bpp.png
 == bmp-size-16x16-1bpp.bmp bmp-size-16x16-1bpp.png
 == bmp-size-17x17-1bpp.bmp bmp-size-17x17-1bpp.png
 == bmp-size-31x31-1bpp.bmp bmp-size-31x31-1bpp.png
 == bmp-size-32x32-1bpp.bmp bmp-size-32x32-1bpp.png
 == bmp-size-33x33-1bpp.bmp bmp-size-33x33-1bpp.png
 == bmp-not-square-1bpp.bmp bmp-not-square-1bpp.png
-
+== os2bmp-size-32x32-1bpp.bmp bmp-size-32x32-1bpp.png
+== top-to-bottom-16x16-1bpp.bmp bmp-size-16x16-1bpp.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8633ef2aaa14468abac0cf2b09319e552fc3d248
GIT binary patch
literal 126
zc${<ctz&=yJ0R8oVgVrj@c;jRMg~T(xC0O$;e%jg093;8YXJkpy$%L2eQN>(!@ETc
r3{^n-8j#)vq(fa97`#?7FnBsKFmP%yFerF2FtCI$FmQkj0O|n%JTn<;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b75ae62ca8a3dec024b0bf4e7f7cabb69ff3a7e0
GIT binary patch
literal 3098
zc$^)UUuY}YeaFA&jBfA9H?2oE4_D(9qH$C3Xj9_xEp#<bX*5nDlCltuQ^*}}AkjF5
zy`vUZ<52LZg+{vjuy@>+)ocp&cne+0Da4}&)^qdXaYC>h3bCArYHkDZ-0g$Mp%lw$
ziD&7x+^Ri?1Lr&(`2G3(zQ3RH+NVB-|6g;{^MBXebQ5F&=A#t-)jj$jAE)P^pg;dD
z=3hQde)5q1==Yg}&odu<G4<U)V*cTEy1h={sWWeXlm6wO)6FOJ%`N7QZ_}^6M<4Cd
zFZG!(e4qZo4`|`Xbn%o~_*eSL4{7!n^f#`UyZ=QAlfJpbUeB<X8TLHOzW5{?zQPWd
z*g+v3e2(2OvtE_$YH9cDY{y{j2HV<XH^0R;Y_{HE^=(#rpH=(mFYdESkd}{F>Ey0B
zVudp{d(Lu~?A`yon_@B(%>Ig*zPOm<q6ge)K64^+M~kyTA@i)r^(&d(>a6>Sb7~pe
z;93oCb2HQU7Weq=Os&H`+R0RVvt^G{_PN4AMmpleAt#Ku?9aK`b1wbw97E@BFqaU1
z%w*#<A7$pkIsQc8k3{}Z;{D}pe}&&I^E)c<e06S1=Uc{{_2yi|;*B<6+u}8cufE4u
zdc3kXC;Pl~m=%wC;be{vdG1A){kJSb=O+*nB3zN&MM{Wfa$!aoW`)7L5QxJ5lF%;*
zy%k}nl<TYtTbj_;bCw~PX3nq#y`9r+L3M<ZD-?HyWlvc01u+nW;~alFe?Ju1p9u`f
zza(Np#W4|MvJf!~;XQG9UmWn_f$)kiE_jmIlSQ|fcghR4Dz-Jzs^v{%!7xSL617%d
zwZ)Q?FS?@K%`bVP=;x=FP5tMFB73^PVCe=@LZmT~E+Cy@aYR4!le9G8q#!H#!eW0x
z+Lfg3!cs?(?9x)Z`mp&(YUq+tmvmFoHl=D?D%*?2ca{p<(qd1_dy9g<^x#0^2GZRh
zFEUh~Ku(A}hJ1lSMC1`&K1me@=|aF2_IdfAa`LVyZ%fM^dD$+?tuM%%>T*MqjdfW!
zWX)VwExG(eR^FBi&a&jn`CWP5TYm6?%ms4#hjNN4w@^NUGR8^_<qRt!QBJ6Ge5V-P
zQ~diyZ*FCGzUbx^=V5V6R-P1<W<}Xhi}goE{cFnF8;aT}mNu1QOOfAJBu5clCD&E5
z-&JOPCH+icP`*JqLFE#qbCe^LMko(SX+X+{OlkjK$;*^`b7fa3ck*RhDz%o&mQrq%
z%Jphx{VSEVub0)wmGYbAqE(h#WofG{I^~>O$-ZBi-K(U(S4v^^25LgoG1LpHzJMB1
z^^~Xsr~y&^RMksYdl_{nt2*=3OsXxZx>-;gD{8%5UH_7*X{uUND~39CNw!p}T@`Ir
zaH?5X<$BfhchnSl{UuquhIUD{7}^=MkZ32+j-dr)Z68{ndDNSE<Z@He*X-O{OPr=u
zGYi_|qPAYv9;s_pO)J;d6hkYRYm%jjtu?{cvK?*K)zW{jF=YLQ=n2us&@WJnpg$-2
zDf9u=1L!_#eNyYD^zC%bxxc=Zt+fTcxuBa%x>3+;Mg8@XzPhScG+oix<;S{Y)<jDe
z+UxvNeOmDBw{?c8za;f*7?-HWFe21L7$-1}@x}q_`!M=2dU)gSQpP(o##Y8?XCGU+
zDf`Cb#d_`c46SIWWusKB7d7M6T7B`cAvWrQWn^1*?y154jlqzOmoTsC#udz%m=PKw
zF^4dZU>;z@N23q3M@*NRom9h4n{Cdt9&DI7)5x1sb2Zsii)N)_uBfK`6;rC2d7~k0
zn7q~Co|x=g4N98-jpjA1F{}&Hj9`t3HH0;Q6`=V6EDy~dtQ}Y#Vm(b+?U`mX)13Y{
zgr=UiG|8&U)|8%Nsaa61#WgEmvxK_En-<q>vVXD3(6?^TzD9eDc8vB5v_ksi6s=>@
z4oKTatB-aMZ5Qo#(Xwf~m1=Fyv>Tb0!ME4vr)u#;U22u(wzASLl%Ghet^8VhzBY|w
zdv>Fh{<C(9*_vSM8uk^oVr)gQN3c)v^qANIp6<i;u(b<&2X+VcQ);)VZQZdOGf(Ro
zd!4tnoL$Y^<)tk}whKjju`)&2&OMrfV9(a=^q)MX^xX;GP0$&`iP1TO6OzseagNam
z;5;KvA5NDzE*ytAHk>wfn$&5eI`wo%&p2yYXNr4e!BLi+sX$1I^GeAPR-LJEbGpNR
z!=dE88@ShS$8ck~5q3tzJ%M`!H^7b$cMon4u8W-xwr#j=Y&Xfy26c_pww~VBGOo(I
zm7J@HJM!X=RM-}a(^}u*t2><L-hJI=$nFj4CA9ZT(u>iH&<oKWqIXPs2k7mi*GI35
zu8W>Sx_^aUoAjFKZjf%Bc58RK+Dx~4zgOYAiqMl6dXm)3%Uwa~@ueQ8_R?SOGEDyl
zUP8Pv_F{N1&=29Az&nB$!1LjG@OtoE^gGzI;XT1#6P`)?b$B}Vw3Ju<m{-Yo3g4Fn
zZ!y0oE_s67=ReoyN_*^U9z*;a_zCf^;K#&|;E#wugg=0P2;YbA;aQjXF8mJJ-y(jS
z_!jXu;2U^WgRfCvP3@Ov_E$3gtNgR6^iLa%@X((&%Z%c)f9Nyh@Fflt1eXY61Q8BL
zBsfJdz+r%3ABP@-E`l8d4hd`oZ4xvQG!Pg#)DdVnQ0YPW&cVt|@ak;v89rDL4s&9_
zF9w_(u%A6($ng!16EYa%D8}Fgjzb&`aXi2vz`)0mhd~bm7lU_kWMk06z{0>J0|Nt{
z4AyY8N(U7>D5j<p&0sMz$Uhhe!hl~Ga7%;q!y|_I=>)@s3@<Ufz%arv#PAfuW1Jjf
z=#!y`llL*)!O+2Qi=4DEY+~3TLj$Ke8LpAxDjAl^aD|@8cZSl;iFkh~@WX6wI4cg*
zzcWnH=Qjuwgky|i5}x6CNJgh5JSJg4LLZ@ru!nFPp@Wf4!xkA?Bs3A$5$fc*hOkP)
z3PuVUEz^;7XC$&=jtl1=OvjKg{izWpAKoCk#*0ftF`@`jNMD>H8j$D^(LSO+qFqET
zi5z-n)2NNJCSI6`47~UTA`Ov>sDwx%k&I}GMETTNZYJV05jPjHzj>Cz#SP*F=a+~t
zaDIk3M0`r(0l5ee`y}=dcS*d1bBCPUh+Bv)#0|s-E_4!WBwi)wWfHF-F5p5!yg*_h
zb)KDxxy*U`<1xcrO)$QuS68?^$2h_`q~jsEJjVDC<9#yT!&Q%rT{3=`jBPS*W8B1*
ziSc8MYZz-7tK_mw#tOzV#!F<JCztbNJjYye_b$`Fe#wwzf+Rt5iR1#;5t8R5IYlzS
zM*$KaiHD?zYZr+_k}V`Hl2}MgBnCdxk*pzE#dR6U3b~d^@{nBTNg^Q0k|e`iv#D!_
zx&0qHc}Z@6NhiOclMk8OpV7%r>Fqz$$q(r5_sQgYbn=g6@*Xq!TYCG~%;YUPX_DJ-
vGLt{0lRu`nU!{{T)7#hR<nwg$S?1<<naQW=<hPm0C+OrpGnrv-e(iq&smZL|
--- a/modules/libpr0n/test/reftest/bmp/bmp-24bpp/reftest.list
+++ b/modules/libpr0n/test/reftest/bmp/bmp-24bpp/reftest.list
@@ -12,9 +12,10 @@
 == bmp-size-9x9-24bpp.bmp   bmp-size-9x9-24bpp.png
 == bmp-size-15x15-24bpp.bmp bmp-size-15x15-24bpp.png
 == bmp-size-16x16-24bpp.bmp bmp-size-16x16-24bpp.png
 == bmp-size-17x17-24bpp.bmp bmp-size-17x17-24bpp.png
 == bmp-size-31x31-24bpp.bmp bmp-size-31x31-24bpp.png
 == bmp-size-32x32-24bpp.bmp bmp-size-32x32-24bpp.png
 == bmp-size-33x33-24bpp.bmp bmp-size-33x33-24bpp.png
 == bmp-not-square-24bpp.bmp bmp-not-square-24bpp.png
-
+== os2bmp-size-32x32-24bpp.bmp bmp-size-32x32-24bpp.png
+== top-to-bottom-16x16-24bpp.bmp bmp-size-16x16-24bpp.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bd18f85d485b6330584fe4470a776ee82109c010
GIT binary patch
literal 822
zc$_uKJ#5@$9DwovYu|_ML>1JptFn<hyUKd$*+pzMvH6e~$Z@tnOg-gXm90tcO(iB0
z@meZdDE5Ka0%r$xEIpqhCL;A5Dz-|og9HmwZPa%0#bF5%6_50r9{qidh5ypdEuMSj
z+>5ibGX$4kj`RP^g_r)X_RneM^m(oPqf-7>D}Sz*_p9Z1)$+^w>1Va_R`ui)wtTO8
z@@B1E<W4Tviwn%N0`eU41hN?N2=WnRKK$)6Ibm`K<u>GRGr3yHn|vk;Pv_9@1tb|H
z2_#cU#*mEQ$VVwfDM5(?i4Cd2Br12*loI^fk-$ElL7YRJLOg{yLU91G2Qh`1K)ecZ
zw-TGep(;-0#uP6;643q(q8y?WqC=RBVKRcqgNQ=3fudD*+!e;A6ln{Q+#2I+4+ZAO
z83Z{5DGCo!IDx$Y_IwCkCLC14zA&=Hz-$E9TA^}1y!7s99(_}QmxGspe+a_~_#ya1
z<h!g-IIk~xR>L=1zIJ^mulUl(-dyGG3Ah>16zCLa1T;i+$Wkg$a*_6%)NZ+^PPG+R
z=~3xZI*;zmfMhU8fy6)}AOSP*_>C{{V6Z?|mx!ekqeIjlk=F^nGZ5HY1>DTRIYv&5
zoC)g$eBZ+kZ8)1P$I%^o#W8!1w&o~Xed%t0p82Ric8;uL)cuvUBECBkyI(ggw`FbW
zma}48J=?f#wYP0~$HL!!D6sDoU}k9fxMIYd5sBugY4}TqtDEEl)9IPkZPWPN)OJke
zdsDi<Jcr&WK+TwT!d-nNwxfm`EUDgGD($q%4Yj|ncDJ<U9ZlWU<eyZ$-xk=#8LMQx
zd~{KX7nI4866%WIxk7siSyygu$=1Cq=B}(hP~-zydfc3=UMe{8sf3dS9AB08b-dTX
z!=B`>;f-y{`AW2QvGD-64{-Ad#>b+7_!o8VFNu31a|c@ep~3xNbNBk(_9nkZ`5Qy7
T6L9*3YfbsrQ|{G2>-B#Dyi_s5
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..08fc30d5fc18df34de805eb79b5b378586121796
GIT binary patch
literal 586
zc$_7T!E4(v7{$G@<8H(Cbx_v9ZmYH$Nw<v=DCwajwkh~j5(R<}OKcZXa`3+pgbBj8
z8XAy~I!U_Zu=bSy$@}EKj}P?T`$_tBbN${MbPf9v_A|^o@55VI!FW|w4X0|@<MHTu
zJ&f1){c!4s72>Ym-Q7k}G)+M#A;c!C-|Wk2?7XP!+J__=Z~qPbru55l8jsTydM$Rl
zeeK_tQJikK8T5R!nk0S^Pt)u)ZXB?$1HVj0f96>xxWH)tX_B19qtQ6aG{%_oNe~1{
z92eV}5E?6vSF7T0QOvTL1_1H=XZSt;J)g5z!5hvwM!{LRn6nwvy5Wf998JFbc!&!o
zlmie7(c)sw7;~>F?0k5YFTiU}U5_r;>j&r?tQtze=i&J|Bu%3o4mupzz2j+vlmpNu
zS>H3Qv_cBCgplxX@yIOjih@YketmM@8AJ#|?csU3Y^Zx)Db>0wSI<@{OFM!HZCm-c
zWZEhNiBZJq+Y|H(8AFKaS_y!q)<pod9U*dQEu{*2BMp&~NM&sY9~xx{e9=nit+9?Z
U(#g8Mvt1|Mt-%A*freWC2UL&(-v9sr
--- a/modules/libpr0n/test/reftest/bmp/bmp-4bpp/reftest.list
+++ b/modules/libpr0n/test/reftest/bmp/bmp-4bpp/reftest.list
@@ -12,9 +12,10 @@
 == bmp-size-9x9-4bpp.bmp   bmp-size-9x9-4bpp.png
 == bmp-size-15x15-4bpp.bmp bmp-size-15x15-4bpp.png
 == bmp-size-16x16-4bpp.bmp bmp-size-16x16-4bpp.png
 == bmp-size-17x17-4bpp.bmp bmp-size-17x17-4bpp.png
 == bmp-size-31x31-4bpp.bmp bmp-size-31x31-4bpp.png
 == bmp-size-32x32-4bpp.bmp bmp-size-32x32-4bpp.png
 == bmp-size-33x33-4bpp.bmp bmp-size-33x33-4bpp.png
 == bmp-not-square-4bpp.bmp bmp-not-square-4bpp.png
-
+== os2bmp-size-32x32-4bpp.bmp bmp-size-32x32-4bpp.png
+== top-to-bottom-16x16-4bpp.bmp  bmp-size-16x16-4bpp.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c77696b325a8e98c987774b59c8d7eeeb191b53d
GIT binary patch
literal 246
zc$_tfp$@_@5Qa-akOZ^v1`L1Mnsp8_6mEl%AYlTBV7l)xu{4!SAQ`fX)l3jDdl(e<
zI2inw@BaI8v&D;b$%rX2BA$rYV}16|ZP+pT{VB+pL?)@FL`g2mCAlPTnuh*}>^qcB
z@VC%fQ`e%ZY#7#`gH)JGl%cVv6k=~f0~cxy#z1+V7%IWt)Ab4fzMtkAfcsghbpV{Z
qsa823528o~fyY<7ZJrm7w~X&f70z+~XjO1Xl6Z4dYV9POxP1c~EM&$2
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b6df221e1b5dc4a719e19f839843657c463767c4
GIT binary patch
literal 1818
zc${^TzfN3N5QitSLQ+I*1(qz690>sh#Y(JpSAbYXk%Ajc<G6to18H`t%o~h^(m)!V
z#-tjgD9<rCjiDkPMT&U@w^<^Q-`u_Ywfx;(?dpCr=giDG-@knJ6;(WYLi7!O3!X3N
z>(NWaL#kT+!;gc1{NwqbRG5lTQ7T5osRS_*7h)zBVkI_WCk_%KDI`oHBuZi=P7>A1
zg_KDJYm*wOlLi@)6*49hG9@!ICkt{SFXT)v<S4~Z4S7%yMWJ8{p->8=aEi!svPu+$
zy|E2eL~>+}rEp;`!bQ0l7v~aLc)kU~tjxyj%#qzl$#)_w%3>_e64|1b3{+uNR%3P6
z$iA&)wh5cE8Jn|34#P_>>B6q;#_sHa32_wc!yz2XVI0m8)yzw7l2gNgFblLDIkQr7
z=OS8Ei)nE!k%P>BP!Xy`LD(DHL{3*q)+nN)DyHHpkt5H1gyJnQRacEX2P@f)Nxm~v
zbG69B@scgNWT2b6s|QX@qo8jMLAHizxJKl0<;_6flBs!$IIzewEF~vVB-bnE#l1ux
zY@P%rB)LgW4FifiZ7Df3k=$9##a$w=Kz5EMCCkYwQBdT)u#(d?$r{bv+%595<W5*r
zvT(PLSJ!`_yS&}kc<B22y83rreg6e7UaYOH{Q!RX6728q|Mec6p8f}J{o1GgbmSY2
z#>U3l#!K)kI6OQ&cz=F=es*^DAw6_sd}E{X>+2(ba8P*!G%Ci&ANa#t|Dn-%TKVzX
zuh;&d_D?IuCnqOggCD_f;4SzYTwIJi^u$E%UybzJqtti43aES?aCGz_AAaI>r4cal
zM;DhD-&K4ICZ?vQegdzywzhr;N5{v<mzQ@Qdg?hm^wuUk^zpmL{(0>;Yya-n&rZ!i
zBVgn=Yd=>p3ueF*@H5!i+}YedIXM{{`_xZEgYE6qW6kDVa}+T%JJQqBwcj53X7gr+
zT2IeI@4^pme0StKH-3J8XBPp3LHcgy&(3wK{PsxC@9qwExBG*^pxbSBli5zE({4X$
zw_B~&!ovIl{Gi_-^t&~k%2yg5Ah!>?_W~YxMC|SD^}DNhy4_x<)9b8s+RLrwR%>Zt
z0iT68gExEq)T{XP(yz2vTFVGof?q@cSgq;xdMn8?SOSYl`m4KuULA1j5%5SaKgb7H
e;8FUm9}X9X_x#Ge<!e8z{O1<9@t<FRIQ$=3q?%Iz
--- a/modules/libpr0n/test/reftest/bmp/bmp-8bpp/reftest.list
+++ b/modules/libpr0n/test/reftest/bmp/bmp-8bpp/reftest.list
@@ -12,9 +12,10 @@
 == bmp-size-9x9-8bpp.bmp   bmp-size-9x9-8bpp.png
 == bmp-size-15x15-8bpp.bmp bmp-size-15x15-8bpp.png
 == bmp-size-16x16-8bpp.bmp bmp-size-16x16-8bpp.png
 == bmp-size-17x17-8bpp.bmp bmp-size-17x17-8bpp.png
 == bmp-size-31x31-8bpp.bmp bmp-size-31x31-8bpp.png
 == bmp-size-32x32-8bpp.bmp bmp-size-32x32-8bpp.png
 == bmp-size-33x33-8bpp.bmp bmp-size-33x33-8bpp.png
 == bmp-not-square-8bpp.bmp bmp-not-square-8bpp.png
-
+== os2bmp-size-32x32-8bpp.bmp bmp-size-32x32-8bpp.png
+== top-to-bottom-16x16-8bpp.bmp  bmp-size-16x16-8bpp.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bb60249ac853eaf89f44ed492c5e2dfb3f42213a
GIT binary patch
literal 1334
zc${6*Jx>%-6vpvO5MssJ2#vrd1~Bp#dD)fs6BDR}Mred$ghr^~8$1b}&<KrC4T<q{
z9EgQbL2of1fmYXK{ogypfID-TIrA(#_jm7ovs`Nn=~H_Y!V9iX?y4m`E`yd3zIT-M
z@S}7Fsl3F48+Q->)5Go6w-BmEWfVa*r<^K6;Bl}j#f_00xse;Wk@F~I<QaKJlaXiS
z8F^ORy_a0%%F-Bu$VD!4ZbMF<ljr0)dCtR}JSXQ8oZQKs+~dIWICzSjGZf?nc|l%~
z7vu$bQIx|ERVp4CB`T+!DoR?F9KYc={D$A~8~()ROU8}iH~fa*@EiU#CHM`$;Wzw-
z-|!p$G+p=&zu`ChhTrfT{xp^N4Zq<x{D$A~8~!xS_zl0|H~fa*@EiWP1cu-68-BxY
z_zl0|FW0-8)WV<E9>4Gle_9&+!Y};7FZ{wU{At<n3%|e$kQlTWn0R?wQvAX%{K7B%
z!Y}-3xp|5BA@OC!J&0fUg+FZt{K7B%!Y};7FZ^kn;1_=37k=Rve&LT>Nce?c_=R8i
zg<ts7_QCII#j~V#{GN`Y+*<e@zvFlOj^FV+{<Q7zJATLS_#MCFcl>Ef;&=Rx-|;(s
z$M5*lcE#`b9lzsu&<@NQeA>$R9lzsu{Epx8JN~rI8Kg51=Vi_hI{$RrXojzGp5g?D
zW;#Q&Szh81AMxi`rLwfNxY*XVzkhLYe*TAkWo3E!@bKW^>gw|HN2OBfpnpsMDfV4m
zU7ek4Ypbir$45suH`l3uO8<`j^UZZ{Z*NaeclXA|`ugeV$;p?y{u%xI*bfX0^!NAm
zwYF|;ZEl{Owg2m%(|<T?9~~VX85tfP8X6qj+1cLyc&~pM`+B`zt4&T$OpK3@jqUC2
iKImWV?Jg`V%+Jrw&CbruOixcuy>9&9HyZc*-+uv8&zc+n
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..af4678a284d18136863c18ad0c03f404c883b698
GIT binary patch
literal 30
ac${<cwPJt(Ga%*xVn#4DU{J5GX8-^oI09q<
--- a/modules/libpr0n/test/reftest/bmp/bmp-corrupted/reftest.list
+++ b/modules/libpr0n/test/reftest/bmp/bmp-corrupted/reftest.list
@@ -1,11 +1,12 @@
 # Corrupted BMP tests
 
 == wrapper.html?invalid-signature.bmp about:blank
 == wrapper.html?invalid-bpp.bmp about:blank
+== wrapper.html?os2-invalid-bpp.bmp about:blank
 # Tests for an unsupported compression value
 == wrapper.html?invalid-compression.bmp about:blank
 # Tests for RLE4 with an invalid BPP
 == wrapper.html?invalid-compression-RLE4.bmp about:blank
 # Tests for RLE8 with an invalid BPP
 == wrapper.html?invalid-compression-RLE8.bmp about:blank
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3285,16 +3285,18 @@ pref("network.tcp.sendbuffer", 131072);
 pref("layers.acceleration.disabled", true);
 #else
 pref("layers.acceleration.disabled", false);
 #endif
 
 // Whether to force acceleration on, ignoring blacklists.
 pref("layers.acceleration.force-enabled", false);
 
+pref("layers.acceleration.draw-fps", false);
+
 #ifdef XP_WIN
 // Whether to disable the automatic detection and use of direct2d.
 #ifdef MOZ_E10S_COMPAT
 pref("gfx.direct2d.disabled", true);
 #else
 pref("gfx.direct2d.disabled", false);
 #endif
 // Whether to attempt to enable Direct2D regardless of automatic detection or
--- a/other-licenses/android/APKOpen.cpp
+++ b/other-licenses/android/APKOpen.cpp
@@ -286,16 +286,17 @@ extractFile(const char * path, const str
     __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't open %s to decompress library", path);
     return;
   }
 
   void * buf = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (buf == (void *)-1) {
     __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't mmap decompression buffer");
+    close(fd);
     return;
   }
 
   z_stream strm = {
     next_in: (Bytef *)data,
     avail_in: letoh32(entry->compressed_size),
     total_in: 0,
 
@@ -505,20 +506,22 @@ static void * mozload(const char * path,
       fd = open(fullpath, O_RDWR | O_CREAT);
       if (fd < 0) {
         __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't create a file either, giving up");
         return NULL;
       }
       // we'd like to use fallocate here, but it doesn't exist currently?
       if (lseek(fd, lib_size - 1, SEEK_SET) == (off_t) - 1) {
          __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "seeking file failed");
+        close(fd);
         return NULL;
       }
       if (write(fd, "", 1) != 1) {
         __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "writting one byte to the file failed");
+        close(fd);
         return NULL;
       }
       skipLibCache = true;
       addLibCacheFd(path + 4, fd);
     }
     buf = mmap(NULL, lib_size,
                PROT_READ | PROT_WRITE,
                MAP_SHARED, fd, 0);
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -28,42 +28,39 @@ if (parent) {
 var ipcMode = false;
 if (parentRunner) {
     ipcMode = parentRunner.ipcMode;
 } else if (typeof SpecialPowers != 'undefined') {
     ipcMode = SpecialPowers.hasContentProcesses();
 }
 
 /* Helper functions pulled out of various MochiKit modules */
-var reprRegistry = [];
-
 if (typeof(repr) == 'undefined') {
     function repr(o) {
         if (typeof(o) == "undefined") {
             return "undefined";
         } else if (o === null) {
             return "null";
         }
         try {
             if (typeof(o.__repr__) == 'function') {
                 return o.__repr__();
             } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) {
                 return o.repr();
             }
-            return reprRegistry.match(o);
+       } catch (e) {
+       }
+       try {
+            if (typeof(o.NAME) == 'string' && (
+                    o.toString == Function.prototype.toString ||
+                    o.toString == Object.prototype.toString
+                )) {
+                return o.NAME;
+            }
         } catch (e) {
-            try {
-                if (typeof(o.NAME) == 'string' && (
-                        o.toString == Function.prototype.toString ||
-                        o.toString == Object.prototype.toString
-                    )) {
-                    return o.NAME;
-                }
-            } catch (e) {
-            }
         }
         try {
             var ostring = (o + "");
         } catch (e) {
             return "[" + typeof(o) + "]";
         }
         if (typeof(o) == "function") {
             o = ostring.replace(/^\s+/, "");
--- a/testing/xpcshell/xpcshell.ini
+++ b/testing/xpcshell/xpcshell.ini
@@ -41,16 +41,17 @@ skip-if = os == "android"
 [include:testing/xpcshell/example/unit/xpcshell.ini]
 [include:xpcom/tests/unit/xpcshell.ini]
 [include:modules/libpref/test/unit/xpcshell.ini]
 [include:intl/strres/tests/unit/xpcshell.ini]
 [include:intl/unicharutil/tests/unit/xpcshell.ini]
 [include:intl/uconv/tests/unit/xpcshell.ini]
 [include:netwerk/test/unit/xpcshell.ini]
 [include:netwerk/test/httpserver/test/xpcshell.ini]
+[include:js/ductwork/debugger/tests/xpcshell.ini]
 [include:js/jetpack/tests/unit/xpcshell.ini]
 [include:js/src/xpconnect/tests/unit/xpcshell.ini]
 [include:modules/libjar/test/unit/xpcshell.ini]
 [include:extensions/cookie/test/unit/xpcshell.ini]
 [include:storage/test/unit/xpcshell.ini]
 [include:rdf/tests/unit/xpcshell.ini]
 [include:gfx/tests/unit/xpcshell.ini]
 [include:widget/tests/unit/xpcshell.ini]
--- a/toolkit/components/places/AsyncFaviconHelpers.cpp
+++ b/toolkit/components/places/AsyncFaviconHelpers.cpp
@@ -854,17 +854,17 @@ AsyncAssociateIconToPage::Run()
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncGetFaviconURLForPage
 
 // static
 nsresult
-AsyncGetFaviconURLForPage::start(nsIURI *aPageURI,
+AsyncGetFaviconURLForPage::start(nsIURI* aPageURI,
                                  nsCOMPtr<mozIStorageConnection>& aDBConn,
                                  nsIFaviconDataCallback* aCallback)
 {
   NS_ENSURE_ARG(aCallback);
   NS_ENSURE_ARG(aPageURI);
   NS_PRECONDITION(NS_IsMainThread(),
                   "This should be called on the main thread.");
 
@@ -923,16 +923,93 @@ AsyncGetFaviconURLForPage::Run()
                             mFaviconSvc, mCallback);
   rv = NS_DispatchToMainThread(event);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+//// AsyncGetFaviconDataForPage
+
+// static
+nsresult
+AsyncGetFaviconDataForPage::start(nsIURI* aPageURI,
+                                  nsCOMPtr<mozIStorageConnection>& aDBConn,
+                                  nsIFaviconDataCallback* aCallback)
+{
+  NS_ENSURE_ARG(aCallback);
+  NS_ENSURE_ARG(aPageURI);
+  NS_PRECONDITION(NS_IsMainThread(),
+                  "This should be called on the main thread.");
+
+  nsRefPtr<nsFaviconService> fs = nsFaviconService::GetFaviconService();
+  NS_ENSURE_TRUE(fs, NS_ERROR_OUT_OF_MEMORY);
+
+  nsCAutoString pageSpec;
+  nsresult rv = aPageURI->GetSpec(pageSpec);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIFaviconDataCallback> callback = aCallback;
+  nsRefPtr<AsyncGetFaviconDataForPage> event =
+    new AsyncGetFaviconDataForPage(pageSpec, aDBConn, fs, callback);
+
+  nsCOMPtr<nsIEventTarget> target = do_GetInterface(aDBConn);
+  NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
+  rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
+
+AsyncGetFaviconDataForPage::AsyncGetFaviconDataForPage(const nsACString& aPageSpec, 
+                                                       nsCOMPtr<mozIStorageConnection>& aDBConn, 
+                                                       nsRefPtr<nsFaviconService>& aFaviconSvc, 
+                                                       nsCOMPtr<nsIFaviconDataCallback>& aCallback)
+  : AsyncFaviconHelperBase(aDBConn, aFaviconSvc, aCallback)
+{
+  mPageSpec.Assign(aPageSpec);
+}
+
+AsyncGetFaviconDataForPage::~AsyncGetFaviconDataForPage()
+{
+}
+
+NS_IMETHODIMP
+AsyncGetFaviconDataForPage::Run()
+{
+  NS_PRECONDITION(!NS_IsMainThread(),
+                  "This should not be called on the main thread.");
+
+  nsCAutoString iconSpec;
+  nsresult rv = FetchIconURL(mFaviconSvc->mSyncStatements,
+                             mPageSpec, iconSpec);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!iconSpec.Length()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  IconData iconData;
+  iconData.spec.Assign(iconSpec);
+
+  PageData pageData;
+  pageData.spec.Assign(mPageSpec);
+
+  rv = FetchIconInfo(mFaviconSvc->mSyncStatements, iconData);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIRunnable> event =
+    new NotifyIconObservers(iconData, pageData, mDBConn,
+                            mFaviconSvc, mCallback);
+  rv = NS_DispatchToMainThread(event);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 //// NotifyIconObservers
 
 NotifyIconObservers::NotifyIconObservers(
   IconData& aIcon
 , PageData& aPage
 , nsCOMPtr<mozIStorageConnection>& aDBConn
 , nsRefPtr<nsFaviconService>& aFaviconSvc
 , nsCOMPtr<nsIFaviconDataCallback>& aCallback
--- a/toolkit/components/places/AsyncFaviconHelpers.h
+++ b/toolkit/components/places/AsyncFaviconHelpers.h
@@ -309,16 +309,63 @@ public:
                             nsCOMPtr<nsIFaviconDataCallback>& aCallback);
 
   virtual ~AsyncGetFaviconURLForPage();
 
 private:
   nsCString mPageSpec;
 };
 
+
+/**
+ * Asynchronously tries to get the URL and data of a page's favicon.  
+ * If this succeeds, notifies the given observer.
+ */
+class AsyncGetFaviconDataForPage : public AsyncFaviconHelperBase
+{
+public:
+  NS_DECL_NSIRUNNABLE
+
+  /**
+   * Creates the event and dispatches it to the I/O thread.
+   *
+   * @param aPageURI
+   *        URL of the page whose favicon URL and data we're fetching
+   * @param aDBConn
+   *        database connection to use
+   * @param aCallback
+   *        function to be called once the URL and data is retrieved from the database
+   */
+  static nsresult start(nsIURI* aPageURI,
+                        nsCOMPtr<mozIStorageConnection>& aDBConn,
+                        nsIFaviconDataCallback* aCallback);
+
+  /**
+   * Constructor.
+   *
+   * @param aPageSpec
+   *        URL of the page whose favicon URL and data we're fetching
+   * @param aDBConn
+   *        database connection to use
+   * @param aFaviconSvc
+   *        the favicon service to query
+   * @param aCallback
+   *        function to be called once the URL is retrieved from the database
+   */
+  AsyncGetFaviconDataForPage(const nsACString& aPageSpec,
+                             nsCOMPtr<mozIStorageConnection>& aDBConn,
+                             nsRefPtr<nsFaviconService>& aFaviconSvc,
+                             nsCOMPtr<nsIFaviconDataCallback>& aCallback);
+
+  virtual ~AsyncGetFaviconDataForPage();
+
+private:
+  nsCString mPageSpec;
+};
+
 /**
  * Notifies the icon change to favicon observers.
  */
 class NotifyIconObservers : public AsyncFaviconHelperBase
 {
 public:
   NS_DECL_NSIRUNNABLE
 
--- a/toolkit/components/places/mozIAsyncFavicons.idl
+++ b/toolkit/components/places/mozIAsyncFavicons.idl
@@ -42,17 +42,17 @@ interface nsIURI;
 interface nsIFaviconDataCallback;
 
 /**
  * Interface for accessing the favicon service asynchronously.
  *
  * @status EXPERIMENTAL
  */
 
-[scriptable, uuid(6D2B0507-245F-452D-9718-5595DCD3CD14)]
+[scriptable, uuid(0cb4e536-e120-41e6-998f-66123d81ec53)]
 interface mozIAsyncFavicons : nsISupports
 {
   /**
    * Declares that a given page uses a favicon with the given URI and 
    * attempts to fetch and save the icon data by loading the favicon URI
    * through an async network request.
    *
    * If the icon data already exists, we won't try to reload the icon unless
@@ -101,9 +101,23 @@ interface mozIAsyncFavicons : nsISupport
    *        Once we've found the favicon's URL, we invoke this callback.  Note
    *        that the callback's aDataLen will be 0, aData will be null, and
    *        aMimeType will be empty -- only aURI will be non-zero/null/empty.
    *
    * @see nsIFaviconDataCallback in nsIFaviconService.idl.
    */
   void getFaviconURLForPage(in nsIURI aPageURI,
                             in nsIFaviconDataCallback aCallback);
+
+  /**
+   * Retrieve the URL and data of the favicon for the given page.
+   *
+   * @param aPageURI
+   *        URI of the page whose favicon's URL and data we're looking up
+   * @param aCallback
+   *        Once we've found the favicon's URL, we invoke this callback with
+   *        the favicon data.
+   *
+   * @see nsIFaviconDataCallback in nsIFaviconService.idl.
+   */
+  void getFaviconDataForPage(in nsIURI aPageURI,
+                             in nsIFaviconDataCallback aCallback);
 };
--- a/toolkit/components/places/nsFaviconService.cpp
+++ b/toolkit/components/places/nsFaviconService.cpp
@@ -713,16 +713,27 @@ nsFaviconService::GetFaviconURLForPage(n
   NS_ENSURE_ARG(aPageURI);
   NS_ENSURE_ARG(aCallback);
 
   nsresult rv = AsyncGetFaviconURLForPage::start(aPageURI, mDBConn, aCallback);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFaviconService::GetFaviconDataForPage(nsIURI* aPageURI,
+                                        nsIFaviconDataCallback* aCallback)
+{
+  NS_ENSURE_ARG(aPageURI);
+  NS_ENSURE_ARG(aCallback);
+
+  nsresult rv = AsyncGetFaviconDataForPage::start(aPageURI, mDBConn, aCallback);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
+}
 
 NS_IMETHODIMP
 nsFaviconService::GetFaviconImageForPage(nsIURI* aPageURI, nsIURI** _retval)
 {
   NS_ENSURE_ARG(aPageURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
   DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetURL);
--- a/toolkit/components/places/tests/unit/test_favicons.js
+++ b/toolkit/components/places/tests/unit/test_favicons.js
@@ -336,16 +336,26 @@ var savedIcon1URI = iconsvc.getFaviconFo
 // Test getFaviconForPage().
 do_test_pending();
 iconsvc.getFaviconURLForPage(page1URI, {
     onFaviconDataAvailable: function(aURI, aDataLen, aData, aMimeType) {
       do_check_true(aURI.equals(savedIcon1URI));
       do_check_eq(aDataLen, 0);
       do_check_eq(aData.length, 0);
       do_check_eq(aMimeType, "");
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFaviconDataCallback])
+});
+
+iconsvc.getFaviconDataForPage(page1URI, {
+    onFaviconDataAvailable: function(aURI, aDataLen, aData, aMimeType) {
+      do_check_true(aURI.equals(savedIcon1URI));
+      do_check_eq(icon1MimeType, out1MimeType.value);
+      checkArrays(icon1Data, aData);
+      do_check_eq(aDataLen, aData.length);
       do_test_finished();
   },
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIFaviconDataCallback])
 });
 
 // set second page icon
 try {
   iconsvc.setFaviconData(icon2URI, icon2Data, icon2Data.length,
--- a/toolkit/library/libxul-config.mk
+++ b/toolkit/library/libxul-config.mk
@@ -137,16 +137,17 @@ COMPONENT_LIBS += \
 	toolkitcomps \
 	pipboot \
 	pipnss \
 	appcomps \
 	jsreflect \
 	composer \
 	jetpack_s \
 	telemetry \
+	jsdebugger \
 	storagecomps \
 	$(NULL)
 
 ifdef BUILD_CTYPES
 COMPONENT_LIBS += \
 	jsctypes \
 	$(NULL)
 endif
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -268,16 +268,17 @@
     OSXPROXY_MODULE                          \
     WINDOWSPROXY_MODULE                      \
     JSCTYPES_MODULE                          \
     JSREFLECT_MODULE                         \
     MODULE(jsperf)                           \
     SERVICES_CRYPTO_MODULE                   \
     MOZ_APP_COMPONENT_MODULES                \
     MODULE(nsTelemetryModule)                \
+    MODULE(jsdebugger)                       \
     /* end of list */
 
 #define MODULE(_name) \
   NSMODULE_DECL(_name);
 
 XUL_MODULES
 
 #undef MODULE
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -678,16 +678,22 @@ MAKEFILES_jsctypes="
   toolkit/components/ctypes/Makefile
   toolkit/components/ctypes/tests/Makefile
 "
 
 MAKEFILES_jsreflect="
   toolkit/components/reflect/Makefile
 "
 
+MAKEFILES_jsductwork="
+  js/ductwork/Makefile
+  js/ductwork/debugger/Makefile
+  js/ductwork/debugger/tests/Makefile
+"
+
 MAKEFILES_libpr0n="
   modules/libpr0n/Makefile
   modules/libpr0n/build/Makefile
   modules/libpr0n/public/Makefile
   modules/libpr0n/src/Makefile
   modules/libpr0n/decoders/Makefile
   modules/libpr0n/decoders/icon/Makefile
   modules/libpr0n/decoders/icon/mac/Makefile
@@ -745,16 +751,17 @@ add_makefiles "
   $MAKEFILES_gfx
   $MAKEFILES_htmlparser
   $MAKEFILES_intl
   $MAKEFILES_xpconnect
   $MAKEFILES_jsipc
   $MAKEFILES_jsdebugger
   $MAKEFILES_jsctypes
   $MAKEFILES_jsreflect
+  $MAKEFILES_jsductwork
   $MAKEFILES_content
   $MAKEFILES_layout
   $MAKEFILES_libimg
   $MAKEFILES_libjar
   $MAKEFILES_libreg
   $MAKEFILES_libpref
   $MAKEFILES_mathml
   $MAKEFILES_plugin
--- a/toolkit/toolkit-tiers.mk
+++ b/toolkit/toolkit-tiers.mk
@@ -219,16 +219,18 @@ endif
 ifdef MOZ_PREF_EXTENSIONS
 tier_platform_dirs += extensions/pref
 endif
 
 tier_platform_dirs += services/crypto/component
 
 tier_platform_dirs += startupcache
 
+tier_platform_dirs += js/ductwork
+
 ifdef APP_LIBXUL_STATICDIRS
 # Applications can cheat and ask for code to be
 # built before libxul so libxul can be linked against it.
 tier_platform_staticdirs += $(APP_LIBXUL_STATICDIRS)
 endif
 ifdef APP_LIBXUL_DIRS
 # Applications can cheat and ask for code to be
 # built before libxul so it can be linked into libxul.
--- a/widget/public/nsIWidget.h
+++ b/widget/public/nsIWidget.h
@@ -102,16 +102,19 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #define NS_NATIVE_WIDGET      3
 #define NS_NATIVE_DISPLAY     4
 #define NS_NATIVE_REGION      5
 #define NS_NATIVE_OFFSETX     6
 #define NS_NATIVE_OFFSETY     7
 #define NS_NATIVE_PLUGIN_PORT 8
 #define NS_NATIVE_SCREEN      9
 #define NS_NATIVE_SHELLWIDGET 10      // Get the shell GtkWidget
+// Has to match to NPNVnetscapeWindow, and shareable across processes
+// HWND on Windows and XID on X11
+#define NS_NATIVE_SHAREABLE_WINDOW 11
 #ifdef XP_MACOSX
 #define NS_NATIVE_PLUGIN_PORT_QD    100
 #define NS_NATIVE_PLUGIN_PORT_CG    101
 #endif
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
--- a/widget/src/android/AndroidBridge.cpp
+++ b/widget/src/android/AndroidBridge.cpp
@@ -79,17 +79,17 @@ AndroidBridge::ConstructBridge(JNIEnv *j
                                jclass jGeckoAppShellClass)
 {
     /* NSS hack -- bionic doesn't handle recursive unloads correctly,
      * because library finalizer functions are called with the dynamic
      * linker lock still held.  This results in a deadlock when trying
      * to call dlclose() while we're already inside dlclose().
      * Conveniently, NSS has an env var that can prevent it from unloading.
      */
-    putenv(strdup("NSS_DISABLE_UNLOAD=1"));
+    putenv("NSS_DISABLE_UNLOAD=1"); 
 
     sBridge = new AndroidBridge();
     if (!sBridge->Init(jEnv, jGeckoAppShellClass)) {
         delete sBridge;
         sBridge = 0;
     }
 
     PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -47,18 +47,18 @@
 
 #include "AndroidJavaWrappers.h"
 
 #include "nsIMutableArray.h"
 #include "nsIMIMEInfo.h"
 #include "nsColor.h"
 
 // Some debug #defines
-// #define ANDROID_DEBUG_EVENTS
-// #define ANDROID_DEBUG_WIDGET
+// #define DEBUG_ANDROID_EVENTS
+// #define DEBUG_ANDROID_WIDGET
 
 class nsWindow;
 
 namespace mozilla {
 
 // The order and number of the members in this structure must correspond
 // to the attrsAppearance array in GeckoAppShell.getSystemColors()
 typedef struct AndroidSystemColors {
--- a/widget/src/android/AndroidJavaWrappers.cpp
+++ b/widget/src/android/AndroidJavaWrappers.cpp
@@ -434,17 +434,17 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
             ReadCharactersField(jenv);
             break;
         }
 
         default:
             break;
     }
 
-#ifndef ANDROID_DEBUG_EVENTS
+#ifndef DEBUG_ANDROID_EVENTS
     ALOG("AndroidGeckoEvent: %p : %d", (void*)jobj, mType);
 #endif
 }
 
 void
 AndroidGeckoEvent::Init(int aType)
 {
     mType = aType;
--- a/widget/src/android/nsAppShell.cpp
+++ b/widget/src/android/nsAppShell.cpp
@@ -55,17 +55,17 @@
 #include <pthread.h>
 #include <wchar.h>
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG
 #include "prlog.h"
 #endif
 
-#ifdef ANDROID_DEBUG_EVENTS
+#ifdef DEBUG_ANDROID_EVENTS
 #define EVLOG(args...)  ALOG(args)
 #else
 #define EVLOG(args...) do { } while (0)
 #endif
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
@@ -212,17 +212,17 @@ nsAppShell::ProcessNextNativeEvent(PRBoo
     nsAutoPtr<AndroidGeckoEvent> curEvent;
     AndroidGeckoEvent *nextEvent;
     {
         MutexAutoLock lock(mCondLock);
 
         curEvent = GetNextEvent();
         if (!curEvent && mayWait) {
             // hmm, should we really hardcode this 10s?
-#if defined(ANDROID_DEBUG_EVENTS)
+#if defined(DEBUG_ANDROID_EVENTS)
             PRTime t0, t1;
             EVLOG("nsAppShell: waiting on mQueueCond");
             t0 = PR_Now();
 
             mQueueCond.Wait(PR_MillisecondsToInterval(10000));
             t1 = PR_Now();
             EVLOG("nsAppShell: wait done, waited %d ms", (int)(t1-t0)/1000);
 #else
@@ -251,17 +251,17 @@ nsAppShell::ProcessNextNativeEvent(PRBoo
             // deal with sequences that look like:
             //   MOVE DRAW MOVE DRAW MOVE DRAW
             // and end up with just
             //   MOVE DRAW
             // when we process all the events.
             RemoveNextEvent();
             delete nextEvent;
 
-#if defined(ANDROID_DEBUG_EVENTS)
+#if defined(DEBUG_ANDROID_EVENTS)
             ALOG("# Removing DRAW event (%d outstanding)", mNumDraws);
 #endif
 
             nextEvent = PeekNextEvent();
             nextType = nextEvent->Type();
         }
 
         // If the next type of event isn't the same as the current type,
@@ -272,17 +272,17 @@ nsAppShell::ProcessNextNativeEvent(PRBoo
         // Can only coalesce motion move events, for motion events
         if (curType != AndroidGeckoEvent::MOTION_EVENT)
             break;
 
         if (!(curEvent->Action() == AndroidMotionEvent::ACTION_MOVE &&
               nextEvent->Action() == AndroidMotionEvent::ACTION_MOVE))
             break;
 
-#if defined(ANDROID_DEBUG_EVENTS)
+#if defined(DEBUG_ANDROID_EVENTS)
         ALOG("# Removing % 2d event", curType);
 #endif
 
         RemoveNextEvent();
         curEvent = nextEvent;
         nextEvent = PeekNextEvent();
     }
 
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -369,17 +369,17 @@ nsWindow::Show(PRBool aState)
                 win->BringToFront();
                 break;
             }
         }
     } else if (FindTopLevel() == TopWindow()) {
         nsAppShell::gAppShell->PostEvent(new AndroidGeckoEvent(-1, -1, -1, -1));
     }
 
-#ifdef ANDROID_DEBUG_WIDGET
+#ifdef DEBUG_ANDROID_WIDGET
     DumpWindows();
 #endif
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::SetModal(PRBool aState)
@@ -1582,23 +1582,23 @@ nsWindow::OnKeyEvent(AndroidGeckoEvent *
     if (!firePress)
         return;
 
     nsKeyEvent pressEvent(PR_TRUE, NS_KEY_PRESS, this);
     InitKeyEvent(pressEvent, *ae);
     if (status == nsEventStatus_eConsumeNoDefault) {
         pressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
     }
-#ifdef ANDROID_DEBUG_WIDGET
+#ifdef DEBUG_ANDROID_WIDGET
     __android_log_print(ANDROID_LOG_INFO, "Gecko", "Dispatching key pressEvent with keyCode %d charCode %d shift %d alt %d sym/ctrl %d metamask %d", pressEvent.keyCode, pressEvent.charCode, pressEvent.isShift, pressEvent.isAlt, pressEvent.isControl, ae->MetaState());
 #endif
     DispatchEvent(&pressEvent);
 }
 
-#ifdef ANDROID_DEBUG_IME
+#ifdef DEBUG_ANDROID_IME
 #define ALOGIME(args...) ALOG(args)
 #else
 #define ALOGIME(args...)
 #endif
 
 void
 nsWindow::OnIMEAddRange(AndroidGeckoEvent *ae)
 {
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -1839,16 +1839,19 @@ nsWindow::GetNativeData(PRUint32 aDataTy
         NS_ASSERTION(nsnull != mToolkit, "NULL toolkit, unable to get a GC");
         return (void *)static_cast<nsGTKToolkit *>(mToolkit)->GetSharedGC();
         break;
     }
 
     case NS_NATIVE_SHELLWIDGET:
         return (void *) mShell;
 
+    case NS_NATIVE_SHAREABLE_WINDOW:
+        return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
+
     default:
         NS_WARNING("nsWindow::GetNativeData called with bad value");
         return nsnull;
     }
 }
 
 NS_IMETHODIMP
 nsWindow::SetTitle(const nsAString& aTitle)
--- a/widget/src/qt/nsWindow.cpp
+++ b/widget/src/qt/nsWindow.cpp
@@ -812,16 +812,22 @@ nsWindow::GetNativeData(PRUint32 aDataTy
     }
 
     case NS_NATIVE_SHELLWIDGET: {
         QWidget* widget = nsnull;
         if (mWidget && mWidget->scene())
             widget = mWidget->scene()->views()[0]->viewport();
         return (void *) widget;
     }
+
+    case NS_NATIVE_SHAREABLE_WINDOW: {
+        QWidget *widget = GetViewWidget();
+        return widget ? (void*)widget->winId() : nsnull;
+    }
+
     default:
         NS_WARNING("nsWindow::GetNativeData called with bad value");
         return nsnull;
     }
 }
 
 NS_IMETHODIMP
 nsWindow::SetTitle(const nsAString& aTitle)
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -555,16 +555,22 @@ nsWindow::Create(nsIWidget *aParent,
   }
 
   nsAutoString className;
   if (aInitData->mDropShadow) {
     GetWindowPopupClass(className);
   } else {
     GetWindowClass(className);
   }
+  // Plugins are created in the disabled state so that they can't
+  // steal focus away from our main window.  This is especially
+  // important if the plugin has loaded in a background tab.
+  if(aInitData->mWindowType == eWindowType_plugin) {
+    style |= WS_DISABLED;
+  }
   mWnd = ::CreateWindowExW(extendedStyle,
                            className.get(),
                            L"",
                            style,
                            aRect.x,
                            aRect.y,
                            aRect.width,
                            GetHeight(aRect.height),
@@ -2780,16 +2786,17 @@ void* nsWindow::GetNativeData(PRUint32 a
                                       CW_USEDEFAULT,
                                       mWnd,
                                       NULL,
                                       nsToolkit::mDllInstance,
                                       NULL);
     case NS_NATIVE_PLUGIN_PORT:
     case NS_NATIVE_WIDGET:
     case NS_NATIVE_WINDOW:
+    case NS_NATIVE_SHAREABLE_WINDOW:
       return (void*)mWnd;
     case NS_NATIVE_GRAPHIC:
       // XXX:  This is sleezy!!  Remember to Release the DC after using it!
 #ifdef MOZ_XUL
       return (void*)(eTransparencyTransparent == mTransparencyMode) ?
         mMemoryDC : ::GetDC(mWnd);
 #else
       return (void*)::GetDC(mWnd);
@@ -7299,16 +7306,27 @@ nsWindow::SetWindowClipRegion(const nsTA
     if (current) {
       if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) {
         ::CombineRgn(dest, dest, current, RGN_AND);
       }
       ::DeleteObject(current);
     }
   }
 
+  // If a plugin is not visibile, especially if it is in a background tab,
+  // it should not be able to steal keyboard focus.  This code checks whether
+  // the region that the plugin is being clipped to is NULLREGION.  If it is,
+  // the plugin window gets disabled.
+  if(mWindowType == eWindowType_plugin) {
+    if(NULLREGION == ::CombineRgn(dest, dest, dest, RGN_OR)) {
+      ::EnableWindow(mWnd, FALSE);
+    } else {
+      ::EnableWindow(mWnd, TRUE);
+    }
+  }
   if (!::SetWindowRgn(mWnd, dest, TRUE)) {
     ::DeleteObject(dest);
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 // WM_DESTROY event handler
--- a/widget/src/xpwidgets/PuppetWidget.cpp
+++ b/widget/src/xpwidgets/PuppetWidget.cpp
@@ -616,10 +616,35 @@ PuppetWidget::GetDPI()
   if (mDPI < 0) {
     NS_ABORT_IF_FALSE(mTabChild, "Need TabChild to get the DPI from!");
     mTabChild->SendGetDPI(&mDPI);
   }
 
   return mDPI;
 }
 
+void*
+PuppetWidget::GetNativeData(PRUint32 aDataType)
+{
+    switch (aDataType) {
+    case NS_NATIVE_SHAREABLE_WINDOW: {
+        NS_ABORT_IF_FALSE(mTabChild, "Need TabChild to get the nativeWindow from!");
+        mozilla::WindowsHandle nativeData = nsnull;
+        mTabChild->SendGetWidgetNativeData(&nativeData);
+        return (void*)nativeData;
+    }
+    case NS_NATIVE_WINDOW:
+    case NS_NATIVE_DISPLAY:
+    case NS_NATIVE_PLUGIN_PORT:
+    case NS_NATIVE_GRAPHIC:
+    case NS_NATIVE_SHELLWIDGET:
+    case NS_NATIVE_WIDGET:
+        NS_WARNING("nsWindow::GetNativeData not implemented for this type");
+        break;
+    default:
+        NS_WARNING("nsWindow::GetNativeData called with bad value");
+        break;
+    }
+    return nsnull;
+}
+
 }  // namespace widget
 }  // namespace mozilla
--- a/widget/src/xpwidgets/PuppetWidget.h
+++ b/widget/src/xpwidgets/PuppetWidget.h
@@ -133,18 +133,17 @@ public:
 
   // This API is going away, steer clear.
   virtual void Scroll(const nsIntPoint& aDelta,
                       const nsTArray<nsIntRect>& aDestRects,
                       const nsTArray<Configuration>& aReconfigureChildren)
   { /* dead man walking */ }
 
   // PuppetWidgets don't have native data, as they're purely nonnative.
-  virtual void* GetNativeData(PRUint32 aDataType)
-  { return nsnull; }
+  virtual void* GetNativeData(PRUint32 aDataType);
   NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent)
   { return NS_ERROR_UNEXPECTED; }
 
   // PuppetWidgets don't have any concept of titles. 
   NS_IMETHOD SetTitle(const nsAString& aTitle)
   { return NS_ERROR_UNEXPECTED; }
   
   // PuppetWidgets are always at <0, 0>.
--- a/widget/src/xpwidgets/nsBaseWidget.cpp
+++ b/widget/src/xpwidgets/nsBaseWidget.cpp
@@ -110,17 +110,16 @@ nsBaseWidget::nsBaseWidget()
 , mUseAcceleratedRendering(PR_FALSE)
 , mTemporarilyUseBasicLayerManager(PR_FALSE)
 , mBounds(0,0,0,0)
 , mOriginalBounds(nsnull)
 , mClipRectCount(0)
 , mZIndex(0)
 , mSizeMode(nsSizeMode_Normal)
 , mPopupLevel(ePopupLevelTop)
-, mDrawFPS(PR_FALSE)
 {
 #ifdef NOISY_WIDGET_LEAKS
   gNumWidgets++;
   printf("WIDGETS+ = %d\n", gNumWidgets);
 #endif
 
 #ifdef DEBUG
     debug_RegisterPrefCallbacks();
@@ -811,21 +810,19 @@ nsBaseWidget::GetShouldAccelerate()
   PRBool accelerateByDefault = PR_FALSE;
 #endif
 
   // we should use AddBoolPrefVarCache
   PRBool disableAcceleration =
     Preferences::GetBool("layers.acceleration.disabled", PR_FALSE);
   PRBool forceAcceleration =
     Preferences::GetBool("layers.acceleration.force-enabled", PR_FALSE);
-  mDrawFPS =
-    Preferences::GetBool("layers.acceleration.draw-fps", PR_FALSE);
 
   const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
-  accelerateByDefault = accelerateByDefault || 
+  accelerateByDefault = accelerateByDefault ||
                         (acceleratedEnv && (*acceleratedEnv != '0'));
 
   nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
   PRBool safeMode = PR_FALSE;
   if (xr)
     xr->GetInSafeMode(&safeMode);
 
   bool whitelisted = false;
@@ -874,17 +871,16 @@ LayerManager* nsBaseWidget::GetLayerMana
       /**
        * XXX - On several OSes initialization is expected to fail for now.
        * If we'd get a none-basic layer manager they'd crash. This is ok though
        * since on those platforms it will fail. Anyone implementing new
        * platforms on LayerManagerOGL should ensure their widget is able to
        * deal with it though!
        */
       if (layerManager->Initialize()) {
-        layerManager->SetRenderFPS(mDrawFPS);
         mLayerManager = layerManager;
       }
     }
     if (!mLayerManager) {
       mBasicLayerManager = mLayerManager = CreateBasicLayerManager();
     }
   }
   if (mTemporarilyUseBasicLayerManager && !mBasicLayerManager) {
--- a/widget/src/xpwidgets/nsBaseWidget.h
+++ b/widget/src/xpwidgets/nsBaseWidget.h
@@ -259,17 +259,17 @@ protected:
   {
     static NS_DEFINE_IID(kCPopUpCID, NS_CHILD_CID);
     nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
     return widget.forget();
   }
 
   BasicLayerManager* CreateBasicLayerManager();
 
-protected: 
+protected:
   void*             mClientData;
   ViewWrapper*      mViewWrapperPtr;
   EVENT_CALLBACK    mEventCallback;
   EVENT_CALLBACK    mViewCallback;
   nsDeviceContext* mContext;
   nsIToolkit*       mToolkit;
   nsRefPtr<LayerManager> mLayerManager;
   nsRefPtr<LayerManager> mBasicLayerManager;
@@ -284,22 +284,21 @@ protected:
   nsIntRect         mBounds;
   nsIntRect*        mOriginalBounds;
   // When this pointer is null, the widget is not clipped
   nsAutoArrayPtr<nsIntRect> mClipRects;
   PRUint32          mClipRectCount;
   PRInt32           mZIndex;
   nsSizeMode        mSizeMode;
   nsPopupLevel      mPopupLevel;
-  PRBool            mDrawFPS;
 
   // the last rolled up popup. Only set this when an nsAutoRollup is in scope,
   // so it can be cleared automatically.
   static nsIContent* mLastRollup;
-    
+
 #ifdef DEBUG
 protected:
   static nsAutoString debug_GuiEventToString(nsGUIEvent * aGuiEvent);
   static PRBool debug_WantPaintFlashing();
 
   static void debug_DumpInvalidate(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
                                    const nsIntRect *     aRect,
@@ -307,17 +306,17 @@ protected:
                                    const nsCAutoString & aWidgetName,
                                    PRInt32               aWindowID);
 
   static void debug_DumpEvent(FILE *                aFileOut,
                               nsIWidget *           aWidget,
                               nsGUIEvent *          aGuiEvent,
                               const nsCAutoString & aWidgetName,
                               PRInt32               aWindowID);
-  
+
   static void debug_DumpPaintEvent(FILE *                aFileOut,
                                    nsIWidget *           aWidget,
                                    nsPaintEvent *        aPaintEvent,
                                    const nsCAutoString & aWidgetName,
                                    PRInt32               aWindowID);
 
   static PRBool debug_GetCachedBoolPref(const char* aPrefName);
 #endif
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -1069,17 +1069,19 @@ struct nsCycleCollector
     void RegisterRuntime(PRUint32 langID, 
                          nsCycleCollectionLanguageRuntime *rt);
     nsCycleCollectionLanguageRuntime * GetRuntime(PRUint32 langID);
     void ForgetRuntime(PRUint32 langID);
 
     void SelectPurple(GCGraphBuilder &builder);
     void MarkRoots(GCGraphBuilder &builder);
     void ScanRoots();
-    PRBool CollectWhite(); // returns whether anything was collected
+
+    // returns whether anything was collected
+    PRBool CollectWhite(nsICycleCollectorListener *aListener);
 
     nsCycleCollector();
     ~nsCycleCollector();
 
     // The first pair of Suspect and Forget functions are only used by
     // old XPCOM binary components.
     PRBool Suspect(nsISupports *n);
     PRBool Forget(nsISupports *n);
@@ -1091,17 +1093,17 @@ struct nsCycleCollector
 
     // Prepare for and cleanup after one or more collection(s).
     PRBool PrepareForCollection(nsTArray<PtrInfo*> *aWhiteNodes);
     void GCIfNeeded(PRBool aForceGC);
     void CleanupAfterCollection();
 
     // Start and finish an individual collection.
     PRBool BeginCollection(nsICycleCollectorListener *aListener);
-    PRBool FinishCollection();
+    PRBool FinishCollection(nsICycleCollectorListener *aListener);
 
     PRUint32 SuspectedCount();
     void Shutdown();
 
     void ClearGraph()
     {
         mGraph.mNodes.Clear();
         mGraph.mEdges.Clear();
@@ -1366,50 +1368,53 @@ public:
     NS_IMETHOD Begin()
     {
         char name[255];
         sprintf(name, "cc-edges-%d.log", ++gLogCounter);
         mStream = fopen(name, "w");
 
         return mStream ? NS_OK : NS_ERROR_FAILURE;
     }
-    NS_IMETHOD NoteObject(PRUint64 aAddress, const char *aObjectDescription)
+    NS_IMETHOD NoteRefCountedObject(PRUint64 aAddress, PRUint32 refCount,
+                                    const char *aObjectDescription)
     {
-        fprintf(mStream, "%p %s\n", (void*)aAddress, aObjectDescription);
+        fprintf(mStream, "%p [rc=%u] %s\n", (void*)aAddress, refCount,
+                aObjectDescription);
 
         return NS_OK;
     }
-    NS_IMETHOD NoteEdge(PRUint64 aFromAddress, PRUint64 aToAddress,
-                        const char *aEdgeName)
+    NS_IMETHOD NoteGCedObject(PRUint64 aAddress, PRBool aMarked,
+                              const char *aObjectDescription)
+    {
+        fprintf(mStream, "%p [gc%s] %s\n", (void*)aAddress,
+                aMarked ? ".marked" : "", aObjectDescription);
+
+        return NS_OK;
+    }
+    NS_IMETHOD NoteEdge(PRUint64 aToAddress, const char *aEdgeName)
     {
         fprintf(mStream, "> %p %s\n", (void*)aToAddress, aEdgeName);
 
         return NS_OK;
     }
-    NS_IMETHOD BeginDescriptions()
+    NS_IMETHOD BeginResults()
     {
         fputs("==========\n", mStream);
 
         return NS_OK;
     }
-    NS_IMETHOD DescribeRefcountedObject(PRUint64 aAddress, PRUint32 aKnownEdges,
-                                        PRUint32 aTotalEdges)
+    NS_IMETHOD DescribeRoot(PRUint64 aAddress, PRUint32 aKnownEdges)
     {
-        PRBool root = aKnownEdges != aTotalEdges;
-        fprintf(mStream, "%p", (void*)aAddress);
-        if (root) {
-            fprintf(mStream, " [root] [%u/%u]", aKnownEdges, aTotalEdges);
-        }
-        fputc('\n', mStream);
+        fprintf(mStream, "%p [known=%u]\n", (void*)aAddress, aKnownEdges);
 
         return NS_OK;
     }
-    NS_IMETHOD DescribeGCedObject(PRUint64 aAddress, PRBool aMarked)
+    NS_IMETHOD DescribeGarbage(PRUint64 aAddress)
     {
-        fprintf(mStream, "%p%s\n", (void*)aAddress, aMarked ? " [root]" : "");
+        fprintf(mStream, "%p [garbage]\n", (void*)aAddress);
 
         return NS_OK;
     }
     NS_IMETHOD End()
     {
         fclose(mStream);
         mStream = nsnull;
 
@@ -1505,28 +1510,20 @@ public:
     // nsCycleCollectionTraversalCallback methods.
     NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root);
 
 private:
     void DescribeNode(PRUint32 refCount,
                       size_t objSz,
                       const char *objName)
     {
+        mCurrPi->mRefCount = refCount;
 #ifdef DEBUG_CC
         mCurrPi->mBytes = objSz;
         mCurrPi->mName = PL_strdup(objName);
-#endif
-
-        if (mListener) {
-            mListener->NoteObject((PRUint64)mCurrPi->mPointer, objName);
-        }
-
-        mCurrPi->mRefCount = refCount;
-
-#ifdef DEBUG_CC
         sCollector->mStats.mVisitedNode++;
 #endif
     }
 
     NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refCount, size_t objSz,
                                              const char *objName);
     NS_IMETHOD_(void) DescribeGCedNode(PRBool isMarked, size_t objSz,
                                        const char *objName);
@@ -1664,25 +1661,37 @@ NS_IMETHODIMP_(void)
 GCGraphBuilder::DescribeRefCountedNode(nsrefcnt refCount, size_t objSz,
                                        const char *objName)
 {
     if (refCount == 0)
         Fault("zero refcount", mCurrPi);
     if (refCount == PR_UINT32_MAX)
         Fault("overflowing refcount", mCurrPi);
     sCollector->mVisitedRefCounted++;
+
+    if (mListener) {
+        mListener->NoteRefCountedObject((PRUint64)mCurrPi->mPointer, refCount,
+                                        objName);
+    }
+
     DescribeNode(refCount, objSz, objName);
 }
 
 NS_IMETHODIMP_(void)
 GCGraphBuilder::DescribeGCedNode(PRBool isMarked, size_t objSz,
                                  const char *objName)
 {
     PRUint32 refCount = isMarked ? PR_UINT32_MAX : 0;
     sCollector->mVisitedGCed++;
+
+    if (mListener) {
+        mListener->NoteGCedObject((PRUint64)mCurrPi->mPointer, isMarked,
+                                  objName);
+    }
+
     DescribeNode(refCount, objSz, objName);
 }
 
 NS_IMETHODIMP_(void)
 GCGraphBuilder::NoteXPCOMChild(nsISupports *child) 
 {
     nsCString edgeName;
     if (WantDebugInfo()) {
@@ -1703,18 +1712,17 @@ GCGraphBuilder::NoteXPCOMChild(nsISuppor
         PtrInfo *childPi = AddNode(child, cp, nsIProgrammingLanguage::CPLUSPLUS);
         if (!childPi)
             return;
         mEdgeBuilder.Add(childPi);
 #ifdef DEBUG_CC
         mCurrPi->mEdgeNames.AppendElement(edgeName);
 #endif
         if (mListener) {
-            mListener->NoteEdge((PRUint64)mCurrPi->mPointer, (PRUint64)child,
-                                edgeName.get());
+            mListener->NoteEdge((PRUint64)child, edgeName.get());
         }
         ++childPi->mInternalRefs;
     }
 }
 
 NS_IMETHODIMP_(void)
 GCGraphBuilder::NoteNativeChild(void *child,
                                 nsCycleCollectionParticipant *participant)
@@ -1732,18 +1740,17 @@ GCGraphBuilder::NoteNativeChild(void *ch
     PtrInfo *childPi = AddNode(child, participant, nsIProgrammingLanguage::CPLUSPLUS);
     if (!childPi)
         return;
     mEdgeBuilder.Add(childPi);
 #ifdef DEBUG_CC
     mCurrPi->mEdgeNames.AppendElement(edgeName);
 #endif
     if (mListener) {
-        mListener->NoteEdge((PRUint64)mCurrPi->mPointer, (PRUint64)child,
-                            edgeName.get());
+        mListener->NoteEdge((PRUint64)child, edgeName.get());
     }
     ++childPi->mInternalRefs;
 }
 
 NS_IMETHODIMP_(void)
 GCGraphBuilder::NoteScriptChild(PRUint32 langID, void *child) 
 {
     nsCString edgeName;
@@ -1778,18 +1785,17 @@ GCGraphBuilder::NoteScriptChild(PRUint32
     PtrInfo *childPi = AddNode(child, cp, langID);
     if (!childPi)
         return;
     mEdgeBuilder.Add(childPi);
 #ifdef DEBUG_CC
     mCurrPi->mEdgeNames.AppendElement(edgeName);
 #endif
     if (mListener) {
-        mListener->NoteEdge((PRUint64)mCurrPi->mPointer, (PRUint64)child,
-                            edgeName.get());
+        mListener->NoteEdge((PRUint64)child, edgeName.get());
     }
     ++childPi->mInternalRefs;
 }
 
 NS_IMETHODIMP_(void)
 GCGraphBuilder::NoteNextEdgeName(const char* name)
 {
     if (WantDebugInfo()) {
@@ -1957,17 +1963,17 @@ nsCycleCollector::ScanRoots()
 }
 
 
 ////////////////////////////////////////////////////////////////////////
 // Bacon & Rajan's |CollectWhite| routine, somewhat modified.
 ////////////////////////////////////////////////////////////////////////
 
 PRBool
-nsCycleCollector::CollectWhite()
+nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
 {
     // Explanation of "somewhat modified": we have no way to collect the
     // set of whites "all at once", we have to ask each of them to drop
     // their outgoing links and assume this will cause the garbage cycle
     // to *mostly* self-destruct (except for the reference we continue
     // to hold). 
     // 
     // To do this "safely" we must make sure that the white nodes we're
@@ -1999,16 +2005,25 @@ nsCycleCollector::CollectWhite()
     }
 
 #if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
     struct _CrtMemState ms1, ms2;
     _CrtMemCheckpoint(&ms1);
 #endif
 
     PRUint32 i, count = mWhiteNodes->Length();
+
+    if (aListener) {
+        for (i = 0; i < count; ++i) {
+            PtrInfo *pinfo = mWhiteNodes->ElementAt(i);
+            aListener->DescribeGarbage((PRUint64)pinfo->mPointer);
+        }
+        aListener->End();
+    }
+
     for (i = 0; i < count; ++i) {
         PtrInfo *pinfo = mWhiteNodes->ElementAt(i);
         rv = pinfo->mParticipant->Unlink(pinfo->mPointer);
         if (NS_FAILED(rv)) {
             Fault("Failed unlink call while unlinking", pinfo);
 #ifdef DEBUG_CC
             mStats.mFailedUnlink++;
 #endif
@@ -2670,17 +2685,18 @@ nsCycleCollector::Collect(PRUint32 aTryC
 
     if (!PrepareForCollection(&whiteNodes))
         return 0;
 
     PRUint32 totalCollections = 0;
     while (aTryCollections > totalCollections) {
         // Synchronous cycle collection. Always force a JS GC beforehand.
         GCIfNeeded(PR_TRUE);
-        if (!(BeginCollection(aListener) && FinishCollection()))
+        if (!(BeginCollection(aListener) &&
+              FinishCollection(aListener)))
             break;
 
         ++totalCollections;
     }
 
     CleanupAfterCollection();
 
     return mCollectedObjects;
@@ -2772,34 +2788,28 @@ nsCycleCollector::BeginCollection(nsICyc
 #ifdef COLLECT_TIME_DEBUG
         printf("cc: ScanRoots() took %lldms\n",
                (PR_Now() - now) / PR_USEC_PER_MSEC);
 #endif
 
         mScanInProgress = PR_FALSE;
 
         if (aListener) {
-            aListener->BeginDescriptions();
+            aListener->BeginResults();
 
             NodePool::Enumerator etor(mGraph.mNodes);
             while (!etor.IsDone()) {
                 PtrInfo *pi = etor.GetNext();
-                if (pi->mColor == black) {
-                    PRUint64 p = (PRUint64)pi->mPointer;
-                    if (pi->mRefCount > 0 && pi->mRefCount < PR_UINT32_MAX) {
-                        aListener->DescribeRefcountedObject(p, pi->mInternalRefs,
-                                                           pi->mRefCount);
-                    }
-                    else {
-                        aListener->DescribeGCedObject(p, pi->mRefCount != 0);
-                    }
+                if (pi->mColor == black &&
+                    pi->mRefCount > 0 && pi->mRefCount < PR_UINT32_MAX &&
+                    pi->mInternalRefs != pi->mRefCount) {
+                    aListener->DescribeRoot((PRUint64)pi->mPointer,
+                                            pi->mInternalRefs);
                 }
             }
-
-            aListener->End();
         }
 
 #ifdef DEBUG_CC
         if (mFollowupCollection && purpleStart != purpleEnd) {
             PRUint32 i = 0;
             NodePool::Enumerator queue(mGraph.mNodes);
             while (i++ < purpleStart) {
                 queue.GetNext();
@@ -2824,23 +2834,23 @@ nsCycleCollector::BeginCollection(nsICyc
     else {
         mScanInProgress = PR_FALSE;
     }
 
     return PR_TRUE;
 }
 
 PRBool
-nsCycleCollector::FinishCollection()
+nsCycleCollector::FinishCollection(nsICycleCollectorListener *aListener)
 {
 #ifdef COLLECT_TIME_DEBUG
     PRTime now = PR_Now();
 #endif
 
-    PRBool collected = CollectWhite();
+    PRBool collected = CollectWhite(aListener);
 
 #ifdef COLLECT_TIME_DEBUG
     printf("cc: CollectWhite() took %lldms\n",
            (PR_Now() - now) / PR_USEC_PER_MSEC);
 #endif
 
 #ifdef DEBUG_CC
     mStats.mCollection++;
@@ -3518,17 +3528,17 @@ public:
         mListener = aListener;
 
         mRequest.Notify();
         mReply.Wait();
 
         mListener = nsnull;
 
         if (mCollected) {
-            mCollected = mCollector->FinishCollection();
+            mCollected = mCollector->FinishCollection(aListener);
 
             mCollector->CleanupAfterCollection();
 
             return mCollected ? mCollector->mCollectedObjects : 0;
         }
 
         return 0;
     }
--- a/xpcom/base/nsICycleCollectorListener.idl
+++ b/xpcom/base/nsICycleCollectorListener.idl
@@ -31,34 +31,39 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-/**
- * Interface to pass to the cycle collector to get information about the CC
- * graph while it's being built. The order of calls will be call to begin();
- * then for every node in the graph a call to noteObject() and calls to
+/** Interface to pass to the cycle collector to get information about
+ * the CC graph while it's being built. The order of calls will be a
+ * call to begin(); then for every node in the graph a call to either
+ * noteRefCountedObject() or noteGCedObject(), followed by calls to
  * noteEdge() for every edge starting at that node; then a call to
- * beginDescriptions(); then for every black node in the CC graph a call to
- * either describeRefcountedObject() or to describeGCedObject(); and then a
- * call to end(). If begin() returns an error none of the other functions will
- * be called.
+ * beginResults(); then a mixture of describeRoot() for ref counted
+ * nodes the CC has identified as roots and describeGarbage() for
+ * nodes the CC has identified as garbage.  Ref counted nodes that are
+ * not identified as either roots or garbage are neither, and have a
+ * known edges count equal to their ref count.  Finally, there will be
+ * a call to end().  If begin() returns an error none of the other
+ * functions will be called.
  */
-[scriptable, uuid(194b749a-4ceb-4dd1-928d-d30b5f14c23e)]
+[scriptable, uuid(3f3901bb-6a1c-4998-b32e-6f10a51db470)]
 interface nsICycleCollectorListener : nsISupports
 {
     void begin();
-    void noteObject(in unsigned long long aAddress,
-                    in string aObjectDescription);
-    void noteEdge(in unsigned long long aFromAddress,
-                  in unsigned long long aToAddress,
+    void noteRefCountedObject (in unsigned long long aAddress,
+			       in unsigned long aRefCount,
+			       in string aObjectDescription);
+    void noteGCedObject (in unsigned long long aAddress,
+			 in boolean aMarked,
+			 in string aObjectDescription);
+    void noteEdge(in unsigned long long aToAddress,
                   in string aEdgeName);
-    void beginDescriptions();
-    void describeRefcountedObject(in unsigned long long aAddress,
-                                  in unsigned long aKnownEdges,
-                                  in unsigned long aTotalEdges);
-    void describeGCedObject(in unsigned long long aAddress, in boolean aMarked);
+    void beginResults();
+    void describeRoot(in unsigned long long aAddress,
+		      in unsigned long aKnownEdges);
+    void describeGarbage(in unsigned long long aAddress);
     void end();
 };
--- a/xpcom/glue/nsISupportsImpl.h
+++ b/xpcom/glue/nsISupportsImpl.h
@@ -170,17 +170,17 @@ public:
       refcount = NS_CCAR_TAGGED_TO_REFCNT(mTagged);
       ++refcount;
       mTagged = NS_CCAR_REFCNT_TO_TAGGED(refcount);
     }
 
     return refcount;
   }
 
-  void stabilizeForDeletion(nsISupports *owner)
+  void stabilizeForDeletion(nsISupports*)
   {
     mTagged = NS_CCAR_TAGGED_STABILIZED_REFCNT;
   }
 
   nsrefcnt decr(nsISupports *owner)
   {
     if (NS_UNLIKELY(mTagged == NS_CCAR_TAGGED_STABILIZED_REFCNT))
       return 1;
--- a/xpcom/typelib/xpt/src/xpt_struct.c
+++ b/xpcom/typelib/xpt/src/xpt_struct.c
@@ -936,17 +936,17 @@ XPT_GetInterfaceIndexByName(XPTInterface
 }
 
 static XPT_TYPELIB_VERSIONS_STRUCT versions[] = XPT_TYPELIB_VERSIONS;
 #define XPT_TYPELIB_VERSIONS_COUNT (sizeof(versions) / sizeof(versions[0]))
 
 XPT_PUBLIC_API(PRUint16)
 XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor)
 {
-    int i;
+    unsigned int i;
     for (i = 0; i < XPT_TYPELIB_VERSIONS_COUNT; i++) {
         if (!strcmp(versions[i].str, str)) {
             *major = versions[i].major;
             *minor = versions[i].minor;
             return versions[i].code;
         }
     }
     return XPT_VERSION_UNKNOWN;
--- a/xpcom/typelib/xpt/src/xpt_xdr.c
+++ b/xpcom/typelib/xpt/src/xpt_xdr.c
@@ -401,17 +401,17 @@ XPT_DoStringInline(XPTArena *arena, XPTC
 
 XPT_PUBLIC_API(PRBool)
 XPT_DoString(XPTArena *arena, XPTCursor *cursor, XPTString **strp)
 {
     XPTCursor my_cursor;
     XPTString *str = *strp;
     PRBool already;
 
-    XPT_PREAMBLE_NO_ALLOC(cursor, strp, XPT_DATA, str->length + 2, my_cursor,
+    XPT_PREAMBLE_NO_ALLOC(cursor, strp, XPT_DATA, str->length + 2u, my_cursor,
                           already)
 
     return XPT_DoStringInline(arena, &my_cursor, strp);
 }
 
 XPT_PUBLIC_API(PRBool)
 XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **identp)
 {