land initial tracemonkey development, pref'd off
authorshaver@mozilla.org
Thu, 21 Aug 2008 11:13:00 -0700
changeset 18320 74a9a3453bd9
parent 17164 73967cc9e4ee (current diff)
parent 18319 4ccf8dc11ab3 (diff)
child 18328 e4d30c562c97
push id1452
push usershaver@mozilla.com
push date2008-08-22 00:08 +0000
Treeherderresults
milestone1.9.1a2pre
land initial tracemonkey development, pref'd off
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -3141,16 +3141,22 @@ nsCanvasRenderingContext2D::GetImageData
     jsval *retvalPtr;
     ncc->GetRetValPtr(&retvalPtr);
     *retvalPtr = OBJECT_TO_JSVAL(result);
     ncc->SetReturnValueWasSet(PR_TRUE);
 
     return NS_OK;
 }
 
+extern "C" {
+extern JSBool
+js_ArrayToJSUint8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                        JSUint8 *dest);
+}
+
 // void putImageData (in ImageData d, in float x, in float y);
 NS_IMETHODIMP
 nsCanvasRenderingContext2D::PutImageData()
 {
     nsresult rv;
 
     if (!mValid)
         return NS_ERROR_FAILURE;
@@ -3211,59 +3217,85 @@ nsCanvasRenderingContext2D::PutImageData
         arrayLen < (jsuint)(w * h * 4))
         return NS_ERROR_DOM_SYNTAX_ERR;
 
     nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[w * h * 4]);
     if (!imageBuffer)
         return NS_ERROR_OUT_OF_MEMORY;
 
     PRUint8 *imgPtr = imageBuffer.get();
-    jsval vr, vg, vb, va;
-    PRUint8 ir, ig, ib, ia;
-    for (int32 j = 0; j < h; j++) {
-        for (int32 i = 0; i < w; i++) {
-            if (!JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 0, &vr) ||
-                !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 1, &vg) ||
-                !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 2, &vb) ||
-                !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 3, &va))
-                return NS_ERROR_DOM_SYNTAX_ERR;
-
-            if (JSVAL_IS_INT(vr))         ir = (PRUint8) JSVAL_TO_INT(vr);
-            else if (JSVAL_IS_DOUBLE(vr)) ir = (PRUint8) (*JSVAL_TO_DOUBLE(vr));
-            else return NS_ERROR_DOM_SYNTAX_ERR;
-
-
-            if (JSVAL_IS_INT(vg))         ig = (PRUint8) JSVAL_TO_INT(vg);
-            else if (JSVAL_IS_DOUBLE(vg)) ig = (PRUint8) (*JSVAL_TO_DOUBLE(vg));
-            else return NS_ERROR_DOM_SYNTAX_ERR;
-
-            if (JSVAL_IS_INT(vb))         ib = (PRUint8) JSVAL_TO_INT(vb);
-            else if (JSVAL_IS_DOUBLE(vb)) ib = (PRUint8) (*JSVAL_TO_DOUBLE(vb));
-            else return NS_ERROR_DOM_SYNTAX_ERR;
-
-            if (JSVAL_IS_INT(va))         ia = (PRUint8) JSVAL_TO_INT(va);
-            else if (JSVAL_IS_DOUBLE(va)) ia = (PRUint8) (*JSVAL_TO_DOUBLE(va));
-            else return NS_ERROR_DOM_SYNTAX_ERR;
-
-            // Convert to premultiplied color (losslessly if the input came from getImageData)
-            ir = (ir*ia + 254) / 255;
-            ig = (ig*ia + 254) / 255;
-            ib = (ib*ia + 254) / 255;
+
+    JSBool ok = js_ArrayToJSUint8Buffer(ctx, dataArray, 0, w*h*4, imageBuffer);
+
+    // no fast path? go slow.
+    if (!ok) {
+        jsval vr, vg, vb, va;
+        PRUint8 ir, ig, ib, ia;
+        for (int32 j = 0; j < h; j++) {
+            for (int32 i = 0; i < w; i++) {
+                if (!JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 0, &vr) ||
+                    !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 1, &vg) ||
+                    !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 2, &vb) ||
+                    !JS_GetElement(ctx, dataArray, (j*w*4) + i*4 + 3, &va))
+                    return NS_ERROR_DOM_SYNTAX_ERR;
+
+                if (JSVAL_IS_INT(vr))         ir = (PRUint8) JSVAL_TO_INT(vr);
+                else if (JSVAL_IS_DOUBLE(vr)) ir = (PRUint8) (*JSVAL_TO_DOUBLE(vr));
+                else return NS_ERROR_DOM_SYNTAX_ERR;
+
+                if (JSVAL_IS_INT(vg))         ig = (PRUint8) JSVAL_TO_INT(vg);
+                else if (JSVAL_IS_DOUBLE(vg)) ig = (PRUint8) (*JSVAL_TO_DOUBLE(vg));
+                else return NS_ERROR_DOM_SYNTAX_ERR;
+
+                if (JSVAL_IS_INT(vb))         ib = (PRUint8) JSVAL_TO_INT(vb);
+                else if (JSVAL_IS_DOUBLE(vb)) ib = (PRUint8) (*JSVAL_TO_DOUBLE(vb));
+                else return NS_ERROR_DOM_SYNTAX_ERR;
+
+                if (JSVAL_IS_INT(va))         ia = (PRUint8) JSVAL_TO_INT(va);
+                else if (JSVAL_IS_DOUBLE(va)) ia = (PRUint8) (*JSVAL_TO_DOUBLE(va));
+                else return NS_ERROR_DOM_SYNTAX_ERR;
+
+                // Convert to premultiplied color (losslessly if the input came from getImageData)
+                ir = (ir*ia + 254) / 255;
+                ig = (ig*ia + 254) / 255;
+                ib = (ib*ia + 254) / 255;
 
 #ifdef IS_LITTLE_ENDIAN
-            *imgPtr++ = ib;
-            *imgPtr++ = ig;
-            *imgPtr++ = ir;
-            *imgPtr++ = ia;
+                *imgPtr++ = ib;
+                *imgPtr++ = ig;
+                *imgPtr++ = ir;
+                *imgPtr++ = ia;
 #else
-            *imgPtr++ = ia;
-            *imgPtr++ = ir;
-            *imgPtr++ = ig;
-            *imgPtr++ = ib;
+                *imgPtr++ = ia;
+                *imgPtr++ = ir;
+                *imgPtr++ = ig;
+                *imgPtr++ = ib;
 #endif
+            }
+        }
+    } else {
+        /* Walk through and premultiply and swap rgba */
+        /* XXX SSE me */
+        PRUint8 ir, ig, ib, ia;
+        PRUint8 *ptr = imgPtr;
+        for (int32 i = 0; i < w*h; i++) {
+#ifdef IS_LITTLE_ENDIAN
+            ir = ptr[0];
+            ig = ptr[1];
+            ib = ptr[2];
+            ia = ptr[3];
+            ptr[0] = (ib*ia + 254) / 255;
+            ptr[1] = (ig*ia + 254) / 255;
+            ptr[2] = (ir*ia + 254) / 255;
+#else
+            ptr[0] = (ptr[0]*ptr[3] + 254) / 255;
+            ptr[1] = (ptr[1]*ptr[3] + 254) / 255;
+            ptr[2] = (ptr[2]*ptr[3] + 254) / 255;
+#endif
+            ptr += 4;
         }
     }
 
     nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(imageBuffer.get(),
                                                             gfxIntSize(w, h),
                                                             w * 4,
                                                             gfxASurface::ImageFormatARGB32);
     if (!imgsurf || imgsurf->CairoStatus())
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -402,17 +402,17 @@ NS_HandleScriptError(nsIScriptGlobalObje
   nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aScriptGlobal));
   nsIDocShell *docShell = win ? win->GetDocShell() : nsnull;
   if (docShell) {
     nsCOMPtr<nsPresContext> presContext;
     docShell->GetPresContext(getter_AddRefs(presContext));
 
     static PRInt32 errorDepth; // Recursion prevention
     ++errorDepth;
-    
+
     if (presContext && errorDepth < 2) {
       // Dispatch() must be synchronous for the recursion block
       // (errorDepth) to work.
       nsEventDispatcher::Dispatch(win, presContext, aErrorEvent, nsnull,
                                   aStatus);
       called = PR_TRUE;
     }
     --errorDepth;
@@ -614,17 +614,17 @@ NS_ScriptErrorReporter(JSContext *cx,
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 LocaleToUnicode(JSContext *cx, char *src, jsval *rval)
 {
   nsresult rv;
 
   if (!gDecoder) {
     // use app default locale
-    nsCOMPtr<nsILocaleService> localeService = 
+    nsCOMPtr<nsILocaleService> localeService =
       do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
     if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<nsILocale> appLocale;
       rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
       if (NS_SUCCEEDED(rv)) {
         nsAutoString localeStr;
         rv = appLocale->
           GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
@@ -924,19 +924,19 @@ nsJSContext::DOMOperationCallback(JSCont
   JSStackFrame* fp = ::JS_GetScriptedCaller(cx, NULL);
   PRBool debugPossible = (fp != nsnull &&
                           cx->debugHooks->debuggerHandler != nsnull);
 #ifdef MOZ_JSDEBUGGER
   // Get the debugger service if necessary.
   if (debugPossible) {
     PRBool jsds_IsOn = PR_FALSE;
     const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
-    nsCOMPtr<jsdIExecutionHook> jsdHook;  
+    nsCOMPtr<jsdIExecutionHook> jsdHook;
     nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
-  
+
     // Check if there's a user for the debugger service that's 'on' for us
     if (NS_SUCCEEDED(rv)) {
       jsds->GetDebuggerHook(getter_AddRefs(jsdHook));
       jsds->GetIsOn(&jsds_IsOn);
       if (jsds_IsOn) { // If this is not true, the next call would start jsd...
         rv = jsds->OnForRuntime(cx->runtime);
         jsds_IsOn = NS_SUCCEEDED(rv);
       }
@@ -954,17 +954,17 @@ nsJSContext::DOMOperationCallback(JSCont
     stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
   if (!stringService)
     return JS_TRUE;
 
   nsCOMPtr<nsIStringBundle> bundle;
   stringService->CreateBundle(kDOMStringBundleURL, getter_AddRefs(bundle));
   if (!bundle)
     return JS_TRUE;
-  
+
   nsXPIDLString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
 
   rv = bundle->GetStringFromName(NS_LITERAL_STRING("KillScriptTitle").get(),
                                   getter_Copies(title));
   rv |= bundle->GetStringFromName(NS_LITERAL_STRING("StopScriptButton").get(),
                                   getter_Copies(stopButton));
   rv |= bundle->GetStringFromName(NS_LITERAL_STRING("WaitForScriptButton").get(),
                                   getter_Copies(waitButton));
@@ -1079,37 +1079,49 @@ nsJSContext::DOMOperationCallback(JSCont
 
 static const char js_options_dot_str[]   = JS_OPTIONS_DOT_STR;
 static const char js_strict_option_str[] = JS_OPTIONS_DOT_STR "strict";
 static const char js_werror_option_str[] = JS_OPTIONS_DOT_STR "werror";
 static const char js_relimit_option_str[]= JS_OPTIONS_DOT_STR "relimit";
 #ifdef JS_GC_ZEAL
 static const char js_zeal_option_str[]   = JS_OPTIONS_DOT_STR "gczeal";
 #endif
+static const char js_jit_content_str[]   = JS_OPTIONS_DOT_STR "jit.content";
+static const char js_jit_chrome_str[]    = JS_OPTIONS_DOT_STR "jit.chrome";
 
 int PR_CALLBACK
 nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
 {
   nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
   PRUint32 oldDefaultJSOptions = context->mDefaultJSOptions;
   PRUint32 newDefaultJSOptions = oldDefaultJSOptions;
 
   PRBool strict = nsContentUtils::GetBoolPref(js_strict_option_str);
   if (strict)
     newDefaultJSOptions |= JSOPTION_STRICT;
   else
     newDefaultJSOptions &= ~JSOPTION_STRICT;
 
+  nsIScriptGlobalObject *global = context->GetGlobalObject();
+  // XXX should we check for sysprin instead of a chrome window, to make
+  // XXX components be covered by the chrome pref instead of the content one?
+  nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(global));
+  PRBool useJIT = nsContentUtils::GetBoolPref(chromeWindow ?
+                                              js_jit_chrome_str :
+                                              js_jit_content_str);
+  if (useJIT)
+    newDefaultJSOptions |= JSOPTION_JIT;
+  else
+    newDefaultJSOptions &= ~JSOPTION_JIT;
+
 #ifdef DEBUG
   // In debug builds, warnings are always enabled in chrome context
   // Note this callback is also called from context's InitClasses thus we don't
   // need to enable this directly from InitContext
   if ((newDefaultJSOptions & JSOPTION_STRICT) == 0) {
-    nsIScriptGlobalObject *global = context->GetGlobalObject();
-    nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(global));
     if (chromeWindow)
       newDefaultJSOptions |= JSOPTION_STRICT;
   }
 #endif
 
   PRBool werror = nsContentUtils::GetBoolPref(js_werror_option_str);
   if (werror)
     newDefaultJSOptions |= JSOPTION_WERROR;
@@ -1501,20 +1513,18 @@ nsJSContext::EvaluateString(const nsAStr
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
     JSPRINCIPALS_DROP(mContext, jsprin);
     return NS_ERROR_FAILURE;
   }
 
   // The result of evaluation, used only if there were no errors.  This need
   // not be a GC root currently, provided we run the GC only from the
   // operation callback or from ScriptEvaluated.
-  //
-  // TODO: use JS_Begin/EndRequest to keep the GC from racing with JS
-  // execution on any thread.
-  jsval val;
+  jsval val = JSVAL_VOID;
+  jsval* vp = aRetValue ? &val : NULL;
 
   nsJSContext::TerminationFuncHolder holder(this);
 
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
     JSAutoRequest ar(mContext);
@@ -1522,31 +1532,31 @@ nsJSContext::EvaluateString(const nsAStr
 
     ok = ::JS_EvaluateUCScriptForPrincipals(mContext,
                                               (JSObject *)aScopeObject,
                                               jsprin,
                                               (jschar*)PromiseFlatString(aScript).get(),
                                               aScript.Length(),
                                               aURL,
                                               aLineNo,
-                                              &val);
+                                              vp);
 
     if (!ok) {
       // Tell XPConnect about any pending exceptions. This is needed
       // to avoid dropping JS exceptions in case we got here through
       // nested calls through XPConnect.
 
       JS_ReportPendingException(mContext);
     }
   }
 
   // Whew!  Finally done with these manually ref-counted things.
   JSPRINCIPALS_DROP(mContext, jsprin);
 
-  // If all went well, convert val to a string (XXXbe unless undefined?).
+  // If all went well, convert val to a string if one is wanted.
   if (ok) {
     JSAutoRequest ar(mContext);
     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
   }
   else {
     if (aIsUndefined) {
       *aIsUndefined = PR_TRUE;
     }
@@ -1948,17 +1958,17 @@ nsJSContext::CallEventHandler(nsISupport
     // right scope anyway, and we want to make sure that the arguments end up
     // in the same scope as aTarget.
     rv = ConvertSupportsTojsvals(aargv, target, &argc,
                                  reinterpret_cast<void **>(&argv), &mark);
     if (NS_FAILED(rv)) {
       stack->Pop(nsnull);
       return rv;
     }
-  
+
     AutoFreeJSStack stackGuard(mContext, mark); // ensure always freed.
 
     jsval funval = OBJECT_TO_JSVAL(aHandler);
     JSAutoRequest ar(mContext);
     PRBool ok = ::JS_CallFunctionValue(mContext, target,
                                        funval, argc, argv, &rval);
 
     if (!ok) {
@@ -2011,17 +2021,17 @@ nsJSContext::BindCompiledEventHandler(ns
   // Get the jsobject associated with this target
   JSObject *target = nsnull;
   nsAutoGCRoot root(&target, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSObject *funobj = (JSObject*) aHandler;
-  
+
   JSAutoRequest ar(mContext);
 
   NS_ASSERTION(JS_TypeOfValue(mContext, OBJECT_TO_JSVAL(funobj)) == JSTYPE_FUNCTION,
                "Event handler object not a function");
 
   // Push our JSContext on our thread's context stack, in case native code
   // called from JS calls back into JS via XPConnect.
   nsCOMPtr<nsIJSContextStack> stack =
@@ -2066,20 +2076,20 @@ nsJSContext::GetBoundEventHandler(nsISup
     NS_ENSURE_SUCCESS(rv, rv);
     JSAutoRequest ar(mContext);
     rv = JSObjectFromInterface(aTarget, aScope, &obj);
     NS_ENSURE_SUCCESS(rv, rv);
 
     const char *charName = AtomToEventHandlerName(aName);
 
     jsval funval;
-    if (!JS_LookupProperty(mContext, obj, 
+    if (!JS_LookupProperty(mContext, obj,
                            charName, &funval))
         return NS_ERROR_FAILURE;
-    
+
     if (JS_TypeOfValue(mContext, funval) != JSTYPE_FUNCTION) {
         NS_WARNING("Event handler object not a function");
         aHandler.drop();
         return NS_OK;
     }
     NS_ASSERTION(aHandler.getScriptTypeID()==JAVASCRIPT,
                  "Expecting JS script object holder");
     return aHandler.set(JSVAL_TO_OBJECT(funval));
@@ -2207,17 +2217,17 @@ nsJSContext::Deserialize(nsIObjectInputS
     if (data)
         nsMemory::Free(data);
     NS_ASSERTION(aResult.getScriptTypeID()==JAVASCRIPT,
                  "Expecting JS script object holder");
 
     // Now that we've cleaned up, handle the case when rv is a failure
     // code, which could happen for all sorts of reasons above.
     NS_ENSURE_SUCCESS(rv, rv);
-    
+
     return aResult.set(result);
 }
 
 void
 nsJSContext::SetDefaultLanguageVersion(PRUint32 aVersion)
 {
   ::JS_SetVersion(mContext, (JSVersion)aVersion);
 }
@@ -2364,17 +2374,17 @@ nsJSContext::InitContext(nsIScriptGlobal
   // If there's already a global object in mContext we won't tell
   // XPConnect to wrap aGlobalObject since it's already wrapped.
 
   nsresult rv;
 
   if (!global) {
     nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(aGlobalObject));
     PRUint32 flags = 0;
-    
+
     if (chromeWindow) {
       // Flag this window's global object and objects under it as "system",
       // for optional automated XPCNativeWrapper construction when chrome JS
       // views a content DOM.
       flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
 
       // Always enable E4X for XUL and other chrome content -- there is no
       // need to preserve the <!-- script hiding hack from JS-in-HTML daze
@@ -2531,17 +2541,17 @@ nsJSContext::ConvertSupportsTojsvals(nsI
       argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
                                 getter_AddRefs(arg));
       if (!arg) {
         *thisval = JSVAL_NULL;
         continue;
       }
       nsCOMPtr<nsIVariant> variant(do_QueryInterface(arg));
       if (variant != nsnull) {
-        rv = xpc->VariantToJS(mContext, (JSObject *)aScope, variant, 
+        rv = xpc->VariantToJS(mContext, (JSObject *)aScope, variant,
                               thisval);
       } else {
         // And finally, support the nsISupportsPrimitives supplied
         // by the AppShell.  It generally will pass only strings, but
         // as we have code for handling all, we may as well use it.
         rv = AddSupportsPrimitiveTojsvals(arg, thisval);
         if (rv == NS_ERROR_NO_INTERFACE) {
           // something else - probably an event object or similar -
@@ -2603,17 +2613,17 @@ nsJSContext::AddSupportsPrimitiveTojsval
     case nsISupportsPrimitive::TYPE_CSTRING : {
       nsCOMPtr<nsISupportsCString> p(do_QueryInterface(argPrimitive));
       NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
 
       nsCAutoString data;
 
       p->GetData(data);
 
-      
+
       JSString *str = ::JS_NewStringCopyN(cx, data.get(), data.Length());
       NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
 
       *aArgv = STRING_TO_JSVAL(str);
 
       break;
     }
     case nsISupportsPrimitive::TYPE_STRING : {
@@ -2800,17 +2810,17 @@ nsresult
 nsJSContext::FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder)
 {
   NS_ASSERTION(!NS_DOMClassInfo_GetXPCNativeWrapperClass(),
                "Why was this called?");
 
   JSObject *globalObj;
   aHolder->GetJSObject(&globalObj);
   NS_ASSERTION(globalObj, "Must have global by now!");
-      
+
   const char* arg = "arg";
   NS_NAMED_LITERAL_STRING(body, "return new XPCNativeWrapper(arg);");
 
   // Can't use CompileFunction() here because our principal isn't
   // inited yet and a null principal makes it fail.
   JSFunction *fun =
     ::JS_CompileUCFunction(mContext,
                            globalObj,
@@ -2820,17 +2830,17 @@ nsJSContext::FindXPCNativeWrapperClass(n
                            body.Length(),
                            "javascript:return new XPCNativeWrapper(arg);",
                            1 // lineno
                            );
   NS_ENSURE_TRUE(fun, NS_ERROR_FAILURE);
 
   jsval globalVal = OBJECT_TO_JSVAL(globalObj);
   jsval wrapper;
-      
+
   JSBool ok = ::JS_CallFunction(mContext, globalObj, fun,
                                 1, &globalVal, &wrapper);
   if (!ok) {
     // No need to notify about pending exceptions here; we don't
     // expect any other than out of memory, really.
     return NS_ERROR_FAILURE;
   }
 
@@ -3167,17 +3177,17 @@ nsJSContext::InitClasses(void *aGlobalOb
 #endif
 
 #ifdef MOZ_VTUNE
   // Attempt to initialize Vtune functions
   ::JS_DefineFunctions(mContext, globalObj, VtuneFunctions);
 #endif
 
   JSOptionChangedCallback(js_options_dot_str, this);
-    
+
   return rv;
 }
 
 void
 nsJSContext::ClearScope(void *aGlobalObj, PRBool aClearFromProtoChain)
 {
   // Push our JSContext on our thread's context stack.
   nsCOMPtr<nsIJSContextStack> stack =
@@ -3257,17 +3267,17 @@ nsJSContext::GC()
 void
 nsJSContext::ScriptEvaluated(PRBool aTerminated)
 {
   if (aTerminated && mTerminations) {
     // Make sure to null out mTerminations before doing anything that
     // might cause new termination funcs to be added!
     nsJSContext::TerminationFuncClosure* start = mTerminations;
     mTerminations = nsnull;
-    
+
     for (nsJSContext::TerminationFuncClosure* cur = start;
          cur;
          cur = cur->mNext) {
       (*(cur->mTerminationFunc))(cur->mTerminationFuncArg);
     }
     delete start;
   }
 
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/public/gfxXlibNativeRenderer.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Novell code.
+ *
+ * The Initial Developer of the Original Code is Novell.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   rocallahan@novell.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 GFXXLIBNATIVERENDER_H_
+#define GFXXLIBNATIVERENDER_H_
+
+#include "gfxColor.h"
+#include <X11/Xlib.h>
+
+class gfxASurface;
+class gfxContext;
+
+/**
+ * This class lets us take code that draws into an X drawable and lets us
+ * use it to draw into any Thebes context. The user should subclass this class,
+ * override NativeDraw, and then call Draw(). The drawing will be subjected
+ * to all Thebes transformations, clipping etc.
+ */
+class THEBES_API gfxXlibNativeRenderer {
+public:
+    /**
+     * Perform the native drawing.
+     * @param offsetX draw at this offset into the given drawable
+     * @param offsetY draw at this offset into the given drawable
+     * @param clipRects an array of rects; clip to the union
+     * @param numClipRects the number of rects in the array, or zero if
+     * no clipping is required
+     */
+    virtual nsresult NativeDraw(Screen* screen, Drawable drawable,
+                                Visual* visual, Colormap colormap,
+                                short offsetX, short offsetY,
+                                XRectangle* clipRects, PRUint32 numClipRects) = 0;
+  
+    enum {
+        // If set, then Draw() is opaque, i.e., every pixel in the intersection
+        // of the clipRect and (offset.x,offset.y,bounds.width,bounds.height)
+        // will be set and there is no dependence on what the existing pixels
+        // in the drawable are set to.
+        DRAW_IS_OPAQUE = 0x01,
+        // If set, then offset may be non-zero; if not set, then Draw() can
+        // only be called with offset==(0,0)
+        DRAW_SUPPORTS_OFFSET = 0x02,
+        // If set, then numClipRects can be zero or one
+        DRAW_SUPPORTS_CLIP_RECT = 0x04,
+        // If set, then numClipRects can be any value. If neither this
+        // nor CLIP_RECT are set, then numClipRects will be zero
+        DRAW_SUPPORTS_CLIP_LIST = 0x08,
+        // If set, then the visual passed in can be any visual, otherwise the
+        // visual passed in must be the default visual for 'screen'
+        DRAW_SUPPORTS_NONDEFAULT_VISUAL = 0x10,
+        // If set, then the Screen 'screen' in the callback can be different
+        // from the default Screen of the display passed to 'Draw' and can be
+        // on a different display.
+        DRAW_SUPPORTS_ALTERNATE_SCREEN = 0x20
+    };
+
+    struct DrawOutput {
+        nsRefPtr<gfxASurface> mSurface;
+        PRPackedBool mUniformAlpha;
+        PRPackedBool mUniformColor;
+        gfxRGBA      mColor;
+    };
+
+    /**
+     * @param flags see above
+     * @param bounds Draw()'s drawing is guaranteed to be restricted to
+     * the rectangle (offset.x,offset.y,bounds.width,bounds.height)
+     * @param dpy a display to use for the drawing if ctx doesn't have one
+     * @param resultSurface if non-null, we will try to capture a copy of the
+     * rendered image into a surface similar to the surface of ctx; if
+     * successful, a pointer to the new gfxASurface is stored in *resultSurface,
+     * otherwise *resultSurface is set to nsnull.
+     */
+    nsresult Draw(Display* dpy, gfxContext* ctx, int width, int height,
+                  PRUint32 flags, DrawOutput* output);
+};
+
+#endif /*GFXXLIBNATIVERENDER_H_*/
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/cairo-xlib-utils.h
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Novell code.
+ *
+ * The Initial Developer of the Original Code is Novell.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   rocallahan@novell.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 CAIROXLIBUTILS_H_
+#define CAIROXLIBUTILS_H_
+
+#include "cairo.h"
+#include <X11/Xlib.h>
+
+CAIRO_BEGIN_DECLS
+
+/**
+ * This callback encapsulates Xlib-based rendering. We assume that the
+ * execution of the callback is equivalent to compositing some RGBA image of
+ * size (bounds_width, bounds_height) onto the drawable at offset (offset_x,
+ * offset_y), clipped to the union of the clip_rects if num_rects is greater
+ * than zero. This includes the assumption that the same RGBA image
+ * is composited if you call the callback multiple times with the same closure,
+ * display and visual during a single cairo_draw_with_xlib call.
+ * 
+ * @return True on success, False on non-recoverable error
+ */
+typedef cairo_bool_t (* cairo_xlib_drawing_callback)
+    (void *closure,
+     Screen *screen,
+     Drawable drawable,
+     Visual *visual,
+     short offset_x, short offset_y,
+     XRectangle* clip_rects, unsigned int num_rects);
+
+/**
+ * This structure captures the result of the native drawing, in case the
+ * caller may wish to reapply the drawing efficiently later.
+ */
+typedef struct {
+    cairo_surface_t *surface;
+    cairo_bool_t    uniform_alpha;
+    cairo_bool_t    uniform_color;
+    double          alpha; /* valid only if uniform_alpha is TRUE */
+    double          r, g, b; /* valid only if uniform_color is TRUE */
+} cairo_xlib_drawing_result_t;
+
+/**
+ * This type specifies whether the native drawing callback draws all pixels
+ * in its bounds opaquely, independent of the contents of the target drawable,
+ * or whether it leaves pixels transparent/translucent or depends on the
+ * existing contents of the target drawable in some way.
+ */
+typedef enum _cairo_xlib_drawing_opacity {
+    CAIRO_XLIB_DRAWING_OPAQUE,
+    CAIRO_XLIB_DRAWING_TRANSPARENT
+} cairo_xlib_drawing_opacity_t;
+
+/**
+ * This type encodes the capabilities of the native drawing callback.
+ * 
+ * If CAIRO_XLIB_DRAWING_SUPPORTS_OFFSET is set, 'offset_x' and 'offset_y'
+ * can be nonzero in the call to the callback; otherwise they will be zero.
+ * 
+ * If CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_RECT is set, then 'num_rects' can be
+ * zero or one in the call to the callback. If
+ * CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_LIST is set, then 'num_rects' can be
+ * anything in the call to the callback. Otherwise 'num_rects' will be zero.
+ * Do not set both of these values.
+ * 
+ * If CAIRO_XLIB_DRAWING_SUPPORTS_ALTERNATE_SCREEN is set, then 'screen' can
+ * be any screen on any display, otherwise it will be the default screen of
+ * the display passed into cairo_draw_with_xlib.
+ * 
+ * If CAIRO_XLIB_DRAWING_SUPPORTS_NONDEFAULT_VISUAL is set, then 'visual' can be
+ * any visual, otherwise it will be equal to
+ * DefaultVisualOfScreen (screen).
+ */
+typedef enum {
+    CAIRO_XLIB_DRAWING_SUPPORTS_OFFSET = 0x01,
+    CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_RECT = 0x02,
+    CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_LIST = 0x04,
+    CAIRO_XLIB_DRAWING_SUPPORTS_ALTERNATE_SCREEN = 0x08,
+    CAIRO_XLIB_DRAWING_SUPPORTS_NONDEFAULT_VISUAL = 0x10
+} cairo_xlib_drawing_support_t;
+
+/**
+ * Draw Xlib output into any cairo context. All cairo transforms and effects
+ * are honored, including the current operator. This is equivalent to a
+ * cairo_set_source_surface and then cairo_paint.
+ * @param cr the context to draw into
+ * @param callback the code to perform Xlib rendering
+ * @param closure associated data
+ * @param dpy an X display to use in case the cairo context has no associated X display
+ * @param width the width of the putative image drawn by the callback
+ * @param height the height of the putative image drawn by the callback
+ * @param is_opaque set to CAIRO_XLIB_DRAWING_IS_OPAQUE to indicate
+ * that all alpha values of the putative image will be 1.0; the pixels drawn into
+ * the Drawable must not depend on the prior contents of the Drawable
+ * in any way
+ * @param capabilities the capabilities of the callback as described above.
+ * @param result if non-NULL, we *may* fill in the struct with information about
+ * the rendered image. 'surface' may be filled in with a surface representing
+ * the image, similar to the target of 'cr'. If 'uniform_alpha' is True then
+ * every pixel of the image has the same alpha value 'alpha'. If
+ * 'uniform_color' is True then every pixel of the image has the same RGB
+ * color (r, g, b). If the image has uniform color and alpha (or alpha is zero,
+ * in which case the color is always uniform) then we won't bother returning
+ * a surface for it.
+ */
+void cairo_draw_with_xlib (cairo_t *cr,
+                           cairo_xlib_drawing_callback callback,
+                           void *closure,
+                           Display *dpy,
+                           unsigned int width, unsigned int height,
+                           cairo_xlib_drawing_opacity_t is_opaque,
+                           cairo_xlib_drawing_support_t capabilities,
+                           cairo_xlib_drawing_result_t *result);
+
+CAIRO_END_DECLS
+
+#endif /*CAIROXLIBUTILS_H_*/
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxXlibNativeRenderer.cpp
@@ -0,0 +1,209 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Novell code.
+ *
+ * The Initial Developer of the Original Code is Novell.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   rocallahan@novell.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 "gfxXlibNativeRenderer.h"
+#include "gfxContext.h"
+
+#include "cairo-xlib-utils.h"
+
+#ifdef MOZ_WIDGET_GTK2
+#include <gdk/gdkscreen.h>
+#include <gdk/gdkx.h>
+#endif
+
+// Look for an existing Colormap that known to be associated with visual.
+static Colormap
+LookupColormapForVisual(const Screen* screen, const Visual* visual)
+{
+    // common case
+    if (visual == DefaultVisualOfScreen(screen))
+        return DefaultColormapOfScreen(screen);
+
+#ifdef MOZ_WIDGET_GTK2
+    // I wish there were a gdk_x11_display_lookup_screen.
+    Display* dpy = DisplayOfScreen(screen);
+    GdkDisplay* gdkDpy = gdk_x11_lookup_xdisplay(dpy);
+    if (gdkDpy) {
+        gint screen_num = 0;
+        for (int s = 0; s < ScreenCount(dpy); ++s) {
+            if (ScreenOfDisplay(dpy, s) == screen) {
+                screen_num = s;
+                break;
+            }
+        }
+        GdkScreen* gdkScreen = gdk_display_get_screen(gdkDpy, screen_num);
+
+        GdkColormap* gdkColormap = NULL;
+        if (visual ==
+            GDK_VISUAL_XVISUAL(gdk_screen_get_rgb_visual(gdkScreen))) {
+            // widget/src/gtk2/mozcontainer.c uses gdk_rgb_get_colormap()
+            // which is inherited by child widgets, so this is the visual
+            // expected when drawing directly to widget surfaces or surfaces
+            // created using cairo_surface_create_similar with
+            // CAIRO_CONTENT_COLOR.
+            // gdk_screen_get_rgb_colormap is the generalization of
+            // gdk_rgb_get_colormap for any screen.
+            gdkColormap = gdk_screen_get_rgb_colormap(gdkScreen);
+        }
+        else if (visual ==
+             GDK_VISUAL_XVISUAL(gdk_screen_get_rgba_visual(gdkScreen))) {
+            // This is the visual expected on displays with the Composite
+            // extension enabled when the surface has been created using
+            // cairo_surface_create_similar with CAIRO_CONTENT_COLOR_ALPHA,
+            // as happens with non-unit opacity.
+            gdkColormap = gdk_screen_get_rgba_colormap(gdkScreen);
+        }
+        if (gdkColormap != NULL)
+            return GDK_COLORMAP_XCOLORMAP(gdkColormap);
+    }
+#endif
+
+    return None;
+}
+
+typedef struct {
+    gfxXlibNativeRenderer* mRenderer;
+    nsresult               mRV;
+} NativeRenderingClosure;
+
+static cairo_bool_t
+NativeRendering(void *closure,
+                Screen *screen,
+                Drawable drawable,
+                Visual *visual,
+                short offset_x, short offset_y,
+                XRectangle* rectangles, unsigned int num_rects)
+{
+    // Cairo doesn't provide a Colormap.
+    // See if a suitable existing Colormap is known.
+    Colormap colormap = LookupColormapForVisual(screen, visual);
+    PRBool allocColormap = colormap == None;
+    if (allocColormap) {
+        // No existing colormap found.
+        // This case is not expected with MOZ_WIDGET_GTK2.
+        // Create a Colormap for the Visual.
+        // This is only really useful for Visual classes with predefined
+        // Colormap entries, but cairo would be all confused with
+        // non-default non-TrueColor colormaps anyway.
+        NS_ASSERTION(visual->c_class == TrueColor ||
+                     visual->c_class == StaticColor ||
+                     visual->c_class == StaticGray,
+                     "Creating empty colormap");
+        // If this case were expected then it might be worth considering
+        // using a service that maintains a set of Colormaps for associated
+        // Visuals so as to avoid repeating the LockDisplay required in
+        // XCreateColormap, but then it's no worse than the XCreatePixmap
+        // that produced the Drawable here.
+        colormap = XCreateColormap(DisplayOfScreen(screen),
+                                   RootWindowOfScreen(screen),
+                                   visual, AllocNone);
+    }
+
+    NativeRenderingClosure* cl = (NativeRenderingClosure*)closure;
+    nsresult rv = cl->mRenderer->
+        NativeDraw(screen, drawable, visual, colormap, offset_x, offset_y,
+                   rectangles, num_rects);
+    cl->mRV = rv;
+
+    if (allocColormap) {
+        XFreeColormap(DisplayOfScreen(screen), colormap);
+    }
+    return NS_SUCCEEDED(rv);
+}
+
+nsresult
+gfxXlibNativeRenderer::Draw(Display* dpy, gfxContext* ctx, int width, int height,
+                            PRUint32 flags, DrawOutput* output)
+{
+    NativeRenderingClosure closure = { this, NS_OK };
+    cairo_xlib_drawing_result_t result;
+    // Make sure result.surface is null to start with; we rely on it
+    // being non-null meaning that a surface actually got allocated.
+    result.surface = NULL;
+
+    if (output) {
+        output->mSurface = NULL;
+        output->mUniformAlpha = PR_FALSE;
+        output->mUniformColor = PR_FALSE;
+    }
+
+    int cairoFlags = 0;
+    if (flags & DRAW_SUPPORTS_OFFSET) {
+        cairoFlags |= CAIRO_XLIB_DRAWING_SUPPORTS_OFFSET;
+    }
+    if (flags & DRAW_SUPPORTS_CLIP_RECT) {
+        cairoFlags |= CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_RECT;
+    }
+    if (flags & DRAW_SUPPORTS_CLIP_LIST) {
+        cairoFlags |= CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_LIST;
+    }
+    if (flags & DRAW_SUPPORTS_ALTERNATE_SCREEN) {
+        cairoFlags |= CAIRO_XLIB_DRAWING_SUPPORTS_ALTERNATE_SCREEN;
+    }
+    if (flags & DRAW_SUPPORTS_NONDEFAULT_VISUAL) {
+        cairoFlags |= CAIRO_XLIB_DRAWING_SUPPORTS_NONDEFAULT_VISUAL;
+    }
+    cairo_draw_with_xlib(ctx->GetCairo(), NativeRendering, &closure, dpy,
+                         width, height,
+                         (flags & DRAW_IS_OPAQUE) ? CAIRO_XLIB_DRAWING_OPAQUE
+                                                  : CAIRO_XLIB_DRAWING_TRANSPARENT,
+                         (cairo_xlib_drawing_support_t)cairoFlags,
+                         output ? &result : NULL);
+    if (NS_FAILED(closure.mRV)) {
+        if (result.surface) {
+            NS_ASSERTION(output, "How did that happen?");
+            cairo_surface_destroy (result.surface);
+        }
+        return closure.mRV;
+    }
+
+    if (output) {
+        if (result.surface) {
+            output->mSurface = gfxASurface::Wrap(result.surface);
+            if (!output->mSurface) {
+                cairo_surface_destroy (result.surface);
+                return NS_ERROR_OUT_OF_MEMORY;
+            }
+        }
+
+        output->mUniformAlpha = result.uniform_alpha;
+        output->mUniformColor = result.uniform_color;
+        output->mColor = gfxRGBA(result.r, result.g, result.b, result.alpha);
+    }
+  
+    return NS_OK;
+}
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -82,16 +82,30 @@ PACKAGE_FILE = js.pkg
 # other modules which are always built shared. Failure to do so results in
 # the js code getting copied into xpinstall and jsd as well as mozilla-bin,
 # and then the static data cells used for locking no longer work.
 
 ifndef JS_STATIC_BUILD
 FORCE_SHARED_LIB = 1
 endif
 
+ifeq (86,$(findstring 86,$(OS_TEST)))
+DEFINES += -DAVMPLUS_IA32
+NANOJIT_ARCH = i386
+ENABLE_JIT = 1
+endif
+
+ifeq ($(OS_ARCH),Linux)
+DEFINES += -DAVMPLUS_LINUX -DLINUX
+endif
+
+ifeq ($(OS_ARCH),WINNT)
+DEFINES += -DAVMPLUS_WIN32
+endif
+
 CPPSRCS		= \
 		jsapi.cpp \
 		jsarena.cpp \
 		jsarray.cpp \
 		jsatom.cpp \
 		jsbool.cpp \
 		jscntxt.cpp \
 		jsdate.cpp \
@@ -169,22 +183,56 @@ EXPORTS		= \
 		jsprvtd.h \
 		jspubtd.h \
 		jsregexp.h \
 		jsscan.h \
 		jsscope.h \
 		jsscript.h \
 		jsstddef.h \
 		jsstr.h \
+		jstracer.h \
 		jstypes.h \
 		jsutil.h \
 		jsxdrapi.h \
 		jsxml.h \
 		$(NULL)
 
+ifdef ENABLE_JIT
+EXPORTS += \
+		nanojit/Assembler.h     \
+		nanojit/LIR.h		\
+		nanojit/avmplus.h	\
+		nanojit/vm_fops.h	\
+		nanojit/Fragmento.h	\
+		nanojit/Native.h	\
+		nanojit/Native$(NANOJIT_ARCH).h \
+		nanojit/RegAlloc.h	\
+		nanojit/nanojit.h	\
+		builtins.tbl \
+		$(NULL)
+
+CPPSRCS += \
+		jstracer.cpp \
+		nanojit/Assembler.cpp  \
+		nanojit/Fragmento.cpp  \
+		nanojit/LIR.cpp        \
+		nanojit/RegAlloc.cpp   \
+		nanojit/avmplus.cpp    \
+		nanojit/Native$(NANOJIT_ARCH).cpp \
+		jsbuiltins.cpp         \
+		$(NULL)
+
+ifdef DEBUG
+EXPORTS += nanojit/TraceTreeDrawer.h
+CPPSRCS += nanojit/TraceTreeDrawer.cpp
+endif
+
+DEFINES += -DFEATURE_NANOJIT -DJS_TRACER
+endif
+
 ifdef HAVE_DTRACE
 EXPORTS 	+= \
 		jsdtracef.h \
 		javascript-trace.h \
 		$(NULL)
 endif
 
 ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH)))
@@ -243,25 +291,32 @@ JSJAVA_CFLAGS	= \
 HOST_SIMPLE_PROGRAMS += host_jskwgen$(HOST_BIN_SUFFIX)
 GARBAGE += jsautokw.h host_jskwgen$(HOST_BIN_SUFFIX)
 
 HOST_SIMPLE_PROGRAMS += host_jsoplengen$(HOST_BIN_SUFFIX)
 GARBAGE += jsautooplen.h host_jsoplengen$(HOST_BIN_SUFFIX)
 
 USE_HOST_CXX = 1
 
+HOST_SIMPLE_PROGRAMS += host_jsoplengen$(HOST_BIN_SUFFIX)
+GARBAGE += jsautooplen.h host_jsoplengen$(HOST_BIN_SUFFIX)
+
 ifdef HAVE_DTRACE
 ifneq ($(OS_ARCH),Darwin)
 DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX)
 endif
 MOZILLA_DTRACE_SRC = $(srcdir)/javascript-trace.d
 endif
 
 include $(topsrcdir)/config/rules.mk
 
+# our build system doesn't handle subdir srcs very gracefully today
+export::
+	mkdir -p nanojit
+
 DEFINES		+= -DEXPORT_JS_API 
 
 INCLUDES	+= -I$(srcdir)
 
 # MSVC '-Gy' cc flag and '/OPT:REF' linker flag cause JS_GetArgument and
 # JS_GetLocalVariable to be folded to the same address by the linker, 
 # leading to a crash on startup. See bug 151066. So, in optimized builds,
 # add the /OPT:NOICF flag, which turns off 'identical COMDAT folding'.
--- a/js/src/Makefile.ref
+++ b/js/src/Makefile.ref
@@ -49,22 +49,42 @@
 
 
 DEPTH = .
 
 include config.mk
 
 #NS_USE_NATIVE = 1
 
+ifndef NANOJIT_ARCH
+$(warning NANOJIT_ARCH not defined in config/$(OS_CONFIG).mk, JIT disabled)
+else
+ifdef DISABLE_JIT
+$(warning disabling JIT per build specification)
+else
+ENABLE_JIT=1
+endif
+endif
+
+ifdef ENABLE_JIT
+DEFINES += -DJS_TRACER
+DEFINES += -DFEATURE_NANOJIT
+INCLUDES += -Inanojit
+endif
+
+#ifndef BUILD_OPT
+#DEFINES += -Ivprof
+#endif
+
 ifdef NARCISSUS
 DEFINES += -DNARCISSUS
 endif
 
 # Look in OBJDIR to find jsautocfg.h and jsautokw.h
-INCLUDES   += -I$(OBJDIR)
+INCLUDES   += -I. -I$(OBJDIR)
 
 ifdef JS_THREADSAFE
 DEFINES += -DJS_THREADSAFE
 INCLUDES += -I$(DIST)/include/nspr
 ifdef USE_MSVC
 OTHER_LIBS += $(DIST)/lib/libnspr$(NSPR_LIBSUFFIX).lib
 else
 OTHER_LIBS += -L$(DIST)/lib -lnspr$(NSPR_LIBSUFFIX)
@@ -74,22 +94,24 @@ endif
 ifdef JS_NO_THIN_LOCKS
 DEFINES += -DJS_USE_ONLY_NSPR_LOCKS
 endif
 
 ifdef JS_HAS_FILE_OBJECT
 DEFINES += -DJS_HAS_FILE_OBJECT
 endif
 
+
 #
 # XCFLAGS may be set in the environment or on the gmake command line
 #
 #CFLAGS += -DDEBUG -DDEBUG_brendan -DJS_ARENAMETER -DJS_HASHMETER -DJS_DUMP_PROPTREE_STATS -DJS_DUMP_SCOPE_METERS -DJS_SCOPE_DEPTH_METER -DJS_BASIC_STATS
 CFLAGS          += $(OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS)
 INTERP_CFLAGS   += $(INTERP_OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS) $(INTERP_XCFLAGS)
+BUILTINS_CFLAGS += $(BUILTINS_OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS) $(BUILTINS_XCFLAGS)
 
 LDFLAGS		= $(XLDFLAGS)
 LDFLAGS += $(OS_LDFLAGS)
 
 ifdef MOZ_SHARK
 DEFINES += -DMOZ_SHARK
 CFLAGS += -F/System/Library/PrivateFrameworks
 LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD
@@ -182,16 +204,38 @@ JS_HFILES =		\
 	jsscan.h	\
 	jsscope.h	\
 	jsscript.h	\
 	jsstr.h		\
 	jsxdrapi.h	\
 	jsxml.h		\
 	$(NULL)
 
+ifdef ENABLE_JIT
+JS_HFILES +=			\
+	jstracer.h		\
+	nanojit/Assembler.h     \
+	nanojit/LIR.h		\
+	nanojit/Native$(NANOJIT_ARCH).h	\
+	nanojit/avmplus.h	\
+	nanojit/vm_fops.h	\
+	nanojit/Fragmento.h	\
+	nanojit/Native.h	\
+	nanojit/RegAlloc.h	\
+	nanojit/nanojit.h	\
+	nanojit/TraceTreeDrawer.h \
+	$(NULL)
+endif
+
+ifndef BUILD_OPT
+#JS_HFILES +=            \
+#        vprof/vprof.h   \
+#        $(NULL)
+endif
+
 API_HFILES =		\
 	jsapi.h		\
 	jsdbgapi.h	\
 	$(NULL)
 
 OTHER_HFILES =		\
 	jsbit.h		\
 	jscompat.h	\
@@ -202,16 +246,20 @@ OTHER_HFILES =		\
 	resource.h	\
 	jsopcode.tbl	\
 	jsproto.tbl     \
 	js.msg		\
 	jsshell.msg	\
 	jskeyword.tbl	\
 	$(NULL)
 
+ifdef ENABLE_JIT
+OTHER_HFILES += builtins.tbl
+endif
+
 ifndef PREBUILT_CPUCFG
 OTHER_HFILES += $(OBJDIR)/jsautocfg.h
 endif
 OTHER_HFILES += $(OBJDIR)/jsautokw.h
 
 HFILES = $(JS_HFILES) $(API_HFILES) $(OTHER_HFILES)
 
 JS_CPPFILES =		\
@@ -248,16 +296,39 @@ JS_CPPFILES =		\
 	jsscript.cpp	\
 	jsstr.cpp	\
 	jsutil.cpp	\
 	jsxdrapi.cpp	\
 	jsxml.cpp	\
 	prmjtime.cpp	\
 	$(NULL)
 
+ifdef ENABLE_JIT
+JS_CPPFILES +=		       \
+	jsbuiltins.cpp         \
+	jstracer.cpp	       \
+	nanojit/Assembler.cpp  \
+	nanojit/Fragmento.cpp  \
+	nanojit/LIR.cpp        \
+	nanojit/Native$(NANOJIT_ARCH).cpp \
+	nanojit/RegAlloc.cpp   \
+	nanojit/avmplus.cpp    \
+	$(NULL)
+
+ifdef DEBUG
+JS_CPPFILES += nanojit/TraceTreeDrawer.cpp
+endif
+endif
+
+ifndef BUILD_OPT
+#JS_CPPFILES +=                 \
+#        vprof/vprof.cpp        \
+#        $(NULL)
+endif
+
 ifdef JS_LIVECONNECT
 DIRS      += liveconnect
 endif
 
 ifdef JS_HAS_FILE_OBJECT
 JS_CPPFILES += jsfile.cpp
 JS_HFILES += jsfile.h
 endif
@@ -350,23 +421,26 @@ ifndef PREBUILT_CPUCFG
 GARBAGE += $(OBJDIR)/jsautocfg.h $(OBJDIR)/jscpucfg \
 	   $(OBJDIR)/jscpucfg.o $(OBJDIR)/jscpucfg.d
 endif
 
 # Automatic make dependencies files
 DEPENDENCIES    = $(CPPFILES:%.cpp=$(OBJDIR)/%.d)
 
 #
-# Hardwire dependencies for jsinvoke.c
+# Hardwire dependencies for some files 
 #
 ifdef USE_MSVC
+OBJ=obj
+else
+OBJ=o
+endif
+
+$(OBJDIR)/jsinvoke.$(OBJ): jsinterp.h jsinterp.cpp
 $(OBJDIR)/jsinvoke.obj : jsinterp.h jsinterp.cpp
-else
-$(OBJDIR)/jsinvoke.o : jsinterp.h jsinterp.cpp
-endif
 
 -include $(DEPENDENCIES)
 
 TARNAME = jsref.tar
 TARFILES = files `cat files`
 
 SUFFIXES: .i
 %.i: %.cpp
new file mode 100755
--- /dev/null
+++ b/js/src/bench.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+T="0"
+for i in t/*.js; do 
+	T+="+"
+	T+=`Darwin_OPT.OBJ/js -j -e 'var d = Date.now(); load("'$i'"); print(Date.now() - d);'`
+	 
+done
+echo $T | bc
+
new file mode 100644
--- /dev/null
+++ b/js/src/builtins.tbl
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=0 ft=C:
+ *
+ * ***** 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.9 code, released
+ * June 22, 2008.
+ *
+ * The Initial Developer of the Original Code is
+ *   Andreas Gal <gal@uci.edu>
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+BUILTIN2(BoxDouble,             LO, F,  P,      jsval,     JSContext*, jsdouble,               1, 1)
+BUILTIN2(BoxInt32,              LO, LO, P,      jsval,     JSContext*, jsint,                  1, 1)
+BUILTIN1(UnboxDouble,           LO,     F,      jsdouble,  jsval,                              1, 1)
+BUILTIN1(UnboxInt32,            LO,     LO,     int32,     jsval,                              1, 1)
+BUILTIN2(dmod,                  F,  F,  F,      jsdouble,  jsdouble, jsdouble,                 1, 1)
+BUILTIN1(DoubleToInt32,         F,      LO,     int32,     jsdouble,                           1, 1)
+BUILTIN1(DoubleToUint32,        F,      LO,     int32,     jsdouble,                           1, 1)
+BUILTIN1(Math_sin,              F,      F,      jsdouble,  jsdouble,                           1, 1)
+BUILTIN1(Math_cos,              F,      F,      jsdouble,  jsdouble,                           1, 1)
+BUILTIN2(Math_pow,              F,  F,  F,      jsdouble,  jsdouble, jsdouble,                 1, 1)
+BUILTIN1(Math_sqrt,             F,      F,      jsdouble,  jsdouble,                           1, 1)
+BUILTIN1(Math_floor,            F,      F,      jsdouble,  jsdouble,                           1, 1)
+BUILTIN4(Array_dense_setelem,   LO, LO, LO, LO, LO, bool,  JSContext*, JSObject*, jsint, jsval, 1, 1)
+BUILTIN3(Array_p_join,          LO, LO, LO, P,  JSString*, JSContext*, JSObject*, JSString*, 1, 1)
+BUILTIN4(String_p_substring,    LO, LO, LO, LO, P,  JSString*, JSContext*, JSString*, jsint, jsint, 1, 1)
+BUILTIN3(String_p_substring_1,  LO, LO, LO, P,  JSString*, JSContext*, JSString*, jsint, 1, 1)
+BUILTIN3(ConcatStrings,         LO, LO, LO, P,  JSString*, JSContext*, JSString*, JSString*, 1, 1)
+BUILTIN3(String_getelem,        LO, LO, LO, P,  JSString*, JSContext*, JSString*, jsint, 1, 1)
+BUILTIN2(String_fromCharCode,   LO, LO, P,      JSString*, JSContext*, jsint, 1, 1)
+BUILTIN2(String_p_charCodeAt,   LO,     LO, LO, jsint,     JSString*, jsint, 1, 1)
+BUILTIN3(String_p_concat_1int,  LO, LO, LO, P,  JSString*, JSContest*, JSString*, jsint, 1, 1)
+BUILTIN4(String_p_match,        LO, LO, LO, LO, P, JSObject*, JSContext*, JSString*, jsbytecode*, JSObject*, 1, 1)
+BUILTIN4(String_p_replace_str,  LO, LO, LO, LO, P, JSString*, JSContext*, JSString*, JSObject*, JSString*, 1, 1)
+BUILTIN5(String_p_replace_str3, LO, LO, LO, LO, LO, P, JSString*, JSContext*, JSString*, JSString*, JSString*, JSString*, 1, 1)
+BUILTIN3(String_p_split,        LO,     LO, LO, P, JSObject*, JSContext*, JSString*, JSString*, 1, 1)
+BUILTIN1(Math_random,           LO,     F,      jsdouble,  JSRuntime*, 1, 1)
+BUILTIN2(EqualStrings,          LO,     LO, LO, bool,      JSString*, JSString*, 1, 1)
+BUILTIN2(CompareStrings,        LO,     LO, LO, bool,      JSString*, JSString*, 1, 1)
+BUILTIN2(StringToNumber,        LO,     LO, F,  jsdouble,  JSContext*, JSString*, 1, 1)
+BUILTIN2(StringToInt32,         LO,     LO, LO, jsint,     JSContext*, JSString*, 1, 1)
+BUILTIN2(ParseInt,              LO,     LO, F,  jsdouble,  JSContext*, JSString*, 1, 1)
+BUILTIN2(ParseFloat,            LO,     LO, F,  jsdouble,  JSContext*, JSString*, 1, 1)
+BUILTIN3(Any_getelem,           LO, LO, LO, P,  jsval,     JSContext*, JSObject*, JSString*, 1, 1)
+BUILTIN4(Any_setelem,           LO, LO, LO, LO, LO, bool,  JSContext*, JSObject*, JSString*, jsval, 1, 1)
+BUILTIN3(FastValueToIterator,   LO, LO, LO, P,  JSObject*, JSContext*, jsuint, jsval, 1, 1)
+BUILTIN2(FastCallIteratorNext,  LO,     LO, P,  JSObject*, JSContext*, JSObject*, 1, 1)
+BUILTIN2(CloseIterator,         LO,     LO, LO, bool,      JSContext*, jsval, 1, 1)
+BUILTIN2(CallTree,              LO, LO, P,      nanojit::GuardRecord*, avmplus::InterpState*, nanojit::Fragment*, 0, 0)
+BUILTIN2(FastNewObject,         LO,     LO, P,  JSObject*, JSContext*, JSObject*, 1, 1)
+BUILTIN3(AddProperty,           LO, LO, LO, LO, bool,      JSContext*, JSObject*, JSScopeProperty*, 1, 1)
+BUILTIN3(CallGetter,            LO, LO, LO, P,  jsval,     JSContext*, JSObject*, JSScopeProperty*, 1, 1)
+BUILTIN2(TypeOfObject,          LO,     LO, P,  JSString*, JSContext*, JSObject*, 1, 1)
+BUILTIN2(TypeOfBoolean,         LO,     LO, P,  JSString*, JSContext*, jsint, 1, 1)
+BUILTIN2(NumberToString,        LO,     F,  P,  JSString*, JSContext*, jsdouble, 1, 1)
+BUILTIN3(Object_p_hasOwnProperty,
+                                LO, LO, LO, LO, jsint,     JSContext*, JSObject*, JSString*, 1, 1)
+BUILTIN3(Object_p_propertyIsEnumerable,
+                                LO, LO, LO, LO, jsint,     JSContext*, JSObject*, JSString*, 1, 1)
+BUILTIN2(BooleanToNumber,       LO, LO, F,      jsdouble,  JSContext*, jsint, 1, 1)
+BUILTIN2(ObjectToString,        LO,     LO, P,  JSString*, JSContext*, JSObject*, 1, 1)
+BUILTIN3(Array_1int,            LO, LO, LO, P,  JSObject*, JSContext*, JSObject*, jsint, 1, 1)
new file mode 100644
--- /dev/null
+++ b/js/src/call.js
@@ -0,0 +1,13 @@
+function g(x) {
+    if ((x & 1) == 1) return 1;
+    return 2;
+}
+
+function f(n) {
+    var q = 0;
+    for (var i = 0; i < n; i++)
+        q += g(i);
+    return q;
+}
+
+print(f(1000));
--- a/js/src/config.mk
+++ b/js/src/config.mk
@@ -119,30 +119,34 @@ else
 INSTALL	= $(DIST)/bin/nsinstall
 CP = cp
 endif
 
 ifdef BUILD_OPT
 ifdef USE_MSVC
 OPTIMIZER  = -O2 -GL
 INTERP_OPTIMIZER = -O2 -GL
+BUILTINS_OPTIMIZER = -O2 -GL
 LDFLAGS    += -LTCG
 else
-OPTIMIZER  = -Os -fno-exceptions -fno-rtti
+OPTIMIZER  = -Os -fno-exceptions -fno-rtti -fstrict-aliasing -Wall -Wstrict-aliasing=2
+BUILTINS_OPTIMIZER = -O9 -fstrict-aliasing
 INTERP_OPTIMIZER = -O3 -fstrict-aliasing -fno-exceptions -fno-rtti
 endif
 DEFINES    += -UDEBUG -DNDEBUG -UDEBUG_$(USER)
 OBJDIR_TAG = _OPT
 else
 ifdef USE_MSVC
 OPTIMIZER  = -Zi
 INTERP_OPTIMIZER = -Zi
+BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER)
 else
-OPTIMIZER  = -g3 -fno-exceptions -fno-rtti
-INTERP_OPTIMIZER = -g3 -fno-exceptions -fno-rtti
+OPTIMIZER  = -g3 -fno-exceptions -fno-rtti -Wall -fstrict-aliasing -Wstrict-aliasing=2
+INTERP_OPTIMIZER = -g3 -fno-exceptions -fno-rtti -Wall -fstrict-aliasing
+BUILTINS_OPTIMIZER = $(INTERP_OPTIMIZER)
 endif
 DEFINES    += -DDEBUG -DDEBUG_$(USER)
 OBJDIR_TAG = _DBG
 endif
 
 SO_SUFFIX = so
 
 NS_USE_NATIVE = 1
--- a/js/src/config/Darwin.mk
+++ b/js/src/config/Darwin.mk
@@ -38,33 +38,35 @@
 #
 # ***** END LICENSE BLOCK *****
 
 #
 # Config for Mac OS X as of PR3
 # Just ripped from Linux config
 #
 
-CC = cc
+CC = gcc
 CCC = g++
 CFLAGS +=  -Wall -Wno-format -MMD
 OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DDARWIN
 
 RANLIB = ranlib
 MKSHLIB = $(CCC) -dynamiclib $(XMKSHLIBOPTS) -framework System
 
 SO_SUFFIX = dylib
 
 #.c.o:
 #      $(CC) -c -MD $*.d $(CFLAGS) $<
 
 CPU_ARCH = $(shell uname -m)
 ifeq (86,$(findstring 86,$(CPU_ARCH)))
 CPU_ARCH = x86
 OS_CFLAGS+= -DX86_LINUX
+OS_CFLAGS += -DAVMPLUS_IA32
+NANOJIT_ARCH = i386
 endif
 GFX_ARCH = x
 
 OS_LIBS = -lc -framework System
 
 ASFLAGS += -x assembler-with-cpp
 
 ifeq ($(CPU_ARCH),alpha)
--- a/js/src/config/Linux_All.mk
+++ b/js/src/config/Linux_All.mk
@@ -39,42 +39,53 @@
 
 #
 # Config for all versions of Linux
 #
 
 CC = gcc
 CCC = g++
 CFLAGS +=  -Wall -Wno-format -MMD
-OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DHAVE_LOCALTIME_R
+OS_CFLAGS = -DXP_UNIX -DSVR4 -DSYSV -D_BSD_SOURCE -DPOSIX_SOURCE -DHAVE_LOCALTIME_R -DLINUX
 
 RANLIB = echo
 MKSHLIB = $(LD) -shared $(XMKSHLIBOPTS)
 
 #.c.o:
 #      $(CC) -c -MD $*.d $(CFLAGS) $<
 
 CPU_ARCH = $(shell uname -m)
 # don't filter in x86-64 architecture
 ifneq (x86_64,$(CPU_ARCH))
 ifeq (86,$(findstring 86,$(CPU_ARCH)))
 CPU_ARCH = x86
-OS_CFLAGS+= -DX86_LINUX
+OS_CFLAGS += -DX86_LINUX -DAVMPLUS_IA32 -DAVMPLUS_LINUX
+NANOJIT_ARCH = i386
 
 ifeq (gcc, $(CC))
 # if using gcc on x86, check version for opt bug 
 # (http://bugzilla.mozilla.org/show_bug.cgi?id=24892)
 GCC_VERSION := $(shell gcc -v 2>&1 | grep version | awk '{ print $$3 }')
 GCC_LIST:=$(sort 2.91.66 $(GCC_VERSION) )
 
 ifeq (2.91.66, $(firstword $(GCC_LIST)))
 CFLAGS+= -DGCC_OPT_BUG
+endif # gcc 2.91.66
+endif # gcc
+endif # 86
+endif # !x86_64
+
+ifeq ($(CPU_ARCH),x86_64)
+OS_CFLAGS += -DAVMPLUS_AMD64 -DAVMPLUS_64BIT -DAVMPLUS_LINUX
+NANOJIT_ARCH = i386
 endif
-endif
-endif
+
+ifeq ($(CPU_ARCH),arm)
+OS_CFLAGS += -DAVMPLUS_ARM -DAVMPLUS_LINUX
+NANOJIT_ARCH = Thumb
 endif
 
 GFX_ARCH = x
 
 OS_LIBS = -lm -lc
 
 ASFLAGS += -x assembler-with-cpp
 
--- a/js/src/config/WINNT5.2.mk
+++ b/js/src/config/WINNT5.2.mk
@@ -85,17 +85,17 @@ OPTIMIZER = $(WIN_OPT_CFLAGS)
 else
 ifdef BUILD_IDG
 OPTIMIZER = $(WIN_IDG_CFLAGS)
 else
 OPTIMIZER = $(WIN_DEBUG_CFLAGS)
 endif
 endif
 
-OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS)
+OS_CFLAGS = -D_X86_=1 -DXP_WIN -DXP_WIN32 -DWIN32 -D_WINDOWS -D_WIN32 -DWINVER=0x500 -D_WIN32_WINNT=0x500 $(WIN_CFLAGS) -DAVMPLUS_WIN32 -DAVMPLUS_IA32
 JSDLL_CFLAGS = -DEXPORT_JS_API
 OS_LIBS = -lm -lc
 
 PREBUILT_CPUCFG = 1
 USE_MSVC = 1
 
 LIB_LINK_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
  advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib oldnames.lib \
new file mode 100644
--- /dev/null
+++ b/js/src/if.js
@@ -0,0 +1,13 @@
+function f() {
+	var q = 0;
+	for (var i = 0; i < 100; i++) {
+		if ((i & 1) == 0)
+			q++;
+		else
+			q--;
+	}	
+	print(q);
+}
+
+f();
+
--- a/js/src/js.cpp
+++ b/js/src/js.cpp
@@ -1,10 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
+ * vim: set ts=8 sw=4 et tw=99:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -229,16 +229,17 @@ Process(JSContext *cx, JSObject *obj, ch
     JSScript *script;
     jsval result;
     JSString *str;
     char buffer[4096];
     char *bufp;
     int lineno;
     int startline;
     FILE *file;
+    uint32 oldopts;
 
     if (forceTTY || !filename || strcmp(filename, "-") == 0) {
         file = stdin;
     } else {
         file = fopen(filename, "r");
         if (!file) {
             JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
                                  JSSMSG_CANT_OPEN, filename, strerror(errno));
@@ -261,20 +262,24 @@ Process(JSContext *cx, JSObject *obj, ch
         int ch = fgetc(file);
         if (ch == '#') {
             while((ch = fgetc(file)) != EOF) {
                 if (ch == '\n' || ch == '\r')
                     break;
             }
         }
         ungetc(ch, file);
+
+        oldopts = JS_GetOptions(cx);
+        JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
         script = JS_CompileFileHandle(cx, obj, filename, file);
+        JS_SetOptions(cx, oldopts);
         if (script) {
             if (!compileOnly)
-                (void)JS_ExecuteScript(cx, obj, script, &result);
+                (void)JS_ExecuteScript(cx, obj, script, NULL);
             JS_DestroyScript(cx, script);
         }
 
         if (file != stdin)
             fclose(file);
         return;
     }
 
@@ -342,16 +347,17 @@ static struct {
     uint32      flag;
 } js_options[] = {
     {"strict",          JSOPTION_STRICT},
     {"werror",          JSOPTION_WERROR},
     {"atline",          JSOPTION_ATLINE},
     {"xml",             JSOPTION_XML},
     {"relimit",         JSOPTION_RELIMIT},
     {"anonfunfix",      JSOPTION_ANONFUNFIX},
+    {"jit",             JSOPTION_JIT},
     {NULL,              0}
 };
 
 extern JSClass global_class;
 
 static int
 ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
 {
@@ -449,16 +455,20 @@ ProcessArgs(JSContext *cx, JSObject *obj
         case 'E':
             JS_ToggleOptions(cx, JSOPTION_RELIMIT);
             break;
 
         case 'x':
             JS_ToggleOptions(cx, JSOPTION_XML);
             break;
 
+        case 'j':
+            JS_ToggleOptions(cx, JSOPTION_JIT);
+            break;
+            
         case 'o':
             if (++i == argc)
                 return usage();
 
             for (j = 0; js_options[j].name; ++j) {
                 if (strcmp(js_options[j].name, argv[i]) == 0) {
                     JS_ToggleOptions(cx, js_options[j].flag);
                     break;
@@ -627,38 +637,37 @@ Options(JSContext *cx, JSObject *obj, ui
 static JSBool
 Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     uintN i;
     JSString *str;
     const char *filename;
     JSScript *script;
     JSBool ok;
-    jsval result;
     uint32 oldopts;
 
     for (i = 0; i < argc; i++) {
         str = JS_ValueToString(cx, argv[i]);
         if (!str)
             return JS_FALSE;
         argv[i] = STRING_TO_JSVAL(str);
         filename = JS_GetStringBytes(str);
         errno = 0;
         oldopts = JS_GetOptions(cx);
-        JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO);
+        JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
         script = JS_CompileFile(cx, obj, filename);
+        JS_SetOptions(cx, oldopts);
         if (!script) {
             ok = JS_FALSE;
         } else {
             ok = !compileOnly
-                 ? JS_ExecuteScript(cx, obj, script, &result)
+                 ? JS_ExecuteScript(cx, obj, script, NULL)
                  : JS_TRUE;
             JS_DestroyScript(cx, script);
         }
-        JS_SetOptions(cx, oldopts);
         if (!ok)
             return JS_FALSE;
     }
 
     return JS_TRUE;
 }
 
 /*
@@ -739,22 +748,24 @@ ReadLine(JSContext *cx, uintN argc, jsva
         return JS_FALSE;
     }
 
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 static JSBool
-Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+Print(JSContext *cx, uintN argc, jsval *vp)
 {
+    jsval *argv;
     uintN i;
     JSString *str;
     char *bytes;
 
+    argv = JS_ARGV(cx, vp);
     for (i = 0; i < argc; i++) {
         str = JS_ValueToString(cx, argv[i]);
         if (!str)
             return JS_FALSE;
         bytes = JS_EncodeString(cx, str);
         if (!bytes)
             return JS_FALSE;
         fprintf(gOutFile, "%s%s", i ? " " : "", bytes);
@@ -855,17 +866,17 @@ GCParameter(JSContext *cx, uintN argc, j
 #ifdef JS_GC_ZEAL
 static JSBool
 GCZeal(JSContext *cx, uintN argc, jsval *vp)
 {
     uint32 zeal;
 
     if (!JS_ValueToECMAUint32(cx, argc == 0 ? JSVAL_VOID : vp[2], &zeal))
         return JS_FALSE;
-    JS_SetGCZeal(cx, zeal);
+    JS_SetGCZeal(cx, (uint8)zeal);
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 #endif /* JS_GC_ZEAL */
 
 typedef struct JSCountHeapNode JSCountHeapNode;
 
 struct JSCountHeapNode {
@@ -1407,16 +1418,52 @@ Disassemble(JSContext *cx, JSObject *obj
             return JS_FALSE;
         SrcNotes(cx, script);
         TryNotes(cx, script);
     }
     return JS_TRUE;
 }
 
 static JSBool
+DisassFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+    JSString *str;
+    const char *filename;
+    JSScript *script;
+    JSBool ok;
+    uint32 oldopts;
+    
+    if (!argc)
+        return JS_TRUE;
+
+    str = JS_ValueToString(cx, argv[0]);
+    if (!str)
+        return JS_FALSE;
+    argv[0] = STRING_TO_JSVAL(str);
+
+    filename = JS_GetStringBytes(str);
+    oldopts = JS_GetOptions(cx);
+    JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
+    script = JS_CompileFile(cx, obj, filename);
+    JS_SetOptions(cx, oldopts);
+    if (!script)
+        return JS_FALSE;
+
+    obj = JS_NewScriptObject(cx, script);
+    if (!obj)
+        return JS_FALSE;
+    
+    *rval = OBJECT_TO_JSVAL(obj); /* I like to root it, root it. */
+    ok = Disassemble(cx, obj, 1, rval, rval); /* gross, but works! */
+    *rval = JSVAL_VOID;
+
+    return ok;
+}
+
+static JSBool
 DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
               jsval *rval)
 {
 #define LINE_BUF_LEN 512
     uintN i, len, line1, line2, bupline;
     JSScript *script;
     FILE *file;
     char linebuf[LINE_BUF_LEN];
@@ -2751,17 +2798,17 @@ fail:
 #endif
 
 /* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
 static JSFunctionSpec shell_functions[] = {
     JS_FS("version",        Version,        0,0,0),
     JS_FS("options",        Options,        0,0,0),
     JS_FS("load",           Load,           1,0,0),
     JS_FN("readline",       ReadLine,       0,0),
-    JS_FS("print",          Print,          0,0,0),
+    JS_FN("print",          Print,          0,0),
     JS_FS("help",           Help,           0,0,0),
     JS_FS("quit",           Quit,           0,0,0),
     JS_FN("gc",             GC,             0,0),
     JS_FN("gcparam",        GCParameter,    2,0),
     JS_FN("countHeap",      CountHeap,      0,0),
 #ifdef JS_GC_ZEAL
     JS_FN("gczeal",         GCZeal,         1,0),
 #endif
@@ -2770,16 +2817,17 @@ static JSFunctionSpec shell_functions[] 
     JS_FS("line2pc",        LineToPC,       0,0,0),
     JS_FS("pc2line",        PCToLine,       0,0,0),
     JS_FN("stackQuota",     StackQuota,     0,0),
     JS_FS("stringsAreUTF8", StringsAreUTF8, 0,0,0),
     JS_FS("testUTF8",       TestUTF8,       1,0,0),
     JS_FS("throwError",     ThrowError,     0,0,0),
 #ifdef DEBUG
     JS_FS("dis",            Disassemble,    1,0,0),
+    JS_FS("disfile",        DisassFile,     1,0,0),
     JS_FS("dissrc",         DisassWithSrc,  1,0,0),
     JS_FN("dumpHeap",       DumpHeap,       0,0),
     JS_FS("notes",          Notes,          1,0,0),
     JS_FS("tracing",        Tracing,        0,0,0),
     JS_FS("stats",          DumpStats,      1,0,0),
 #endif
 #ifdef TEST_CVTARGS
     JS_FS("cvtargs",        ConvertArgs,    0,0,12),
@@ -2849,16 +2897,17 @@ static const char *const shell_help_mess
 "line2pc([fun,] line)     Map line number to PC",
 "pc2line(fun[, pc])       Map PC to line number",
 "stackQuota([number])     Query/set script stack quota",
 "stringsAreUTF8()         Check if strings are UTF-8 encoded",
 "testUTF8(mode)           Perform UTF-8 tests (modes are 1 to 4)",
 "throwError()             Throw an error from JS_ReportError",
 #ifdef DEBUG
 "dis([fun])               Disassemble functions into bytecodes",
+"disfile('foo.js')        Disassemble script file into bytecodes",
 "dissrc([fun])            Disassemble functions with source lines",
 "dumpHeap([fileName[, start[, toFind[, maxDepth[, toIgnore]]]]])\n"
 "  Interface to JS_DumpHeap with output sent to file",
 "notes([fun])             Show source notes for functions",
 "tracing([toggle])        Turn tracing on or off",
 "stats([string ...])      Dump 'arena', 'atom', 'global' stats",
 #endif
 #ifdef TEST_CVTARGS
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -99,17 +99,17 @@ MSG_DEF(JSMSG_STACK_UNDERFLOW,         1
 MSG_DEF(JSMSG_NEED_DIET,               17, 1, JSEXN_INTERNALERR, "{0} too large")
 MSG_DEF(JSMSG_TOO_MANY_LOCAL_ROOTS,    18, 0, JSEXN_ERR, "out of local root space")
 MSG_DEF(JSMSG_READ_ONLY,               19, 1, JSEXN_ERR, "{0} is read-only")
 MSG_DEF(JSMSG_BAD_FORMAL,              20, 0, JSEXN_SYNTAXERR, "malformed formal parameter")
 MSG_DEF(JSMSG_BAD_ITERATOR,            21, 3, JSEXN_TYPEERR, "{0} has invalid {1} value {2}")
 MSG_DEF(JSMSG_NOT_FUNCTION,            22, 1, JSEXN_TYPEERR, "{0} is not a function")
 MSG_DEF(JSMSG_NOT_CONSTRUCTOR,         23, 1, JSEXN_TYPEERR, "{0} is not a constructor")
 MSG_DEF(JSMSG_SCRIPT_STACK_QUOTA,      24, 0, JSEXN_INTERNALERR, "script stack space quota is exhausted")
-MSG_DEF(JSMSG_UNUSED25,                25, 0, JSEXN_NONE, "unused25")
+MSG_DEF(JSMSG_TOO_DEEP,                25, 1, JSEXN_INTERNALERR, "{0} nested too deeply")
 MSG_DEF(JSMSG_OVER_RECURSED,           26, 0, JSEXN_INTERNALERR, "too much recursion")
 MSG_DEF(JSMSG_IN_NOT_OBJECT,           27, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
 MSG_DEF(JSMSG_BAD_NEW_RESULT,          28, 1, JSEXN_TYPEERR, "invalid new expression result {0}")
 MSG_DEF(JSMSG_BAD_SHARP_DEF,           29, 1, JSEXN_ERR, "invalid sharp variable definition #{0}=")
 MSG_DEF(JSMSG_BAD_SHARP_USE,           30, 1, JSEXN_ERR, "invalid sharp variable use #{0}#")
 MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS,      31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
 MSG_DEF(JSMSG_BAD_BYTECODE,            32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
 MSG_DEF(JSMSG_BAD_RADIX,               33, 1, JSEXN_ERR, "illegal radix {0}")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -74,16 +74,20 @@
 #include "jsparse.h"
 #include "jsregexp.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "prmjtime.h"
 
+#if !defined JS_THREADSAFE && defined JS_TRACER
+#include "jstracer.h"
+#endif
+
 #if JS_HAS_FILE_OBJECT
 #include "jsfile.h"
 #endif
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
@@ -775,16 +779,21 @@ JS_NewRuntime(uint32 maxbytes)
         goto bad;
     rt->titleSharingTodo = NO_TITLE_SHARING_TODO;
     rt->debuggerLock = JS_NEW_LOCK();
     if (!rt->debuggerLock)
         goto bad;
 #endif
     if (!js_InitPropertyTree(rt))
         goto bad;
+
+#if !defined JS_THREADSAFE && defined JS_TRACER
+    js_InitJIT(&rt->traceMonitor);
+#endif
+
     return rt;
 
 bad:
     JS_DestroyRuntime(rt);
     return NULL;
 }
 
 JS_PUBLIC_API(void)
@@ -802,16 +811,20 @@ JS_DestroyRuntime(JSRuntime *rt)
             cxcount++;
         }
         fprintf(stderr,
 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
                 cxcount, (cxcount == 1) ? "" : "s");
     }
 #endif
 
+#if !defined JS_THREADSAFE && defined JS_TRACER
+    js_FinishJIT(&rt->traceMonitor);
+#endif
+
     js_FreeRuntimeScriptState(rt);
     js_FinishAtomState(rt);
 
     /*
      * Free unit string storage only after all strings have been finalized, so
      * that js_FinalizeString can detect unit strings and avoid calling free
      * on their chars storage.
      */
@@ -2781,29 +2794,30 @@ JS_InitClass(JSContext *cx, JSObject *ob
          */
         if ((clasp->flags & JSCLASS_IS_ANONYMOUS) &&
             (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) &&
             key != JSProto_Null) {
             named = JS_FALSE;
         } else {
             named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
                                         OBJECT_TO_JSVAL(proto),
-                                        NULL, NULL,
+                                        JS_PropertyStub, JS_PropertyStub,
                                         (clasp->flags & JSCLASS_IS_ANONYMOUS)
                                         ? JSPROP_READONLY | JSPROP_PERMANENT
                                         : 0,
                                         NULL);
             if (!named)
                 goto bad;
         }
 
         ctor = proto;
     } else {
         /* Define the constructor function in obj's scope. */
-        fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
+        fun = js_DefineFunction(cx, obj, atom, constructor, nargs,
+                                JSFUN_STUB_GSOPS);
         named = (fun != NULL);
         if (!fun)
             goto bad;
 
         /*
          * Remember the class this function is a constructor for so that
          * we know to create an object of this class when we call the
          * constructor.
@@ -4581,27 +4595,31 @@ JS_CompileUCScript(JSContext *cx, JSObje
 #define LAST_FRAME_CHECKS(cx,result)                                          \
     JS_BEGIN_MACRO                                                            \
         if (!(cx)->fp) {                                                      \
             (cx)->weakRoots.lastInternalResult = JSVAL_NULL;                  \
             LAST_FRAME_EXCEPTION_CHECK(cx, result);                           \
         }                                                                     \
     JS_END_MACRO
 
+#define JS_OPTIONS_TO_TCFLAGS(cx)                                             \
+    ((((cx)->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |       \
+     (((cx)->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0))
+
 JS_PUBLIC_API(JSScript *)
 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
                                 JSPrincipals *principals,
                                 const jschar *chars, size_t length,
                                 const char *filename, uintN lineno)
 {
     uint32 tcflags;
     JSScript *script;
 
     CHECK_REQUEST(cx);
-    tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
+    tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
     script = js_CompileScript(cx, obj, principals, tcflags,
                               chars, length, NULL, filename, lineno);
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
@@ -4657,17 +4675,17 @@ JS_CompileFile(JSContext *cx, JSObject *
         fp = fopen(filename, "r");
         if (!fp) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
                                  filename, "No such file or directory");
             return NULL;
         }
     }
 
-    tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
+    tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
     script = js_CompileScript(cx, obj, NULL, tcflags,
                               NULL, 0, fp, filename, 1);
     if (fp != stdin)
         fclose(fp);
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
@@ -4682,50 +4700,52 @@ JS_PUBLIC_API(JSScript *)
 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
                                   const char *filename, FILE *file,
                                   JSPrincipals *principals)
 {
     uint32 tcflags;
     JSScript *script;
 
     CHECK_REQUEST(cx);
-    tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
+    tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
     script = js_CompileScript(cx, obj, principals, tcflags,
                               NULL, 0, file, filename, 1);
     LAST_FRAME_CHECKS(cx, script);
     return script;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewScriptObject(JSContext *cx, JSScript *script)
 {
     JSTempValueRooter tvr;
     JSObject *obj;
 
     CHECK_REQUEST(cx);
     if (!script)
         return js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
 
+    JS_ASSERT(!script->u.object);
+
     JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
     obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
     if (obj) {
         JS_SetPrivate(cx, obj, script);
-        script->object = obj;
+        script->u.object = obj;
 #ifdef CHECK_SCRIPT_OWNER
         script->owner = NULL;
 #endif
     }
     JS_POP_TEMP_ROOT(cx, &tvr);
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetScriptObject(JSScript *script)
 {
-    return script->object;
+    return script->u.object;
 }
 
 JS_PUBLIC_API(void)
 JS_DestroyScript(JSContext *cx, JSScript *script)
 {
     CHECK_REQUEST(cx);
     js_DestroyScript(cx, script);
 }
@@ -5019,17 +5039,20 @@ JS_EvaluateUCScriptForPrincipals(JSConte
                                  const jschar *chars, uintN length,
                                  const char *filename, uintN lineno,
                                  jsval *rval)
 {
     JSScript *script;
     JSBool ok;
 
     CHECK_REQUEST(cx);
-    script = js_CompileScript(cx, obj, principals, TCF_COMPILE_N_GO,
+    script = js_CompileScript(cx, obj, principals,
+                              !rval
+                              ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
+                              : TCF_COMPILE_N_GO,
                               chars, length, NULL, filename, lineno);
     if (!script)
         return JS_FALSE;
     ok = js_Execute(cx, obj, script, NULL, 0, rval);
     LAST_FRAME_CHECKS(cx, ok);
     JS_DestroyScript(cx, script);
     return ok;
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -580,16 +580,23 @@ JS_StringToVersion(const char *string);
                                                    regular expression which
                                                    backtracks more than n^3
                                                    times, where n is length
                                                    of the input string */
 #define JSOPTION_ANONFUNFIX     JS_BIT(10)      /* Disallow function () {} in
                                                    statement context per
                                                    ECMA-262 Edition 3. */
 
+#define JSOPTION_JIT            JS_BIT(11)      /* Enable JIT compilation. */
+
+#define JSOPTION_NO_SCRIPT_RVAL JS_BIT(12)      /* A promise to the compiler
+                                                   that a null rval out-param
+                                                   will be passed to each call
+                                                   to JS_ExecuteScript. */
+
 extern JS_PUBLIC_API(uint32)
 JS_GetOptions(JSContext *cx);
 
 extern JS_PUBLIC_API(uint32)
 JS_SetOptions(JSContext *cx, uint32 options);
 
 extern JS_PUBLIC_API(uint32)
 JS_ToggleOptions(JSContext *cx, uint32 options);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1178,30 +1178,24 @@ js_MakeArraySlow(JSContext *cx, JSObject
 
     return JS_TRUE;
 
 out_bad:
     js_DestroyObjectMap(cx, map);
     return JS_FALSE;
 }
 
-enum ArrayToStringOp {
-    TO_STRING,
-    TO_LOCALE_STRING,
-    TO_SOURCE
-};
-
 /*
  * When op is TO_STRING or TO_LOCALE_STRING sep indicates a separator to use
  * or "," when sep is NULL.
  * When op is TO_SOURCE sep must be NULL.
  */
-static JSBool
-array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
-               JSString *sep, jsval *rval)
+JSBool
+js_array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
+                  JSString *sep, jsval *rval)
 {
     JSBool ok, hole;
     jsuint length, index;
     jschar *chars, *ochars;
     size_t nchars, growth, seplen, tmplen, extratail;
     const jschar *sepstr;
     JSString *str;
     JSHashEntry *he;
@@ -1409,31 +1403,31 @@ array_toSource(JSContext *cx, uintN argc
 {
     JSObject *obj;
 
     obj = JS_THIS_OBJECT(cx, vp);
     if (OBJ_GET_CLASS(cx, obj) != &js_SlowArrayClass &&
         !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) {
         return JS_FALSE;
     }
-    return array_join_sub(cx, obj, TO_SOURCE, NULL, vp);
+    return js_array_join_sub(cx, obj, TO_SOURCE, NULL, vp);
 }
 #endif
 
 static JSBool
 array_toString(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
 
     obj = JS_THIS_OBJECT(cx, vp);
     if (OBJ_GET_CLASS(cx, obj) != &js_SlowArrayClass &&
         !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) {
         return JS_FALSE;
     }
-    return array_join_sub(cx, obj, TO_STRING, NULL, vp);
+    return js_array_join_sub(cx, obj, TO_STRING, NULL, vp);
 }
 
 static JSBool
 array_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
 
     obj = JS_THIS_OBJECT(cx, vp);
@@ -1441,17 +1435,17 @@ array_toLocaleString(JSContext *cx, uint
         !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) {
         return JS_FALSE;
     }
 
     /*
      *  Passing comma here as the separator. Need a way to get a
      *  locale-specific version.
      */
-    return array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp);
+    return js_array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp);
 }
 
 static JSBool
 InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint end,
                   jsval *vector)
 {
     if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
         if (!EnsureLength(cx, obj, end))
@@ -1500,32 +1494,32 @@ InitArrayObject(JSContext *cx, JSObject 
         obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
     }
     return JS_TRUE;
 }
 
 /*
  * Perl-inspired join, reverse, and sort.
  */
-static JSBool
-array_join(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_array_join(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str;
     JSObject *obj;
 
     if (argc == 0 || JSVAL_IS_VOID(vp[2])) {
         str = NULL;
     } else {
         str = js_ValueToString(cx, vp[2]);
         if (!str)
             return JS_FALSE;
         vp[2] = STRING_TO_JSVAL(str);
     }
     obj = JS_THIS_OBJECT(cx, vp);
-    return obj && array_join_sub(cx, obj, TO_STRING, str, vp);
+    return obj && js_array_join_sub(cx, obj, TO_STRING, str, vp);
 }
 
 static JSBool
 array_reverse(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
     JSTempValueRooter tvr;
     jsuint len, half, i;
@@ -2875,17 +2869,17 @@ static JSPropertySpec array_props[] = {
 static JSFunctionSpec array_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,      array_toSource,     0,0),
 #endif
     JS_FN(js_toString_str,      array_toString,     0,0),
     JS_FN(js_toLocaleString_str,array_toLocaleString,0,0),
 
     /* Perl-ish methods. */
-    JS_FN("join",               array_join,         1,JSFUN_GENERIC_NATIVE),
+    JS_FN("join",               js_array_join,      1,JSFUN_GENERIC_NATIVE),
     JS_FN("reverse",            array_reverse,      0,JSFUN_GENERIC_NATIVE),
     JS_FN("sort",               array_sort,         1,JSFUN_GENERIC_NATIVE),
     JS_FN("push",               array_push,         1,JSFUN_GENERIC_NATIVE),
     JS_FN("pop",                array_pop,          0,JSFUN_GENERIC_NATIVE),
     JS_FN("shift",              array_shift,        0,JSFUN_GENERIC_NATIVE),
     JS_FN("unshift",            array_unshift,      1,JSFUN_GENERIC_NATIVE),
     JS_FN("splice",             array_splice,       2,JSFUN_GENERIC_NATIVE),
 
@@ -2903,18 +2897,18 @@ static JSFunctionSpec array_methods[] = 
     JS_FN("filter",             array_filter,       1,JSFUN_GENERIC_NATIVE),
     JS_FN("some",               array_some,         1,JSFUN_GENERIC_NATIVE),
     JS_FN("every",              array_every,        1,JSFUN_GENERIC_NATIVE),
 #endif
 
     JS_FS_END
 };
 
-static JSBool
-Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+JSBool
+js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     jsuint length;
     jsval *vector;
 
     /* If called without new, replace obj with a new Array object. */
     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
         obj = js_NewObject(cx, &js_ArrayClass, NULL, NULL, 0);
         if (!obj)
@@ -2946,17 +2940,17 @@ js_InitArrayClass(JSContext *cx, JSObjec
     JSObject *proto;
 
     /* Initialize the ops structure used by slow arrays */
     memcpy(&js_SlowArrayObjectOps, &js_ObjectOps, sizeof(JSObjectOps));
     js_SlowArrayObjectOps.trace = slowarray_trace;
     js_SlowArrayObjectOps.enumerate = slowarray_enumerate;
     js_SlowArrayObjectOps.call = NULL;
 
-    proto = JS_InitClass(cx, obj, NULL, &js_ArrayClass, Array, 1,
+    proto = JS_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1,
                          array_props, array_methods, NULL, NULL);
 
     /* Initialize the Array prototype object so it gets a length property. */
     if (!proto || !InitArrayObject(cx, proto, 0, NULL))
         return NULL;
     return proto;
 }
 
@@ -3018,8 +3012,198 @@ js_ArrayInfo(JSContext *cx, JSObject *ob
                     ARRAY_DENSE_LENGTH(array));
         }
         fputs(")\n", stderr);
         JS_free(cx, bytes);
     }
     return JS_TRUE;
 }
 #endif
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSUint8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                        JSUint8 *dest)
+{
+    uint32 length;
+
+    if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj))
+        return JS_FALSE;
+
+    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    if (length < offset + count)
+        return JS_FALSE;
+
+    jsval v;
+    jsint vi;
+
+    JSUint8 *dp = dest;
+    for (uintN i = offset; i < offset+count; i++) {
+        v = obj->dslots[i];
+        if (!JSVAL_IS_INT(v) || (vi = JSVAL_TO_INT(v)) < 0)
+            return JS_FALSE;
+
+        *dp++ = (JSUint8) vi;
+    }
+
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSUint16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                         JSUint16 *dest)
+{
+    uint32 length;
+
+    if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj))
+        return JS_FALSE;
+
+    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    if (length < offset + count)
+        return JS_FALSE;
+
+    jsval v;
+    jsint vi;
+
+    JSUint16 *dp = dest;
+    for (uintN i = offset; i < offset+count; i++) {
+        v = obj->dslots[i];
+        if (!JSVAL_IS_INT(v) || (vi = JSVAL_TO_INT(v)) < 0)
+            return JS_FALSE;
+
+        *dp++ = (JSUint16) vi;
+    }
+
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSUint32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                         JSUint32 *dest)
+{
+    uint32 length;
+
+    if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj))
+        return JS_FALSE;
+
+    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    if (length < offset + count)
+        return JS_FALSE;
+
+    jsval v;
+    jsint vi;
+
+    JSUint32 *dp = dest;
+    for (uintN i = offset; i < offset+count; i++) {
+        v = obj->dslots[i];
+        if (!JSVAL_IS_INT(v) || (vi = JSVAL_TO_INT(v)) < 0)
+            return JS_FALSE;
+
+        *dp++ = (JSUint32) vi;
+    }
+
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSInt8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                       JSInt8 *dest)
+{
+    uint32 length;
+
+    if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj))
+        return JS_FALSE;
+
+    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    if (length < offset + count)
+        return JS_FALSE;
+
+    jsval v;
+    JSInt8 *dp = dest;
+    for (uintN i = offset; i < offset+count; i++) {
+        v = obj->dslots[i];
+        if (!JSVAL_IS_INT(v))
+            return JS_FALSE;
+
+        *dp++ = (JSInt8) JSVAL_TO_INT(v);
+    }
+
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSInt16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                        JSInt16 *dest)
+{
+    uint32 length;
+
+    if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj))
+        return JS_FALSE;
+
+    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    if (length < offset + count)
+        return JS_FALSE;
+
+    jsval v;
+    JSInt16 *dp = dest;
+    for (uintN i = offset; i < offset+count; i++) {
+        v = obj->dslots[i];
+        if (!JSVAL_IS_INT(v))
+            return JS_FALSE;
+
+        *dp++ = (JSInt16) JSVAL_TO_INT(v);
+    }
+
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSInt32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                        JSInt32 *dest)
+{
+    uint32 length;
+
+    if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj))
+        return JS_FALSE;
+
+    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    if (length < offset + count)
+        return JS_FALSE;
+
+    jsval v;
+    JSInt32 *dp = dest;
+    for (uintN i = offset; i < offset+count; i++) {
+        v = obj->dslots[i];
+        if (!JSVAL_IS_INT(v))
+            return JS_FALSE;
+
+        *dp++ = (JSInt32) JSVAL_TO_INT(v);
+    }
+
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSDoubleBuffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                         jsdouble *dest)
+{
+    uint32 length;
+
+    if (!obj || !OBJ_IS_DENSE_ARRAY(cx, obj))
+        return JS_FALSE;
+
+    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    if (length < offset + count)
+        return JS_FALSE;
+
+    jsval v;
+    jsdouble *dp = dest;
+    for (uintN i = offset; i < offset+count; i++) {
+        v = obj->dslots[i];
+        if (JSVAL_IS_INT(v))
+            *dp++ = (jsdouble) JSVAL_TO_INT(v);
+        else if (JSVAL_IS_DOUBLE(v))
+            *dp++ = *(JSVAL_TO_DOUBLE(v));
+        else
+            return JS_FALSE;
+    }
+
+    return JS_TRUE;
+}
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -118,11 +118,79 @@ extern JSBool
 js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp,
              void *arg, void *tmp);
 
 #ifdef DEBUG_ARRAYS
 extern JSBool
 js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
 #endif
 
+extern JSBool
+js_array_join(JSContext *cx, uintN argc, jsval *vp);
+
+enum ArrayToStringOp {
+    TO_STRING,
+    TO_LOCALE_STRING,
+    TO_SOURCE
+};
+
+extern JSBool
+js_array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
+                  JSString *sep, jsval *rval);
+
+/*
+ * Fast dense-array-to-buffer conversions.
+ *
+ * If the array is a dense array, fill [offset..offset+count] values
+ * into destination, assuming that types are consistent.  Return
+ * JS_TRUE if successful, otherwise JS_FALSE -- note that the
+ * destination buffer may be modified even if JS_FALSE is returned
+ * (e.g. due to finding an inappropriate type later on in the array).
+ * If JS_FALSE is returned, no error conditions or exceptions are set
+ * on the context.
+ *
+ * For ArrayToJSUint8, ArrayToJSUint16, and ArrayToJSUint32, each element
+ * in the array a) must be an integer; b) must be >= 0.  Integers
+ * are clamped to fit in the destination size.  Only JSVAL_IS_INT values
+ * are considered to be valid, so for JSUint32, the maximum value that
+ * can be fast-converted is less than the full unsigned 32-bit range.
+ *
+ * For ArrayToJSInt8, ArrayToJSInt16, ArrayToJSInt32, each element in
+ * the array must be an integer.  Integers are clamped to fit in the
+ * destination size.  Only JSVAL_IS_INT values are considered to be
+ * valid, so for JSInt32, the maximum value that can be
+ * fast-converted is less than the full signed 32-bit range.
+ * 
+ * For ArrayToJSDouble, each element in the array must be an
+ * integer -or- a double (JSVAL_IS_NUMBER).
+ */
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSUint8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                        JSUint8 *dest);
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSUint16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                         JSUint16 *dest);
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSUint32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                         JSUint32 *dest);
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSInt8Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                       JSInt8 *dest);
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSInt16Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                        JSInt16 *dest);
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSInt32Buffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                        JSInt32 *dest);
+
+JS_FRIEND_API(JSBool)
+js_ArrayToJSDoubleBuffer(JSContext *cx, JSObject *obj, jsuint offset, jsuint count,
+                         jsdouble *dest);
+
 JS_END_EXTERN_C
 
 #endif /* jsarray_h___ */
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -93,16 +93,17 @@ struct JSAtomListElement {
 #define ALE_INDEX(ale)  ((jsatomid) JS_PTR_TO_UINT32((ale)->entry.value))
 #define ALE_JSOP(ale)   ((JSOp) JS_PTR_TO_UINT32((ale)->entry.value))
 #define ALE_VALUE(ale)  ((jsval) (ale)->entry.value)
 #define ALE_NEXT(ale)   ((JSAtomListElement *) (ale)->entry.next)
 
 #define ALE_SET_ATOM(ale,atom)  ((ale)->entry.key = (const void *)(atom))
 #define ALE_SET_INDEX(ale,index)((ale)->entry.value = JS_UINT32_TO_PTR(index))
 #define ALE_SET_JSOP(ale,op)    ((ale)->entry.value = JS_UINT32_TO_PTR(op))
+#define ALE_SET_VALUE(ale, v)   ((ale)->entry.value = (void *)(v))
 
 struct JSAtomList {
     JSHashEntry         *list;          /* literals indexed for mapping */
     JSHashTable         *table;         /* hash table if list gets too long */
     jsuint              count;          /* count of indexed literals */
 };
 
 #define ATOM_LIST_INIT(al)  ((al)->list = NULL, (al)->table = NULL,           \
--- a/js/src/jsbit.h
+++ b/js/src/jsbit.h
@@ -82,28 +82,28 @@ extern JS_PUBLIC_API(JSIntn) JS_FloorLog
 
 unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask);
 unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask);
 # pragma intrinsic(_BitScanForward,_BitScanReverse)
 
 __forceinline static int
 __BitScanForward32(unsigned int val)
 {
-   unsigned long idx;
+    unsigned long idx;
 
-   _BitScanForward(&idx, (unsigned long)val);
-   return (int)idx;
+    _BitScanForward(&idx, (unsigned long)val);
+    return (int)idx;
 }
 __forceinline static int
 __BitScanReverse32(unsigned int val)
 {
-   unsigned long idx;
+    unsigned long idx;
 
-   _BitScanReverse(&idx, (unsigned long)val);
-   return (int)(31-idx);
+    _BitScanReverse(&idx, (unsigned long)val);
+    return (int)(31-idx);
 }
 # define js_bitscan_ctz32(val)  __BitScanForward32(val)
 # define js_bitscan_clz32(val)  __BitScanReverse32(val)
 # define JS_HAS_BUILTIN_BITSCAN32
 
 #elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 
 # define js_bitscan_ctz32(val)  __builtin_ctz(val)
@@ -204,27 +204,27 @@ unsigned char _BitScanReverse(unsigned l
  */
 #define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n))
 
 #if JS_BYTES_PER_WORD == 4
 
 # ifdef JS_HAS_BUILTIN_BITSCAN32
 JS_STATIC_ASSERT(sizeof(unsigned) == sizeof(JSUword));
 #  define js_FloorLog2wImpl(n)                                                \
-   ((JSUword)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
+    ((JSUword)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
 # else
 #  define js_FloorLog2wImpl(n) ((JSUword)JS_FloorLog2(n))
 #endif
 
 #elif JS_BYTES_PER_WORD == 8
 
 # ifdef JS_HAS_BUILTIN_BITSCAN64
 JS_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(JSUword));
 #  define js_FloorLog2wImpl(n)                                                \
-   ((JSUword)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
+    ((JSUword)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
 # else
 extern JSUword js_FloorLog2wImpl(JSUword n);
 # endif
 
 #else
 
 # error "NOT SUPPORTED"
 
new file mode 100644
--- /dev/null
+++ b/js/src/jsbuiltins.cpp
@@ -0,0 +1,640 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
+ * May 28, 2008.
+ *
+ * The Initial Developer of the Original Code is
+ *   Andreas Gal <gal@mozilla.com>
+ *
+ * Contributor(s):
+ *   Brendan Eich <brendan@mozilla.org>
+ *   Mike Shaver <shaver@mozilla.org>
+ *   David Anderson <danderson@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "jsstddef.h"
+#include <math.h>
+
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsgc.h"
+#include "jsiter.h"
+#include "jsmath.h"
+#include "jsnum.h"
+#include "jsscope.h"
+#include "jsstr.h"
+#include "jstracer.h"
+
+#include "nanojit/avmplus.h"
+#include "nanojit/nanojit.h"
+
+using namespace avmplus;
+using namespace nanojit;
+
+jsdouble FASTCALL
+js_dmod(jsdouble a, jsdouble b)
+{
+    if (b == 0.0) {
+        jsdpun u;
+        u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
+        u.s.lo = 0xffffffff;
+        return u.d;
+    }
+    jsdouble r;
+#ifdef XP_WIN
+    /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
+    if (JSDOUBLE_IS_FINITE(a) && JSDOUBLE_IS_INFINITE(b))
+        r = a;
+    else
+#endif
+        r = fmod(a, b);
+    return r;
+}
+
+/* The following boxing/unboxing primitives we can't emit inline because
+   they either interact with the GC and depend on Spidermonkey's 32-bit
+   integer representation. */
+
+jsval FASTCALL
+js_BoxDouble(JSContext* cx, jsdouble d)
+{
+    jsint i;
+    if (JSDOUBLE_IS_INT(d, i))
+        return INT_TO_JSVAL(i);
+    JS_ASSERT(cx->gcDontBlock);
+    jsval v; /* not rooted but ok here because we know GC won't run */
+    if (!js_NewDoubleInRootedValue(cx, d, &v))
+        return JSVAL_ERROR_COOKIE;
+    return v;
+}
+
+jsval FASTCALL
+js_BoxInt32(JSContext* cx, jsint i)
+{
+    if (JS_LIKELY(INT_FITS_IN_JSVAL(i)))
+        return INT_TO_JSVAL(i);
+    JS_ASSERT(cx->gcDontBlock);
+    jsval v; /* not rooted but ok here because we know GC won't run */
+    jsdouble d = (jsdouble)i;
+    if (!js_NewDoubleInRootedValue(cx, d, &v))
+        return JSVAL_ERROR_COOKIE;
+    return v;
+} 
+
+jsdouble FASTCALL
+js_UnboxDouble(jsval v)
+{
+    if (JS_LIKELY(JSVAL_IS_INT(v)))
+        return (jsdouble)JSVAL_TO_INT(v);
+    return *JSVAL_TO_DOUBLE(v);
+}
+
+jsint FASTCALL
+js_UnboxInt32(jsval v)
+{
+    if (JS_LIKELY(JSVAL_IS_INT(v)))
+        return JSVAL_TO_INT(v);
+    return js_DoubleToECMAInt32(*JSVAL_TO_DOUBLE(v));
+}
+
+int32 FASTCALL
+js_DoubleToInt32(jsdouble d)
+{
+    return js_DoubleToECMAInt32(d);
+}
+
+int32 FASTCALL
+js_DoubleToUint32(jsdouble d)
+{
+    return js_DoubleToECMAUint32(d);
+}
+
+jsdouble FASTCALL
+js_Math_sin(jsdouble d)
+{
+    return sin(d);
+}
+
+jsdouble FASTCALL
+js_Math_cos(jsdouble d)
+{
+    return cos(d);
+}
+
+jsdouble FASTCALL
+js_Math_floor(jsdouble d)
+{
+    return floor(d);
+}
+
+jsdouble FASTCALL
+js_Math_pow(jsdouble d, jsdouble p)
+{
+#ifdef NOTYET
+    /* XXX Need to get a NaN here without parameterizing on context all the time. */
+    if (!JSDOUBLE_IS_FINITE(p) && (d == 1.0 || d == -1.0))
+        return NaN;
+#endif
+    if (p == 0)
+        return 1.0;
+    return pow(d, p);
+}
+
+jsdouble FASTCALL
+js_Math_sqrt(jsdouble d)
+{
+    return sqrt(d);
+}
+
+bool FASTCALL
+js_Array_dense_setelem(JSContext* cx, JSObject* obj, jsint i, jsval v)
+{
+    JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj));
+
+    jsuint length = ARRAY_DENSE_LENGTH(obj);
+    if ((jsuint)i < length) {
+        if (obj->dslots[i] == JSVAL_HOLE) {
+            if (i >= obj->fslots[JSSLOT_ARRAY_LENGTH])
+                obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1;
+            obj->fslots[JSSLOT_ARRAY_COUNT]++;
+        }
+        obj->dslots[i] = v;
+        return true;
+    }
+    return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(i), &v) ? true : false;
+}
+
+JSString* FASTCALL
+js_Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
+{
+    jsval v;
+    if (!js_array_join_sub(cx, obj, TO_STRING, str, &v))
+        return NULL;
+    JS_ASSERT(JSVAL_IS_STRING(v));
+    return JSVAL_TO_STRING(v);
+}
+
+JSString* FASTCALL
+js_String_p_substring(JSContext* cx, JSString* str, jsint begin, jsint end)
+{
+    JS_ASSERT(end >= begin);
+    JS_ASSERT(cx->gcDontBlock);
+    return js_NewDependentString(cx, str, (size_t)begin, (size_t)(end - begin));
+}
+
+JSString* FASTCALL
+js_String_p_substring_1(JSContext* cx, JSString* str, jsint begin)
+{
+    jsint end = JSSTRING_LENGTH(str);
+    JS_ASSERT(end >= begin);
+    JS_ASSERT(cx->gcDontBlock);
+    return js_NewDependentString(cx, str, (size_t)begin, (size_t)(end - begin));
+}
+
+JSString* FASTCALL
+js_String_getelem(JSContext* cx, JSString* str, jsint i)
+{
+    if ((size_t)i >= JSSTRING_LENGTH(str))
+        return NULL;
+    return js_GetUnitString(cx, str, (size_t)i);
+}
+
+JSString* FASTCALL
+js_String_fromCharCode(JSContext* cx, jsint i)
+{
+    JS_ASSERT(cx->gcDontBlock);
+    jschar c = (jschar)i;
+    if (c < UNIT_STRING_LIMIT)
+        return js_GetUnitStringForChar(cx, c);
+    return js_NewStringCopyN(cx, &c, 1);
+}
+
+jsint FASTCALL
+js_String_p_charCodeAt(JSString* str, jsint i)
+{
+    if (i < 0 || (jsint)JSSTRING_LENGTH(str) <= i)
+        return -1;
+    return JSSTRING_CHARS(str)[i];
+}
+
+jsdouble FASTCALL
+js_Math_random(JSRuntime* rt)
+{
+    JS_LOCK_RUNTIME(rt);
+    js_random_init(rt);
+    jsdouble z = js_random_nextDouble(rt);
+    JS_UNLOCK_RUNTIME(rt);
+    return z;
+}
+
+JSString* FASTCALL
+js_String_p_concat_1int(JSContext* cx, JSString* str, jsint i)
+{
+    // FIXME: should be able to use stack buffer and avoid istr...
+    JSString* istr = js_NumberToString(cx, i);
+    if (!istr)
+        return NULL;
+    return js_ConcatStrings(cx, str, istr);
+}
+
+JSObject* FASTCALL
+js_String_p_match(JSContext* cx, JSString* str, jsbytecode *pc, JSObject* regexp)
+{
+    jsval vp[3] = { JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) };
+    if (!js_StringMatchHelper(cx, 1, vp, pc))
+        return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID);
+    JS_ASSERT(JSVAL_IS_NULL(vp[0]) ||
+              (!JSVAL_IS_PRIMITIVE(vp[0]) && OBJ_IS_ARRAY(cx, JSVAL_TO_OBJECT(vp[0]))));
+    return JSVAL_TO_OBJECT(vp[0]);
+}
+
+JSString* FASTCALL
+js_String_p_replace_str(JSContext* cx, JSString* str, JSObject* regexp, JSString* repstr)
+{
+    jsval vp[4] = {
+        JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(repstr)
+    };
+    if (!js_StringReplaceHelper(cx, 2, NULL, repstr, vp))
+        return NULL;
+    JS_ASSERT(JSVAL_IS_STRING(vp[0]));
+    return JSVAL_TO_STRING(vp[0]);
+}
+
+JSString* FASTCALL
+js_String_p_replace_str3(JSContext* cx, JSString* str, JSString* patstr, JSString* repstr,
+                         JSString* flagstr)
+{
+    jsval vp[5] = {
+        JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(patstr), STRING_TO_JSVAL(repstr),
+        STRING_TO_JSVAL(flagstr)
+    };
+    if (!js_StringReplaceHelper(cx, 3, NULL, repstr, vp))
+        return NULL;
+    JS_ASSERT(JSVAL_IS_STRING(vp[0]));
+    return JSVAL_TO_STRING(vp[0]);
+}
+
+JSObject* FASTCALL
+js_String_p_split(JSContext* cx, JSString* str, JSString* sepstr)
+{
+    // FIXME: optimize by calling into a lower level exported from jsstr.cpp.
+    jsval vp[3] = { JSVAL_NULL, STRING_TO_JSVAL(str), STRING_TO_JSVAL(sepstr) };
+    if (!js_str_split(cx, 2, vp))
+        return NULL;
+    JS_ASSERT(JSVAL_IS_OBJECT(vp[0]));
+    return JSVAL_TO_OBJECT(vp[0]);
+}
+
+jsdouble FASTCALL
+js_StringToNumber(JSContext* cx, JSString* str)
+{
+    const jschar* bp;
+    const jschar* end;
+    const jschar* ep;
+    jsdouble d;
+
+    JSSTRING_CHARS_AND_END(str, bp, end);
+    if ((!js_strtod(cx, bp, end, &ep, &d) ||
+         js_SkipWhiteSpace(ep, end) != end) &&
+        (!js_strtointeger(cx, bp, end, &ep, 0, &d) ||
+         js_SkipWhiteSpace(ep, end) != end)) {
+        return *cx->runtime->jsNaN;
+    }
+    return d;
+}
+
+jsint FASTCALL
+js_StringToInt32(JSContext* cx, JSString* str)
+{
+    const jschar* bp;
+    const jschar* end;
+    const jschar* ep;
+    jsdouble d;
+
+    JSSTRING_CHARS_AND_END(str, bp, end);
+    if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end)
+        return 0;
+    return (jsint)d;
+}
+
+jsdouble FASTCALL
+js_ParseFloat(JSContext* cx, JSString* str)
+{
+    const jschar* bp;
+    const jschar* end;
+    const jschar* ep;
+    jsdouble d;
+
+    JSSTRING_CHARS_AND_END(str, bp, end);
+    if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
+        return *cx->runtime->jsNaN;
+    return d;
+}
+
+jsdouble FASTCALL
+js_ParseInt(JSContext* cx, JSString* str)
+{
+    const jschar* bp;
+    const jschar* end;
+    const jschar* ep;
+    jsdouble d;
+
+    JSSTRING_CHARS_AND_END(str, bp, end);
+    if (!js_strtointeger(cx, bp, end, &ep, 0, &d) || ep == bp)
+        return *cx->runtime->jsNaN;
+    return d;
+}
+
+jsval FASTCALL
+js_Any_getelem(JSContext* cx, JSObject* obj, JSString* idstr)
+{
+    jsval v;
+    jsid id;
+
+    if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
+        return JSVAL_ERROR_COOKIE;
+    if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+        return JSVAL_ERROR_COOKIE;
+    return v;
+}
+
+bool FASTCALL
+js_Any_setelem(JSContext* cx, JSObject* obj, JSString* idstr, jsval v)
+{
+    jsid id;
+    if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
+        return false;
+    return OBJ_SET_PROPERTY(cx, obj, id, &v);
+}
+
+JSObject* FASTCALL
+js_FastValueToIterator(JSContext* cx, jsuint flags, jsval v)
+{
+    if (!js_ValueToIterator(cx, flags, &v))
+        return NULL;
+    return JSVAL_TO_OBJECT(v);
+}
+
+jsval FASTCALL
+js_FastCallIteratorNext(JSContext* cx, JSObject* iterobj)
+{
+    jsval v;
+    if (!js_CallIteratorNext(cx, iterobj, &v))
+        return JSVAL_ERROR_COOKIE;
+    return v;
+}
+
+GuardRecord* FASTCALL
+js_CallTree(InterpState* state, Fragment* f)
+{
+    union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;
+    u.code = f->code();
+    return u.func(state, NULL);
+}
+
+JS_STATIC_ASSERT(JSSLOT_PRIVATE == JSSLOT_ARRAY_LENGTH);
+JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH + 1 == JSSLOT_ARRAY_COUNT);
+
+JSObject* FASTCALL
+js_FastNewObject(JSContext* cx, JSObject* ctor)
+{
+    JS_ASSERT(HAS_FUNCTION_CLASS(ctor));
+    JSFunction* fun = GET_FUNCTION_PRIVATE(cx, ctor);
+    JSClass* clasp = FUN_INTERPRETED(fun) ? &js_ObjectClass : fun->u.n.clasp;
+
+    JS_ASSERT(cx->gcDontBlock);
+    JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
+    if (!obj)
+        return NULL;
+
+    JS_LOCK_OBJ(cx, ctor);
+    JSScope *scope = OBJ_SCOPE(ctor);
+    JS_ASSERT(scope->object == ctor);
+    JSAtom* atom = cx->runtime->atomState.classPrototypeAtom;
+
+    JSScopeProperty *sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
+    JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, scope));
+    jsval v = LOCKED_OBJ_GET_SLOT(ctor, sprop->slot);
+    JS_UNLOCK_SCOPE(cx, scope);
+
+    JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
+    JSObject* proto = JSVAL_TO_OBJECT(v);
+
+    obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
+    obj->fslots[JSSLOT_PARENT] = ctor->fslots[JSSLOT_PARENT];
+    obj->fslots[JSSLOT_CLASS] = PRIVATE_TO_JSVAL(clasp);
+
+    unsigned i = JSSLOT_PRIVATE;
+    if (clasp == &js_ArrayClass) {
+        obj->fslots[JSSLOT_ARRAY_LENGTH] = 0;
+        obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
+        i += 2;
+    }
+    for (; i != JS_INITIAL_NSLOTS; ++i)
+        obj->fslots[i] = JSVAL_VOID;
+
+    if (clasp == &js_ArrayClass) {
+        JSObjectOps* ops = clasp->getObjectOps(cx, clasp);
+        obj->map = ops->newObjectMap(cx, 1, ops, clasp, obj);
+        if (!obj->map)
+            return NULL;
+    } else {
+        obj->map = js_HoldObjectMap(cx, proto->map);
+    }
+    obj->dslots = NULL;
+    return obj;
+}
+
+bool FASTCALL
+js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
+{
+    JSScopeProperty* sprop2 = NULL; // initialize early to make MSVC happy
+
+    JS_ASSERT(OBJ_IS_NATIVE(obj));
+    JS_ASSERT(SPROP_HAS_STUB_SETTER(sprop));
+
+    JS_LOCK_OBJ(cx, obj);
+    JSScope* scope = OBJ_SCOPE(obj);
+    if (scope->object == obj) {
+        JS_ASSERT(!SCOPE_HAS_PROPERTY(scope, sprop));
+    } else {
+        scope = js_GetMutableScope(cx, obj);
+        if (!scope) {
+            JS_UNLOCK_OBJ(cx, obj);
+            return false;
+        }
+    }
+
+    uint32 slot = sprop->slot;
+    if (!scope->table && sprop->parent == scope->lastProp && slot == scope->map.freeslot) {
+        if (slot < STOBJ_NSLOTS(obj) && !OBJ_GET_CLASS(cx, obj)->reserveSlots) {
+            ++scope->map.freeslot;
+        } else {
+            if (!js_AllocSlot(cx, obj, &slot)) {
+                JS_UNLOCK_SCOPE(cx, scope);
+                return false;
+            }
+
+            if (slot != sprop->slot)
+                goto slot_changed;
+        }
+
+        SCOPE_EXTEND_SHAPE(cx, scope, sprop);
+        ++scope->entryCount;
+        scope->lastProp = sprop;
+        JS_UNLOCK_SCOPE(cx, scope);
+        return true;
+    }
+
+    sprop2 = js_AddScopeProperty(cx, scope, sprop->id,
+                                 sprop->getter, sprop->setter, SPROP_INVALID_SLOT,
+                                 sprop->attrs, sprop->flags, sprop->shortid);
+    if (sprop2 == sprop) {
+        JS_UNLOCK_SCOPE(cx, scope);
+        return true;
+    }
+    slot = sprop2->slot;
+
+  slot_changed:
+    js_FreeSlot(cx, obj, slot);
+    JS_UNLOCK_SCOPE(cx, scope);
+    return false;
+}
+
+jsval FASTCALL
+js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
+{
+    JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
+    jsval v;
+    if (!SPROP_GET(cx, sprop, obj, obj, &v))
+        return JSVAL_ERROR_COOKIE;
+    return v;
+}
+
+JSString* FASTCALL
+js_TypeOfObject(JSContext* cx, JSObject* obj)
+{
+    JSType type = JS_TypeOfValue(cx, OBJECT_TO_JSVAL(obj));
+    return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
+}
+
+JSString* FASTCALL
+js_TypeOfBoolean(JSContext* cx, jsint unboxed)
+{
+    jsval boxed = BOOLEAN_TO_JSVAL(unboxed);
+    JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed));
+    JSType type = JS_TypeOfValue(cx, boxed);
+    return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
+}
+
+jsint FASTCALL
+js_Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str)
+{
+    jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str));
+    jsval v;
+    if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v))
+        return JSVAL_TO_BOOLEAN(JSVAL_VOID);
+    JS_ASSERT(JSVAL_IS_BOOLEAN(v));
+    return JSVAL_TO_BOOLEAN(v);
+}
+
+jsint FASTCALL
+js_Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str)
+{
+    jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str));
+    jsval v;
+    if (!js_PropertyIsEnumerable(cx, obj, id, &v))
+        return JSVAL_TO_BOOLEAN(JSVAL_VOID);
+    JS_ASSERT(JSVAL_IS_BOOLEAN(v));
+    return JSVAL_TO_BOOLEAN(v);
+}
+
+jsdouble FASTCALL
+js_BooleanToNumber(JSContext* cx, jsint unboxed)
+{
+    if (unboxed == JSVAL_TO_BOOLEAN(JSVAL_VOID))
+        return *cx->runtime->jsNaN;
+    return unboxed;
+}
+
+JSString* FASTCALL
+js_ObjectToString(JSContext* cx, JSObject* obj)
+{
+    if (!obj)
+        return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);
+    jsval v;
+    if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_STRING, &v))
+        return NULL;
+    JS_ASSERT(JSVAL_IS_STRING(v));
+    return JSVAL_TO_STRING(v);
+}
+
+JSObject* FASTCALL
+js_Array_1int(JSContext* cx, JSObject* ctor, jsint i)
+{
+    JS_ASSERT(cx->gcDontBlock);
+    JSObject* obj = js_FastNewObject(cx, ctor);
+    if (obj)
+        obj->fslots[JSSLOT_ARRAY_LENGTH] = i;
+    return obj;
+}
+
+#define LO ARGSIZE_LO
+#define F  ARGSIZE_F
+#define Q  ARGSIZE_Q
+
+#if defined AVMPLUS_64BIT
+#define P	ARGSIZE_Q
+#else
+#define P	ARGSIZE_LO
+#endif
+
+#ifdef DEBUG
+#define NAME(op) ,#op
+#else
+#define NAME(op)
+#endif
+
+#define BUILTIN1(op, at0, atr, tr, t0, cse, fold) \
+    { (intptr_t)&js_##op, (at0 << 2) | atr, cse, fold NAME(op) },
+#define BUILTIN2(op, at0, at1, atr, tr, t0, t1, cse, fold) \
+    { (intptr_t)&js_##op, (at0 << 4) | (at1 << 2) | atr, cse, fold NAME(op) },
+#define BUILTIN3(op, at0, at1, at2, atr, tr, t0, t1, t2, cse, fold) \
+    { (intptr_t)&js_##op, (at0 << 6) | (at1 << 4) | (at2 << 2) | atr, cse, fold NAME(op) },
+#define BUILTIN4(op, at0, at1, at2, at3, atr, tr, t0, t1, t2, t3, cse, fold) \
+    { (intptr_t)&js_##op, (at0 << 8) | (at1 << 6) | (at2 << 4) | (at3 << 2) | atr, cse, fold NAME(op) },
+#define BUILTIN5(op, at0, at1, at2, at3, at4, atr, tr, t0, t1, t2, t3, t4, cse, fold) \
+    { (intptr_t)&js_##op, (at0 << 10) | (at1 << 8) | (at2 << 6) | (at3 << 4) | (at4 << 2) | atr, cse, fold NAME(op) },
+
+struct CallInfo builtins[] = {
+#include "builtins.tbl"
+};
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -60,16 +60,19 @@
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
+#ifdef JS_TRACER
+#include "jstracer.h"
+#endif
 
 #ifdef JS_THREADSAFE
 #include "prtypes.h"
 
 /*
  * The index for JSThread info, returned by PR_NewThreadPrivateIndex.  The
  * index value is visible and shared by all threads, but the data associated
  * with it is private to each thread.
@@ -105,16 +108,19 @@ js_ThreadDestructorCB(void *ptr)
         return;
 
     /*
      * Check that this thread properly called either JS_DestroyContext or
      * JS_ClearContextThread on each JSContext it created or used.
      */
     JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
     GSN_CACHE_CLEAR(&thread->gsnCache);
+#if defined JS_TRACER
+    js_FinishJIT(&thread->traceMonitor);
+#endif
     free(thread);
 }
 
 /*
  * Get current thread-local JSThread info, creating one if it doesn't exist.
  * Each thread has a unique JSThread pointer.
  *
  * Since we are dealing with thread-local data, no lock is needed.
@@ -140,16 +146,21 @@ js_GetCurrentThread(JSRuntime *rt)
         if (PR_FAILURE == PR_SetThreadPrivate(threadTPIndex, thread)) {
             free(thread);
             return NULL;
         }
 
         JS_INIT_CLIST(&thread->contextList);
         thread->id = js_CurrentThreadId();
         thread->gcMallocBytes = 0;
+#ifdef JS_TRACER
+        memset(&thread->traceMonitor, 0, sizeof(thread->traceMonitor));
+        js_InitJIT(&thread->traceMonitor);
+#endif
+        thread->scriptsToGC = NULL;
 
         /*
          * js_SetContextThread initializes the remaining fields as necessary.
          */
     }
     return thread;
 }
 
@@ -322,16 +333,17 @@ js_NewContext(JSRuntime *rt, size_t stac
         JS_UNLOCK_GC(rt);
     }
 
     cxCallback = rt->cxCallback;
     if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
         js_DestroyContext(cx, JSDCM_NEW_FAILED);
         return NULL;
     }
+
     return cx;
 }
 
 void
 js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
 {
     JSRuntime *rt;
     JSContextCallback cxCallback;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -88,16 +88,57 @@ typedef struct JSGSNCache {
         }                                                                     \
         GSN_CACHE_METER(cache, clears);                                       \
     JS_END_MACRO
 
 /* These helper macros take a cx as parameter and operate on its GSN cache. */
 #define JS_CLEAR_GSN_CACHE(cx)      GSN_CACHE_CLEAR(&JS_GSN_CACHE(cx))
 #define JS_METER_GSN_CACHE(cx,cnt)  GSN_CACHE_METER(&JS_GSN_CACHE(cx), cnt)
 
+#ifdef __cplusplus
+namespace nanojit {
+    class Fragment;
+    class Fragmento;
+}
+class TraceRecorder;
+extern "C++" template<typename T> class Queue;
+typedef Queue<uint16> SlotList;
+class TypeMap;
+
+# define CLS(T)  T*
+#else
+# define CLS(T)  void*
+#endif
+
+/* 
+ * Fragment quick cache entry.
+ */
+typedef struct JSFragmentCacheEntry {
+    jsbytecode*             pc;
+    CLS(nanojit::Fragment)  fragment;
+} JSFragmentCacheEntry;
+
+#define JS_FRAGMENT_CACHE_LOG2  2
+#define JS_FRAGMENT_CACHE_SIZE  JS_BIT(JS_FRAGMENT_CACHE_LOG2)
+#define JS_FRAGMENT_CACHE_MASK  JS_BITMASK(JS_FRAGMENT_CACHE_LOG2)
+
+/*
+ * Trace monitor. Every JSThread (if JS_THREADSAFE) or JSRuntime (if not
+ * JS_THREADSAFE) has an associated trace monitor that keeps track of loop
+ * frequencies for all JavaScript code loaded into that runtime.
+ */
+typedef struct JSTraceMonitor {
+    CLS(nanojit::Fragmento) fragmento;
+    CLS(TraceRecorder)      recorder;
+    uint32                  globalShape;
+    CLS(SlotList)           globalSlots;
+    CLS(TypeMap)            globalTypeMap;
+    JSFragmentCacheEntry    fcache[JS_FRAGMENT_CACHE_SIZE];
+} JSTraceMonitor;
+
 #ifdef JS_THREADSAFE
 
 /*
  * Structure uniquely representing a thread.  It holds thread-private data
  * that can be accessed without a global lock.
  */
 struct JSThread {
     /* Linked list of all contexts active on this thread. */
@@ -121,20 +162,28 @@ struct JSThread {
      * or another Gecko application) that uses many contexts per thread is
      * unlikely to interleave js_GetSrcNote-intensive loops in the decompiler
      * among two or more contexts running script in one thread.
      */
     JSGSNCache          gsnCache;
 
     /* Property cache for faster call/get/set invocation. */
     JSPropertyCache     propertyCache;
+
+    /* Trace-tree JIT recorder/interpreter state. */
+    JSTraceMonitor      traceMonitor;
+
+    /* Lock-free list of scripts created by eval to garbage-collect. */
+    JSScript            *scriptsToGC;
 };
 
 #define JS_GSN_CACHE(cx)        ((cx)->thread->gsnCache)
 #define JS_PROPERTY_CACHE(cx)   ((cx)->thread->propertyCache)
+#define JS_TRACE_MONITOR(cx)    ((cx)->thread->traceMonitor)
+#define JS_SCRIPTS_TO_GC(cx)    ((cx)->thread->scriptsToGC)
 
 extern void JS_DLL_CALLBACK
 js_ThreadDestructorCB(void *ptr);
 
 extern JSBool
 js_SetContextThread(JSContext *cx);
 
 extern void
@@ -386,18 +435,26 @@ struct JSRuntime {
      * a longer script, then hit repeatedly as js_GetSrcNote is called during
      * the decompiler activation that filled it.
      */
     JSGSNCache          gsnCache;
 
     /* Property cache for faster call/get/set invocation. */
     JSPropertyCache     propertyCache;
 
+    /* Trace-tree JIT recorder/interpreter state. */
+    JSTraceMonitor      traceMonitor;
+
+    /* Lock-free list of scripts created by eval to garbage-collect. */
+    JSScript            *scriptsToGC;
+
 #define JS_GSN_CACHE(cx)        ((cx)->runtime->gsnCache)
 #define JS_PROPERTY_CACHE(cx)   ((cx)->runtime->propertyCache)
+#define JS_TRACE_MONITOR(cx)    ((cx)->runtime->traceMonitor)
+#define JS_SCRIPTS_TO_GC(cx)    ((cx)->runtime->scriptsToGC)
 #endif
 
     /*
      * Object shape (property cache structural type) identifier generator.
      *
      * Type 0 stands for the empty scope, and must not be regenerated due to
      * uint32 wrap-around. Since we use atomic pre-increment, the initial
      * value for the first typed non-empty scope will be 1.
@@ -434,16 +491,21 @@ struct JSRuntime {
 #ifdef JS_DUMP_ENUM_CACHE_STATS
     int32               nativeEnumProbes;
     int32               nativeEnumMisses;
 # define ENUM_CACHE_METER(name)     JS_ATOMIC_INCREMENT(&cx->runtime->name)
 #else
 # define ENUM_CACHE_METER(name)     ((void) 0)
 #endif
 
+#ifdef JS_DUMP_LOOP_STATS
+    /* Loop statistics, to trigger trace recording and compiling. */
+    JSBasicStats        loopStats;
+#endif
+
 #if defined DEBUG || defined JS_DUMP_PROPTREE_STATS
     /* Function invocation metering. */
     jsrefcount          inlineCalls;
     jsrefcount          nativeCalls;
     jsrefcount          nonInlineCalls;
     jsrefcount          constructs;
 
     /* Title lock and scope property metering. */
@@ -674,21 +736,34 @@ struct JSContext {
 #if JS_HAS_XML_SUPPORT
     /*
      * Bit-set formed from binary exponentials of the XML_* tiny-ids defined
      * for boolean settings in jsxml.c, plus an XSF_CACHE_VALID bit.  Together
      * these act as a cache of the boolean XML.ignore* and XML.prettyPrinting
      * property values associated with this context's global object.
      */
     uint8               xmlSettingFlags;
+#else
     uint8               padding;
-#else
-    uint16              padding;
 #endif
 
+    /*
+     * Flag to prevent last-ditch garbage collection when up against runtime
+     * memory limits. This also suppresses calls to JS_ReportOutOfMemory when
+     * failing due to runtime limits.
+     */
+    JSPackedBool        gcDontBlock;
+
+    /*
+     * Classic Algol "display" static link optimization.
+     */
+#define JS_DISPLAY_SIZE 16
+
+    JSStackFrame        *display[JS_DISPLAY_SIZE];
+
     /* Runtime version control identifier. */
     uint16              version;
 
     /* Per-context options. */
     uint32              options;            /* see jsapi.h for JSOPTION_* */
 
     /* Locale specific callbacks for string conversion. */
     JSLocaleCallbacks   *localeCallbacks;
--- a/js/src/jsconfig.mk
+++ b/js/src/jsconfig.mk
@@ -77,17 +77,17 @@ ifeq ($(OS_ARCH), WINNT)
     NSPR_OBJDIR  = WINNT4.0_OPT.OBJ
   endif
 endif
 NSPR_SHARED      = /share/builds/components/nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR)
 ifeq ($(OS_ARCH), WINNT)
   NSPR_SHARED    = nspr20/$(NSPR_VERSION)/$(NSPR_OBJDIR)
 endif
 NSPR_VERSIONFILE = $(NSPR_LOCAL)/Version
-NSPR_CURVERSION := $(shell cat $(NSPR_VERSIONFILE))
+NSPR_CURVERSION := $(shell cat $(NSPR_VERSIONFILE) 2>/dev/null)
 
 get_nspr:
 	@echo "Grabbing NSPR component..."
 ifeq ($(NSPR_VERSION), $(NSPR_CURVERSION))
 	@echo "No need, NSPR is up to date in this tree (ver=$(NSPR_VERSION))."
 else
 	mkdir -p $(NSPR_LOCAL)
 	mkdir -p $(NSPR_DIST)
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1584,18 +1584,18 @@ JS_GetScriptTotalSize(JSContext *cx, JSS
 {
     size_t nbytes, pbytes;
     jsatomid i;
     jssrcnote *sn, *notes;
     JSObjectArray *objarray;
     JSPrincipals *principals;
 
     nbytes = sizeof *script;
-    if (script->object)
-        nbytes += JS_GetObjectTotalSize(cx, script->object);
+    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 (i = 0; i < script->atomMap.length; i++)
         nbytes += GetAtomTotalSize(cx, script->atomMap.vector[i]);
 
     if (script->filename)
         nbytes += strlen(script->filename) + 1;
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1,10 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
+ * vim: set ts=8 sw=4 et tw=99:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -73,18 +73,16 @@
 #define SRCNOTE_CHUNK   64      /* initial srcnote allocation increment */
 #define TRYNOTE_CHUNK   64      /* trynote allocation increment */
 
 /* Macros to compute byte sizes from typed element counts. */
 #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
 #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
 #define TRYNOTE_SIZE(n)         ((n) * sizeof(JSTryNote))
 
-#define CG_TS(cg) TS((cg)->treeContext.parseContext)
-
 static JSBool
 NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
            uintN stackDepth, size_t start, size_t end);
 
 JS_FRIEND_API(void)
 js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
                      JSArenaPool *codePool, JSArenaPool *notePool,
                      uintN lineno)
@@ -95,26 +93,32 @@ js_InitCodeGenerator(JSContext *cx, JSCo
     cg->notePool = notePool;
     cg->codeMark = JS_ARENA_MARK(codePool);
     cg->noteMark = JS_ARENA_MARK(notePool);
     cg->current = &cg->main;
     cg->firstLine = cg->prolog.currentLine = cg->main.currentLine = lineno;
     ATOM_LIST_INIT(&cg->atomList);
     cg->prolog.noteMask = cg->main.noteMask = SRCNOTE_CHUNK - 1;
     ATOM_LIST_INIT(&cg->constList);
+    ATOM_LIST_INIT(&cg->upvarList);
 }
 
 JS_FRIEND_API(void)
 js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg)
 {
     TREE_CONTEXT_FINISH(cx, &cg->treeContext);
     JS_ARENA_RELEASE(cg->codePool, cg->codeMark);
     JS_ARENA_RELEASE(cg->notePool, cg->noteMark);
-    if (cg->spanDeps) /* non-null only after OOM */
+
+    /* NB: non-null only after OOM. */
+    if (cg->spanDeps)
         JS_free(cx, cg->spanDeps);
+
+    if (cg->upvarMap.vector)
+        JS_free(cx, cg->upvarMap.vector);
 }
 
 static ptrdiff_t
 EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
 {
     jsbytecode *base, *limit, *next;
     ptrdiff_t offset, length;
     size_t incr, size;
@@ -1489,17 +1493,17 @@ js_DefineCompileTimeConstant(JSContext *
             valueAtom = js_AtomizeDouble(cx, dval);
             if (!valueAtom)
                 return JS_FALSE;
             v = ATOM_KEY(valueAtom);
         }
         ale = js_IndexAtom(cx, atom, &cg->constList);
         if (!ale)
             return JS_FALSE;
-        ale->entry.value = (void *)v;
+        ALE_SET_VALUE(ale, v);
     }
     return JS_TRUE;
 }
 
 JSStmtInfo *
 js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp)
 {
     JSStmtInfo *stmt;
@@ -1830,17 +1834,18 @@ BindNameToSlot(JSContext *cx, JSCodeGene
     /*
      * We can't optimize if we are compiling a with statement and its body,
      * or we're in a catch block whose exception variable has the same name
      * as this node.  FIXME: we should be able to optimize catch vars to be
      * block-locals.
      */
     tc = &cg->treeContext;
     atom = pn->pn_atom;
-    if ((stmt = js_LexicalLookup(tc, atom, &slot))) {
+    stmt = js_LexicalLookup(tc, atom, &slot);
+    if (stmt) {
         if (stmt->type == STMT_WITH)
             return JS_TRUE;
 
         JS_ASSERT(stmt->flags & SIF_SCOPE);
         JS_ASSERT(slot >= 0);
         op = PN_OP(pn);
         switch (op) {
           case JSOP_NAME:     op = JSOP_GETLOCAL; break;
@@ -1866,18 +1871,62 @@ BindNameToSlot(JSContext *cx, JSCodeGene
     /*
      * We can't optimize if var and closure (a local function not in a larger
      * expression and not at top-level within another's body) collide.
      * XXX suboptimal: keep track of colliding names and deoptimize only those
      */
     if (tc->flags & TCF_FUN_CLOSURE_VS_VAR)
         return JS_TRUE;
 
-    if (!(tc->flags & TCF_IN_FUNCTION) &&
-        !((cx->fp->flags & JSFRAME_SPECIAL) && cx->fp->fun)) {
+    if (!(tc->flags & TCF_IN_FUNCTION)) {
+        if ((cx->fp->flags & JSFRAME_SPECIAL) && cx->fp->fun) {
+            localKind = js_LookupLocal(cx, cx->fp->fun, atom, &index);
+            if (localKind != JSLOCAL_NONE) {
+                if (PN_OP(pn) == JSOP_NAME) {
+                    ATOM_LIST_SEARCH(ale, &cg->upvarList, atom);
+                    if (!ale) {
+                        uint32 cookie, length, *vector;
+
+                        ale = js_IndexAtom(cx, atom, &cg->upvarList);
+                        if (!ale)
+                            return JS_FALSE;
+                        JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);
+
+                        length = cg->upvarMap.length;
+                        JS_ASSERT(ALE_INDEX(ale) <= length);
+                        if (ALE_INDEX(ale) == length) {
+                            length = 2 * JS_MAX(2, length);
+                            vector = (uint32 *)
+                                     JS_realloc(cx, cg->upvarMap.vector,
+                                                length * sizeof *vector);
+                            if (!vector)
+                                return JS_FALSE;
+                            cg->upvarMap.vector = vector;
+                            cg->upvarMap.length = length;
+                        }
+
+                        if (localKind != JSLOCAL_ARG)
+                            index += cx->fp->fun->nargs;
+                        if (index >= JS_BIT(16)) {
+                            cg->treeContext.flags |= TCF_FUN_USES_NONLOCALS;
+                            return JS_TRUE;
+                        }
+
+                        cookie = MAKE_UPVAR_COOKIE(1, index);
+                        cg->upvarMap.vector[ALE_INDEX(ale)] = cookie;
+                    }
+
+                    pn->pn_op = JSOP_GETUPVAR;
+                    pn->pn_slot = ALE_INDEX(ale);
+                    return JS_TRUE;
+                }
+            }
+            goto out;
+        }
+
         /*
          * We are compiling a script or eval, and eval is not inside a function
          * activation.
          */
         fp = cx->fp;
         if (fp->scopeChain != fp->varobj)
             return JS_TRUE;
 
@@ -1930,17 +1979,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
           case JSOP_SETNAME:  op = JSOP_SETGVAR; break;
           case JSOP_SETCONST: /* NB: no change */ break;
           case JSOP_INCNAME:  op = JSOP_INCGVAR; break;
           case JSOP_NAMEINC:  op = JSOP_GVARINC; break;
           case JSOP_DECNAME:  op = JSOP_DECGVAR; break;
           case JSOP_NAMEDEC:  op = JSOP_GVARDEC; break;
           case JSOP_FORNAME:  /* NB: no change */ break;
           case JSOP_DELNAME:  /* NB: no change */ break;
-          default: JS_ASSERT(0);
+          default: JS_NOT_REACHED("gvar");
         }
         pn->pn_const = constOp;
         if (op != pn->pn_op) {
             pn->pn_op = op;
             pn->pn_slot = slot;
         }
         return JS_TRUE;
     }
@@ -1959,43 +2008,44 @@ BindNameToSlot(JSContext *cx, JSCodeGene
                   case JSOP_NAME:     op = JSOP_GETARG; break;
                   case JSOP_SETNAME:  op = JSOP_SETARG; break;
                   case JSOP_INCNAME:  op = JSOP_INCARG; break;
                   case JSOP_NAMEINC:  op = JSOP_ARGINC; break;
                   case JSOP_DECNAME:  op = JSOP_DECARG; break;
                   case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;
                   case JSOP_FORNAME:  op = JSOP_FORARG; break;
                   case JSOP_DELNAME:  op = JSOP_FALSE; break;
-                  default: JS_ASSERT(0);
+                  default: JS_NOT_REACHED("arg");
                 }
                 pn->pn_const = JS_FALSE;
             } else {
                 JS_ASSERT(localKind == JSLOCAL_VAR ||
                           localKind == JSLOCAL_CONST);
                 switch (op) {
                   case JSOP_NAME:     op = JSOP_GETLOCAL; break;
                   case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
                   case JSOP_SETCONST: op = JSOP_SETLOCAL; break;
                   case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
                   case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
                   case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
                   case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
                   case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;
                   case JSOP_DELNAME:  op = JSOP_FALSE; break;
-                  default: JS_ASSERT(0);
+                  default: JS_NOT_REACHED("local");
                 }
                 pn->pn_const = (localKind == JSLOCAL_CONST);
             }
             pn->pn_op = op;
             pn->pn_slot = index;
             return JS_TRUE;
         }
         tc->flags |= TCF_FUN_USES_NONLOCALS;
     }
 
+out:
     /*
      * Here we either compiling a function body or an eval script inside a
      * function and couldn't optimize pn, so it's not a global or local slot
      * name.
      *
      * Now we must check for the predefined arguments variable.  It may be
      * overridden by assignment, in which case the function is heavyweight
      * and the interpreter will look up 'arguments' in the function's call
@@ -2215,16 +2265,19 @@ EmitNameOp(JSContext *cx, JSCodeGenerato
             op = JSOP_CALLGVAR;
             break;
           case JSOP_GETARG:
             op = JSOP_CALLARG;
             break;
           case JSOP_GETLOCAL:
             op = JSOP_CALLLOCAL;
             break;
+          case JSOP_GETUPVAR:
+            op = JSOP_CALLUPVAR;
+            break;
           default:
             JS_ASSERT(op == JSOP_ARGUMENTS);
             break;
         }
     }
 
     if (op == JSOP_ARGUMENTS) {
         if (js_Emit1(cx, cg, op) < 0)
@@ -2278,52 +2331,54 @@ EmitPropOp(JSContext *cx, JSParseNode *p
 
     pn2 = pn->pn_expr;
     if (callContext) {
         JS_ASSERT(pn->pn_type == TOK_DOT);
         JS_ASSERT(op == JSOP_GETPROP);
         op = JSOP_CALLPROP;
     } else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) {
         if (pn2->pn_op == JSOP_THIS) {
-            /* Fast path for gets of |this.foo|. */
-            return EmitAtomOp(cx, pn, JSOP_GETTHISPROP, cg);
-        }
-
-        if (pn2->pn_type == TOK_NAME) {
+            if (pn->pn_atom != cx->runtime->atomState.lengthAtom) {
+                /* Fast path for gets of |this.foo|. */
+                return EmitAtomOp(cx, pn, JSOP_GETTHISPROP, cg);
+            }
+        } else if (pn2->pn_type == TOK_NAME) {
             /*
              * Try to optimize:
              *  - arguments.length into JSOP_ARGCNT
              *  - argname.prop into JSOP_GETARGPROP
              *  - localname.prop into JSOP_GETLOCALPROP
+             * but don't do this if the property is 'length' -- prefer to emit
+             * JSOP_GETARG, etc., and then JSOP_LENGTH.
              */
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
-            switch (pn2->pn_op) {
-              case JSOP_ARGUMENTS:
-                if (pn->pn_atom == cx->runtime->atomState.lengthAtom)
+            if (pn->pn_atom == cx->runtime->atomState.lengthAtom) {
+                if (pn2->pn_op == JSOP_ARGUMENTS)
                     return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0;
-                break;
-
-              case JSOP_GETARG:
-                op = JSOP_GETARGPROP;
-                goto do_indexconst;
-              case JSOP_GETLOCAL:
-                op = JSOP_GETLOCALPROP;
-              do_indexconst: {
-                JSAtomListElement *ale;
-                jsatomid atomIndex;
-
-                ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
-                if (!ale)
-                    return JS_FALSE;
-                atomIndex = ALE_INDEX(ale);
-                return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);
-              }
-
-              default:;
+            } else {
+                switch (pn2->pn_op) {
+                  case JSOP_GETARG:
+                    op = JSOP_GETARGPROP;
+                    goto do_indexconst;
+                  case JSOP_GETLOCAL:
+                    op = JSOP_GETLOCALPROP;
+                  do_indexconst: {
+                        JSAtomListElement *ale;
+                        jsatomid atomIndex;
+                        
+                        ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
+                        if (!ale)
+                            return JS_FALSE;
+                        atomIndex = ALE_INDEX(ale);
+                        return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);
+                    }
+                    
+                  default:;
+                }
             }
         }
     }
 
     /*
      * If the object operand is also a dotted property reference, reverse the
      * list linked via pn_expr temporarily so we can iterate over it from the
      * bottom up (reversing again as we go), to avoid excessive recursion.
@@ -3119,16 +3174,21 @@ js_EmitFunctionScript(JSContext *cx, JSC
         /* JSOP_GENERATOR must be the first instruction. */
         CG_SWITCH_TO_PROLOG(cg);
         JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
         if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0)
             return JS_FALSE;
         CG_SWITCH_TO_MAIN(cg);
     }
 
+    if (!(cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT) &&
+        (cg->treeContext.flags & TCF_COMPILE_N_GO)) {
+        STOBJ_SET_PARENT(FUN_OBJECT(cg->treeContext.fun), cx->fp->scopeChain);
+    }
+
     return js_EmitTree(cx, cg, body) &&
            js_Emit1(cx, cg, JSOP_STOP) >= 0 &&
            js_NewScriptFromCG(cx, cg);
 }
 
 /* A macro for inlining at the top of js_EmitTree (whence it came). */
 #define UPDATE_LINE_NUMBER_NOTES(cx, cg, pn)                                  \
     JS_BEGIN_MACRO                                                            \
@@ -3922,44 +3982,56 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             JS_ASSERT(pn->pn_op == JSOP_NOP);
             JS_ASSERT(cg->treeContext.flags & TCF_IN_FUNCTION);
             JS_ASSERT(pn->pn_index != (uint32) -1);
             if (!EmitFunctionDefNop(cx, cg, pn->pn_index))
                 return JS_FALSE;
             break;
         }
 
+        /*
+         * Limit static nesting depth to fit in 16 bits. See cg2->staticDepth
+         * assignment below.
+         */
+        if (cg->staticDepth == JS_BITMASK(16)) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_DEEP,
+                                 js_function_str);
+            return JS_FALSE;
+        }
+
         /* Generate code for the function's body. */
         cg2mark = JS_ARENA_MARK(cg->codePool);
         JS_ARENA_ALLOCATE_TYPE(cg2, JSCodeGenerator, cg->codePool);
         if (!cg2) {
             js_ReportOutOfScriptQuota(cx);
             return JS_FALSE;
         }
         js_InitCodeGenerator(cx, cg2, cg->treeContext.parseContext,
                              cg->codePool, cg->notePool,
                              pn->pn_pos.begin.lineno);
         cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION);
         cg2->treeContext.fun = fun;
+        cg2->staticDepth = cg->staticDepth + 1;
         cg2->parent = cg;
 
         /* We metered the max scope depth when parsed the function. */ 
         JS_SCOPE_DEPTH_METERING(cg2->treeContext.maxScopeDepth = (uintN) -1);
         if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) {
             pn = NULL;
         } else {
             /*
              * We need an activation object if an inner peeks out, or if such
              * inner-peeking caused one of our inners to become heavyweight.
              */
             if (cg2->treeContext.flags &
                 (TCF_FUN_USES_NONLOCALS | TCF_FUN_HEAVYWEIGHT)) {
                 cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;
             }
         }
+
         js_FinishCodeGenerator(cx, cg2);
         JS_ARENA_RELEASE(cg->codePool, cg2mark);
         cg2 = NULL;
         if (!pn)
             return JS_FALSE;
 
         /* Make the function object a literal in the outer script's pool. */
         index = IndexParsedObject(pn->pn_funpob, &cg->objectList);
@@ -5141,18 +5213,22 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
       case TOK_SEMI:
         pn2 = pn->pn_kid;
         if (pn2) {
             /*
              * Top-level or called-from-a-native JS_Execute/EvaluateScript,
              * debugger, and eval frames may need the value of the ultimate
              * expression statement as the script's result, despite the fact
              * that it appears useless to the compiler.
+             *
+             * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
+             * calling JS_Compile* to suppress JSOP_POPV.
              */
-            useful = wantval = !(cg->treeContext.flags & TCF_IN_FUNCTION);
+            useful = wantval =
+                !(cg->treeContext.flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));
             if (!useful) {
                 if (!CheckSideEffects(cx, cg, pn2, &useful))
                     return JS_FALSE;
             }
 
             /*
              * Don't eliminate apparently useless expressions if they are
              * labeled expression statements.  The tc->topStmt->update test
@@ -5852,19 +5928,22 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     return JS_FALSE;
                 break;
             }
 #endif
             /* FALL THROUGH */
           default:
             /*
              * Push null as a placeholder for the global object, per ECMA-262
-             * 11.2.3 step 6.
+             * 11.2.3 step 6. We use JSOP_NULLTHIS to distinguish this opcode
+             * from JSOP_NULL (see jstracer.cpp for one use-case).
              */
-            if (!js_EmitTree(cx, cg, pn2) || js_Emit1(cx, cg, JSOP_NULL) < 0)
+            if (!js_EmitTree(cx, cg, pn2))
+                return JS_FALSE;
+            if (js_Emit1(cx, cg, JSOP_NULLTHIS) < 0)
                 return JS_FALSE;
         }
 
         /* Remember start of callable-object bytecode for decompilation hint. */
         off = top;
 
         /*
          * Emit code for each argument in order, then emit the JSOP_*CALL or
@@ -6840,20 +6919,20 @@ js_FinishTakingTryNotes(JSCodeGenerator 
  * that shares the same JSRegExp private data created for the object literal
  * in pob. We need clones to hold lastIndex and other direct properties that
  * should not be shared among threads sharing a precompiled function or
  * script.
  *
  * If the code being compiled is function code, allocate a reserved slot in
  * the cloned function object that shares its precompiled script with other
  * cloned function objects and with the compiler-created clone-parent. There
- * are script->nregexps such reserved slots in each function object cloned
- * from fun->object. NB: during compilation, funobj slots must never be
- * allocated, because js_AllocSlot could hand out one of the slots that should
- * be given to a regexp clone.
+ * are nregexps = JS_SCRIPT_REGEXPS(script)->length such reserved slots in each
+ * function object cloned from fun->object. NB: during compilation, a funobj
+ * slots element must never be allocated, because js_AllocSlot could hand out
+ * one of the slots that should be given to a regexp clone.
  *
  * If the code being compiled is global code, the cloned regexp are stored in
  * fp->vars slot after cg->treeContext.ngvars and to protect regexp slots from
  * GC we set fp->nvars to ngvars + nregexps.
  *
  * The slots initially contain undefined or null. We populate them lazily when
  * JSOP_REGEXP is executed for the first time.
  *
--- a/js/src/jsemit.h
+++ b/js/src/jsemit.h
@@ -1,10 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
+ * vim: set ts=8 sw=4 et tw=79:
  *
  * ***** 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/
@@ -95,18 +95,18 @@ typedef enum JSStmtType {
  *
  * STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly
  * links to other scoping statement info records.  It excludes the two early
  * "maybe" types, block and switch, as well as the try and both finally types,
  * since try and the other trailing maybe-scope types don't need block scope
  * unless they contain let declarations.
  *
  * We treat WITH as a static scope because it prevents lexical binding from
- * continuing further up the static scope chain. With the "reformed with"
- * proposal for JS2, we'll be able to model it statically, too.
+ * continuing further up the static scope chain. With the lost "reformed with"
+ * proposal for ES4, we would be able to model it statically, too.
  */
 #define STMT_TYPE_MAYBE_SCOPE(type)                                           \
     (type != STMT_WITH &&                                                     \
      STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE))
 
 #define STMT_TYPE_LINKS_SCOPE(type)                                           \
     STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH)
 
@@ -188,16 +188,18 @@ struct JSTreeContext {              /* t
 #define TCF_FUN_HEAVYWEIGHT    0x40 /* function needs Call object per call */
 #define TCF_FUN_IS_GENERATOR   0x80 /* parsed yield statement in function */
 #define TCF_HAS_DEFXMLNS      0x100 /* default xml namespace = ...; parsed */
 #define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */
 #define TCF_GENEXP_LAMBDA     0x400 /* flag lambda from generator expression */
 #define TCF_COMPILE_N_GO      0x800 /* compiler-and-go mode of script, can
                                        optimize name references based on scope
                                        chain */
+#define TCF_NO_SCRIPT_RVAL   0x1000 /* API caller does not want result value
+                                       from global script */
 
 /*
  * Flags to propagate out of the blocks.
  */
 #define TCF_RETURN_FLAGS        (TCF_RETURN_EXPR | TCF_RETURN_VOID)
 
 /*
  * Flags to propagate from FunctionBody.
@@ -324,18 +326,18 @@ struct JSCodeGenerator {
         jsbytecode  *next;          /* pointer to next free bytecode */
         jssrcnote   *notes;         /* source notes, see below */
         uintN       noteCount;      /* number of source notes so far */
         uintN       noteMask;       /* growth increment for notes */
         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
         uintN       currentLine;    /* line number for tree-based srcnote gen */
     } prolog, main, *current;
 
+    JSAtomList      atomList;       /* literals indexed for mapping */
     uintN           firstLine;      /* first line, for js_NewScriptFromCG */
-    JSAtomList      atomList;       /* literals indexed for mapping */
 
     intN            stackDepth;     /* current stack depth in script frame */
     uintN           maxStackDepth;  /* maximum stack depth so far */
 
     uintN           ntrynotes;      /* number of allocated so far try notes */
     JSTryNode       *lastTryNode;   /* the last allocated try node */
 
     JSSpanDep       *spanDeps;      /* span dependent instruction records */
@@ -350,19 +352,24 @@ struct JSCodeGenerator {
 
     uintN           emitLevel;      /* js_EmitTree recursion level */
     JSAtomList      constList;      /* compile time constants */
 
     JSEmittedObjectList objectList; /* list of emitted so far objects */
     JSEmittedObjectList regexpList; /* list of emitted so far regexp
                                        that will be cloned during execution */
 
+    uintN           staticDepth;    /* static frame chain depth */
+    JSAtomList      upvarList;      /* map of atoms to upvar indexes */
+    JSUpvarArray    upvarMap;       /* indexed upvar pairs (JS_realloc'ed) */
     JSCodeGenerator *parent;        /* enclosing function or global context */
 };
 
+#define CG_TS(cg)               TS((cg)->treeContext.parseContext)
+
 #define CG_BASE(cg)             ((cg)->current->base)
 #define CG_LIMIT(cg)            ((cg)->current->limit)
 #define CG_NEXT(cg)             ((cg)->current->next)
 #define CG_CODE(cg,offset)      (CG_BASE(cg) + (offset))
 #define CG_OFFSET(cg)           PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode)
 
 #define CG_NOTES(cg)            ((cg)->current->notes)
 #define CG_NOTE_COUNT(cg)       ((cg)->current->noteCount)
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -895,16 +895,19 @@ exn_toSource(JSContext *cx, uintN argc, 
     name = js_ValueToString(cx, *vp);
     if (!name)
         return JS_FALSE;
     *vp = STRING_TO_JSVAL(name);
 
     /* After this, control must flow through label out: to exit. */
     JS_PUSH_TEMP_ROOT(cx, 3, localroots, &tvr);
 
+#ifdef __GNUC__
+    message = filename = NULL;
+#endif
     ok = JS_GetProperty(cx, obj, js_message_str, &localroots[0]) &&
          (message = js_ValueToSource(cx, localroots[0]));
     if (!ok)
         goto out;
     localroots[0] = STRING_TO_JSVAL(message);
 
     ok = JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) &&
          (filename = js_ValueToSource(cx, localroots[1]));
--- a/js/src/jsfile.cpp
+++ b/js/src/jsfile.cpp
@@ -1900,17 +1900,17 @@ file_list(JSContext *cx, JSObject *obj, 
     JSString    *str;
     jsval       args[1];
     char        *filePath;
 
     SECURITY_CHECK(cx, NULL, "list", file);
     JSFILE_CHECK_NATIVE("list");
 
     if (argc==1) {
-        if (JSVAL_IS_REGEXP(cx, argv[0])) {
+        if (VALUE_IS_REGEXP(cx, argv[0])) {
             re = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
         }else
         if (VALUE_IS_FUNCTION(cx, argv[0])) {
             func = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
         }else{
             JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
                 JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, argv[0]);
             goto out;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1009,17 +1009,17 @@ fun_getProperty(JSContext *cx, JSObject 
     /*
      * Loop because getter and setter can be delegated from another class,
      * but loop only for ARGS_LENGTH because we must pretend that f.length
      * is in each function instance f, per ECMA-262, instead of only in the
      * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
      * to make it appear so).
      *
      * This code couples tightly to the attributes for the function_props[]
-     * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper.
+     * initializers above, and to js_SetProperty and js_HasOwnProperty.
      *
      * It's important to allow delegating objects, even though they inherit
      * this getter (fun_getProperty), to override arguments, arity, caller,
      * and name.  If we didn't return early for slot != ARGS_LENGTH, we would
      * clobber *vp with the native property value, instead of letting script
      * override that value in delegating objects.
      *
      * Note how that clobbering is what simulates JSPROP_READONLY for all of
@@ -1471,27 +1471,32 @@ fun_finalize(JSContext *cx, JSObject *ob
         DestroyLocalNames(cx, fun);
     }
 }
 
 static uint32
 fun_reserveSlots(JSContext *cx, JSObject *obj)
 {
     JSFunction *fun;
+    uint32 nslots;
 
     /*
      * We use JS_GetPrivate and not GET_FUNCTION_PRIVATE because during
      * js_InitFunctionClass invocation the function is called before the
      * private slot of the function object is set.
      */
     fun = (JSFunction *) JS_GetPrivate(cx, obj);
-    return (fun && FUN_INTERPRETED(fun) &&
-            fun->u.i.script && fun->u.i.script->regexpsOffset != 0)
-           ? JS_SCRIPT_REGEXPS(fun->u.i.script)->length
-           : 0;
+    nslots = 0;
+    if (fun && FUN_INTERPRETED(fun) && fun->u.i.script) {
+        if (fun->u.i.script->upvarsOffset != 0)
+            nslots = JS_SCRIPT_UPVARS(fun->u.i.script)->length;
+        if (fun->u.i.script->regexpsOffset != 0)
+            nslots += JS_SCRIPT_REGEXPS(fun->u.i.script)->length;
+    }
+    return nslots;
 }
 
 /*
  * Reserve two slots in all function objects for XPConnect.  Note that this
  * does not bloat every instance, only those on which reserved slots are set,
  * and those on which ad-hoc properties are defined.
  */
 JS_FRIEND_DATA(JSClass) js_FunctionClass = {
@@ -2023,17 +2028,17 @@ js_InitFunctionClass(JSContext *cx, JSOb
 
     proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
                          function_props, function_methods, NULL, NULL);
     if (!proto)
         return NULL;
     fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
     if (!fun)
         goto bad;
-    fun->u.i.script = js_NewScript(cx, 1, 0, 0, 0, 0, 0);
+    fun->u.i.script = js_NewScript(cx, 1, 0, 0, 0, 0, 0, 0);
     if (!fun->u.i.script)
         goto bad;
     fun->u.i.script->code[0] = JSOP_STOP;
 #ifdef CHECK_SCRIPT_OWNER
     fun->u.i.script->owner = NULL;
 #endif
     return proto;
 
@@ -2079,17 +2084,17 @@ js_NewFunction(JSContext *cx, JSObject *
 
     /* Initialize all function members. */
     fun->nargs = nargs;
     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED);
     if (flags & JSFUN_INTERPRETED) {
         JS_ASSERT(!native);
         JS_ASSERT(nargs == 0);
         fun->u.i.nvars = 0;
-        fun->u.i.spare = 0;
+        fun->u.i.nupvars = 0;
         fun->u.i.script = NULL;
 #ifdef DEBUG
         fun->u.i.names.taggedAtom = 0;
 #endif
     } else {
         fun->u.n.native = native;
         fun->u.n.extra = 0;
         fun->u.n.spare = 0;
@@ -2361,16 +2366,18 @@ js_AddLocal(JSContext *cx, JSFunction *f
     JSLocalNameMap *map;
 
     JS_ASSERT(FUN_INTERPRETED(fun));
     JS_ASSERT(!fun->u.i.script);
     JS_ASSERT(((jsuword) atom & 1) == 0);
     taggedAtom = (jsuword) atom;
     if (kind == JSLOCAL_ARG) {
         indexp = &fun->nargs;
+    } else if (kind == JSLOCAL_UPVAR) {
+        indexp = &fun->u.i.nupvars;
     } else {
         indexp = &fun->u.i.nvars;
         if (kind == JSLOCAL_CONST)
             taggedAtom |= 1;
         else
             JS_ASSERT(kind == JSLOCAL_VAR);
     }
     n = JS_GET_LOCAL_NAME_COUNT(fun);
@@ -2456,37 +2463,43 @@ js_AddLocal(JSContext *cx, JSFunction *f
     /* Update the argument or variable counter. */
     ++*indexp;
     return JS_TRUE;
 }
 
 JSLocalKind
 js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp)
 {
-    uintN n, i;
+    uintN n, i, upvar_base;
     jsuword *array;
     JSLocalNameHashEntry *entry;
 
     JS_ASSERT(FUN_INTERPRETED(fun));
     n = JS_GET_LOCAL_NAME_COUNT(fun);
     if (n == 0)
         return JSLOCAL_NONE;
     if (n <= MAX_ARRAY_LOCALS) {
         array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
 
         /* Search from the tail to pick up the last duplicated name. */
         i = n;
+        upvar_base = JS_UPVAR_LOCAL_NAME_START(fun);
         do {
             --i;
             if (atom == JS_LOCAL_NAME_TO_ATOM(array[i])) {
                 if (i < fun->nargs) {
                     if (indexp)
                         *indexp = i;
                     return JSLOCAL_ARG;
                 }
+                if (i >= upvar_base) {
+                    if (indexp)
+                        *indexp = i - upvar_base;
+                    return JSLOCAL_UPVAR;
+                }
                 if (indexp)
                     *indexp = i - fun->nargs;
                 return JS_LOCAL_NAME_IS_CONST(array[i])
                        ? JSLOCAL_CONST
                        : JSLOCAL_VAR;
             }
         } while (i != 0);
     } else {
@@ -2661,17 +2674,17 @@ DestroyLocalNames(JSContext *cx, JSFunct
 void
 js_FreezeLocalNames(JSContext *cx, JSFunction *fun)
 {
     uintN n;
     jsuword *array;
 
     JS_ASSERT(FUN_INTERPRETED(fun));
     JS_ASSERT(!fun->u.i.script);
-    n = fun->nargs + fun->u.i.nvars;
+    n = fun->nargs + fun->u.i.nvars + fun->u.i.nupvars;
     if (2 <= n && n < MAX_ARRAY_LOCALS) {
         /* Shrink over-allocated array ignoring realloc failures. */
         array = (jsuword *) JS_realloc(cx, fun->u.i.names.array,
                                        n * sizeof *array);
         if (array)
             fun->u.i.names.array = array;
     }
 }
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -59,35 +59,36 @@ typedef struct JSLocalNameMap JSLocalNam
  */
 typedef union JSLocalNames {
     jsuword         taggedAtom;
     jsuword         *array;
     JSLocalNameMap  *map;
 } JSLocalNames;
 
 struct JSFunction {
-    JSObject        object;     /* GC'ed object header */
-    uint16          nargs;      /* maximum number of specified arguments,
-                                   reflected as f.length/f.arity */
-    uint16          flags;      /* bound method and other flags, see jsapi.h */
+    JSObject        object;       /* GC'ed object header */
+    uint16          nargs;        /* maximum number of specified arguments,
+                                     reflected as f.length/f.arity */
+    uint16          flags;        /* flags, see JSFUN_* below and in jsapi.h */
     union {
         struct {
-            uint16      extra;  /* number of arg slots for local GC roots */
-            uint16      spare;  /* reserved for future use */
-            JSNative    native; /* native method pointer or null */
-            JSClass     *clasp; /* if non-null, constructor for this class */
+            uint16      extra;    /* number of arg slots for local GC roots */
+            uint16      spare;    /* reserved for future use */
+            JSNative    native;   /* native method pointer or null */
+            JSClass     *clasp;   /* if non-null, constructor for this class */
         } n;
         struct {
-            uint16      nvars;  /* number of local variables */
-            uint16      spare;  /* reserved for future use */
-            JSScript    *script;/* interpreted bytecode descriptor or null */
-            JSLocalNames names; /* argument and variable names */
+            uint16      nvars;    /* number of local variables */
+            uint16      nupvars;  /* number of upvars (computable from script
+                                     but here for faster access) */
+            JSScript    *script;  /* interpreted bytecode descriptor or null */
+            JSLocalNames names;   /* argument and variable names */
         } i;
     } u;
-    JSAtom          *atom;      /* name for diagnostics and decompiling */
+    JSAtom          *atom;        /* name for diagnostics and decompiling */
 };
 
 #define JSFUN_EXPR_CLOSURE   0x4000 /* expression closure: function(x)x*x */
 #define JSFUN_INTERPRETED    0x8000 /* use u.i if set, u.n if unset */
 
 #define JSFUN_SCRIPT_OR_FAST_NATIVE (JSFUN_INTERPRETED | JSFUN_FAST_NATIVE)
 
 #define FUN_OBJECT(fun)      (&(fun)->object)
@@ -200,46 +201,53 @@ js_PutArgsObject(JSContext *cx, JSStackF
 
 extern JSBool
 js_XDRFunction(JSXDRState *xdr, JSObject **objp);
 
 typedef enum JSLocalKind {
     JSLOCAL_NONE,
     JSLOCAL_ARG,
     JSLOCAL_VAR,
-    JSLOCAL_CONST
+    JSLOCAL_CONST,
+    JSLOCAL_UPVAR
 } JSLocalKind;
 
-#define JS_GET_LOCAL_NAME_COUNT(fun)    ((fun)->nargs + (fun)->u.i.nvars)
+#define JS_UPVAR_LOCAL_NAME_START(fun)  ((fun)->nargs + (fun)->u.i.nvars)
+#define JS_GET_LOCAL_NAME_COUNT(fun)    (JS_UPVAR_LOCAL_NAME_START(fun) +     \
+                                         (fun)->u.i.nupvars)
 
 extern JSBool
 js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind);
 
 /*
  * Look up an argument or variable name returning its kind when found or
  * JSLOCAL_NONE when no such name exists. When indexp is not null and the name
  * exists, *indexp will receive the index of the corresponding argument or
  * variable.
  */
 extern JSLocalKind
 js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp);
 
 /*
  * Functions to work with local names as an array of words.
  *
- * js_GetLocalNameArray returns the array or null when it cannot be allocated
- * The function must be called only when JS_GET_LOCAL_NAME_COUNT(fun) is not
- * zero. The function use the supplied pool to allocate the array.
+ * js_GetLocalNameArray returns the array, or null if we are out of memory.
+ * This function must not be called when JS_GET_LOCAL_NAME_COUNT(fun) is zero.
  *
- * The elements of the array with index below fun->nargs correspond to the
- * names of function arguments and of function variables otherwise. Use
- * JS_LOCAL_NAME_TO_ATOM to convert array's element into an atom. It can be
- * null when the element is an argument corresponding to a destructuring
- * pattern. For a variable use JS_LOCAL_NAME_IS_CONST to check if it
- * corresponds to the const declaration.
+ * The supplied pool is used to allocate the returned array, so the caller is
+ * obligated to mark and release to free it.
+ *
+ * The elements of the array with index less than fun->nargs correspond to the
+ * names of function formal parameters. An index >= fun->nargs addresses a var
+ * binding. Use JS_LOCAL_NAME_TO_ATOM to convert array's element to an atom
+ * pointer. This pointer can be null when the element is for a formal parameter
+ * corresponding to a destructuring pattern.
+ *
+ * If nameWord does not name a formal parameter, use JS_LOCAL_NAME_IS_CONST to
+ * check if nameWord corresponds to the const declaration.
  */
 extern jsuword *
 js_GetLocalNameArray(JSContext *cx, JSFunction *fun, struct JSArenaPool *pool);
 
 #define JS_LOCAL_NAME_TO_ATOM(nameWord)                                       \
     ((JSAtom *) ((nameWord) & ~(jsuword) 1))
 
 #define JS_LOCAL_NAME_IS_CONST(nameWord)                                      \
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -45,39 +45,42 @@
  * jsgc.h). It allocates from a special GC arena pool with each arena allocated
  * using malloc. It uses an ideally parallel array of flag bytes to hold the
  * mark bit, finalizer type index, etc.
  *
  * XXX swizzle page to freelist for better locality of reference
  */
 #include "jsstddef.h"
 #include <stdlib.h>     /* for free */
+#include <math.h>
 #include <string.h>     /* for memset used when DEBUG */
 #include "jstypes.h"
 #include "jsutil.h" /* Added by JSIFY */
 #include "jshash.h" /* Added by JSIFY */
+#include "jsbit.h"
+#include "jsclist.h"
+#include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
-#include "jsbit.h"
-#include "jsclist.h"
 #include "jscntxt.h"
 #include "jsconfig.h"
 #include "jsdbgapi.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsparse.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
+#include "jstracer.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 /*
  * Check if posix_memalign is available.
  */
@@ -1741,17 +1744,17 @@ js_NewGCThing(JSContext *cx, uintN flags
 
     doGC = (rt->gcMallocBytes >= rt->gcMaxMallocBytes && rt->gcPoke);
 #ifdef JS_GC_ZEAL
     doGC = doGC || rt->gcZeal >= 2 || (rt->gcZeal >= 1 && rt->gcPoke);
 #endif
 
     arenaList = &rt->gcArenaList[flindex];
     for (;;) {
-        if (doGC) {
+        if (doGC && !cx->gcDontBlock) {
             /*
              * Keep rt->gcLock across the call into js_GC so we don't starve
              * and lose to racing threads who deplete the heap just after
              * js_GC has replenished it (or has synchronized with a racing
              * GC that collected a bunch of garbage).  This unfair scheduling
              * can happen on certain operating systems. For the gory details,
              * see bug 162779 at https://bugzilla.mozilla.org/.
              */
@@ -1801,17 +1804,17 @@ js_NewGCThing(JSContext *cx, uintN flags
          */
         thingsLimit = THINGS_PER_ARENA(nbytes);
         if (arenaList->lastCount != thingsLimit) {
             JS_ASSERT(arenaList->lastCount < thingsLimit);
             a = arenaList->last;
         } else {
             a = NewGCArena(rt);
             if (!a) {
-                if (doGC)
+                if (doGC || cx->gcDontBlock)
                     goto fail;
                 doGC = JS_TRUE;
                 continue;
             }
             a->list = arenaList;
             a->prev = arenaList->last;
             a->prevUntracedPage = 0;
             a->u.untracedThings = 0;
@@ -1904,17 +1907,18 @@ js_NewGCThing(JSContext *cx, uintN flags
     return thing;
 
 fail:
 #ifdef JS_THREADSAFE
     if (gcLocked)
         JS_UNLOCK_GC(rt);
 #endif
     METER(astats->fail++);
-    JS_ReportOutOfMemory(cx);
+    if (!cx->gcDontBlock)
+        JS_ReportOutOfMemory(cx);
     return NULL;
 }
 
 static JSGCDoubleCell *
 RefillDoubleFreeList(JSContext *cx)
 {
     JSRuntime *rt;
     jsbitmap *doubleFlags, usedBits;
@@ -2729,16 +2733,17 @@ js_TraceStackFrame(JSTracer *trc, JSStac
                 JS_ASSERT(!(fp->fun->flags & JSFUN_FAST_NATIVE));
                 nslots += fp->fun->u.n.extra;
             }
             if (fp->fun->flags & JSFRAME_ROOTED_ARGV)
                 skip = 2 + fp->argc;
         }
         TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand");
     }
+
     JS_CALL_VALUE_TRACER(trc, fp->rval, "rval");
     if (fp->scopeChain)
         JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");
     if (fp->sharpArray)
         JS_CALL_OBJECT_TRACER(trc, fp->sharpArray, "sharp array");
 
     if (fp->xmlNamespace)
         JS_CALL_OBJECT_TRACER(trc, fp->xmlNamespace, "xmlNamespace");
@@ -2884,16 +2889,21 @@ js_TraceContext(JSTracer *trc, JSContext
         }
     }
 
     if (acx->sharpObjectMap.depth > 0)
         js_TraceSharpMap(trc, &acx->sharpObjectMap);
 }
 
 void
+js_TraceTraceMonitor(JSTracer *trc, JSTraceMonitor *tm)
+{
+}
+
+void
 js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
 {
     JSRuntime *rt = trc->context->runtime;
     JSContext *iter, *acx;
 
     JS_DHashTableEnumerate(&rt->gcRootsHash, gc_root_traversal, trc);
     if (rt->gcLocksHash)
         JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_traversal, trc);
@@ -2902,16 +2912,27 @@ js_TraceRuntime(JSTracer *trc, JSBool al
     js_TraceRuntimeNumberState(trc);
 
     iter = NULL;
     while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
         js_TraceContext(trc, acx);
 
     if (rt->gcExtraRootsTraceOp)
         rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
+
+#ifdef JS_THREADSAFE
+    /* Trace the loop table(s) which can contain pointers to code objects. */
+   while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
+       if (!acx->thread)
+           continue;
+       js_TraceTraceMonitor(trc, &acx->thread->traceMonitor);
+   }
+#else
+   js_TraceTraceMonitor(trc, &rt->traceMonitor);
+#endif
 }
 
 static void
 ProcessSetSlotRequest(JSContext *cx, JSSetSlotRequest *ssr)
 {
     JSObject *obj, *pobj;
     uint32 slot;
 
@@ -2978,16 +2999,28 @@ ProcessSetSlotRequest(JSContext *cx, JSS
             oldproto = STOBJ_GET_PROTO(scope->object);
         }
     }
 
     /* Finally, do the deed. */
     STOBJ_SET_SLOT(obj, slot, OBJECT_TO_JSVAL(pobj));
 }
 
+static void
+DestroyScriptsToGC(JSContext *cx, JSScript **listp)
+{
+    JSScript *script;
+
+    while ((script = *listp) != NULL) {
+        *listp = script->u.nextToGC;
+        script->u.nextToGC = NULL;
+        js_DestroyScript(cx, script);
+    }
+}
+
 /*
  * The gckind flag bit GC_LOCK_HELD indicates a call from js_NewGCThing with
  * rt->gcLock already held, so the lock should be kept on return.
  */
 void
 js_GC(JSContext *cx, JSGCInvocationKind gckind)
 {
     JSRuntime *rt;
@@ -3205,18 +3238,25 @@ js_GC(JSContext *cx, JSGCInvocationKind 
     rt->gcMallocBytes = 0;
 
 #ifdef JS_DUMP_SCOPE_METERS
   { extern void js_DumpScopeMeters(JSRuntime *rt);
     js_DumpScopeMeters(rt);
   }
 #endif
 
-    /* Clear property cache weak references. */
+    /* Clear property and JIT caches (only for cx->thread if JS_THREADSAFE). */
     js_FlushPropertyCache(cx);
+#ifdef JS_TRACER
+    js_FlushJITCache(cx);
+    js_FlushJITOracle(cx);
+#endif
+
+    /* Destroy eval'ed scripts. */
+    DestroyScriptsToGC(cx, &JS_SCRIPTS_TO_GC(cx));
 
 #ifdef JS_THREADSAFE
     /*
      * Set all thread local freelists to NULL. We may visit a thread's
      * freelist more than once. To avoid redundant clearing we unroll the
      * current thread's step.
      *
      * Also, in case a JSScript wrapped within an object was finalized, we
@@ -3228,16 +3268,20 @@ js_GC(JSContext *cx, JSGCInvocationKind 
     memset(cx->thread->gcFreeLists, 0, sizeof cx->thread->gcFreeLists);
     iter = NULL;
     while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
         if (!acx->thread || acx->thread == cx->thread)
             continue;
         memset(acx->thread->gcFreeLists, 0, sizeof acx->thread->gcFreeLists);
         GSN_CACHE_CLEAR(&acx->thread->gsnCache);
         js_FlushPropertyCache(acx);
+#ifdef JS_TRACER
+        js_FlushJITCache(acx);
+#endif
+        DestroyScriptsToGC(cx, &acx->thread->scriptsToGC);
     }
 #else
     /* The thread-unsafe case just has to clear the runtime's GSN cache. */
     GSN_CACHE_CLEAR(&rt->gsnCache);
 #endif
 
   restart:
     rt->gcNumber++;
@@ -3486,16 +3530,27 @@ js_GC(JSContext *cx, JSGCInvocationKind 
         JS_DumpBasicStats(&rt->lexicalScopeDepthStats, "lexical scope depth", fp);
 
         putc('\n', fp);
         fflush(fp);
     }
   }
 #endif /* JS_SCOPE_DEPTH_METER */
 
+#ifdef JS_DUMP_LOOP_STATS
+  { static FILE *lsfp;
+    if (!lsfp)
+        lsfp = fopen("/tmp/loopstats", "w");
+    if (lsfp) {
+        JS_DumpBasicStats(&rt->loopStats, "loops", lsfp);
+        fflush(lsfp);
+    }
+  }
+#endif /* JS_DUMP_LOOP_STATS */
+
     JS_LOCK_GC(rt);
 
     /*
      * We want to restart GC if js_GC was called recursively or if any of the
      * finalizers called js_RemoveRoot or js_UnlockGCThingRT.
      */
     if (rt->gcLevel > 1 || rt->gcPoke) {
         rt->gcLevel = 1;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -282,18 +282,18 @@ typedef enum JSGCInvocationKind {
 
     /*
      * Called from js_SetProtoOrParent with a request to set an object's proto
      * or parent slot inserted on rt->setSlotRequests.
      */
     GC_SET_SLOT_REQUEST = GC_LOCK_HELD | 1,
 
     /*
-     * Called from js_NewGCThing as a last-ditch GC attempt. See comments
-     * in jsgc.c just before js_GC's definition for details.
+     * Called from js_NewGCThing as a last-ditch GC attempt. See comments in
+     * jsgc.c just before js_GC's definition for details.
      */
     GC_LAST_DITCH       = GC_LOCK_HELD | 2
 } JSGCInvocationKind;
 
 extern void
 js_GC(JSContext *cx, JSGCInvocationKind gckind);
 
 /* Call this after succesful malloc of memory for GC-related things. */
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1,10 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
+ * vim: set ts=8 sw=4 et tw=79:
  *
  * ***** 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/
@@ -63,16 +63,19 @@
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
+#ifdef JS_TRACER
+#include "jstracer.h"
+#endif
 
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "jsdtracef.h"
 #endif
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
@@ -117,17 +120,17 @@ js_FillPropertyCache(JSContext *cx, JSOb
     ptrdiff_t pcoff;
     jsuword khash;
     JSAtom *atom;
     JSPropCacheEntry *entry;
 
     JS_ASSERT(!cx->runtime->gcRunning);
     cache = &JS_PROPERTY_CACHE(cx);
     pc = cx->fp->regs->pc;
-    if (cache->disabled) {
+    if (cache->disabled || (cx->fp->flags & JSFRAME_EVAL)) {
         PCMETER(cache->disfills++);
         *entryp = NULL;
         return;
     }
 
     /*
      * Check for fill from js_SetPropertyHelper where the setter removed sprop
      * from pobj's scope (via unwatch or delete, e.g.).
@@ -465,16 +468,17 @@ js_FlushPropertyCache(JSContext *cx)
         P(setpcmisses);
         P(slotchanges);
         P(setmisses);
         P(idmisses);
         P(komisses);
         P(vcmisses);
         P(misses);
         P(flushes);
+        P(pcpurges);
 # undef P
 
         fprintf(fp, "hit rates: pc %g%% (proto %g%%), set %g%%, ini %g%%, full %g%%\n",
                 (100. * cache->pchits) / cache->tests,
                 (100. * cache->protopchits) / cache->tests,
                 (100. * (cache->addpchits + cache->setpchits))
                 / cache->settests,
                 (100. * cache->inipchits) / cache->initests,
@@ -1218,17 +1222,17 @@ have_fun:
         do {
             *sp++ = JSVAL_VOID;
         } while (--i != 0);
     }
 
     /* Allocate space for local variables and stack of interpreted function. */
     if (script && script->nslots != 0) {
         if (!AllocateAfterSP(cx, sp, script->nslots)) {
-            /* NB: Discontinuity between argv and vars, stack slots. */
+            /* NB: Discontinuity between argv and slots, stack slots. */
             sp = js_AllocRawStack(cx, script->nslots, NULL);
             if (!sp) {
                 ok = JS_FALSE;
                 goto out2;
             }
         }
 
         /* Push void to initialize local variables. */
@@ -1295,16 +1299,17 @@ have_fun:
             frame.varobj = frame.down->varobj;
             frame.scopeChain = frame.down->scopeChain;
         }
 
         /* But ensure that we have a scope chain. */
         if (!frame.scopeChain)
             frame.scopeChain = parent;
 
+        frame.displaySave = NULL;
         ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);
         JS_RUNTIME_METER(cx->runtime, nativeCalls);
 #ifdef DEBUG_NOT_THROWING
         if (ok && !alreadyThrowing)
             ASSERT_NOT_THROWING(cx);
 #endif
     } else if (script) {
         /* Use parent scope so js_GetCallObject can find the right "Call". */
@@ -1312,20 +1317,22 @@ have_fun:
         if (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) {
             /* Scope with a call object parented by the callee's parent. */
             if (!js_GetCallObject(cx, &frame, parent)) {
                 ok = JS_FALSE;
                 goto out;
             }
         }
         frame.slots = sp - fun->u.i.nvars;
+
         ok = js_Interpret(cx);
     } else {
         /* fun might be onerror trying to report a syntax error in itself. */
         frame.scopeChain = NULL;
+        frame.displaySave = NULL;
         ok = JS_TRUE;
     }
 
 out:
     if (hookData) {
         hook = cx->debugHooks->callHook;
         if (hook)
             hook(cx, &frame, JS_FALSE, &ok, hookData);
@@ -1535,17 +1542,18 @@ js_Execute(JSContext *cx, JSObject *chai
     }
 
     if (hook) {
         hookData = hook(cx, &frame, JS_TRUE, 0,
                         cx->debugHooks->executeHookData);
     }
 
     ok = js_Interpret(cx);
-    *result = frame.rval;
+    if (result)
+        *result = frame.rval;
 
     if (hookData) {
         hook = cx->debugHooks->executeHook;
         if (hook)
             hook(cx, &frame, JS_FALSE, &ok, hookData);
     }
 
 out2:
@@ -2385,38 +2393,39 @@ JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(IN
     (__IBMC__ >= 700 && defined __IBM_COMPUTED_GOTO) ||                       \
     __SUNPRO_C >= 0x570)
 #  define JS_THREADED_INTERP 1
 # else
 #  define JS_THREADED_INTERP 0
 # endif
 #endif
 
-
 /*
  * Interpreter assumes the following to implement condition-free interrupt
  * implementation when !JS_THREADED_INTERP.
  */
 JS_STATIC_ASSERT(JSOP_INTERRUPT == 0);
 
 /*
  * Ensure that the intrepreter switch can close call-bytecode cases in the
  * same way as non-call bytecodes.
  */
 JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETGVAR_LENGTH == JSOP_CALLGVAR_LENGTH);
+JS_STATIC_ASSERT(JSOP_GETUPVAR_LENGTH == JSOP_CALLUPVAR_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
 JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
 JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
 
 /*
  * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
- * remain distinct for the decompiler.
+ * remain distinct for the decompiler. Ditto for JSOP_NULL{,THIS}.
  */
 JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
+JS_STATIC_ASSERT(JSOP_NULL_LENGTH == JSOP_NULLTHIS_LENGTH);
 
 /* Ensure we can share deffun and closure code. */
 JS_STATIC_ASSERT(JSOP_DEFFUN_LENGTH == JSOP_CLOSURE_LENGTH);
 
 /* See TRY_BRANCH_AFTER_COND. */
 JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
 JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
 
@@ -2477,33 +2486,55 @@ js_Interpret(JSContext *cx)
 #if JS_THREADED_INTERP
     static void *const normalJumpTable[] = {
 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
         JS_EXTENSION &&L_##op,
 # include "jsopcode.tbl"
 # undef OPDEF
     };
 
+#ifdef JS_TRACER
+    static void *const recordingJumpTable[] = {
+# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
+        JS_EXTENSION &&R_##op,
+# include "jsopcode.tbl"
+# undef OPDEF
+    };
+#endif /* JS_TRACER */
+
     static void *const interruptJumpTable[] = {
 # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)              \
         JS_EXTENSION &&L_JSOP_INTERRUPT,
 # include "jsopcode.tbl"
 # undef OPDEF
     };
 
     METER_OP_INIT(op);      /* to nullify first METER_OP_PAIR */
 
-# define DO_OP()            JS_EXTENSION_(goto *jumpTable[op])
+# ifdef JS_TRACER
+#  define CHECK_RECORDER()  JS_BEGIN_MACRO                                    \
+                                JS_ASSERT(!JS_TRACE_MONITOR(cx).recorder ^    \
+                                          (jumpTable == recordingJumpTable)); \
+                            JS_END_MACRO
+# else
+#  define CHECK_RECORDER()  ((void)0)
+# endif
+
+# define DO_OP()            JS_BEGIN_MACRO                                    \
+                                CHECK_RECORDER();                             \
+                                JS_EXTENSION_(goto *jumpTable[op]);           \
+                            JS_END_MACRO
 # define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
                                 METER_OP_PAIR(op, regs.pc[n]);                \
                                 op = (JSOp) *(regs.pc += (n));                \
                                 DO_OP();                                      \
                             JS_END_MACRO
 
-# define BEGIN_CASE(OP)     L_##OP:
+# define BEGIN_CASE(OP)     L_##OP:                                           \
+                                CHECK_RECORDER();
 # define END_CASE(OP)       DO_NEXT_OP(OP##_LENGTH);
 # define END_VARLEN_CASE    DO_NEXT_OP(len);
 # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)                                    \
                                 JS_ASSERT(js_CodeSpec[OP].length == 1);       \
                                 op = (JSOp) *++regs.pc;                       \
                                 DO_OP();
 
 # define END_EMPTY_CASES
@@ -2546,17 +2577,17 @@ js_Interpret(JSContext *cx)
     script = fp->script;
     JS_ASSERT(script->length != 0);
 
     /* Count of JS function calls that nest in this C js_Interpret frame. */
     inlineCallCount = 0;
 
     /*
      * Initialize the index segment register used by LOAD_ATOM and
-     * GET_FULL_INDEX macros bellow. As a register we use a pointer based on
+     * 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.
      */
     atoms = script->atomMap.vector;
 
 #define LOAD_ATOM(PCOFF)                                                      \
     JS_BEGIN_MACRO                                                            \
@@ -2570,65 +2601,132 @@ js_Interpret(JSContext *cx)
     (atoms - script->atomMap.vector + GET_INDEX(regs.pc + PCOFF))
 
 #define LOAD_OBJECT(PCOFF)                                                    \
     JS_GET_SCRIPT_OBJECT(script, GET_FULL_INDEX(PCOFF), obj)
 
 #define LOAD_FUNCTION(PCOFF)                                                  \
     JS_GET_SCRIPT_FUNCTION(script, GET_FULL_INDEX(PCOFF), fun)
 
+#ifdef JS_TRACER
+
+#define MONITOR_BRANCH(oldpc)                                                 \
+    JS_BEGIN_MACRO                                                            \
+        if (TRACING_ENABLED(cx)) {                                            \
+            ENABLE_TRACER(js_LoopEdge(cx, oldpc, inlineCallCount));           \
+            fp = cx->fp;                                                      \
+            script = fp->script;                                              \
+            atoms = script->atomMap.vector;                                   \
+            currentVersion = (JSVersion) script->version;                     \
+            JS_ASSERT(fp->regs == &regs);                                     \
+        }                                                                     \
+    JS_END_MACRO
+
+#else /* !JS_TRACER */
+
+#define MONITOR_BRANCH(oldpc) ((void) 0)
+
+#endif /* !JS_TRACER */
+
     /*
      * Prepare to call a user-supplied branch handler, and abort the script
      * if it returns false.
      */
-#define CHECK_BRANCH(len)                                                     \
+#define CHECK_BRANCH()                                                        \
     JS_BEGIN_MACRO                                                            \
-        if (len <= 0 && (cx->operationCount -= JSOW_SCRIPT_JUMP) <= 0) {      \
+        if ((cx->operationCount -= JSOW_SCRIPT_JUMP) <= 0) {                  \
             if (!js_ResetOperationCount(cx))                                  \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
+#define BRANCH(n)                                                             \
+    JS_BEGIN_MACRO                                                            \
+        regs.pc += n;                                                         \
+        if (n <= 0) {                                                         \
+            MONITOR_BRANCH(regs.pc - n);                                      \
+            CHECK_BRANCH();                                                   \
+        }                                                                     \
+        op = (JSOp) *regs.pc;                                                 \
+        DO_OP();                                                              \
+    JS_END_MACRO
+
+    /* From this point control must flow through the label exit. */
+    ++cx->interpLevel;
 
     /*
-     * From this point control must flow through the label exit.
-     *
      * Optimized Get and SetVersion for proper script language versioning.
      *
      * If any native method or JSClass/JSObjectOps hook calls js_SetVersion
      * and changes cx->version, the effect will "stick" and we will stop
      * maintaining currentVersion.  This is relied upon by testsuites, for
      * the most part -- web browsers select version before compiling and not
      * at run-time.
      */
     currentVersion = (JSVersion) script->version;
     originalVersion = (JSVersion) cx->version;
     if (currentVersion != originalVersion)
         js_SetVersion(cx, currentVersion);
 
-    ++cx->interpLevel;
+    /* Update the static-link display. */
+    if (script->staticDepth < JS_DISPLAY_SIZE) {
+        JSStackFrame **disp = &cx->display[script->staticDepth];
+        fp->displaySave = *disp;
+        *disp = fp;
+    }
 #ifdef DEBUG
     fp->pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled;
 #endif
 
     /*
      * Load the debugger's interrupt hook here and after calling out to native
      * functions (but not to getters, setters, or other native hooks), so we do
      * not have to reload it each time through the interpreter loop -- we hope
      * the compiler can keep it in a register when it is non-null.
      */
 #if JS_THREADED_INTERP
+#ifdef JS_TRACER
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (jumpTable = (cx)->debugHooks->interruptHandler                   \
+                         ? interruptJumpTable                                 \
+                         : JS_TRACE_MONITOR(cx).recorder                      \
+                         ? recordingJumpTable                                 \
+                         : normalJumpTable))
+# define ENABLE_TRACER(flag)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        bool flag_ = (flag);                                                  \
+        JS_ASSERT(flag_ == !!JS_TRACE_MONITOR(cx).recorder);                  \
+        jumpTable = flag_ ? recordingJumpTable : normalJumpTable;             \
+    JS_END_MACRO
+#else /* !JS_TRACER */
 # define LOAD_INTERRUPT_HANDLER(cx)                                           \
     ((void) (jumpTable = (cx)->debugHooks->interruptHandler                   \
                          ? interruptJumpTable                                 \
                          : normalJumpTable))
-#else
+# define ENABLE_TRACER(flag) ((void)0)
+#endif /* !JS_TRACER */
+#else /* !JS_THREADED_INTERP */
+#ifdef JS_TRACER
 # define LOAD_INTERRUPT_HANDLER(cx)                                           \
-    ((void) (switchMask = (cx)->debugHooks->interruptHandler ? 0 : 255))
-#endif
+    ((void) (switchMask = ((cx)->debugHooks->interruptHandler ||              \
+                           JS_TRACE_MONITOR(cx).recorder)                     \
+                          ? 0 : 255))
+# define ENABLE_TRACER(flag)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        bool flag_ = (flag);                                                  \
+        JS_ASSERT(flag_ == !!JS_TRACE_MONITOR(cx).recorder);                  \
+        switchMask = flag_ ? 0 : 255;                                         \
+    JS_END_MACRO
+#else /* !JS_TRACER */
+# define LOAD_INTERRUPT_HANDLER(cx)                                           \
+    ((void) (switchMask = ((cx)->debugHooks->interruptHandler                 \
+                           ? 0 : 255)))
+# define ENABLE_TRACER(flag) ((void)0)
+#endif /* !JS_TRACER */
+#endif /* !JS_THREADED_INTERP */
 
     LOAD_INTERRUPT_HANDLER(cx);
 
     /* Initialize the pc and pc registers unless we're resuming a generator. */
     if (JS_LIKELY(!fp->regs)) {
         ASSERT_NOT_THROWING(cx);
         regs.pc = script->code;
         regs.sp = StackBase(fp);
@@ -2715,16 +2813,23 @@ js_Interpret(JSContext *cx)
                     ok = JS_TRUE;
                     goto forced_return;
                   case JSTRAP_THROW:
                     cx->throwing = JS_TRUE;
                     cx->exception = rval;
                     goto error;
                   default:;
                 }
+#if !JS_THREADED_INTERP
+            } else {
+                /* this was not a real interrupt, the tracer is trying to
+                   record a trace */
+                switchOp = op + 256;
+                goto do_switch;
+#endif
             }
             LOAD_INTERRUPT_HANDLER(cx);
 
 #if JS_THREADED_INTERP
             JS_EXTENSION_(goto *normalJumpTable[op]);
 #else
             switchOp = op;
             goto do_switch;
@@ -2802,17 +2907,17 @@ js_Interpret(JSContext *cx)
 
           BEGIN_CASE(JSOP_LEAVEWITH)
             JS_ASSERT(regs.sp[-1] == OBJECT_TO_JSVAL(fp->scopeChain));
             regs.sp--;
             js_LeaveWith(cx);
           END_CASE(JSOP_LEAVEWITH)
 
           BEGIN_CASE(JSOP_RETURN)
-            CHECK_BRANCH(-1);
+            CHECK_BRANCH();
             fp->rval = POP_OPND();
             /* FALL THROUGH */
 
           BEGIN_CASE(JSOP_RETRVAL)    /* fp->rval already set */
           BEGIN_CASE(JSOP_STOP)
             /*
              * When the inlined frame exits with an exception or an error, ok
              * will be false after the inline_return label.
@@ -2825,16 +2930,19 @@ js_Interpret(JSContext *cx)
             {
                 JSInlineFrame *ifp = (JSInlineFrame *) fp;
                 void *hookData = ifp->hookData;
 
                 JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
                 JS_ASSERT(!fp->blockChain);
                 JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
 
+                if (script->staticDepth < JS_DISPLAY_SIZE)
+                    cx->display[script->staticDepth] = fp->displaySave;
+
                 if (hookData) {
                     JSInterpreterHook hook;
                     JSBool status;
 
                     hook = cx->debugHooks->callHook;
                     if (hook) {
                         /*
                          * Do not pass &ok directly as exposing the address
@@ -2869,16 +2977,27 @@ js_Interpret(JSContext *cx)
 
                 /* Restore context version only if callee hasn't set version. */
                 if (JS_LIKELY(cx->version == currentVersion)) {
                     currentVersion = ifp->callerVersion;
                     if (currentVersion != cx->version)
                         js_SetVersion(cx, currentVersion);
                 }
 
+                /*
+                 * If inline-constructing, replace primitive rval with the new
+                 * object passed in via |this|, and instrument this constructor
+                 * invocation
+                 */
+                if (fp->flags & JSFRAME_CONSTRUCTING) {
+                    if (JSVAL_IS_PRIMITIVE(fp->rval))
+                        fp->rval = OBJECT_TO_JSVAL(fp->thisp);
+                    JS_RUNTIME_METER(cx->runtime, constructs);
+                }
+
                 /* Restore caller's registers. */
                 regs = ifp->callerRegs;
 
                 /* Store the return value in the caller's operand frame. */
                 regs.sp -= 1 + (size_t) ifp->frame.argc;
                 regs.sp[-1] = fp->rval;
 
                 /* Restore cx->fp and release the inline frame's space. */
@@ -2889,47 +3008,49 @@ js_Interpret(JSContext *cx)
 
                 /* Restore the calling script's interpreter registers. */
                 script = fp->script;
                 atoms = script->atomMap.vector;
 
                 /* Resume execution in the calling frame. */
                 inlineCallCount--;
                 if (JS_LIKELY(ok)) {
+#ifdef JS_TRACER
+                    if (JS_TRACE_MONITOR(cx).recorder)
+                        RECORD(LeaveFrame);
+#endif
                     JS_ASSERT(js_CodeSpec[*regs.pc].length == JSOP_CALL_LENGTH);
                     len = JSOP_CALL_LENGTH;
                     DO_NEXT_OP(len);
                 }
                 goto error;
             }
             goto exit;
 
           BEGIN_CASE(JSOP_DEFAULT)
             (void) POP();
             /* FALL THROUGH */
           BEGIN_CASE(JSOP_GOTO)
             len = GET_JUMP_OFFSET(regs.pc);
-            CHECK_BRANCH(len);
-          END_VARLEN_CASE
+            BRANCH(len);
+          END_CASE(JSOP_GOTO)
 
           BEGIN_CASE(JSOP_IFEQ)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_FALSE) {
                 len = GET_JUMP_OFFSET(regs.pc);
-                CHECK_BRANCH(len);
-                DO_NEXT_OP(len);
+                BRANCH(len);
             }
           END_CASE(JSOP_IFEQ)
 
           BEGIN_CASE(JSOP_IFNE)
             POP_BOOLEAN(cx, rval, cond);
             if (cond != JS_FALSE) {
                 len = GET_JUMP_OFFSET(regs.pc);
-                CHECK_BRANCH(len);
-                DO_NEXT_OP(len);
+                BRANCH(len);
             }
           END_CASE(JSOP_IFNE)
 
           BEGIN_CASE(JSOP_OR)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_TRUE) {
                 len = GET_JUMP_OFFSET(regs.pc);
                 PUSH_OPND(rval);
@@ -2946,34 +3067,32 @@ js_Interpret(JSContext *cx)
             }
           END_CASE(JSOP_AND)
 
           BEGIN_CASE(JSOP_DEFAULTX)
             (void) POP();
             /* FALL THROUGH */
           BEGIN_CASE(JSOP_GOTOX)
             len = GET_JUMPX_OFFSET(regs.pc);
-            CHECK_BRANCH(len);
-          END_VARLEN_CASE
+            BRANCH(len);
+          END_CASE(JSOP_GOTOX);
 
           BEGIN_CASE(JSOP_IFEQX)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_FALSE) {
                 len = GET_JUMPX_OFFSET(regs.pc);
-                CHECK_BRANCH(len);
-                DO_NEXT_OP(len);
+                BRANCH(len);
             }
           END_CASE(JSOP_IFEQX)
 
           BEGIN_CASE(JSOP_IFNEX)
             POP_BOOLEAN(cx, rval, cond);
             if (cond != JS_FALSE) {
                 len = GET_JUMPX_OFFSET(regs.pc);
-                CHECK_BRANCH(len);
-                DO_NEXT_OP(len);
+                BRANCH(len);
             }
           END_CASE(JSOP_IFNEX)
 
           BEGIN_CASE(JSOP_ORX)
             POP_BOOLEAN(cx, rval, cond);
             if (cond == JS_TRUE) {
                 len = GET_JUMPX_OFFSET(regs.pc);
                 PUSH_OPND(rval);
@@ -3370,18 +3489,17 @@ js_Interpret(JSContext *cx)
         uintN diff_;                                                          \
         JS_ASSERT(js_CodeSpec[op].length == 1);                               \
         diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ;                       \
         if (diff_ <= 1) {                                                     \
             regs.sp -= spdec;                                                 \
             if (cond == (diff_ != 0)) {                                       \
                 ++regs.pc;                                                    \
                 len = GET_JUMP_OFFSET(regs.pc);                               \
-                CHECK_BRANCH(len);                                            \
-                DO_NEXT_OP(len);                                              \
+                BRANCH(len);                                                  \
             }                                                                 \
             len = 1 + JSOP_IFEQ_LENGTH;                                       \
             DO_NEXT_OP(len);                                                  \
         }                                                                     \
     JS_END_MACRO
 
 #define RELATIONAL_OP(OP)                                                     \
     JS_BEGIN_MACRO                                                            \
@@ -3524,29 +3642,27 @@ js_Interpret(JSContext *cx)
             STRICT_EQUALITY_OP(!=);
           END_CASE(JSOP_STRICTNE)
 
           BEGIN_CASE(JSOP_CASE)
             STRICT_EQUALITY_OP(==);
             (void) POP();
             if (cond) {
                 len = GET_JUMP_OFFSET(regs.pc);
-                CHECK_BRANCH(len);
-                DO_NEXT_OP(len);
+                BRANCH(len);
             }
             PUSH(lval);
           END_CASE(JSOP_CASE)
 
           BEGIN_CASE(JSOP_CASEX)
             STRICT_EQUALITY_OP(==);
             (void) POP();
             if (cond) {
                 len = GET_JUMPX_OFFSET(regs.pc);
-                CHECK_BRANCH(len);
-                DO_NEXT_OP(len);
+                BRANCH(len);
             }
             PUSH(lval);
           END_CASE(JSOP_CASEX)
 
           BEGIN_CASE(JSOP_LT)
             RELATIONAL_OP(<);
           END_CASE(JSOP_LT)
 
@@ -3765,28 +3881,16 @@ js_Interpret(JSContext *cx)
                     if (!js_NewNumberInRootedValue(cx, d, &regs.sp[-1]))
                         goto error;
                 } else {
                     JS_ASSERT(JSVAL_IS_NUMBER(rval));
                 }
             }
           END_CASE(JSOP_POS)
 
-          BEGIN_CASE(JSOP_NEW)
-            /* Get immediate argc and find the constructor function. */
-            argc = GET_ARGC(regs.pc);
-            vp = regs.sp - (2 + argc);
-            JS_ASSERT(vp >= StackBase(fp));
-
-            if (!js_InvokeConstructor(cx, argc, vp))
-                goto error;
-            regs.sp = vp + 1;
-            LOAD_INTERRUPT_HANDLER(cx);
-          END_CASE(JSOP_NEW)
-
           BEGIN_CASE(JSOP_DELNAME)
             LOAD_ATOM(0);
             id = ATOM_TO_JSID(atom);
             if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
                 goto error;
 
             /* ECMA says to return true if name is undefined or inherited. */
             PUSH_OPND(JSVAL_TRUE);
@@ -4109,22 +4213,24 @@ js_Interpret(JSContext *cx)
           do_getprop_body:
             lval = FETCH_OPND(-1);
 
           do_getprop_with_lval:
             VALUE_TO_OBJECT(cx, -1, lval, obj);
 
           do_getprop_with_obj:
             do {
+                JSObject *aobj;
                 JSPropCacheEntry *entry;
 
-                if (JS_LIKELY(obj->map->ops->getProperty == js_GetProperty)) {
-                    PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom);
+                aobj = OBJ_IS_DENSE_ARRAY(cx, obj) ? OBJ_GET_PROTO(cx, obj) : obj;
+                if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) {
+                    PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom);
                     if (!atom) {
-                        ASSERT_VALID_PROPERTY_CACHE_HIT(i, obj, obj2, entry);
+                        ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry);
                         if (PCVAL_IS_OBJECT(entry->vword)) {
                             rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
                         } else if (PCVAL_IS_SLOT(entry->vword)) {
                             slot = PCVAL_TO_SLOT(entry->vword);
                             JS_ASSERT(slot < obj2->map->freeslot);
                             rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
                         } else {
                             JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
@@ -4138,17 +4244,17 @@ js_Interpret(JSContext *cx)
                     entry = NULL;
                     if (i < 0)
                         atom = rt->atomState.lengthAtom;
                     else
                         LOAD_ATOM(i);
                 }
                 id = ATOM_TO_JSID(atom);
                 if (entry
-                    ? !js_GetPropertyHelper(cx, obj, id, &rval, &entry)
+                    ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry)
                     : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
                     goto error;
                 }
             } while (0);
 
             STORE_OPND(-1, rval);
             JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length);
             len = JSOP_GETPROP_LENGTH + i;
@@ -4245,17 +4351,17 @@ js_Interpret(JSContext *cx)
                     JSXMLObjectOps *ops;
 
                     ops = (JSXMLObjectOps *) obj->map->ops;
                     obj = ops->getMethod(cx, obj, id, &rval);
                     if (!obj)
                         goto error;
                 } else
 #endif
-                if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
+                if (entry
                     ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry)
                     : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
                     goto error;
                 }
                 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
                 STORE_OPND(-2, rval);
             } else {
                 JS_ASSERT(obj->map->ops->getProperty == js_GetProperty);
@@ -4583,26 +4689,74 @@ js_Interpret(JSContext *cx)
             rval = FETCH_OPND(-3);
             FETCH_OBJECT(cx, -2, lval, obj);
             FETCH_ELEMENT_ID(obj, -1, id);
             if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
                 goto error;
             regs.sp -= 3;
           END_CASE(JSOP_ENUMELEM)
 
+          BEGIN_CASE(JSOP_NEW)
+            /* Get immediate argc and find the constructor function. */
+            argc = GET_ARGC(regs.pc);
+            vp = regs.sp - (2 + argc);
+            JS_ASSERT(vp >= StackBase(fp));
+
+            /*
+             * Assign lval, obj, and fun exactly as the code at inline_call:
+             * expects to find them, to avoid nesting a js_Interpret call via
+             * js_InvokeConstructor.
+             */
+            lval = *vp;
+            if (VALUE_IS_FUNCTION(cx, lval)) {
+                obj = JSVAL_TO_OBJECT(lval);
+                fun = GET_FUNCTION_PRIVATE(cx, obj);
+                if (FUN_INTERPRETED(fun)) {
+                    /* Root as we go using vp[1]. */
+                    if (!OBJ_GET_PROPERTY(cx, obj,
+                                          ATOM_TO_JSID(cx->runtime->atomState
+                                                       .classPrototypeAtom),
+                                          &vp[1])) {
+                        goto error;
+                    }
+                    rval = vp[1];
+                    obj2 = js_NewObject(cx, &js_ObjectClass,
+                                        JSVAL_IS_OBJECT(rval)
+                                        ? JSVAL_TO_OBJECT(rval)
+                                        : NULL,
+                                        OBJ_GET_PARENT(cx, obj),
+                                        0);
+                    if (!obj2)
+                        goto error;
+                    vp[1] = OBJECT_TO_JSVAL(obj2);
+                    flags = JSFRAME_CONSTRUCTING;
+                    goto inline_call;
+                }
+            }
+
+            if (!js_InvokeConstructor(cx, argc, vp))
+                goto error;
+            regs.sp = vp + 1;
+            LOAD_INTERRUPT_HANDLER(cx);
+          END_CASE(JSOP_NEW)
+
           BEGIN_CASE(JSOP_CALL)
           BEGIN_CASE(JSOP_EVAL)
             argc = GET_ARGC(regs.pc);
             vp = regs.sp - (argc + 2);
             lval = *vp;
             if (VALUE_IS_FUNCTION(cx, lval)) {
                 obj = JSVAL_TO_OBJECT(lval);
                 fun = GET_FUNCTION_PRIVATE(cx, obj);
 
-                if (FUN_INTERPRETED(fun)) {
+                /* Clear frame flags since this is not a constructor call. */
+                flags = 0;
+                if (FUN_INTERPRETED(fun))
+              inline_call:
+                {
                     uintN nframeslots, nvars, missing;
                     JSArena *a;
                     jsuword nbytes;
                     void *newmark;
                     jsval *newsp;
                     JSInlineFrame *newifp;
                     JSInterpreterHook hook;
 
@@ -4635,17 +4789,17 @@ js_Interpret(JSContext *cx)
                             } while (newsp != regs.sp);
                             missing = 0;
                         } else {
                             missing = fun->nargs - argc;
                             nbytes += (2 + fun->nargs) * sizeof(jsval);
                         }
                     }
 
-                    /* Allocate the inline frame with its vars and operands. */
+                    /* Allocate the inline frame with its slots and operands. */
                     if (a->avail + nbytes <= a->limit) {
                         newsp = (jsval *) a->avail;
                         a->avail += nbytes;
                         JS_ASSERT(missing == 0);
                     } else {
                         JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool,
                                                nbytes);
                         if (!newsp) {
@@ -4679,20 +4833,25 @@ js_Interpret(JSContext *cx)
                     newifp->frame.argc = argc;
                     newifp->frame.argv = vp + 2;
                     newifp->frame.rval = JSVAL_VOID;
                     newifp->frame.down = fp;
                     newifp->frame.annotation = NULL;
                     newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj);
                     newifp->frame.sharpDepth = 0;
                     newifp->frame.sharpArray = NULL;
-                    newifp->frame.flags = 0;
+                    newifp->frame.flags = flags;
                     newifp->frame.dormantNext = NULL;
                     newifp->frame.xmlNamespace = NULL;
                     newifp->frame.blockChain = NULL;
+                    if (script->staticDepth < JS_DISPLAY_SIZE) {
+                        JSStackFrame **disp = &cx->display[script->staticDepth];
+                        newifp->frame.displaySave = *disp;
+                        *disp = &newifp->frame;
+                    }
 #ifdef DEBUG
                     newifp->frame.pcDisabledSave =
                         JS_PROPERTY_CACHE(cx).disabled;
 #endif
                     newifp->mark = newmark;
 
                     /* Compute the 'this' parameter now that argv is set. */
                     JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
@@ -4734,16 +4893,21 @@ js_Interpret(JSContext *cx)
                     /* Push the frame and set interpreter registers. */
                     newifp->callerRegs = regs;
                     fp->regs = &newifp->callerRegs;
                     regs.sp = newsp;
                     regs.pc = script->code;
                     newifp->frame.regs = &regs;
                     cx->fp = fp = &newifp->frame;
 
+#ifdef JS_TRACER
+                    if (JS_TRACE_MONITOR(cx).recorder)
+                        RECORD(EnterFrame);
+#endif
+
                     inlineCallCount++;
                     JS_RUNTIME_METER(rt, inlineCalls);
 
 #ifdef INCLUDE_MOZILLA_DTRACE
                     /* DTrace function entry, inlines */
                     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
                         jsdtrace_function_entry(cx, fp, fun);
                     if (JAVASCRIPT_FUNCTION_INFO_ENABLED())
@@ -4784,19 +4948,19 @@ js_Interpret(JSContext *cx)
 #ifdef INCLUDE_MOZILLA_DTRACE
                     if (VALUE_IS_FUNCTION(cx, lval)) {
                         if (JAVASCRIPT_FUNCTION_RVAL_ENABLED())
                             jsdtrace_function_rval(cx, fp, fun);
                         if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
                             jsdtrace_function_return(cx, fp, fun);
                     }
 #endif
+                    regs.sp = vp + 1;
                     if (!ok)
                         goto error;
-                    regs.sp = vp + 1;
                     goto end_call;
                 }
             }
 
             ok = js_Invoke(cx, argc, vp, 0);
 #ifdef INCLUDE_MOZILLA_DTRACE
             /* DTrace function return, non-inlines */
             if (VALUE_IS_FUNCTION(cx, lval)) {
@@ -5029,21 +5193,23 @@ js_Interpret(JSContext *cx)
             index = GET_FULL_INDEX(0);
             JS_ASSERT(index < JS_SCRIPT_REGEXPS(script)->length);
 
             slot = index;
             if (fp->fun) {
                 /*
                  * We're in function code, not global or eval code (in eval
                  * code, JSOP_REGEXP is never emitted). The cloned funobj
-                 * contains script->regexps->nregexps reserved slot for the
-                 * cloned regexps, see fun_reserveSlots, jsfun.c.
+                 * contains JS_SCRIPT_REGEXPS(script)->length reserved slots
+                 * for the cloned regexps; see fun_reserveSlots, jsfun.c.
                  */
                 funobj = fp->callee;
                 slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
+                if (script->upvarsOffset != 0)
+                    slot += JS_SCRIPT_UPVARS(script)->length;
                 if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
                     goto error;
                 if (JSVAL_IS_VOID(rval))
                     rval = JSVAL_NULL;
             } else {
                 /*
                  * We're in global code. The code generator reserved a slot
                  * for the regexp among script->nfixed slots. All such slots
@@ -5114,16 +5280,17 @@ js_Interpret(JSContext *cx)
             PUSH_OPND(JSVAL_ZERO);
           END_CASE(JSOP_ZERO)
 
           BEGIN_CASE(JSOP_ONE)
             PUSH_OPND(JSVAL_ONE);
           END_CASE(JSOP_ONE)
 
           BEGIN_CASE(JSOP_NULL)
+          BEGIN_CASE(JSOP_NULLTHIS)
             PUSH_OPND(JSVAL_NULL);
           END_CASE(JSOP_NULL)
 
           BEGIN_CASE(JSOP_FALSE)
             PUSH_OPND(JSVAL_FALSE);
           END_CASE(JSOP_FALSE)
 
           BEGIN_CASE(JSOP_TRUE)
@@ -5336,41 +5503,70 @@ js_Interpret(JSContext *cx)
           BEGIN_CASE(JSOP_SETLOCAL)
             slot = GET_SLOTNO(regs.pc);
             JS_ASSERT(slot < script->nslots);
             vp = &fp->slots[slot];
             GC_POKE(cx, *vp);
             *vp = FETCH_OPND(-1);
           END_SET_CASE(JSOP_SETLOCAL)
 
+          BEGIN_CASE(JSOP_GETUPVAR)
+          BEGIN_CASE(JSOP_CALLUPVAR)
+          {
+            JSUpvarArray *uva;
+            uint32 skip;
+            JSStackFrame *fp2;
+
+            index = GET_UINT16(regs.pc);
+            uva = JS_SCRIPT_UPVARS(script);
+            JS_ASSERT(index < uva->length);
+            skip = UPVAR_FRAME_SKIP(uva->vector[index]);
+            fp2 = cx->display[script->staticDepth - skip];
+            JS_ASSERT(fp2->fun && fp2->script);
+
+            slot = UPVAR_FRAME_SLOT(uva->vector[index]);
+            if (slot < fp2->fun->nargs) {
+                vp = fp2->argv;
+            } else {
+                slot -= fp2->fun->nargs;
+                JS_ASSERT(slot < fp2->script->nslots);
+                vp = fp2->slots;
+            }
+
+            PUSH_OPND(vp[slot]);
+            if (op == JSOP_CALLUPVAR)
+                PUSH_OPND(JSVAL_NULL);
+          }
+          END_CASE(JSOP_GETUPVAR)
+
           BEGIN_CASE(JSOP_GETGVAR)
           BEGIN_CASE(JSOP_CALLGVAR)
             slot = GET_SLOTNO(regs.pc);
             JS_ASSERT(slot < GlobalVarCount(fp));
             METER_SLOT_OP(op, slot);
             lval = fp->slots[slot];
             if (JSVAL_IS_NULL(lval)) {
                 op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME;
                 DO_OP();
             }
+            obj = fp->varobj;
             slot = JSVAL_TO_INT(lval);
-            obj = fp->varobj;
             rval = OBJ_GET_SLOT(cx, obj, slot);
             PUSH_OPND(rval);
             if (op == JSOP_CALLGVAR)
                 PUSH_OPND(OBJECT_TO_JSVAL(obj));
           END_CASE(JSOP_GETGVAR)
 
           BEGIN_CASE(JSOP_SETGVAR)
             slot = GET_SLOTNO(regs.pc);
             JS_ASSERT(slot < GlobalVarCount(fp));
             METER_SLOT_OP(op, slot);
             rval = FETCH_OPND(-1);
+            obj = fp->varobj;
             lval = fp->slots[slot];
-            obj = fp->varobj;
             if (JSVAL_IS_NULL(lval)) {
                 /*
                  * Inline-clone and deoptimize JSOP_SETNAME code here because
                  * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval]
                  * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
                  */
                 LOAD_ATOM(0);
                 id = ATOM_TO_JSID(atom);
@@ -5523,40 +5719,67 @@ js_Interpret(JSContext *cx)
 
             /*
              * We define the function as a property of the variable object and
              * not the current scope chain even for the case of function
              * expression statements and functions defined by eval inside let
              * or with blocks.
              */
             parent = fp->varobj;
+            if (!parent)
+                goto error;
 
             /*
              * Check for a const property of the same name -- or any kind
              * of property if executing with the strict option.  We check
              * here at runtime as well as at compile-time, to handle eval
              * as well as multiple HTML script tags.
              */
             id = ATOM_TO_JSID(fun->atom);
             ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
             if (ok) {
                 if (attrs == JSPROP_ENUMERATE) {
                     JS_ASSERT(fp->flags & JSFRAME_EVAL);
                     JS_ASSERT(op == JSOP_CLOSURE);
                     ok = OBJ_SET_PROPERTY(cx, parent, id, &rval);
                 } else {
+                    JS_ASSERT(attrs & JSPROP_PERMANENT);
+
                     ok = OBJ_DEFINE_PROPERTY(cx, parent, id, rval,
                                              (flags & JSPROP_GETTER)
                                              ? JS_EXTENSION (JSPropertyOp) obj
                                              : JS_PropertyStub,
                                              (flags & JSPROP_SETTER)
                                              ? JS_EXTENSION (JSPropertyOp) obj
                                              : JS_PropertyStub,
                                              attrs,
-                                             NULL);
+                                             &prop);
+
+                    /*
+                     * Try to optimize a property we either just created, or
+                     * found directly in the global object, that is permanent,
+                     * has a slot, and has stub getter and setter, into a
+                     * "fast global" accessed by the JSOP_*GVAR opcodes.
+                     */
+                    if (ok && index < script->nfixed) {
+                        JS_ASSERT(OBJ_IS_NATIVE(obj));
+                        sprop = (JSScopeProperty *) prop;
+                        if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) &&
+                            SPROP_HAS_STUB_GETTER(sprop) &&
+                            SPROP_HAS_STUB_SETTER(sprop)) {
+                            /*
+                             * Fast globals use fp->slots to map the global
+                             * name's atom index to the permanent fp->varobj
+                             * slot number, tagged as a jsval. The atom index
+                             * for the global's name literal is identical to
+                             * its fp->slots index.
+                             */
+                            fp->slots[index] = INT_TO_JSVAL(sprop->slot);
+                        }
+                    }
                 }
             }
 
             /* Restore fp->scopeChain now that obj is defined in fp->varobj. */
             fp->scopeChain = obj2;
             if (!ok) {
                 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
                 goto error;
@@ -5574,19 +5797,22 @@ js_Interpret(JSContext *cx)
              * a call object for the outer function's activation.
              */
             slot = GET_SLOTNO(regs.pc);
 
             parent = js_GetScopeChain(cx, fp);
             if (!parent)
                 goto error;
 
-            obj = js_CloneFunctionObject(cx, fun, parent);
-            if (!obj)
-                goto error;
+            obj = FUN_OBJECT(fun);
+            if (OBJ_GET_PARENT(cx, obj) != parent) {
+                obj = js_CloneFunctionObject(cx, fun, parent);
+                if (!obj)
+                    goto error;
+            }
 
             fp->slots[slot] = OBJECT_TO_JSVAL(obj);
           END_CASE(JSOP_DEFLOCALFUN)
 
           BEGIN_CASE(JSOP_ANONFUNOBJ)
             /* Load the specified function object literal. */
             LOAD_FUNCTION(0);
 
@@ -6316,18 +6542,17 @@ js_Interpret(JSContext *cx)
                  * to root temporaries.
                  */
                 JS_ASSERT(VALUE_IS_XML(cx, regs.sp[-1]));
                 if (!js_EnterWith(cx, -2))
                     goto error;
                 regs.sp--;
                 len = GET_JUMP_OFFSET(regs.pc);
                 JS_ASSERT(len < 0);
-                CHECK_BRANCH(len);
-                DO_NEXT_OP(len);
+                BRANCH(len);
             }
             regs.sp--;
           END_CASE(JSOP_ENDFILTER);
 
           BEGIN_CASE(JSOP_TOXML)
             rval = FETCH_OPND(-1);
             obj = js_ValueToXMLObject(cx, rval);
             if (!obj)
@@ -6590,44 +6815,55 @@ js_Interpret(JSContext *cx)
           L_JSOP_TOATTRNAME:
           L_JSOP_QNAME:
           L_JSOP_QNAMECONST:
           L_JSOP_QNAMEPART:
           L_JSOP_ANYNAME:
           L_JSOP_DEFXMLNS:
 # endif
 
-          L_JSOP_UNUSED75:
           L_JSOP_UNUSED76:
           L_JSOP_UNUSED77:
           L_JSOP_UNUSED78:
           L_JSOP_UNUSED79:
-          L_JSOP_UNUSED186:
           L_JSOP_UNUSED201:
           L_JSOP_UNUSED202:
           L_JSOP_UNUSED203:
           L_JSOP_UNUSED204:
           L_JSOP_UNUSED205:
           L_JSOP_UNUSED206:
           L_JSOP_UNUSED207:
-          L_JSOP_UNUSED213:
           L_JSOP_UNUSED219:
           L_JSOP_UNUSED226:
 
 #else /* !JS_THREADED_INTERP */
           default:
 #endif
           {
             char numBuf[12];
             JS_snprintf(numBuf, sizeof numBuf, "%d", op);
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_BAD_BYTECODE, numBuf);
             goto error;
           }
 
+#ifdef JS_TRACER
+
+#if JS_THREADED_INTERP
+# define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format)               \
+    R_##x: RECORD(x); goto L_##x;
+#else
+# define OPDEF(x,val,name,token,length,nuses,ndefs,prec,format)               \
+    case 256 + x: RECORD(x); op = x; switchOp = x; goto do_switch;
+#endif
+#include "jsopcode.tbl"
+#undef OPDEF
+
+#endif /* JS_TRACER */
+
 #if !JS_THREADED_INTERP
 
         } /* switch (op) */
     }
 #endif /* !JS_THREADED_INTERP */
 
   error:
     JS_ASSERT((size_t)(regs.pc - script->code) < script->length);
@@ -6797,34 +7033,41 @@ js_Interpret(JSContext *cx)
      * (c) a generator (SendToGenerator, jsiter.c).
      *
      * We must not be in an inline frame. The check above ensures that for the
      * error case and for a normal return, the code jumps directly to parent's
      * frame pc.
      */
     JS_ASSERT(inlineCallCount == 0);
     JS_ASSERT(fp->regs == &regs);
+#ifdef JS_TRACER
+    if (JS_TRACE_MONITOR(cx).recorder)
+        js_AbortRecording(cx, regs.pc, "recording out of js_Interpret");
+#endif
     if (JS_UNLIKELY(fp->flags & JSFRAME_YIELDING)) {
         JSGenerator *gen;
 
         gen = FRAME_TO_GENERATOR(fp);
         gen->savedRegs = regs;
         gen->frame.regs = &gen->savedRegs;
         JS_PROPERTY_CACHE(cx).disabled -= js_CountWithBlocks(cx, fp);
         JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0);
     } else {
         JS_ASSERT(!fp->blockChain);
         JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
         fp->regs = NULL;
     }
 
+    /* Undo the remaining effects committed on entry to js_Interpret. */
+    if (script->staticDepth < JS_DISPLAY_SIZE)
+        cx->display[script->staticDepth] = fp->displaySave;
     JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
     if (cx->version == currentVersion && currentVersion != originalVersion)
         js_SetVersion(cx, originalVersion);
-    cx->interpLevel--;
+    --cx->interpLevel;
     return ok;
 
   atom_not_defined:
     {
         const char *printable;
 
         printable = js_AtomToPrintableString(cx, atom);
         if (printable)
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -83,16 +83,18 @@ struct JSStackFrame {
     void            *annotation;    /* used by Java security */
     JSObject        *scopeChain;    /* scope chain */
     uintN           sharpDepth;     /* array/object initializer depth */
     JSObject        *sharpArray;    /* scope for #n= initializer vars */
     uint32          flags;          /* frame flags -- see below */
     JSStackFrame    *dormantNext;   /* next dormant frame chain */
     JSObject        *xmlNamespace;  /* null or default xml namespace in E4X */
     JSObject        *blockChain;    /* active compile-time block scopes */
+    JSStackFrame    *displaySave;   /* previous value of display entry for
+                                       script->staticDepth */
 #ifdef DEBUG
     jsrefcount      pcDisabledSave; /* for balanced property cache control */
 #endif
 };
 
 static JS_INLINE jsval *
 StackBase(JSStackFrame *fp)
 {
@@ -143,18 +145,23 @@ typedef struct JSInlineFrame {
  * polymorphic callsite method/get/set speedups.
  *
  * See bug https://bugzilla.mozilla.org/show_bug.cgi?id=365851.
  */
 #define PROPERTY_CACHE_LOG2     12
 #define PROPERTY_CACHE_SIZE     JS_BIT(PROPERTY_CACHE_LOG2)
 #define PROPERTY_CACHE_MASK     JS_BITMASK(PROPERTY_CACHE_LOG2)
 
+/*
+ * Add kshape rather than xor it to avoid collisions between nearby bytecode
+ * that are evolving an object by setting successive properties, incrementing
+ * the object's scope->shape on each set.
+ */
 #define PROPERTY_CACHE_HASH(pc,kshape)                                        \
-    ((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc) ^ (kshape)) &    \
+    (((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) &  \
      PROPERTY_CACHE_MASK)
 
 #define PROPERTY_CACHE_HASH_PC(pc,kshape)                                     \
     PROPERTY_CACHE_HASH(pc, kshape)
 
 #define PROPERTY_CACHE_HASH_ATOM(atom,obj,pobj)                               \
     PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SCOPE(obj)->shape)
 
@@ -225,16 +232,17 @@ typedef struct JSPropertyCache {
     uint32              slotchanges;    /* clasp->reserveSlots result variance-
                                            induced slot changes */
     uint32              setmisses;      /* JSOP_SET{NAME,PROP} total misses */
     uint32              idmisses;       /* slow-path key id == atom misses */
     uint32              komisses;       /* slow-path key object misses */
     uint32              vcmisses;       /* value capability misses */
     uint32              misses;         /* cache misses */
     uint32              flushes;        /* cache flushes */
+    uint32              pcpurges;       /* shadowing purges on proto chain */
 # define PCMETER(x)     x
 #else
 # define PCMETER(x)     ((void)0)
 #endif
 } JSPropertyCache;
 
 /*
  * Property cache value tagging/untagging macros.
--- a/js/src/jsinvoke.cpp
+++ b/js/src/jsinvoke.cpp
@@ -9,25 +9,24 @@
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.8 code, released
+ * March 4, 2008.
  *
  * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
+ *   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
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -64,19 +64,16 @@
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
-#define JSSLOT_ITER_STATE       (JSSLOT_PRIVATE)
-#define JSSLOT_ITER_FLAGS       (JSSLOT_PRIVATE + 1)
-
 #if JSSLOT_ITER_FLAGS >= JS_INITIAL_NSLOTS
 #error JS_INITIAL_NSLOTS must be greater than JSSLOT_ITER_FLAGS.
 #endif
 
 #if JS_HAS_GENERATORS
 
 static JSBool
 CloseGenerator(JSContext *cx, JSObject *genobj);
@@ -220,21 +217,21 @@ IteratorNextImpl(JSContext *cx, JSObject
     uintN flags;
     JSBool foreach, ok;
     jsid id;
 
     JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_IteratorClass);
 
     iterable = OBJ_GET_PARENT(cx, obj);
     JS_ASSERT(iterable);
-    state = OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_STATE);
+    state = STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE);
     if (JSVAL_IS_NULL(state))
         goto stop;
 
-    flags = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_FLAGS));
+    flags = JSVAL_TO_INT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_FLAGS));
     JS_ASSERT(!(flags & JSITER_ENUMERATE));
     foreach = (flags & JSITER_FOREACH) != 0;
     ok =
 #if JS_HAS_XML_SUPPORT
          (foreach && OBJECT_IS_XML(cx, iterable))
          ? ((JSXMLObjectOps *) iterable->map->ops)->
                enumerateValues(cx, iterable, JSENUMERATE_NEXT, &state,
                                &id, rval)
@@ -258,17 +255,17 @@ IteratorNextImpl(JSContext *cx, JSObject
         if (!NewKeyValuePair(cx, id, *rval, rval))
             return JS_FALSE;
     } else {
         *rval = ID_TO_VALUE(id);
     }
     return JS_TRUE;
 
   stop:
-    JS_ASSERT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_STATE) == JSVAL_NULL);
+    JS_ASSERT(STOBJ_GET_SLOT(obj, JSSLOT_ITER_STATE) == JSVAL_NULL);
     *rval = JSVAL_HOLE;
     return JS_TRUE;
 }
 
 JSBool
 js_ThrowStopIteration(JSContext *cx)
 {
     jsval v;
@@ -314,17 +311,17 @@ static JSFunctionSpec iterator_methods[]
     JS_FS_END
 };
 
 uintN
 js_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj)
 {
     if (OBJ_GET_CLASS(cx, iterobj) != &js_IteratorClass)
         return 0;
-    return JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_FLAGS));
+    return JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS));
 }
 
 /*
  * Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
  * Otherwise construct the default iterator.
  */
 JS_FRIEND_API(JSBool)
 js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
@@ -432,17 +429,17 @@ js_ValueToIterator(JSContext *cx, uintN 
     if (obj)
         JS_POP_TEMP_ROOT(cx, &tvr);
     return ok;
   bad:
     ok = JS_FALSE;
     goto out;
 }
 
-JS_FRIEND_API(JSBool)
+JS_FRIEND_API(bool) JS_FASTCALL
 js_CloseIterator(JSContext *cx, jsval v)
 {
     JSObject *obj;
     JSClass *clasp;
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
     obj = JSVAL_TO_OBJECT(v);
     clasp = OBJ_GET_CLASS(cx, obj);
@@ -593,17 +590,17 @@ CallEnumeratorNext(JSContext *cx, JSObje
 
 JS_FRIEND_API(JSBool)
 js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval)
 {
     uintN flags;
 
     /* Fast path for native iterators */
     if (OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass) {
-        flags = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_FLAGS));
+        flags = JSVAL_TO_INT(STOBJ_GET_SLOT(iterobj, JSSLOT_ITER_FLAGS));
         if (flags & JSITER_ENUMERATE)
             return CallEnumeratorNext(cx, iterobj, flags, rval);
 
         /*
          * Call next directly as all the methods of the native iterator are
          * read-only and permanent.
          */
         if (!IteratorNextImpl(cx, iterobj, rval))
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -53,25 +53,31 @@ JS_BEGIN_EXTERN_C
  * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's
  * JSXDR_BYTECODE_VERSION.
  */
 #define JSITER_ENUMERATE  0x1   /* for-in compatible hidden default iterator */
 #define JSITER_FOREACH    0x2   /* return [key, value] pair rather than key */
 #define JSITER_KEYVALUE   0x4   /* destructuring for-in wants [key, value] */
 
 /*
+ * Native iterator object slots, shared between jsiter.cpp and jstracer.cpp.
+ */
+#define JSSLOT_ITER_STATE       (JSSLOT_PRIVATE)
+#define JSSLOT_ITER_FLAGS       (JSSLOT_PRIVATE + 1)
+
+/*
  * Convert the value stored in *vp to its iteration object. The flags should
  * contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating
  * for-in semantics are required, and when the caller can guarantee that the
  * iterator will never be exposed to scripts.
  */
 extern JS_FRIEND_API(JSBool)
 js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp);
 
-extern JS_FRIEND_API(JSBool)
+extern JS_FRIEND_API(bool) JS_FASTCALL
 js_CloseIterator(JSContext *cx, jsval v);
 
 /*
  * Given iterobj, call iterobj.next().  If the iterator stopped, set *rval to
  * JSVAL_HOLE. Otherwise set it to the result of the next call.
  */
 extern JS_FRIEND_API(JSBool)
 js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval);
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -234,18 +234,18 @@ math_ceil(JSContext *cx, uintN argc, jsv
     }
     x = js_ValueToNumber(cx, &vp[2]);
     if (JSVAL_IS_NULL(vp[2]))
         return JS_FALSE;
     z = fd_ceil(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_cos(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_cos(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
@@ -278,18 +278,18 @@ math_exp(JSContext *cx, uintN argc, jsva
             return JS_TRUE;
         }
     }
 #endif
     z = fd_exp(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_floor(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_floor(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
@@ -372,18 +372,18 @@ math_min(JSContext *cx, uintN argc, jsva
         if (x == 0 && x == z && fd_copysign(1.0,x) == -1)
             z = x;
         else
             z = (x < z) ? x : z;
     }
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_pow(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_pow(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, y, z;
 
     if (argc <= 1) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
@@ -418,18 +418,18 @@ random_setSeed(JSRuntime *rt, int64 seed
     int64 tmp;
 
     JSLL_I2L(tmp, 1000);
     JSLL_DIV(seed, seed, tmp);
     JSLL_XOR(tmp, seed, rt->rngMultiplier);
     JSLL_AND(rt->rngSeed, tmp, rt->rngMask);
 }
 
-static void
-random_init(JSRuntime *rt)
+void
+js_random_init(JSRuntime *rt)
 {
     int64 tmp, tmp2;
 
     /* Do at most once. */
     if (rt->rngInitialized)
         return;
     rt->rngInitialized = JS_TRUE;
 
@@ -464,39 +464,39 @@ random_next(JSRuntime *rt, int bits)
     JSLL_ADD(nextseed, nextseed, rt->rngAddend);
     JSLL_AND(nextseed, nextseed, rt->rngMask);
     rt->rngSeed = nextseed;
     JSLL_USHR(tmp, nextseed, 48 - bits);
     JSLL_L2I(retval, tmp);
     return retval;
 }
 
-static jsdouble
-random_nextDouble(JSRuntime *rt)
+jsdouble
+js_random_nextDouble(JSRuntime *rt)
 {
     int64 tmp, tmp2;
     jsdouble d;
 
     JSLL_ISHL(tmp, random_next(rt, 26), 27);
     JSLL_UI2L(tmp2, random_next(rt, 27));
     JSLL_ADD(tmp, tmp, tmp2);
     JSLL_L2D(d, tmp);
     return d / rt->rngDscale;
 }
 
-static JSBool
-math_random(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_random(JSContext *cx, uintN argc, jsval *vp)
 {
     JSRuntime *rt;
     jsdouble z;
 
     rt = cx->runtime;
     JS_LOCK_RUNTIME(rt);
-    random_init(rt);
-    z = random_nextDouble(rt);
+    js_random_init(rt);
+    z = js_random_nextDouble(rt);
     JS_UNLOCK_RUNTIME(rt);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
 #if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
 /* Try to work around apparent _copysign bustage in VC6 and VC7. */
 double
 js_copysign(double x, double y)
@@ -522,34 +522,34 @@ math_round(JSContext *cx, uintN argc, js
     }
     x = js_ValueToNumber(cx, &vp[2]);
     if (JSVAL_IS_NULL(vp[2]))
         return JS_FALSE;
     z = fd_copysign(fd_floor(x + 0.5), x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_sin(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_sin(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
     if (JSVAL_IS_NULL(vp[2]))
         return JS_FALSE;
     z = fd_sin(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_sqrt(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_sqrt(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
@@ -589,38 +589,42 @@ static JSFunctionSpec math_static_method
     JS_FN(js_toSource_str,  math_toSource,      0, 0),
 #endif
     JS_FN("abs",            math_abs,           1, 0),
     JS_FN("acos",           math_acos,          1, 0),
     JS_FN("asin",           math_asin,          1, 0),
     JS_FN("atan",           math_atan,          1, 0),
     JS_FN("atan2",          math_atan2,         2, 0),
     JS_FN("ceil",           math_ceil,          1, 0),
-    JS_FN("cos",            math_cos,           1, 0),
+    JS_FN("cos",            js_math_cos,        1, 0),
     JS_FN("exp",            math_exp,           1, 0),
-    JS_FN("floor",          math_floor,         1, 0),
+    JS_FN("floor",          js_math_floor,      1, 0),
     JS_FN("log",            math_log,           1, 0),
     JS_FN("max",            math_max,           2, 0),
     JS_FN("min",            math_min,           2, 0),
-    JS_FN("pow",            math_pow,           2, 0),
-    JS_FN("random",         math_random,        0, 0),
+    JS_FN("pow",            js_math_pow,        2, 0),
+    JS_FN("random",         js_math_random,     0, 0),
     JS_FN("round",          math_round,         1, 0),
-    JS_FN("sin",            math_sin,           1, 0),
-    JS_FN("sqrt",           math_sqrt,          1, 0),
+    JS_FN("sin",            js_math_sin,        1, 0),
+    JS_FN("sqrt",           js_math_sqrt,       1, 0),
     JS_FN("tan",            math_tan,           1, 0),
     JS_FS_END
 };
 
 JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj)
 {
     JSObject *Math;
 
-    Math = JS_DefineObject(cx, obj, js_Math_str, &js_MathClass, NULL,
-                           JSPROP_READONLY | JSPROP_PERMANENT);
+    Math = JS_NewObject(cx, &js_MathClass, NULL, obj);
     if (!Math)
         return NULL;
+    if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
+                           JS_PropertyStub, JS_PropertyStub,
+                           JSPROP_READONLY | JSPROP_PERMANENT))
+        return NULL;
+
     if (!JS_DefineFunctions(cx, Math, math_static_methods))
         return NULL;
     if (!JS_DefineConstDoubles(cx, Math, math_constants))
         return NULL;
     return Math;
 }
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -47,11 +47,17 @@
 
 JS_BEGIN_EXTERN_C
 
 extern JSClass js_MathClass;
 
 extern JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj);
 
+extern void
+js_random_init(JSRuntime *rt);
+
+extern jsdouble
+js_random_nextDouble(JSRuntime *rt);
+
 JS_END_EXTERN_C
 
 #endif /* jsmath_h___ */
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -93,18 +93,18 @@ num_isFinite(JSContext *cx, uintN argc, 
     }
     x = js_ValueToNumber(cx, &vp[2]);
     if (JSVAL_IS_NULL(vp[2]))
         return JS_FALSE;
     *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
     return JS_TRUE;
 }
 
-static JSBool
-num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str;
     jsdouble d;
     const jschar *bp, *end, *ep;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
@@ -118,18 +118,18 @@ num_parseFloat(JSContext *cx, uintN argc
     if (ep == bp) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     return js_NewNumberInRootedValue(cx, d, vp);
 }
 
 /* See ECMA 15.1.2.2. */
-static JSBool
-num_parseInt(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_num_parseInt(JSContext *cx, uintN argc, jsval *vp)
 {
     jsint radix;
     JSString *str;
     jsdouble d;
     const jschar *bp, *end, *ep;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
@@ -170,18 +170,18 @@ const char js_NaN_str[]        = "NaN";
 const char js_isNaN_str[]      = "isNaN";
 const char js_isFinite_str[]   = "isFinite";
 const char js_parseFloat_str[] = "parseFloat";
 const char js_parseInt_str[]   = "parseInt";
 
 static JSFunctionSpec number_functions[] = {
     JS_FN(js_isNaN_str,         num_isNaN,              1,0),
     JS_FN(js_isFinite_str,      num_isFinite,           1,0),
-    JS_FN(js_parseFloat_str,    num_parseFloat,         1,0),
-    JS_FN(js_parseInt_str,      num_parseInt,           2,0),
+    JS_FN(js_parseFloat_str,    js_num_parseFloat,      1,0),
+    JS_FN(js_parseInt_str,      js_num_parseInt,        2,0),
     JS_FS_END
 };
 
 JSClass js_NumberClass = {
     js_Number_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,
@@ -552,17 +552,17 @@ static JSConstDoubleSpec number_constant
     {0,                         js_NaN_str,          0,{0,0,0}},
     {0,                         "POSITIVE_INFINITY", 0,{0,0,0}},
     {0,                         "NEGATIVE_INFINITY", 0,{0,0,0}},
     {1.7976931348623157E+308,   "MAX_VALUE",         0,{0,0,0}},
     {0,                         "MIN_VALUE",         0,{0,0,0}},
     {0,0,0,{0,0,0}}
 };
 
-static jsdouble NaN;
+jsdouble js_NaN;
 
 #if (defined XP_WIN || defined XP_OS2) &&                                     \
     !defined WINCE &&                                                         \
     !defined __MWERKS__ &&                                                    \
     (defined _M_IX86 ||                                                       \
      (defined __GNUC__ && !defined __MINGW32__))
 
 /*
@@ -587,18 +587,18 @@ js_InitRuntimeNumberState(JSContext *cx)
 
     rt = cx->runtime;
     JS_ASSERT(!rt->jsNaN);
 
     FIX_FPU();
 
     u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
     u.s.lo = 0xffffffff;
-    number_constants[NC_NaN].dval = NaN = u.d;
-    rt->jsNaN = js_NewWeaklyRootedDouble(cx, NaN);
+    number_constants[NC_NaN].dval = js_NaN = u.d;
+    rt->jsNaN = js_NewWeaklyRootedDouble(cx, js_NaN);
     if (!rt->jsNaN)
         return JS_FALSE;
 
     u.s.hi = JSDOUBLE_HI32_EXPMASK;
     u.s.lo = 0x00000000;
     number_constants[NC_POSITIVE_INFINITY].dval = u.d;
     rt->jsPositiveInfinity = js_NewWeaklyRootedDouble(cx, u.d);
     if (!rt->jsPositiveInfinity)
@@ -721,17 +721,17 @@ js_NumberToCString(JSContext *cx, jsdoub
         if (!numStr) {
             JS_ReportOutOfMemory(cx);
             return NULL;
         }
     }
     return numStr;
 }
 
-JSString *
+JSString * JS_FASTCALL
 js_NumberToString(JSContext *cx, jsdouble d)
 {
     char buf[DTOSTR_STANDARD_BUFFER_SIZE];
     char *numStr;
 
     numStr = js_NumberToCString(cx, d, buf, sizeof buf);
     if (!numStr)
         return NULL;
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -64,16 +64,17 @@ JS_BEGIN_EXTERN_C
 typedef union jsdpun {
     struct {
 #if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA)
         uint32 lo, hi;
 #else
         uint32 hi, lo;
 #endif
     } s;
+    uint64   u64;
     jsdouble d;
 } jsdpun;
 
 #if (__GNUC__ == 2 && __GNUC_MINOR__ > 95) || __GNUC__ > 2
 /*
  * This version of the macros is safe for the alias optimizations that gcc
  * does, but uses gcc-specific extensions.
  */
@@ -137,16 +138,18 @@ typedef union jsdpun {
 #define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN)                               \
     ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL))                         \
      ? (IFNAN)                                                                \
      : (LVAL) OP (RVAL))
 #else
 #define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))
 #endif
 
+extern jsdouble js_NaN;
+
 /* Initialize number constants and runtime state for the first context. */
 extern JSBool
 js_InitRuntimeNumberState(JSContext *cx);
 
 extern void
 js_TraceRuntimeNumberState(JSTracer *trc);
 
 extern void
@@ -170,17 +173,17 @@ extern const char js_parseInt_str[];
 
 /*
  * vp must be a root.
  */
 extern JSBool
 js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp);
 
 /* Convert a number to a GC'ed string. */
-extern JSString *
+extern JSString * JS_FASTCALL
 js_NumberToString(JSContext *cx, jsdouble d);
 
 /*
  * Convert int to C string. The buf must be big enough for MIN_INT to fit
  * including '-' and '\0'.
  */
 char *
 js_IntToCString(jsint i, char *buf, size_t bufSize);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1159,18 +1159,18 @@ js_ComputeFilename(JSContext *cx, JSStac
         *linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH);
     } else {
         *linenop = js_PCToLineNumber(cx, caller->script,
                                      caller->regs ? caller->regs->pc : NULL);
     }
     return caller->script->filename;
 }
 
-static JSBool
-obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+JSBool
+js_obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     JSStackFrame *fp, *caller;
     JSBool indirectCall;
     JSObject *scopeobj;
     JSString *str;
     const char *file;
     uintN line;
     JSPrincipals *principals;
@@ -1224,18 +1224,16 @@ obj_eval(JSContext *cx, JSObject *obj, u
     if (argc >= 2 &&
         !JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT,
                                       js_GetErrorMessage, NULL,
                                       JSMSG_EVAL_ARITY)) {
         return JS_FALSE;
     }
 
     /* From here on, control must exit through label out with ok set. */
-    js_DisablePropertyCache(cx);
-
     if (!scopeobj) {
 #if JS_HAS_EVAL_THIS_SCOPE
         /* If obj.eval(str), emulate 'with (obj) eval(str)' in the caller. */
         if (indirectCall) {
             callerScopeChain = js_GetScopeChain(cx, caller);
             if (!callerScopeChain) {
                 ok = JS_FALSE;
                 goto out;
@@ -1320,47 +1318,50 @@ obj_eval(JSContext *cx, JSObject *obj, u
 
     script = js_CompileScript(cx, scopeobj, principals, TCF_COMPILE_N_GO,
                               JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
                               NULL, file, line);
     if (!script) {
         ok = JS_FALSE;
         goto out;
     }
+    script->staticDepth = caller->script->staticDepth + 1;
 
     if (argc < 2) {
         /* Execute using caller's new scope object (might be a Call object). */
         if (caller)
             scopeobj = caller->scopeChain;
     }
 
     /*
      * Belt-and-braces: check that the lesser of eval's principals and the
      * caller's principals has access to scopeobj.
      */
     ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
                                   cx->runtime->atomState.evalAtom);
     if (ok)
         ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
 
-    JS_DestroyScript(cx, script);
+    script->u.nextToGC = JS_SCRIPTS_TO_GC(cx);
+    JS_SCRIPTS_TO_GC(cx) = script;
+#ifdef CHECK_SCRIPT_OWNER
+    script->owner = NULL;
+#endif
 
 out:
 #if JS_HAS_EVAL_THIS_SCOPE
     /* Restore OBJ_GET_PARENT(scopeobj) not callerScopeChain in case of Call. */
     if (setCallerScopeChain) {
         caller->scopeChain = callerScopeChain;
         JS_ASSERT(OBJ_GET_CLASS(cx, setCallerScopeChain) == &js_WithClass);
         JS_SetPrivate(cx, setCallerScopeChain, NULL);
     }
     if (setCallerVarObj)
         caller->varobj = callerVarObj;
 #endif
-
-    js_EnablePropertyCache(cx);
     return ok;
 }
 
 #if JS_HAS_OBJ_WATCHPOINT
 
 static JSBool
 obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp,
                   void *closure)
@@ -1464,39 +1465,48 @@ obj_unwatch(JSContext *cx, uintN argc, j
 #endif /* JS_HAS_OBJ_WATCHPOINT */
 
 /*
  * Prototype and property query methods, to complement the 'in' and
  * 'instanceof' operators.
  */
 
 /* Proposed ECMA 15.2.4.5. */
-static JSBool
-obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
 
     obj = JS_THIS_OBJECT(cx, vp);
     return obj &&
            js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, argc, vp);
 }
 
 JSBool
 js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc,
                         jsval *vp)
 {
     jsid id;
-    JSObject *obj, *obj2;
-    JSProperty *prop;
-    JSScopeProperty *sprop;
+    JSObject *obj;
 
     if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
         return JS_FALSE;
     obj = JS_THIS_OBJECT(cx, vp);
-    if (!obj || !lookup(cx, obj, id, &obj2, &prop))
+    return obj && js_HasOwnProperty(cx, lookup, obj, id, vp);
+}
+
+JSBool
+js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
+                  jsval *vp)
+{
+    JSObject *obj2;
+    JSProperty *prop;
+    JSScopeProperty *sprop;
+
+    if (!lookup(cx, obj, id, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         *vp = JSVAL_FALSE;
     } else if (obj2 == obj) {
         *vp = JSVAL_TRUE;
     } else {
         JSClass *clasp;
         JSExtendedClass *xclasp;
@@ -1550,30 +1560,38 @@ obj_isPrototypeOf(JSContext *cx, uintN a
                        argc != 0 ? vp[2] : JSVAL_VOID, &b)) {
         return JS_FALSE;
     }
     *vp = BOOLEAN_TO_JSVAL(b);
     return JS_TRUE;
 }
 
 /* Proposed ECMA 15.2.4.7. */
-static JSBool
-obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp)
 {
     jsid id;
-    JSObject *obj, *pobj;
+    JSObject *obj;
+
+    if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
+        return JS_FALSE;
+
+    obj = JS_THIS_OBJECT(cx, vp);
+    return obj && js_PropertyIsEnumerable(cx, obj, id, vp);
+}
+
+JSBool
+js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
+{
+    JSObject *pobj;
     uintN attrs;
     JSProperty *prop;
     JSBool ok;
 
-    if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id))
-        return JS_FALSE;
-
-    obj = JS_THIS_OBJECT(cx, vp);
-    if (!obj || !OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
+    if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
         return JS_FALSE;
 
     if (!prop) {
         *vp = JSVAL_FALSE;
         return JS_TRUE;
     }
 
     /*
@@ -1756,33 +1774,33 @@ const char js_propertyIsEnumerable_str[]
 const char js_defineGetter_str[] = "__defineGetter__";
 const char js_defineSetter_str[] = "__defineSetter__";
 const char js_lookupGetter_str[] = "__lookupGetter__";
 const char js_lookupSetter_str[] = "__lookupSetter__";
 #endif
 
 static JSFunctionSpec object_methods[] = {
 #if JS_HAS_TOSOURCE
-    JS_FN(js_toSource_str,             obj_toSource, 0,0),
+    JS_FN(js_toSource_str,             obj_toSource,                0,0),
 #endif
-    JS_FN(js_toString_str,             obj_toString,             0,0),
-    JS_FN(js_toLocaleString_str,       obj_toLocaleString,       0,0),
-    JS_FN(js_valueOf_str,              obj_valueOf,              0,0),
+    JS_FN(js_toString_str,             obj_toString,                0,0),
+    JS_FN(js_toLocaleString_str,       obj_toLocaleString,          0,0),
+    JS_FN(js_valueOf_str,              obj_valueOf,                 0,0),
 #if JS_HAS_OBJ_WATCHPOINT
-    JS_FN(js_watch_str,                obj_watch,                2,0),
-    JS_FN(js_unwatch_str,              obj_unwatch,              1,0),
+    JS_FN(js_watch_str,                obj_watch,                   2,0),
+    JS_FN(js_unwatch_str,              obj_unwatch,                 1,0),
 #endif
-    JS_FN(js_hasOwnProperty_str,       obj_hasOwnProperty,       1,0),
-    JS_FN(js_isPrototypeOf_str,        obj_isPrototypeOf,        1,0),
-    JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0),
+    JS_FN(js_hasOwnProperty_str,       js_obj_hasOwnProperty,       1,0),
+    JS_FN(js_isPrototypeOf_str,        obj_isPrototypeOf,           1,0),
+    JS_FN(js_propertyIsEnumerable_str, js_obj_propertyIsEnumerable, 1,0),
 #if JS_HAS_GETTER_SETTER
-    JS_FN(js_defineGetter_str,         obj_defineGetter,         2,0),
-    JS_FN(js_defineSetter_str,         obj_defineSetter,         2,0),
-    JS_FN(js_lookupGetter_str,         obj_lookupGetter,         1,0),
-    JS_FN(js_lookupSetter_str,         obj_lookupSetter,         1,0),
+    JS_FN(js_defineGetter_str,         obj_defineGetter,            2,0),
+    JS_FN(js_defineSetter_str,         obj_defineSetter,            2,0),
+    JS_FN(js_lookupGetter_str,         obj_lookupGetter,            1,0),
+    JS_FN(js_lookupSetter_str,         obj_lookupSetter,            1,0),
 #endif
     JS_FS_END
 };
 
 static JSFunctionSpec object_static_methods[] = {
     JS_FN("getPrototypeOf",            obj_getPrototypeOf,       1,0),
     JS_FS_END
 };
@@ -2263,17 +2281,17 @@ js_InitBlockClass(JSContext *cx, JSObjec
     return proto;
 }
 
 JSObject *
 js_InitEval(JSContext *cx, JSObject *obj)
 {
     /* ECMA (15.1.2.1) says 'eval' is a property of the global object. */
     if (!js_DefineFunction(cx, obj, cx->runtime->atomState.evalAtom,
-                           obj_eval, 1, 0)) {
+                           js_obj_eval, 1, 0)) {
         return NULL;
     }
 
     return obj;
 }
 
 JSObject *
 js_InitObjectClass(JSContext *cx, JSObject *obj)
@@ -2991,16 +3009,17 @@ PurgeProtoChain(JSContext *cx, JSObject 
         if (!OBJ_IS_NATIVE(obj)) {
             obj = OBJ_GET_PROTO(cx, obj);
             continue;
         }
         JS_LOCK_OBJ(cx, obj);
         scope = OBJ_SCOPE(obj);
         sprop = SCOPE_GET_PROPERTY(scope, id);
         if (sprop) {
+            PCMETER(JS_PROPERTY_CACHE(cx).pcpurges++);
             SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
             JS_UNLOCK_SCOPE(cx, scope);
             return JS_TRUE;
         }
         obj = LOCKED_OBJ_GET_PROTO(scope->object);
         JS_UNLOCK_SCOPE(cx, scope);
     }
     return JS_FALSE;
@@ -4337,17 +4356,17 @@ js_Enumerate(JSContext *cx, JSObject *ob
         JS_UNLOCK_SCOPE(cx, scope);
 
         if (!ne) {
             JS_ASSERT(length == 0);
             JS_ASSERT(allocated == 0);
             *statep = JSVAL_ZERO;
         } else {
             JS_ASSERT(length != 0);
-            JS_ASSERT(ne->cursor == length);
+            JS_ASSERT(ne->cursor == (jsword) length);
             if (allocated != 0) {
                 JS_LOCK_GC(cx->runtime);
                 if (!js_AddAsGCBytes(cx, allocated)) {
                     /* js_AddAsGCBytes releases the GC lock on failures. */
                     JS_free(cx, ne);
                     return JS_FALSE;
                 }
                 ne->next = cx->runtime->nativeEnumerators;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -383,19 +383,32 @@ js_LeaveSharpObject(JSContext *cx, JSIdA
 /*
  * Mark objects stored in map if GC happens between js_EnterSharpObject
  * and js_LeaveSharpObject. GC calls this when map->depth > 0.
  */
 extern void
 js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map);
 
 extern JSBool
+js_obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
 js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc,
                         jsval *vp);
 
+extern JSBool
+js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
+                  jsval *vp);
+
+extern JSBool
+js_obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
+js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
+
 extern JSObject *
 js_InitBlockClass(JSContext *cx, JSObject* obj);
 
 extern JSObject *
 js_InitEval(JSContext *cx, JSObject *obj);
 
 extern JSObject *
 js_InitObjectClass(JSContext *cx, JSObject *obj);
@@ -679,17 +692,17 @@ js_Clear(JSContext *cx, JSObject *obj);
 
 extern jsval
 js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot);
 
 extern JSBool
 js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v);
 
 /*
- * obj must be locked.
+ * Precondition: obj must be locked.
  */
 extern JSBool
 js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots,
                 JSBool exactAllocation);
 
 extern JSObject *
 js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller);
 
@@ -700,11 +713,15 @@ js_CheckPrincipalsAccess(JSContext *cx, 
 /* Infallible -- returns its argument if there is no wrapped object. */
 extern JSObject *
 js_GetWrappedObject(JSContext *cx, JSObject *obj);
 
 /* NB: Infallible. */
 extern const char *
 js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
                    JSPrincipals *principals, uintN *linenop);
+
+extern JSBool
+js_obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
 JS_END_EXTERN_C
 
 #endif /* jsobj_h___ */
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1,10 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set sw=4 ts=8 et tw=78:
+ * vim: set sw=4 ts=8 et tw=99:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -319,20 +319,16 @@ js_Disassemble1(JSContext *cx, JSScript 
             return 0;
         fprintf(fp, " %s", bytes);
         break;
 
       case JOF_UINT16:
         i = (jsint)GET_UINT16(pc);
         goto print_int;
 
-      case JOF_2BYTE:
-        fprintf(fp, " %u", (uintN)pc[1]);
-        break;
-
       case JOF_TABLESWITCH:
       case JOF_TABLESWITCHX:
       {
         jsbytecode *pc2;
         jsint i, low, high;
 
         jmplen = (type == JOF_TABLESWITCH) ? JUMP_OFFSET_LEN
                                            : JUMPX_OFFSET_LEN;
@@ -408,16 +404,20 @@ js_Disassemble1(JSContext *cx, JSScript 
         fprintf(fp, " %s", bytes);
         break;
 
       case JOF_UINT24:
         JS_ASSERT(op == JSOP_UINT24 || op == JSOP_NEWARRAY);
         i = (jsint)GET_UINT24(pc);
         goto print_int;
 
+      case JOF_UINT8:
+        i = pc[1];
+        goto print_int;
+
       case JOF_INT8:
         i = GET_INT8(pc);
         goto print_int;
 
       case JOF_INT32:
         JS_ASSERT(op == JSOP_INT32);
         i = GET_INT32(pc);
       print_int:
@@ -1176,17 +1176,17 @@ DecompileSwitch(SprintStack *ss, TableEn
     JS_END_MACRO
 
 static JSAtom *
 GetArgOrVarAtom(JSPrinter *jp, uintN slot)
 {
     JSAtom *name;
 
     LOCAL_ASSERT_RV(jp->fun, NULL);
-    LOCAL_ASSERT_RV(slot < JS_GET_LOCAL_NAME_COUNT(jp->fun), NULL);
+    LOCAL_ASSERT_RV(slot < (uintN) JS_GET_LOCAL_NAME_COUNT(jp->fun), NULL);
     name = JS_LOCAL_NAME_TO_ATOM(jp->localNames[slot]);
 #if !JS_HAS_DESTRUCTURING
     LOCAL_ASSERT_RV(name, NULL);
 #endif
     return name;
 }
 
 const char *
@@ -2130,16 +2130,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 }
                 break;
 
               case JSOP_GROUP:
                 cs = &js_CodeSpec[lastop];
                 if ((cs->prec != 0 &&
                      cs->prec <= js_CodeSpec[NEXT_OP(pc)].prec) ||
                     pc[JSOP_GROUP_LENGTH] == JSOP_NULL ||
+                    pc[JSOP_GROUP_LENGTH] == JSOP_NULLTHIS ||
                     pc[JSOP_GROUP_LENGTH] == JSOP_DUP ||
                     pc[JSOP_GROUP_LENGTH] == JSOP_IFEQ ||
                     pc[JSOP_GROUP_LENGTH] == JSOP_IFNE) {
                     /*
                      * Force parens if this JSOP_GROUP forced re-association
                      * against precedence, or if this is a call or constructor
                      * expression, or if it is destructured (JSOP_DUP), or if
                      * it is an if or loop condition test.
@@ -2687,16 +2688,22 @@ Decompile(SprintStack *ss, jsbytecode *p
                 top -= depth;
                 ss->top = top;
                 ss->sprinter.offset = GetOff(ss, top);
                 if (op == JSOP_LEAVEBLOCKEXPR)
                     todo = SprintCString(&ss->sprinter, rval);
                 break;
               }
 
+              case JSOP_CALLUPVAR:
+              case JSOP_GETUPVAR:
+                i = JS_UPVAR_LOCAL_NAME_START(jp->fun) + GET_UINT16(pc);
+                atom = GetArgOrVarAtom(jp, i);
+                goto do_name;
+
               case JSOP_CALLLOCAL:
               case JSOP_GETLOCAL:
                 if (IsVarSlot(jp, pc, &i)) {
                     atom = GetArgOrVarAtom(jp, i);
                     LOCAL_ASSERT(atom);
                     goto do_name;
                 }
                 LOCAL_ASSERT((uintN)i < ss->top);
@@ -3867,17 +3874,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                     }
                     jp->script = outer;
 
                     /*
                      * Advance over this op and its global |this| push, and
                      * arrange to advance over the call to this lambda.
                      */
                     pc += len;
-                    LOCAL_ASSERT(*pc == JSOP_NULL);
+                    LOCAL_ASSERT(*pc == JSOP_NULL || *pc == JSOP_NULLTHIS);
                     pc += JSOP_NULL_LENGTH;
                     LOCAL_ASSERT(*pc == JSOP_CALL);
                     LOCAL_ASSERT(GET_ARGC(pc) == 0);
                     len = JSOP_CALL_LENGTH;
 
                     /*
                      * Arrange to parenthesize this genexp unless:
                      *
@@ -5093,41 +5100,46 @@ DecompileExpression(JSContext *cx, JSScr
         script->code = oldcode;
         script->main = oldmain;
     }
 
     JS_free(cx, pcstack);
     return name;
 }
 
+uintN
+js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc)
+{
+    return ReconstructPCStack(cx, script, pc, NULL);
+}
+
 static intN
-ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc,
+ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
                    jsbytecode **pcstack)
 {
     intN pcdepth, nuses, ndefs;
-    jsbytecode *begin;
+    jsbytecode *pc;
     JSOp op;
     const JSCodeSpec *cs;
     ptrdiff_t oplen;
     jssrcnote *sn;
     intN i;
 
 #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, -1);
 
     /*
      * Walk forward from script->main and compute the stack depth and stack of
      * operand-generating opcode PCs in pcstack.
      *
      * FIXME: Code to compute oplen copied from js_Disassemble1 and reduced.
      * FIXME: Optimize to use last empty-stack sequence point.
      */
-    LOCAL_ASSERT(script->main <= pc && pc < script->code + script->length);
+    LOCAL_ASSERT(script->main <= target && target < script->code + script->length);
     pcdepth = 0;
-    begin = pc;
-    for (pc = script->main; pc < begin; pc += oplen) {
+    for (pc = script->main; pc < target; pc += oplen) {
         op = (JSOp) *pc;
         if (op == JSOP_TRAP)
             op = JS_GetTrapOpcode(cx, script, pc);
         cs = &js_CodeSpec[op];
         oplen = cs->length;
         if (oplen < 0)
             oplen = js_GetVariableBytecodeLength(pc);
 
@@ -5141,41 +5153,42 @@ ReconstructPCStack(JSContext *cx, JSScri
             pcdepth -= GET_UINT24(pc) - 1;
             LOCAL_ASSERT(pcdepth > 0);
             if (pcstack)
                 pcstack[pcdepth - 1] = pc;
             continue;
         }
 
         /*
-         * A (C ? T : E) expression requires skipping either T (if begin is in
-         * E) or both T and E (if begin is after the whole expression) before
+         * A (C ? T : E) expression requires skipping either T (if target is in
+         * E) or both T and E (if target is after the whole expression) before
          * adjusting pcdepth based on the JSOP_IFEQ or JSOP_IFEQX at pc that
          * tests condition C.  We know that the stack depth can't change from
          * what it was with C on top of stack.
          */
         sn = js_GetSrcNote(script, pc);
         if (sn && SN_TYPE(sn) == SRC_COND) {
             ptrdiff_t jmpoff, jmplen;
 
             jmpoff = js_GetSrcNoteOffset(sn, 0);
-            if (pc + jmpoff < begin) {
+            if (pc + jmpoff < target) {
                 pc += jmpoff;
                 op = (JSOp) *pc;
                 JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX);
                 cs = &js_CodeSpec[op];
                 oplen = cs->length;
+                JS_ASSERT(oplen > 0);
                 jmplen = GetJumpOffset(pc, pc);
-                if (pc + jmplen < begin) {
+                if (pc + jmplen < target) {
                     oplen = (uintN) jmplen;
                     continue;
                 }
 
                 /*
-                 * Ok, begin lies in E.  Manually pop C off the model stack,
+                 * Ok, target lies in E. Manually pop C off the model stack,
                  * since we have moved beyond the IFEQ now.
                  */
                 --pcdepth;
                 LOCAL_ASSERT(pcdepth >= 0);
             }
         }
 
         if (sn && SN_TYPE(sn) == SRC_HIDDEN)
@@ -5214,56 +5227,62 @@ ReconstructPCStack(JSContext *cx, JSScri
 
         /*
          * Fill the slots that the opcode defines withs its pc unless it just
          * reshuffle the stack. In the latter case we want to preserve the
          * opcode that generated the original value.
          */
         switch (op) {
           default:
-            for (i = 0; i != ndefs; ++i)
-                pcstack[pcdepth + i] = pc;
+            if (pcstack) {
+                for (i = 0; i != ndefs; ++i)
+                    pcstack[pcdepth + i] = pc;
+            }
             break;
 
           case JSOP_CASE:
           case JSOP_CASEX:
             /* Keep the switch value. */
             JS_ASSERT(ndefs == 1);
             break;
 
           case JSOP_DUP:
             JS_ASSERT(ndefs == 2);
-            pcstack[pcdepth + 1] = pcstack[pcdepth];
+            if (pcstack)
+                pcstack[pcdepth + 1] = pcstack[pcdepth];
             break;
 
           case JSOP_DUP2:
             JS_ASSERT(ndefs == 4);
-            pcstack[pcdepth + 2] = pcstack[pcdepth];
-            pcstack[pcdepth + 3] = pcstack[pcdepth + 1];
+            if (pcstack) {
+                pcstack[pcdepth + 2] = pcstack[pcdepth];
+                pcstack[pcdepth + 3] = pcstack[pcdepth + 1];
+            }
             break;
 
           case JSOP_LEAVEBLOCKEXPR:
             /*
              * The decompiler wants to see [leaveblockexpr] on pcstack, not
              * [enterblock] or the pc that ended a simulated let expression
              * when [enterblock] defines zero locals as in:
              *
              *   let ([] = []) expr
              */
             JS_ASSERT(ndefs == 0);
             LOCAL_ASSERT(pcdepth >= 1);
-            LOCAL_ASSERT(nuses == 0 ||
+            LOCAL_ASSERT(nuses == 0 || !pcstack ||
                          *pcstack[pcdepth - 1] == JSOP_ENTERBLOCK ||
                          (*pcstack[pcdepth - 1] == JSOP_TRAP &&
                           JS_GetTrapOpcode(cx, script, pcstack[pcdepth - 1])
                           == JSOP_ENTERBLOCK));
-            pcstack[pcdepth - 1] = pc;
+            if (pcstack)
+                pcstack[pcdepth - 1] = pc;
             break;
         }
         pcdepth += ndefs;
     }
-    LOCAL_ASSERT(pc == begin);
+    LOCAL_ASSERT(pc == target);
     return pcdepth;
 
 #undef LOCAL_ASSERT
 }
 
 #undef LOCAL_ASSERT_RV
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -71,17 +71,17 @@ typedef enum JSOp {
 #define JOF_LOOKUPSWITCH  5       /* lookup switch */
 #define JOF_QARG          6       /* quickened get/set function argument ops */
 #define JOF_LOCAL         7       /* var or block-local variable */
 #define JOF_SLOTATOM      8       /* uint16 slot index + constant pool index */
 #define JOF_JUMPX         9       /* signed 32-bit jump offset immediate */
 #define JOF_TABLESWITCHX  10      /* extended (32-bit offset) table switch */
 #define JOF_LOOKUPSWITCHX 11      /* extended (32-bit offset) lookup switch */
 #define JOF_UINT24        12      /* extended unsigned 24-bit literal (index) */
-#define JOF_2BYTE         13      /* 2-byte opcode, e.g., upper 8 bits of 24-bit
+#define JOF_UINT8         13      /* uint8 immediate, e.g. top 8 bits of 24-bit
                                      atom index */
 #define JOF_INT32         14      /* int32 immediate operand */
 #define JOF_OBJECT        15      /* unsigned 16-bit object pool index */
 #define JOF_SLOTOBJECT    16      /* uint16 slot index + object pool index */
 #define JOF_REGEXP        17      /* unsigned 16-bit regexp pool index */
 #define JOF_INT8          18      /* int8 immediate operand */
 #define JOF_TYPEMASK      0x001f  /* mask for above immediate types */
 
@@ -380,11 +380,18 @@ js_DecompileFunction(JSPrinter *jp);
  */
 extern char *
 js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
                            JSString *fallback);
 
 #define JSDVG_IGNORE_STACK      0
 #define JSDVG_SEARCH_STACK      1
 
+/*
+ * Given bytecode address pc in script's main program code, return the operand
+ * stack depth just before (JSOp) *pc executes.
+ */
+extern uintN
+js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc);
+
 JS_END_EXTERN_C
 
 #endif /* jsopcode_h___ */
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -182,17 +182,19 @@ OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswit
 
 /* New, infallible/transitive identity ops. */
 OPDEF(JSOP_STRICTEQ,  72, "stricteq",   NULL,         1,  2,  1,  10,  JOF_BYTE|JOF_DETECTING)
 OPDEF(JSOP_STRICTNE,  73, "strictne",   NULL,         1,  2,  1,  10,  JOF_BYTE|JOF_DETECTING)
 
 /* Lexical closure constructor. */
 OPDEF(JSOP_CLOSURE,   74, "closure",    NULL,         3,  0,  0,  0,  JOF_OBJECT)
 
-OPDEF(JSOP_UNUSED75,  75, "unused75",   NULL,         1,  0,  0,  0,  JOF_BYTE)
+/* Variant of JSOP_NULL for default (global) |this| parameter pushing. */
+OPDEF(JSOP_NULLTHIS,  75, js_null_str,  js_null_str,  1,  0,  1, 19,  JOF_BYTE)
+
 OPDEF(JSOP_UNUSED76,  76, "unused76",   NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED77,  77, "unused77",   NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED78,  78, "unused78",   NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED79,  79, "unused79",   NULL,         1,  0,  0,  0,  JOF_BYTE)
 
 /* Push object literal. */
 OPDEF(JSOP_OBJECT,    80, "object",     NULL,         3,  0,  1, 19,  JOF_OBJECT)
 
@@ -232,17 +234,17 @@ OPDEF(JSOP_INCLOCAL,  99, "inclocal",   
 OPDEF(JSOP_DECLOCAL,  100,"declocal",   NULL,         3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_DEC)
 OPDEF(JSOP_LOCALINC,  101,"localinc",   NULL,         3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_INC|JOF_POST)
 OPDEF(JSOP_LOCALDEC,  102,"localdec",   NULL,         3,  0,  1, 15,  JOF_LOCAL|JOF_NAME|JOF_DEC|JOF_POST)
 
 /*
  * Initialize for-in iterator using the JSITER_* flag bits in this op's uint8
  * immediate operand. See also JSOP_ENDITER.
  */
-OPDEF(JSOP_ITER,      103,"iter",       NULL,         2,  1,  1,  0,  JOF_2BYTE)
+OPDEF(JSOP_ITER,      103,"iter",       NULL,         2,  1,  1,  0,  JOF_UINT8)
 
 /* ECMA-compliant for/in ops. */
 OPDEF(JSOP_FORNAME,   104,"forname",    NULL,         3,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_FOR)
 OPDEF(JSOP_FORPROP,   105,"forprop",    NULL,         3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_FOR)
 OPDEF(JSOP_FORELEM,   106,"forelem",    NULL,         1,  1,  3, 18,  JOF_BYTE |JOF_ELEM|JOF_FOR)
 OPDEF(JSOP_POPN,      107,"popn",       NULL,         3, -1,  0,  0,  JOF_UINT16)
 
 /* ECMA-compliant assignment ops. */
@@ -406,31 +408,36 @@ OPDEF(JSOP_TOXMLLIST,     177,"toxmllist
 OPDEF(JSOP_XMLTAGEXPR,    178,"xmltagexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_XMLELTEXPR,    179,"xmleltexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
 OPDEF(JSOP_XMLOBJECT,     180,"xmlobject",  NULL,     3,  0,  1, 19,  JOF_OBJECT)
 OPDEF(JSOP_XMLCDATA,      181,"xmlcdata",   NULL,     3,  0,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_XMLCOMMENT,    182,"xmlcomment", NULL,     3,  0,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_XMLPI,         183,"xmlpi",      NULL,     3,  1,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_CALLPROP,      184,"callprop",   NULL,     3,  1,  2, 18,  JOF_ATOM|JOF_PROP|JOF_CALLOP)
 OPDEF(JSOP_GETFUNNS,      185,"getfunns",   NULL,     1,  0,  1, 19,  JOF_BYTE)
-OPDEF(JSOP_UNUSED186,     186,"unused186",  NULL,     1,  0,  0,  0,  JOF_BYTE)
+
+/*
+ * Get a display (free) variable from the closure's reserved slots.
+ */
+OPDEF(JSOP_GETUPVAR,      186,"getupvar",   NULL,     3,  0,  1, 19,  JOF_UINT16|JOF_NAME)
+
 OPDEF(JSOP_DELDESC,       187,"deldesc",    NULL,     1,  2,  1, 17,  JOF_BYTE |JOF_ELEM|JOF_DEL)
 
 /*
  * Opcode to hold 24-bit immediate integer operands.
  */
 OPDEF(JSOP_UINT24,        188,"uint24",     NULL,     4,  0,  1, 16,  JOF_UINT24)
 
 /*
  * Opcodes to allow 24-bit atom or object indexes. Whenever an index exceeds
  * the 16-bit limit, the index-accessing bytecode must be bracketed by
  * JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index.
  * See jsemit.c, EmitIndexOp.
  */
-OPDEF(JSOP_INDEXBASE,     189,"atombase",   NULL,     2,  0,  0,  0,  JOF_2BYTE|JOF_INDEXBASE)
+OPDEF(JSOP_INDEXBASE,     189,"atombase",   NULL,     2,  0,  0,  0,  JOF_UINT8|JOF_INDEXBASE)
 OPDEF(JSOP_RESETBASE,     190,"resetbase",  NULL,     1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_RESETBASE0,    191,"resetbase0", NULL,     1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Opcodes to help the decompiler deal with XML.
  */
 OPDEF(JSOP_STARTXML,      192,"startxml",    NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_STARTXMLEXPR,  193,"startxmlexpr",NULL,    1,  0,  0,  0,  JOF_BYTE)
@@ -473,17 +480,20 @@ OPDEF(JSOP_UNUSED207,     207,"unused207
  * Iterator, generator, and array comprehension support.
  */
 OPDEF(JSOP_FORCONST,      208,"forconst",    NULL,    3,  0,  1, 19,  JOF_LOCAL|JOF_NAME|JOF_FOR)
 OPDEF(JSOP_ENDITER,       209,"enditer",     NULL,    1,  1,  0,  0,  JOF_BYTE|JOF_TMPSLOT)
 OPDEF(JSOP_GENERATOR,     210,"generator",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_YIELD,         211,"yield",       NULL,    1,  1,  1,  1,  JOF_BYTE)
 OPDEF(JSOP_ARRAYPUSH,     212,"arraypush",   NULL,    3,  1,  0,  3,  JOF_LOCAL)
 
-OPDEF(JSOP_UNUSED213,     213,"unused213",   NULL,    1,  0,  0,  0,  JOF_BYTE)
+/*
+ * In the forthcoming great opcode reorg, this should go next to JSOP_GETUPVAR.
+ */
+OPDEF(JSOP_CALLUPVAR,     213, "callupvar",  NULL,    3,  0,  2, 19,  JOF_UINT16|JOF_NAME|JOF_CALLOP)
 
 /*
  * Variant of JSOP_ENUMELEM for destructuring const (const [a, b] = ...).
  */
 OPDEF(JSOP_ENUMCONSTELEM, 214,"enumconstelem",NULL,   1,  3,  0,  3,  JOF_BYTE|JOF_SET)
 
 /*
  * Variant of JSOP_LEAVEBLOCK has a result on the stack above the locals,
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -1,10 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
+ * vim: set ts=8 sw=4 et tw=99:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -561,17 +561,17 @@ js_CompileScript(JSContext *cx, JSObject
     JSTokenType tt;
     JSParseNode *pn;
     uint32 scriptGlobals;
     JSScript *script;
 #ifdef METER_PARSENODES
     void *sbrk(ptrdiff_t), *before = sbrk(0);
 #endif
 
-    JS_ASSERT(!(tcflags & ~TCF_COMPILE_N_GO));
+    JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL)));
 
     if (!js_InitParseContext(cx, &pc, principals, chars, length, file,
                              filename, lineno)) {
         return NULL;
     }
 
     /*
      * From this point the control must flow through the label out.
@@ -620,35 +620,35 @@ js_CompileScript(JSContext *cx, JSObject
             !js_EmitTree(cx, &cg, pn)) {
             script = NULL;
             goto out;
         }
         RecycleTree(pn, &cg.treeContext);
     }
 
     /*
-     * Global variables and regexps shares the index space with locals. Due
-     * to incremental code generation we need to patch the bytecode to adjust
-     * the local references to skip the globals.
+     * Global variables and regexps shares the index space with locals. Due to
+     * incremental code generation we need to patch the bytecode to adjust the
+     * local references to skip the globals.
      */
     scriptGlobals = cg.treeContext.ngvars + cg.regexpList.length;
     if (scriptGlobals != 0) {
         jsbytecode *code, *end;
         JSOp op;
         const JSCodeSpec *cs;
         uintN len, slot;
 
         if (scriptGlobals >= SLOTNO_LIMIT)
             goto too_many_slots;
         code = CG_BASE(&cg);
         for (end = code + CG_OFFSET(&cg); code != end; code += len) {
             JS_ASSERT(code < end);
             op = (JSOp) *code;
             cs = &js_CodeSpec[op];
-            len = cs->length > 0
+            len = (cs->length > 0)
                   ? (uintN) cs->length
                   : js_GetVariableBytecodeLength(code);
             if (JOF_TYPE(cs->format) == JOF_LOCAL ||
                 (JOF_TYPE(cs->format) == JOF_SLOTATOM)) {
                 /*
                  * JSOP_GETARGPROP also has JOF_SLOTATOM type, but it may be
                  * emitted only for a function.
                  */
@@ -1234,17 +1234,17 @@ FunctionDef(JSContext *cx, JSTokenStream
      * last-ditch GC.
      */
     funpob = js_NewParsedObjectBox(cx, tc->parseContext, FUN_OBJECT(fun));
     if (!funpob)
         return NULL;
 
     /* Initialize early for possible flags mutation via DestructuringExpr. */
     TREE_CONTEXT_INIT(&funtc, tc->parseContext);
-    funtc.flags |= TCF_IN_FUNCTION;
+    funtc.flags |= TCF_IN_FUNCTION | (tc->flags & TCF_COMPILE_N_GO);
     funtc.fun = fun;
 
     /* Now parse formal argument list and compute fun->nargs. */
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);
     if (!js_MatchToken(cx, ts, TOK_RP)) {
         do {
             tt = js_GetToken(cx, ts);
             switch (tt) {
@@ -1441,17 +1441,17 @@ FunctionDef(JSContext *cx, JSTokenStream
         op = JSOP_CLOSURE;
     } else {
         op = JSOP_NOP;
     }
 
     pn->pn_funpob = funpob;
     pn->pn_op = op;
     pn->pn_body = body;
-    pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS);
+    pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS | TCF_COMPILE_N_GO);
     TREE_CONTEXT_FINISH(cx, &funtc);
     return result;
 }
 
 static JSParseNode *
 FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
 {
     return FunctionDef(cx, ts, tc, 0);
@@ -3217,47 +3217,48 @@ Statement(JSContext *cx, JSTokenStream *
 
                 pn = Variables(cx, ts, tc);
                 if (!pn)
                     return NULL;
                 pn->pn_extra |= PNX_POPVAR;
                 break;
             }
 
+            /*
+             * Some obvious assertions here, but they may help clarify the
+             * situation. This stmt is not yet a scope, so it must not be a
+             * catch block (which is a lexical scope by definition).
+             */
+            JS_ASSERT(!(stmt->flags & SIF_SCOPE));
+            JS_ASSERT(stmt != tc->topScopeStmt);
+            JS_ASSERT(stmt->type == STMT_BLOCK ||
+                      stmt->type == STMT_SWITCH ||
+                      stmt->type == STMT_TRY ||
+                      stmt->type == STMT_FINALLY);
+            JS_ASSERT(!stmt->downScope);
+
             /* Convert the block statement into a scope statement. */
             obj = js_NewBlockObject(cx);
             if (!obj)
                 return NULL;
             blockpob = js_NewParsedObjectBox(cx, tc->parseContext, obj);
             if (!blockpob)
                 return NULL;
 
             /*
              * Insert stmt on the tc->topScopeStmt/stmtInfo.downScope linked
              * list stack, if it isn't already there.  If it is there, but it
              * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
              * block.
              */
-            JS_ASSERT(!(stmt->flags & SIF_SCOPE));
             stmt->flags |= SIF_SCOPE;
-            if (stmt != tc->topScopeStmt) {
-                JS_ASSERT(!stmt->downScope);
-                JS_ASSERT(stmt->type == STMT_BLOCK ||
-                          stmt->type == STMT_SWITCH ||
-                          stmt->type == STMT_TRY ||
-                          stmt->type == STMT_FINALLY);
-                stmt->downScope = tc->topScopeStmt;
-                tc->topScopeStmt = stmt;
-                JS_SCOPE_DEPTH_METERING(
-                    ++tc->scopeDepth > tc->maxScopeDepth &&
-                    tc->maxScopeDepth = tc->scopeDepth);
-            } else {
-                JS_ASSERT(stmt->type == STMT_CATCH);
-                JS_ASSERT(stmt->downScope);
-            }
+            stmt->downScope = tc->topScopeStmt;
+            tc->topScopeStmt = stmt;
+            JS_SCOPE_DEPTH_METERING(++tc->scopeDepth > tc->maxScopeDepth &&
+                                    (tc->maxScopeDepth = tc->scopeDepth));
 
             STOBJ_SET_PARENT(obj, tc->blockChain);
             tc->blockChain = obj;
             stmt->u.blockObj = obj;
 
 #ifdef DEBUG
             pn1 = tc->blockNode;
             JS_ASSERT(!pn1 || pn1->pn_type != TOK_LEXICALSCOPE);
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -1078,17 +1078,17 @@ lexHex:
                 rangeStart = localMax;   /* one run of the uc/dc loop below */
         }
 
         if (state->flags & JSREG_FOLD) {
             jschar maxch = localMax;
 
             for (i = rangeStart; i <= localMax; i++) {
                 jschar uch, dch;
-            
+
                 uch = upcase(i);
                 dch = downcase(i);
                 maxch = JS_MAX(maxch, uch);
                 maxch = JS_MAX(maxch, dch);
             }
             localMax = maxch;
         }
 
@@ -3587,25 +3587,16 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp
 
 out:
     JS_FinishArenaPool(&gData.pool);
     return ok;
 }
 
 /************************************************************************/
 
-enum regexp_tinyid {
-    REGEXP_SOURCE       = -1,
-    REGEXP_GLOBAL       = -2,
-    REGEXP_IGNORE_CASE  = -3,
-    REGEXP_LAST_INDEX   = -4,
-    REGEXP_MULTILINE    = -5,
-    REGEXP_STICKY       = -6
-};
-
 #define REGEXP_PROP_ATTRS     (JSPROP_PERMANENT | JSPROP_SHARED)
 #define RO_REGEXP_PROP_ATTRS  (REGEXP_PROP_ATTRS | JSPROP_READONLY)
 
 static JSPropertySpec regexp_props[] = {
     {"source",     REGEXP_SOURCE,      RO_REGEXP_PROP_ATTRS,0,0},
     {"global",     REGEXP_GLOBAL,      RO_REGEXP_PROP_ATTRS,0,0},
     {"ignoreCase", REGEXP_IGNORE_CASE, RO_REGEXP_PROP_ATTRS,0,0},
     {"lastIndex",  REGEXP_LAST_INDEX,  REGEXP_PROP_ATTRS,0,0},
--- a/js/src/jsregexp.h
+++ b/js/src/jsregexp.h
@@ -136,22 +136,31 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp
  * well-ordered.
  */
 extern JSBool
 js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res);
 
 extern void
 js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res);
 
-#define JSVAL_IS_REGEXP(cx, v)                                                \
+#define VALUE_IS_REGEXP(cx, v)                                                \
     (JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) &&                              \
      OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_RegExpClass)
 
 extern JSClass js_RegExpClass;
 
+enum regexp_tinyid {
+    REGEXP_SOURCE       = -1,
+    REGEXP_GLOBAL       = -2,
+    REGEXP_IGNORE_CASE  = -3,
+    REGEXP_LAST_INDEX   = -4,
+    REGEXP_MULTILINE    = -5,
+    REGEXP_STICKY       = -6
+};
+
 extern JSObject *
 js_InitRegExpClass(JSContext *cx, JSObject *obj);
 
 /*
  * Export js_regexp_toString to the decompiler.
  */
 extern JSBool
 js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp);
--- a/js/src/jsscan.cpp
+++ b/js/src/jsscan.cpp
@@ -1198,17 +1198,17 @@ js_GetToken(JSContext *cx, JSTokenStream
 retry:
     do {
         c = GetChar(ts);
         if (c == '\n') {
             ts->flags &= ~TSF_DIRTYLINE;
             if (ts->flags & TSF_NEWLINES)
                 break;
         }
-    } while (ScanAsSpace(c));
+    } while (ScanAsSpace((jschar)c));
 
     tp = NewToken(ts, -1);
     if (c == EOF) {
         tt = TOK_EOF;
         goto out;
     }
 
     hadUnicodeEscape = JS_FALSE;
@@ -1720,44 +1720,44 @@ retry:
 
                 if (PeekChars(ts, 5, cp) &&
                     cp[0] == '@' &&
                     cp[1] == 'l' &&
                     cp[2] == 'i' &&
                     cp[3] == 'n' &&
                     cp[4] == 'e') {
                     SkipChars(ts, 5);
-                    while ((c = GetChar(ts)) != '\n' && ScanAsSpace(c))
+                    while ((c = GetChar(ts)) != '\n' && ScanAsSpace((jschar)c))
                         continue;
                     if (JS7_ISDEC(c)) {
                         line = JS7_UNDEC(c);
                         while ((c = GetChar(ts)) != EOF && JS7_ISDEC(c)) {
                             temp = 10 * line + JS7_UNDEC(c);
                             if (temp < line) {
                                 /* Ignore overlarge line numbers. */
                                 goto skipline;
                             }
                             line = temp;
                         }
-                        while (c != '\n' && ScanAsSpace(c))
+                        while (c != '\n' && ScanAsSpace((jschar)c))
                             c = GetChar(ts);
                         i = 0;
                         if (c == '"') {
                             while ((c = GetChar(ts)) != EOF && c != '"') {
                                 if (c == '\n') {
                                     UngetChar(ts, c);
                                     goto skipline;
                                 }
                                 if ((c >> 8) != 0 || i >= sizeof filename - 1)
                                     goto skipline;
                                 filename[i++] = (char) c;
                             }
                             if (c == '"') {
                                 while ((c = GetChar(ts)) != '\n' &&
-                                       ScanAsSpace(c)) {
+                                       ScanAsSpace((jschar)c)) {
                                     continue;
                                 }
                             }
                         }
                         filename[i] = '\0';
                         if (c == '\n') {
                             if (i > 0) {
                                 if (ts->flags & TSF_OWNFILENAME)
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -288,17 +288,17 @@ script_compile_sub(JSContext *cx, JSObje
     v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
     oldscript = (JSScript*) (!JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL);
     LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
     JS_UNLOCK_OBJ(cx, obj);
 
     if (oldscript)
         js_DestroyScript(cx, oldscript);
 
-    script->object = obj;
+    script->u.object = obj;
     js_CallNewScriptHook(cx, script, NULL);
 
 out:
     /* Return the object. */
     *rval = OBJECT_TO_JSVAL(obj);
     return JS_TRUE;
 }
 
@@ -416,27 +416,27 @@ script_exec(JSContext *cx, uintN argc, j
 JSBool
 js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
 {
     JSContext *cx;
     JSScript *script, *oldscript;
     JSBool ok;
     jsbytecode *code;
     uint32 length, lineno, nslots, magic;
-    uint32 natoms, nsrcnotes, ntrynotes, nobjects, nregexps, i;
+    uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i;
     uint32 prologLength, version;
     JSTempValueRooter tvr;
     JSPrincipals *principals;
     uint32 encodeable;
     JSBool filenameWasSaved;
     jssrcnote *notes, *sn;
 
     cx = xdr->cx;
     script = *scriptp;
-    nsrcnotes = ntrynotes = natoms = nobjects = nregexps = 0;
+    nsrcnotes = ntrynotes = natoms = nobjects = nupvars = nregexps = 0;
     filenameWasSaved = JS_FALSE;
     notes = NULL;
 
     if (xdr->mode == JSXDR_ENCODE)
         magic = JSXDR_MAGIC_SCRIPT_CURRENT;
     if (!JS_XDRUint32(xdr, &magic))
         return JS_FALSE;
     if (magic != JSXDR_MAGIC_SCRIPT_CURRENT) {
@@ -454,58 +454,63 @@ js_XDRScript(JSXDRState *xdr, JSScript *
 
     if (xdr->mode == JSXDR_ENCODE) {
         length = script->length;
         prologLength = PTRDIFF(script->main, script->code, jsbytecode);
         JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);
         version = (uint32)script->version | (script->nfixed << 16);
         lineno = (uint32)script->lineno;
         nslots = (uint32)script->nslots;
+        nslots = (uint32)((script->staticDepth << 16) | script->nslots);
         natoms = (uint32)script->atomMap.length;
 
         /* Count the srcnotes, keeping notes pointing at the first one. */
         notes = SCRIPT_NOTES(script);
         for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
             continue;
         nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
         nsrcnotes++;            /* room for the terminator */
 
         if (script->objectsOffset != 0)
             nobjects = JS_SCRIPT_OBJECTS(script)->length;
+        if (script->upvarsOffset != 0)
+            nupvars = JS_SCRIPT_UPVARS(script)->length;
         if (script->regexpsOffset != 0)
             nregexps = JS_SCRIPT_REGEXPS(script)->length;
         if (script->trynotesOffset != 0)
             ntrynotes = JS_SCRIPT_TRYNOTES(script)->length;
     }
 
     if (!JS_XDRUint32(xdr, &length))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &prologLength))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &version))
         return JS_FALSE;
 
     /*
-     * To fuse allocations, we need srcnote, atom, objects, regexp and trynote
-     * counts early.
+     * To fuse allocations, we need srcnote, atom, objects, upvar, regexp,
+     * and trynote counts early.
      */
     if (!JS_XDRUint32(xdr, &natoms))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &nsrcnotes))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &ntrynotes))
         return JS_FALSE;
     if (!JS_XDRUint32(xdr, &nobjects))
         return JS_FALSE;
+    if (!JS_XDRUint32(xdr, &nupvars))
+        return JS_FALSE;
     if (!JS_XDRUint32(xdr, &nregexps))
         return JS_FALSE;
 
     if (xdr->mode == JSXDR_DECODE) {
-        script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nregexps,
-                              ntrynotes);
+        script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars,
+                              nregexps, ntrynotes);
         if (!script)
             return JS_FALSE;
 
         script->main += prologLength;
         script->version = (JSVersion) (version & 0xffff);
         script->nfixed = (uint16) (version >> 16);
 
         /* If we know nsrcnotes, we allocated space for notes in script. */
@@ -572,34 +577,39 @@ js_XDRScript(JSXDRState *xdr, JSScript *
             filename = js_SaveScriptFilename(cx, filename);
             if (!filename)
                 goto error;
             JS_free(cx, (void *) script->filename);
             script->filename = filename;
             filenameWasSaved = JS_TRUE;
         }
         script->lineno = (uintN)lineno;
-        script->nslots = (uintN)nslots;
+        script->nslots = (uint16)nslots;
+        script->staticDepth = nslots >> 16;
     }
 
     for (i = 0; i != natoms; ++i) {
         if (!js_XDRAtom(xdr, &script->atomMap.vector[i]))
             goto error;
     }
 
     /*
      * Here looping from 0-to-length to xdr objects is essential. It ensures
-     * that block objects from the script->objects will be written and
-     * restored in the outer-to-inner order. block_xdrObject uses this to
+     * that block objects from the script->objects array will be written and
+     * restored in the outer-to-inner order. block_xdrObject relies on this to
      * restore the parent chain.
      */
     for (i = 0; i != nobjects; ++i) {
         if (!js_XDRObject(xdr, &JS_SCRIPT_OBJECTS(script)->vector[i]))
             goto error;
     }
+    for (i = 0; i != nupvars; ++i) {
+        if (!JS_XDRUint32(xdr, &JS_SCRIPT_UPVARS(script)->vector[i]))
+            goto error;
+    }
     for (i = 0; i != nregexps; ++i) {
         if (!js_XDRObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i]))
             goto error;
     }
 
     if (ntrynotes != 0) {
         /*
          * We combine tn->kind and tn->stackDepth when serializing as XDR is not
@@ -798,17 +808,17 @@ script_thaw(JSContext *cx, uintN argc, j
     v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
     oldscript = !JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL;
     LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
     JS_UNLOCK_OBJ(cx, obj);
 
     if (oldscript)
         js_DestroyScript(cx, oldscript);
 
-    script->object = obj;
+    script->u.object = obj;
     js_CallNewScriptHook(cx, script, NULL);
 
 out:
     /*
      * We reset the buffer to be NULL so that it doesn't free the chars
      * memory owned by str (vp[2]).
      */
     JS_XDRMemSetData(xdr, NULL, 0);
@@ -1318,34 +1328,39 @@ JS_STATIC_ASSERT(sizeof(JSObjectArray) %
 JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray));
 JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *));
 JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32) == 0);
 JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32));
 JS_STATIC_ASSERT(sizeof(uint32) % sizeof(jsbytecode) == 0);
 JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0);
 
 /*
- * Check that uint8 offset for object, regexp and try note arrays is sufficient.
+ * Check that uint8 offset for object, upvar, regexp, and try note arrays is
+ * sufficient.
  */
-JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) < JS_BIT(8));
+JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) +
+                 sizeof(JSUpvarArray) < JS_BIT(8));
 
 JSScript *
 js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
-             uint32 nobjects, uint32 nregexps, uint32 ntrynotes)
+             uint32 nobjects, uint32 nupvars, uint32 nregexps,
+             uint32 ntrynotes)
 {
     size_t size, vectorSize;
     JSScript *script;
     uint8 *cursor;
 
     size = sizeof(JSScript) +
            sizeof(JSAtom *) * natoms +
            length * sizeof(jsbytecode) +
            nsrcnotes * sizeof(jssrcnote);
     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);
 
     script = (JSScript *) JS_malloc(cx, size);
     if (!script)
         return NULL;
@@ -1353,16 +1368,20 @@ js_NewScript(JSContext *cx, uint32 lengt
     script->length = length;
     script->version = cx->version;
 
     cursor = (uint8 *)script + sizeof(JSScript);
     if (nobjects != 0) {
         script->objectsOffset = (uint8)(cursor - (uint8 *)script);
         cursor += sizeof(JSObjectArray);
     }
+    if (nupvars != 0) {
+        script->upvarsOffset = (uint8)(cursor - (uint8 *)script);
+        cursor += sizeof(JSUpvarArray);
+    }
     if (nregexps != 0) {
         script->regexpsOffset = (uint8)(cursor - (uint8 *)script);
         cursor += sizeof(JSObjectArray);
     }
     if (ntrynotes != 0) {
         script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
         cursor += sizeof(JSTryNoteArray);
     }
@@ -1374,30 +1393,41 @@ js_NewScript(JSContext *cx, uint32 lengt
 
         /*
          * 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 (nobjects != 0) {
         JS_SCRIPT_OBJECTS(script)->length = nobjects;
         JS_SCRIPT_OBJECTS(script)->vector = (JSObject **)cursor;
         vectorSize = nobjects * sizeof(JS_SCRIPT_OBJECTS(script)->vector[0]);
         memset(cursor, 0, vectorSize);
         cursor += vectorSize;
     }
+
+    if (nupvars != 0) {
+        JS_SCRIPT_UPVARS(script)->length = nupvars;
+        JS_SCRIPT_UPVARS(script)->vector = (uint32 *)cursor;
+        vectorSize = nupvars * sizeof(JS_SCRIPT_UPVARS(script)->vector[0]);
+        memset(cursor, 0, vectorSize);
+        cursor += vectorSize;
+    }
+
     if (nregexps != 0) {
         JS_SCRIPT_REGEXPS(script)->length = nregexps;
         JS_SCRIPT_REGEXPS(script)->vector = (JSObject **)cursor;
         vectorSize = nregexps * sizeof(JS_SCRIPT_REGEXPS(script)->vector[0]);
         memset(cursor, 0, vectorSize);
         cursor += vectorSize;
     }
+
     if (ntrynotes != 0) {
         JS_SCRIPT_TRYNOTES(script)->length = ntrynotes;
         JS_SCRIPT_TRYNOTES(script)->vector = (JSTryNote *)cursor;
         vectorSize = ntrynotes * sizeof(JS_SCRIPT_TRYNOTES(script)->vector[0]);
 #ifdef DEBUG
         memset(cursor, 0, vectorSize);
 #endif
         cursor += vectorSize;
@@ -1428,17 +1458,18 @@ js_NewScriptFromCG(JSContext *cx, JSCode
     JS_ASSERT(cg->objectList.length <= INDEX_LIMIT);
     JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT);
 
     mainLength = CG_OFFSET(cg);
     prologLength = CG_PROLOG_OFFSET(cg);
     CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
     script = js_NewScript(cx, prologLength + mainLength, nsrcnotes,
                           cg->atomList.count, cg->objectList.length,
-                          cg->regexpList.length, cg->ntrynotes);
+                          cg->upvarList.count, cg->regexpList.length,
+                          cg->ntrynotes);
     if (!script)
         return NULL;
 
     /* Now that we have script, error control flow must go to label bad. */
     script->main += prologLength;
     memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
     memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
     nfixed = (cg->treeContext.flags & TCF_IN_FUNCTION)
@@ -1450,38 +1481,58 @@ js_NewScriptFromCG(JSContext *cx, JSCode
 
     filename = cg->treeContext.parseContext->tokenStream.filename;
     if (filename) {
         script->filename = js_SaveScriptFilename(cx, filename);
         if (!script->filename)
             goto bad;
     }
     script->lineno = cg->firstLine;
+    if (script->nfixed + cg->maxStackDepth >= JS_BIT(16)) {
+        js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR,
+                                    JSMSG_NEED_DIET, "script");
+        goto bad;
+    }
     script->nslots = script->nfixed + cg->maxStackDepth;
+    script->staticDepth = cg->staticDepth;
     script->principals = cg->treeContext.parseContext->principals;
     if (script->principals)
         JSPRINCIPALS_HOLD(cx, script->principals);
 
     if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script)))
         goto bad;
     if (cg->ntrynotes != 0)
         js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script));
     if (cg->objectList.length != 0)
         FinishParsedObjects(&cg->objectList, JS_SCRIPT_OBJECTS(script));
     if (cg->regexpList.length != 0)
         FinishParsedObjects(&cg->regexpList, JS_SCRIPT_REGEXPS(script));
+    if (cg->treeContext.flags & TCF_NO_SCRIPT_RVAL)
+        script->flags |= JSSF_NO_SCRIPT_RVAL;
+
+    if (cg->upvarList.count != 0) {
+        JS_ASSERT(cg->upvarList.count <= cg->upvarMap.length);
+        memcpy(JS_SCRIPT_UPVARS(script)->vector, cg->upvarMap.vector,
+               cg->upvarList.count * sizeof(uint32));
+        ATOM_LIST_INIT(&cg->upvarList);
+        JS_free(cx, cg->upvarMap.vector);
+        cg->upvarMap.vector = NULL;
+    }
 
     /*
      * We initialize fun->u.script to be the script constructed above
      * so that the debugger has a valid FUN_SCRIPT(fun).
      */
     fun = NULL;
     if (cg->treeContext.flags & TCF_IN_FUNCTION) {
         fun = cg->treeContext.fun;
         JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
+        JS_ASSERT_IF(script->upvarsOffset != 0,
+                     JS_SCRIPT_UPVARS(script)->length == fun->u.i.nupvars);
+
         js_FreezeLocalNames(cx, fun);
         fun->u.i.script = script;
 #ifdef CHECK_SCRIPT_OWNER
         script->owner = NULL;
 #endif
         if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)
             fun->flags |= JSFUN_HEAVYWEIGHT;
     }
@@ -1544,22 +1595,23 @@ js_DestroyScript(JSContext *cx, JSScript
      * 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
 
-    if (!cx->runtime->gcRunning &&
-        !(cx->fp && (cx->fp->flags & JSFRAME_EVAL))) {
+    if (!cx->runtime->gcRunning) {
+        if (!(cx->fp && (cx->fp->flags & JSFRAME_EVAL))) {
 #ifdef CHECK_SCRIPT_OWNER
-        JS_ASSERT(script->owner == cx->thread);
+            JS_ASSERT(script->owner == cx->thread);
 #endif
-        js_FlushPropertyCacheForScript(cx, script);
+            js_FlushPropertyCacheForScript(cx, script);
+        }
     }
 
     JS_free(cx, script);
 }
 
 void
 js_TraceScript(JSTracer *trc, JSScript *script)
 {
@@ -1599,19 +1651,19 @@ js_TraceScript(JSTracer *trc, JSScript *
             --i;
             if (objarray->vector[i]) {
                 JS_SET_TRACING_INDEX(trc, "regexps", i);
                 JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
             }
         } while (i != 0);
     }
 
-    if (script->object) {
+    if (script->u.object) {
         JS_SET_TRACING_NAME(trc, "object");
-        JS_CallTracer(trc, script->object, JSTRACE_OBJECT);
+        JS_CallTracer(trc, script->u.object, JSTRACE_OBJECT);
     }
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 }
 
 typedef struct GSNCacheEntry {
     JSDHashEntryHdr     hdr;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1,10 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
+ * vim: set ts=8 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
  * http://www.mozilla.org/MPL/
@@ -44,18 +44,18 @@
  * JS script descriptor.
  */
 #include "jsatom.h"
 #include "jsprvtd.h"
 
 JS_BEGIN_EXTERN_C
 
 /*
- * Type of try note associated with each catch or finally block or with for-in
- * loop.
+ * Type of try note associated with each catch or finally block, and also with
+ * for-in loops.
  */
 typedef enum JSTryNoteKind {
     JSTN_CATCH,
     JSTN_FINALLY,
     JSTN_ITER
 } JSTryNoteKind;
 
 /*
@@ -67,69 +67,92 @@ struct JSTryNote {
     uint16          stackDepth; /* stack depth upon exception handler entry */
     uint32          start;      /* start of the try statement or for-in loop
                                    relative to script->main */
     uint32          length;     /* length of the try statement or for-in loop */
 };
 
 typedef struct JSTryNoteArray {
     JSTryNote       *vector;    /* array of indexed try notes */
-    uint32          length;     /* count of indexded try notes */
+    uint32          length;     /* count of indexed try notes */
 } JSTryNoteArray;
 
 typedef struct JSObjectArray {
     JSObject        **vector;   /* array of indexed objects */
-    uint32          length;     /* count of indexded objects */
+    uint32          length;     /* count of indexed objects */
 } JSObjectArray;
 
+typedef struct JSUpvarArray {
+    uint32          *vector;    /* array of indexed upvar cookies */
+    uint32          length;     /* count of indexed upvar cookies */
+} JSUpvarArray;
+
+#define MAKE_UPVAR_COOKIE(skip,slot)    ((skip) << 16 | (slot))
+#define UPVAR_FRAME_SKIP(cookie)        ((uint32)(cookie) >> 16)
+#define UPVAR_FRAME_SLOT(cookie)        ((uint16)(cookie))
+
 #define JS_OBJECT_ARRAY_SIZE(length)                                          \
     (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length))
 
 #if defined DEBUG && defined JS_THREADSAFE
 # define CHECK_SCRIPT_OWNER 1
 #endif
 
 struct JSScript {
     jsbytecode      *code;      /* bytecodes and their immediate operands */
     uint32          length;     /* length of code vector */
     uint16          version;    /* JS version under which script was compiled */
     uint16          nfixed;     /* number of slots besides stack operands in
                                    slot array */
     uint8           objectsOffset;  /* offset to the array of nested function,
                                        block, scope, xml and one-time regexps
                                        objects or 0 if none */
+    uint8           upvarsOffset;   /* offset of the array of display ("up")
+                                       closure vars or 0 if none */
     uint8           regexpsOffset;  /* offset to the array of to-be-cloned
                                        regexps or 0 if none. */
     uint8           trynotesOffset; /* offset to the array of try notes or
                                        0 if none */
+    uint8           flags;      /* see below */
     jsbytecode      *main;      /* main entry point, after predef'ing prolog */
     JSAtomMap       atomMap;    /* maps immediate index to literal struct */
     const char      *filename;  /* source filename or null */
-    uintN           lineno;     /* base line number of script */
-    uintN           nslots;     /* vars plus maximum stack depth */
+    uint32          lineno;     /* base line number of script */
+    uint16          nslots;     /* vars plus maximum stack depth */
+    uint16          staticDepth;/* static depth for display maintenance */
     JSPrincipals    *principals;/* principals for this script */
-    JSObject        *object;    /* optional Script-class object wrapper */
+    union {
+        JSObject    *object;    /* optional Script-class object wrapper */
+        JSScript    *nextToGC;  /* next to GC in rt->scriptsToGC list */
+    } u;
 #ifdef CHECK_SCRIPT_OWNER
     JSThread        *owner;     /* for thread-safe life-cycle assertions */
 #endif
 };
 
+#define JSSF_NO_SCRIPT_RVAL     0x01    /* no need for result value of last
+                                           expression statement */
+
 static JS_INLINE uintN
 StackDepth(JSScript *script)
 {
     return script->nslots - script->nfixed;
 }
 
 /* No need to store script->notes now that it is allocated right after code. */
 #define SCRIPT_NOTES(script)    ((jssrcnote*)((script)->code+(script)->length))
 
 #define JS_SCRIPT_OBJECTS(script)                                             \
     (JS_ASSERT((script)->objectsOffset != 0),                                 \
      (JSObjectArray *)((uint8 *)(script) + (script)->objectsOffset))
 
+#define JS_SCRIPT_UPVARS(script)                                              \
+    (JS_ASSERT((script)->upvarsOffset != 0),                                  \
+     (JSUpvarArray *)((uint8 *)(script) + (script)->upvarsOffset))
+
 #define JS_SCRIPT_REGEXPS(script)                                             \
     (JS_ASSERT((script)->regexpsOffset != 0),                                 \
      (JSObjectArray *)((uint8 *)(script) + (script)->regexpsOffset))
 
 #define JS_SCRIPT_TRYNOTES(script)                                            \
     (JS_ASSERT((script)->trynotesOffset != 0),                                \
      (JSTryNoteArray *)((uint8 *)(script) + (script)->trynotesOffset))
 
@@ -229,17 +252,18 @@ js_SweepScriptFilenames(JSRuntime *rt);
  * The js_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 js_NewScript
  * are responsible for notifying the debugger after successfully creating any
  * kind (function or other) of new JSScript.
  */
 extern JSScript *
 js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
-             uint32 nobjects, uint32 nregexps, uint32 ntrynotes);
+             uint32 nobjects, uint32 nupvars, uint32 nregexps,
+             uint32 ntrynotes);
 
 extern JSScript *
 js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
 
 /*
  * New-script-hook calling is factored from js_NewScriptFromCG so that it
  * and callers of js_XDRScript can share this code.  In the case of callers
  * of js_XDRScript, the hook should be invoked only after successful decode
--- a/js/src/jsstddef.h
+++ b/js/src/jsstddef.h
@@ -75,9 +75,13 @@ typedef long ptrdiff_t;
 
 #define PTRDIFF(p1, p2, type)                                 \
         ((p1) - (p2))
 
 #endif
 
 #include <stddef.h>
 
-
+#ifdef __cplusplus
+# define __cplusplus_only(x)    x
+#else
+# define __cplusplus_only(x)    /* nothing */
+#endif
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -118,17 +118,17 @@ js_GetDependentStringChars(JSString *str
 const jschar *
 js_GetStringChars(JSContext *cx, JSString *str)
 {
     if (!js_MakeStringImmutable(cx, str))
         return NULL;
     return JSFLATSTR_CHARS(str);
 }
 
-JSString *
+JSString * JS_FASTCALL
 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
 {
     size_t rn, ln, lrdist, n;
     jschar *rs, *ls, *s;
     JSString *ldep;             /* non-null if left should become dependent */
     JSString *str;
 
     JSSTRING_CHARS_AND_LENGTH(right, rs, rn);
@@ -727,18 +727,18 @@ static JSBool
 str_toString(JSContext *cx, uintN argc, jsval *vp)
 {
     return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp);
 }
 
 /*
  * Java-like string native methods.
  */
-static JSBool
-str_substring(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_str_substring(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str;
     jsdouble d;
     jsdouble length, begin, end;
 
     NORMALIZE_THIS(cx, vp, str);
     if (argc != 0) {
         d = js_ValueToNumber(cx, &vp[2]);
@@ -875,18 +875,18 @@ str_localeCompare(JSContext *cx, uintN a
             vp[2] = STRING_TO_JSVAL(thatStr);
             return cx->localeCallbacks->localeCompare(cx, str, thatStr, vp);
         }
         *vp = INT_TO_JSVAL(js_CompareStrings(str, thatStr));
     }
     return JS_TRUE;
 }
 
-static JSBool
-str_charAt(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_str_charAt(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval t;
     JSString *str;
     jsint i;
     jsdouble d;
 
     t = vp[1];
     if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) {
@@ -919,18 +919,18 @@ str_charAt(JSContext *cx, uintN argc, js
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 
 out_of_range:
     *vp = JS_GetEmptyStringValue(cx);
     return JS_TRUE;
 }
 
-static JSBool
-str_charCodeAt(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_str_charCodeAt(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval t;
     JSString *str;
     jsint i;
     jsdouble d;
 
     t = vp[1];
     if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) {
@@ -1126,16 +1126,17 @@ str_lastIndexOf(JSContext *cx, uintN arg
     *vp = INT_TO_JSVAL(i);
     return JS_TRUE;
 }
 
 /*
  * Perl-inspired string functions.
  */
 typedef struct GlobData {
+    jsbytecode  *pc;            /* in: program counter resulting in us matching */
     uintN       flags;          /* inout: mode and flag bits, see below */
     uintN       optarg;         /* in: index of optional flags argument */
     JSString    *str;           /* out: 'this' parameter object as string */
     JSRegExp    *regexp;        /* out: regexp parameter object private data */
 } GlobData;
 
 /*
  * Mode and flag bit definitions for match_or_replace's GlobData.flags field.
@@ -1162,17 +1163,17 @@ match_or_replace(JSContext *cx,
     JSRegExp *re;
     size_t index, length;
     JSBool ok, test;
     jsint count;
 
     NORMALIZE_THIS(cx, vp, str);
     data->str = str;
 
-    if (argc != 0 && JSVAL_IS_REGEXP(cx, vp[2])) {
+    if (argc != 0 && VALUE_IS_REGEXP(cx, vp[2])) {
         reobj = JSVAL_TO_OBJECT(vp[2]);
         re = (JSRegExp *) JS_GetPrivate(cx, reobj);
     } else {
         src = ArgToRootedString(cx, argc, vp, 0);
         if (!src)
             return JS_FALSE;
         if (data->optarg < argc) {
             opt = js_ValueToString(cx, vp[2 + data->optarg]);
@@ -1225,34 +1226,28 @@ match_or_replace(JSContext *cx,
             if (!ok && destroy)
                 destroy(cx, data);
         }
     } else {
         if (GET_MODE(data->flags) == MODE_REPLACE) {
             test = JS_TRUE;
         } else {
             /*
-             * MODE_MATCH implies str_match is being called from a script or a
-             * scripted function.  If the caller cares only about testing null
+             * MODE_MATCH implies js_str_match is being called from a script or
+             * a scripted function.  If the caller cares only about testing null
              * vs. non-null return value, optimize away the array object that
              * would normally be returned in *vp.
+             *
+             * Assume a full array result is required, then prove otherwise.
              */
-            JSStackFrame *fp;
-
-            /* Skip Function.prototype.call and .apply frames. */
-            for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
-                JS_ASSERT(!fp->script);
-
-            /* Assume a full array result is required, then prove otherwise. */
             test = JS_FALSE;
-            if (fp) {
-                JS_ASSERT(*fp->regs->pc == JSOP_CALL ||
-                          *fp->regs->pc == JSOP_NEW);
-                JS_ASSERT(js_CodeSpec[*fp->regs->pc].length == 3);
-                switch (fp->regs->pc[3]) {
+            if (data->pc) {
+                JS_ASSERT(*data->pc == JSOP_CALL || *data->pc == JSOP_NEW);
+                JS_ASSERT(js_CodeSpec[*data->pc].length == 3);
+                switch (data->pc[3]) {
                   case JSOP_POP:
                   case JSOP_IFEQ:
                   case JSOP_IFNE:
                   case JSOP_IFEQX:
                   case JSOP_IFNEX:
                     test = JS_TRUE;
                     break;
                   default:;
@@ -1301,34 +1296,45 @@ match_glob(JSContext *cx, jsint count, G
     matchstr = js_NewStringCopyN(cx, matchsub->chars, matchsub->length);
     if (!matchstr)
         return JS_FALSE;
     v = STRING_TO_JSVAL(matchstr);
     JS_ASSERT(count <= JSVAL_INT_MAX);
     return OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(count), &v);
 }
 
-static JSBool
-str_match(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc)
 {
     JSTempValueRooter tvr;
     MatchData mdata;
     JSBool ok;
 
     JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
+    mdata.base.pc = pc;
     mdata.base.flags = MODE_MATCH;
     mdata.base.optarg = 1;
     mdata.arrayval = &tvr.u.value;
     ok = match_or_replace(cx, match_glob, NULL, &mdata.base, argc, vp);
     if (ok && !JSVAL_IS_NULL(*mdata.arrayval))
         *vp = *mdata.arrayval;
     JS_POP_TEMP_ROOT(cx, &tvr);
     return ok;
 }
 
+JSBool
+js_str_match(JSContext *cx, uintN argc, jsval *vp)
+{
+    JSStackFrame *fp;
+
+    for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
+        JS_ASSERT(!fp->script);
+    return js_StringMatchHelper(cx, argc, vp, fp ? fp->regs->pc : NULL);
+}
+
 static JSBool
 str_search(JSContext *cx, uintN argc, jsval *vp)
 {
     GlobData data;
 
     data.flags = MODE_SEARCH;
     data.optarg = 1;
     return match_or_replace(cx, NULL, NULL, &data, argc, vp);
@@ -1420,17 +1426,17 @@ find_replen(JSContext *cx, ReplaceData *
         jsval *invokevp, *sp;
         void *mark;
         JSBool ok;
 
         /*
          * Save the regExpStatics from the current regexp, since they may be
          * clobbered by a RegExp usage in the lambda function.  Note that all
          * members of JSRegExpStatics are JSSubStrings, so not GC roots, save
-         * input, which is rooted otherwise via vp[1] in str_replace.
+         * input, which is rooted otherwise via vp[1] in js_str_replace.
          */
         JSRegExpStatics save = cx->regExpStatics;
         JSBool freeMoreParens = JS_FALSE;
 
         /*
          * In the lambda case, not only do we find the replacement string's
          * length, we compute repstr and return it via rdata for use within
          * do_replace.  The lambda is called with arguments ($&, $1, $2, ...,
@@ -1600,36 +1606,45 @@ replace_glob(JSContext *cx, jsint count,
     chars += rdata->index;
     rdata->index += growth;
     js_strncpy(chars, left, leftlen);
     chars += leftlen;
     do_replace(cx, rdata, chars);
     return JS_TRUE;
 }
 
-static JSBool
-str_replace(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_str_replace(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *lambda;
-    JSString *repstr, *str;
-    ReplaceData rdata;
-    JSBool ok;
-    jschar *chars;
-    size_t leftlen, rightlen, length;
+    JSString *repstr;
 
     if (argc >= 2 && JS_TypeOfValue(cx, vp[3]) == JSTYPE_FUNCTION) {
         lambda = JSVAL_TO_OBJECT(vp[3]);
         repstr = NULL;
     } else {
         lambda = NULL;
         repstr = ArgToRootedString(cx, argc, vp, 1);
         if (!repstr)
             return JS_FALSE;
     }
 
+    return js_StringReplaceHelper(cx, argc, lambda, repstr, vp);
+}
+
+JSBool
+js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda,
+                       JSString *repstr, jsval *vp)
+{
+    ReplaceData rdata;
+    JSBool ok;
+    size_t leftlen, rightlen, length;
+    jschar *chars;
+    JSString *str;
+
     /*
      * For ECMA Edition 3, the first argument is to be converted to a string
      * to match in a "flat" sense (without regular expression metachars having
      * special meanings) UNLESS the first arg is a RegExp object.
      */
     rdata.base.flags = MODE_REPLACE | KEEP_REGEXP | FORCE_FLAT;
     rdata.base.optarg = 2;
 
@@ -1698,20 +1713,20 @@ str_replace(JSContext *cx, uintN argc, j
 out:
     /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */
     if (rdata.base.flags & KEEP_REGEXP)
         js_DestroyRegExp(cx, rdata.base.regexp);
     return ok;
 }
 
 /*
- * Subroutine used by str_split to find the next split point in str, starting
- * at offset *ip and looking either for the separator substring given by sep,
- * or for the next re match.  In the re case, return the matched separator in
- * *sep, and the possibly updated offset in *ip.
+ * Subroutine used by js_str_split to find the next split point in str, starting
+ * at offset *ip and looking either for the separator substring given by sep, or
+ * for the next re match.  In the re case, return the matched separator in *sep,
+ * and the possibly updated offset in *ip.
  *
  * Return -2 on error, -1 on end of string, >= 0 for a valid index of the next
  * separator occurrence if found, or str->length if no separator is found.
  */
 static jsint
 find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip,
            JSSubString *sep)
 {
@@ -1723,17 +1738,17 @@ find_split(JSContext *cx, JSString *str,
      * Stop if past end of string.  If at end of string, we will compare the
      * null char stored there (by js_NewString*) to sep->chars[j] in the while
      * loop at the end of this function, so that
      *
      *  "ab,".split(',') => ["ab", ""]
      *
      * and the resulting array converts back to the string "ab," for symmetry.
      * However, we ape Perl and do this only if there is a sufficiently large
-     * limit argument (see str_split).
+     * limit argument (see js_str_split).
      */
     i = *ip;
     length = JSSTRING_LENGTH(str);
     if ((size_t)i > length)
         return -1;
 
     chars = JSSTRING_CHARS(str);
 
@@ -1809,18 +1824,18 @@ find_split(JSContext *cx, JSString *str,
         } else {
             i++;
             j = 0;
         }
     }
     return k;
 }
 
-static JSBool
-str_split(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_str_split(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str, *sub;
     JSObject *arrayobj;
     jsval v;
     JSBool ok, limited;
     JSRegExp *re;
     JSSubString *sep, tmp;
     jsdouble d;
@@ -1833,17 +1848,17 @@ str_split(JSContext *cx, uintN argc, jsv
     if (!arrayobj)
         return JS_FALSE;
     *vp = OBJECT_TO_JSVAL(arrayobj);
 
     if (argc == 0) {
         v = STRING_TO_JSVAL(str);
         ok = OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(0), &v);
     } else {
-        if (JSVAL_IS_REGEXP(cx, vp[2])) {
+        if (VALUE_IS_REGEXP(cx, vp[2])) {
             re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2]));
             sep = &tmp;
 
             /* Set a magic value so we can detect a successful re match. */
             sep->chars = NULL;
             sep->length = 0;
         } else {
             JSString *str2 = js_ValueToString(cx, vp[2]);
@@ -1962,18 +1977,18 @@ str_substr(JSContext *cx, uintN argc, js
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 #endif /* JS_HAS_PERL_SUBSTR */
 
 /*
  * Python-esque sequence operations.
  */
-static JSBool
-str_concat(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_str_concat(JSContext *cx, uintN argc, jsval *vp)
 {
     JSString *str, *str2;
     jsval *argv;
     uintN i;
 
     NORMALIZE_THIS(cx, vp, str);
 
     for (i = 0, argv = vp + 2; i < argc; i++) {
@@ -2234,38 +2249,38 @@ static JSFunctionSpec string_methods[] =
 #if JS_HAS_TOSOURCE
     JS_FN("quote",             str_quote,             0,GENERIC_PRIMITIVE),
     JS_FN(js_toSource_str,     str_toSource,          0,JSFUN_THISP_STRING),
 #endif
 
     /* Java-like methods. */
     JS_FN(js_toString_str,     str_toString,          0,JSFUN_THISP_STRING),
     JS_FN(js_valueOf_str,      str_toString,          0,JSFUN_THISP_STRING),
-    JS_FN("substring",         str_substring,         2,GENERIC_PRIMITIVE),
+    JS_FN("substring",         js_str_substring,      2,GENERIC_PRIMITIVE),
     JS_FN("toLowerCase",       str_toLowerCase,       0,GENERIC_PRIMITIVE),
     JS_FN("toUpperCase",       str_toUpperCase,       0,GENERIC_PRIMITIVE),
-    JS_FN("charAt",            str_charAt,            1,GENERIC_PRIMITIVE),
-    JS_FN("charCodeAt",        str_charCodeAt,        1,GENERIC_PRIMITIVE),
+    JS_FN("charAt",            js_str_charAt,         1,GENERIC_PRIMITIVE),
+    JS_FN("charCodeAt",        js_str_charCodeAt,     1,GENERIC_PRIMITIVE),
     JS_FN("indexOf",           str_indexOf,           1,GENERIC_PRIMITIVE),
     JS_FN("lastIndexOf",       str_lastIndexOf,       1,GENERIC_PRIMITIVE),
     JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,GENERIC_PRIMITIVE),
     JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,GENERIC_PRIMITIVE),
     JS_FN("localeCompare",     str_localeCompare,     1,GENERIC_PRIMITIVE),
 
     /* Perl-ish methods (search is actually Python-esque). */
-    JS_FN("match",             str_match,             1,GENERIC_PRIMITIVE),
+    JS_FN("match",             js_str_match,          1,GENERIC_PRIMITIVE),
     JS_FN("search",            str_search,            1,GENERIC_PRIMITIVE),
-    JS_FN("replace",           str_replace,           2,GENERIC_PRIMITIVE),
-    JS_FN("split",             str_split,             2,GENERIC_PRIMITIVE),
+    JS_FN("replace",           js_str_replace,        2,GENERIC_PRIMITIVE),
+    JS_FN("split",             js_str_split,          2,GENERIC_PRIMITIVE),
 #if JS_HAS_PERL_SUBSTR
     JS_FN("substr",            str_substr,            2,GENERIC_PRIMITIVE),
 #endif
 
     /* Python-esque sequence methods. */
-    JS_FN("concat",            str_concat,            1,GENERIC_PRIMITIVE),
+    JS_FN("concat",            js_str_concat,         1,GENERIC_PRIMITIVE),
     JS_FN("slice",             str_slice,             2,GENERIC_PRIMITIVE),
 
     /* HTML string methods. */
 #if JS_HAS_STR_HTML_HELPERS
     JS_FN("bold",              str_bold,              0,PRIMITIVE),
     JS_FN("italics",           str_italics,           0,PRIMITIVE),
     JS_FN("fixed",             str_fixed,             0,PRIMITIVE),
     JS_FN("fontsize",          str_fontsize,          1,PRIMITIVE),
@@ -2299,27 +2314,35 @@ String(JSContext *cx, JSObject *obj, uin
     if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
         *rval = STRING_TO_JSVAL(str);
         return JS_TRUE;
     }
     STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, STRING_TO_JSVAL(str));
     return JS_TRUE;
 }
 
-static JSBool
-str_fromCharCode(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_str_fromCharCode(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv;
-    jschar *chars;
     uintN i;
     uint16 code;
+    jschar *chars;
     JSString *str;
 
     argv = vp + 2;
     JS_ASSERT(argc < ARRAY_INIT_LIMIT);
+    if (argc == 1 &&
+        (code = js_ValueToUint16(cx, &argv[0])) < UNIT_STRING_LIMIT) {
+        str = js_GetUnitStringForChar(cx, code);
+        if (!str)
+            return JS_FALSE;
+        *vp = STRING_TO_JSVAL(str);
+        return JS_TRUE;
+    }
     chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar));
     if (!chars)
         return JS_FALSE;
     for (i = 0; i < argc; i++) {
         code = js_ValueToUint16(cx, &argv[i]);
         if (JSVAL_IS_NULL(argv[i])) {
             JS_free(cx, chars);
             return JS_FALSE;
@@ -2332,17 +2355,17 @@ str_fromCharCode(JSContext *cx, uintN ar
         JS_free(cx, chars);
         return JS_FALSE;
     }
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 static JSFunctionSpec string_static_methods[] = {
-    JS_FN("fromCharCode",    str_fromCharCode,       1,0),
+    JS_FN("fromCharCode",    js_str_fromCharCode,    1,0),
     JS_FS_END
 };
 
 JS_STATIC_DLL_CALLBACK(JSHashNumber)
 js_hash_string_pointer(const void *key)
 {
     return (JSHashNumber)JS_PTR_TO_UINT32(key) >> JSVAL_TAGBITS;
 }
@@ -2384,27 +2407,23 @@ js_InitDeflatedStringCache(JSRuntime *rt
 #define UNIT_STRING_SPACE_RT(rt) UNIT_STRING_SPACE((rt)->unitStrings)
 
 #define IN_UNIT_STRING_SPACE(sp,cp)                                           \
     ((size_t)((cp) - UNIT_STRING_SPACE(sp)) < 2 * UNIT_STRING_LIMIT)
 #define IN_UNIT_STRING_SPACE_RT(rt,cp)                                        \
     IN_UNIT_STRING_SPACE((rt)->unitStrings, cp)
 
 JSString *
-js_GetUnitString(JSContext *cx, JSString *str, size_t index)
+js_GetUnitStringForChar(JSContext *cx, jschar c)
 {
-    jschar c, *cp, i;
+    jschar *cp, i;
     JSRuntime *rt;
     JSString **sp;
 
-    JS_ASSERT(index < JSSTRING_LENGTH(str));
-    c = JSSTRING_CHARS(str)[index];
-    if (c >= UNIT_STRING_LIMIT)
-        return js_NewDependentString(cx, str, index, 1);
-
+    JS_ASSERT(c < UNIT_STRING_LIMIT);
     rt = cx->runtime;
     if (!rt->unitStrings) {
         sp = (JSString **) calloc(UNIT_STRING_LIMIT * sizeof(JSString *) +
                                   UNIT_STRING_LIMIT * 2 * sizeof(jschar),
                                   1);
         if (!sp) {
             JS_ReportOutOfMemory(cx);
             return NULL;
@@ -2419,28 +2438,42 @@ js_GetUnitString(JSContext *cx, JSString
             rt->unitStrings = sp;
             JS_UNLOCK_GC(rt);
         } else {
             JS_UNLOCK_GC(rt);
             free(sp);
         }
     }
     if (!rt->unitStrings[c]) {
+        JSString *str;
+
         cp = UNIT_STRING_SPACE_RT(rt);
         str = js_NewString(cx, cp + 2 * c, 1);
         if (!str)
             return NULL;
         JS_LOCK_GC(rt);
         if (!rt->unitStrings[c])
             rt->unitStrings[c] = str;
         JS_UNLOCK_GC(rt);
     }
     return rt->unitStrings[c];
 }
 
+JSString *
+js_GetUnitString(JSContext *cx, JSString *str, size_t index)
+{
+    jschar c;
+
+    JS_ASSERT(index < JSSTRING_LENGTH(str));
+    c = JSSTRING_CHARS(str)[index];
+    if (c >= UNIT_STRING_LIMIT)
+        return js_NewDependentString(cx, str, index, 1);
+    return js_GetUnitStringForChar(cx, c);
+}
+
 void
 js_FinishUnitStrings(JSRuntime *rt)
 {
     free(rt->unitStrings);
     rt->unitStrings = NULL;
 }
 
 void
@@ -2782,47 +2815,47 @@ js_HashString(JSString *str)
     for (h = 0; n; s++, n--)
         h = JS_ROTATE_LEFT32(h, 4) ^ *s;
     return h;
 }
 
 /*
  * str is not necessarily a GC thing here.
  */
-JSBool
+bool JS_FASTCALL
 js_EqualStrings(JSString *str1, JSString *str2)
 {
     size_t n;
     const jschar *s1, *s2;
 
     JS_ASSERT(str1);
     JS_ASSERT(str2);
 
     /* Fast case: pointer equality could be a quick win. */
     if (str1 == str2)
-        return JS_TRUE;
+        return true;
 
     n = JSSTRING_LENGTH(str1);
     if (n != JSSTRING_LENGTH(str2))
-        return JS_FALSE;
+        return false;
 
     if (n == 0)
-        return JS_TRUE;
+        return true;
 
     s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2);
     do {
         if (*s1 != *s2)
-            return JS_FALSE;
+            return false;
         ++s1, ++s2;
     } while (--n != 0);
 
-    return JS_TRUE;
+    return true;
 }
 
-intN
+jsint JS_FASTCALL
 js_CompareStrings(JSString *str1, JSString *str2)
 {
     size_t l1, l2, n, i;
     const jschar *s1, *s2;
     intN cmp;
 
     JS_ASSERT(str1);
     JS_ASSERT(str2);
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -235,17 +235,17 @@ extern size_t
 js_MinimizeDependentStrings(JSString *str, int level, JSString **basep);
 
 extern jschar *
 js_GetDependentStringChars(JSString *str);
 
 extern const jschar *
 js_GetStringChars(JSContext *cx, JSString *str);
 
-extern JSString *
+extern JSString * JS_FASTCALL
 js_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
 
 extern const jschar *
 js_UndependString(JSContext *cx, JSString *str);
 
 extern JSBool
 js_MakeStringImmutable(JSContext *cx, JSString *str);
 
@@ -406,16 +406,23 @@ js_InitDeflatedStringCache(JSRuntime *rt
 
 /*
  * Get the independent string containing only character code at index in str
  * (backstopped with a zero character as usual for independent strings).
  */
 extern JSString *
 js_GetUnitString(JSContext *cx, JSString *str, size_t index);
 
+/*
+ * Get the independent string containing only the character code c, which must
+ * be less than UNIT_STRING_LIMIT.
+ */
+extern JSString *
+js_GetUnitStringForChar(JSContext *cx, jschar c);
+
 extern void
 js_FinishUnitStrings(JSRuntime *rt);
 
 extern void
 js_FinishRuntimeStringState(JSContext *cx);
 
 extern void
 js_FinishDeflatedStringCache(JSRuntime *rt);
@@ -490,28 +497,30 @@ js_ValueToSource(JSContext *cx, jsval v)
 
 /*
  * Compute a hash function from str. The caller can call this function even if
  * str is not a GC-allocated thing.
  */
 extern uint32
 js_HashString(JSString *str);
 
+#ifdef __cplusplus
 /*
  * Test if strings are equal. The caller can call the function even if str1
  * or str2 are not GC-allocated things.
  */
-extern JSBool
+extern bool JS_FASTCALL
 js_EqualStrings(JSString *str1, JSString *str2);
+#endif
 
 /*
  * Return less than, equal to, or greater than zero depending on whether
  * str1 is less than, equal to, or greater than str2.
  */
-extern intN
+extern jsint JS_FASTCALL
 js_CompareStrings(JSString *str1, JSString *str2);
 
 /*
  * Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen.
  * The patlen argument must be positive and no greater than BMH_PATLEN_MAX.
  * The start argument tells where in text to begin the search.
  *
  * Return the index of pat in text, or -1 if not found.
@@ -594,20 +603,37 @@ js_SetStringBytes(JSContext *cx, JSStrin
  */
 extern const char *
 js_GetStringBytes(JSContext *cx, JSString *str);
 
 /* Remove a deflated string cache entry associated with str if any. */
 extern void
 js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str);
 
-JSBool
+/* Export a few natives and a helper to other files in SpiderMonkey. */
+extern JSBool
 js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
               jsval *rval);
 
+extern JSBool
+js_StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc);
+
+extern JSBool
+js_str_match(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
+js_str_replace(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
+js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda,
+                       JSString *repstr, jsval *vp);
+
+extern JSBool
+js_str_split(JSContext *cx, uintN argc, jsval *vp);
+
 /*
  * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
  * least 6 bytes long.  Return the number of UTF-8 bytes of data written.
  */
 extern int
 js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char);
 
 /*
new file mode 100644
--- /dev/null
+++ b/js/src/jstracer.cpp
@@ -0,0 +1,5755 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=99:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
+ * May 28, 2008.
+ *
+ * The Initial Developer of the Original Code is
+ *   Brendan Eich <brendan@mozilla.org>
+ *
+ * Contributor(s):
+ *   Andreas Gal <gal@mozilla.com>
+ *   Mike Shaver <shaver@mozilla.org>
+ *   David Anderson <danderson@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "jsstddef.h"           // always first
+#include "jsbit.h"              // low-level (NSPR-based) headers next
+#include "jsprf.h"
+#include <math.h>               // standard headers next
+#ifdef _MSC_VER
+#include <malloc.h>
+#define alloca _alloca
+#endif
+
+#include "nanojit/avmplus.h"    // nanojit
+#include "nanojit/nanojit.h"
+#include "jsarray.h"            // higher-level library and API headers
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsdbgapi.h"
+#include "jsemit.h"
+#include "jsfun.h"
+#include "jsinterp.h"
+#include "jsiter.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jsregexp.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jstracer.h"
+
+#include "jsautooplen.h"        // generated headers last
+
+/* Number of iterations of a loop before we start tracing. */
+#define HOTLOOP 2
+
+/* Number of times we wait to exit on a side exit before we try to extend the tree. */
+#define HOTEXIT 1
+
+/* Max call depths for inlining. */
+#define MAX_CALLDEPTH 5
+
+/* Max number of type mismatchs before we trash the tree. */
+#define MAX_MISMATCH 5
+
+/* Max native stack size. */
+#define MAX_NATIVE_STACK_SLOTS 1024
+
+/* Max call stack size. */
+#define MAX_CALL_STACK_ENTRIES 64
+
+#ifdef DEBUG
+#define ABORT_TRACE(msg)   do { debug_only_v(fprintf(stdout, "abort: %d: %s\n", __LINE__, msg);)  return false; } while (0)
+#else
+#define ABORT_TRACE(msg)   return false
+#endif
+
+#ifdef DEBUG
+static struct {
+    uint64
+        recorderStarted, recorderAborted, traceCompleted, sideExitIntoInterpreter,
+        typeMapMismatchAtEntry, returnToDifferentLoopHeader, traceTriggered,
+        globalShapeMismatchAtEntry, treesTrashed, slotPromoted,
+        unstableLoopVariable;
+} stat = { 0LL, };
+#define AUDIT(x) (stat.x++)
+#else
+#define AUDIT(x) ((void)0)
+#endif
+
+#define INS_CONST(c)    addName(lir->insImm(c), #c)
+#define INS_CONSTPTR(p) addName(lir->insImmPtr((void*) (p)), #p)
+
+using namespace avmplus;
+using namespace nanojit;
+
+static GC gc = GC();
+static avmplus::AvmCore s_core = avmplus::AvmCore();
+static avmplus::AvmCore* core = &s_core;
+
+/* We really need a better way to configure the JIT. Shaver, where is my fancy JIT object? */
+static bool nesting_enabled = true;
+static bool oracle_enabled = true;
+
+#ifdef DEBUG
+static bool verbose_debug = getenv("TRACEMONKEY") && strstr(getenv("TRACEMONKEY"), "verbose");
+#define debug_only_v(x) if (verbose_debug) { x; }
+#else
+#define debug_only_v(x)
+#endif
+
+/* The entire VM shares one oracle. Collisions and concurrent updates are tolerated and worst
+   case cause performance regressions. */
+static Oracle oracle;
+
+Tracker::Tracker()
+{
+    pagelist = 0;
+}
+
+Tracker::~Tracker()
+{
+    clear();
+}
+
+jsuword
+Tracker::getPageBase(const void* v) const
+{
+    return jsuword(v) & ~jsuword(NJ_PAGE_SIZE-1);
+}
+
+struct Tracker::Page*
+Tracker::findPage(const void* v) const
+{
+    jsuword base = getPageBase(v);
+    struct Tracker::Page* p = pagelist;
+    while (p) {
+        if (p->base == base) {
+            return p;
+        }
+        p = p->next;
+    }
+    return 0;
+}
+
+struct Tracker::Page*
+Tracker::addPage(const void* v) {
+    jsuword base = getPageBase(v);
+    struct Tracker::Page* p = (struct Tracker::Page*)
+        GC::Alloc(sizeof(*p) - sizeof(p->map) + (NJ_PAGE_SIZE >> 2) * sizeof(LIns*));
+    p->base = base;
+    p->next = pagelist;
+    pagelist = p;
+    return p;
+}
+
+void
+Tracker::clear()
+{
+    while (pagelist) {
+        Page* p = pagelist;
+        pagelist = pagelist->next;
+        GC::Free(p);
+    }
+}
+
+bool
+Tracker::has(const void *v) const
+{
+    return get(v) != NULL;
+}
+
+#if defined NANOJIT_64BIT
+#define PAGEMASK	0x7ff
+#else
+#define PAGEMASK	0xfff
+#endif
+
+LIns*
+Tracker::get(const void* v) const
+{
+    struct Tracker::Page* p = findPage(v);
+    if (!p)
+        return NULL;
+    return p->map[(jsuword(v) & PAGEMASK) >> 2];
+}
+
+void
+Tracker::set(const void* v, LIns* i)
+{
+    struct Tracker::Page* p = findPage(v);
+    if (!p)
+        p = addPage(v);
+    p->map[(jsuword(v) & PAGEMASK) >> 2] = i;
+}
+
+static inline bool isNumber(jsval v)
+{
+    return JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v);
+}
+
+static inline jsdouble asNumber(jsval v)
+{
+    JS_ASSERT(isNumber(v));
+    if (JSVAL_IS_DOUBLE(v))
+        return *JSVAL_TO_DOUBLE(v);
+    return (jsdouble)JSVAL_TO_INT(v);
+}
+
+static inline bool isInt32(jsval v)
+{
+    if (!isNumber(v))
+        return false;
+    jsdouble d = asNumber(v);
+    jsint i;
+    return JSDOUBLE_IS_INT(d, i);
+}
+
+static inline uint8 getCoercedType(jsval v)
+{
+    return isInt32(v) ? JSVAL_INT : JSVAL_TAG(v);
+}
+
+/* Tell the oracle that a certain global variable should not be demoted. */
+void
+Oracle::markGlobalSlotUndemotable(JSScript* script, unsigned slot)
+{
+    _dontDemote.set(&gc, (slot % ORACLE_SIZE));
+}
+
+/* Consult with the oracle whether we shouldn't demote a certain global variable. */
+bool
+Oracle::isGlobalSlotUndemotable(JSScript* script, unsigned slot) const
+{
+    return !oracle_enabled || _dontDemote.get(slot % ORACLE_SIZE);
+}
+
+/* Tell the oracle that a certain slot at a certain bytecode location should not be demoted. */
+void
+Oracle::markStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot)
+{
+    uint32 hash = uint32(intptr_t(ip)) + (slot << 5);
+    hash %= ORACLE_SIZE;
+    _dontDemote.set(&gc, hash);
+}
+
+/* Consult with the oracle whether we shouldn't demote a certain slot. */
+bool
+Oracle::isStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot) const
+{
+    uint32 hash = uint32(intptr_t(ip)) + (slot << 5);
+    hash %= ORACLE_SIZE;
+    return !oracle_enabled || _dontDemote.get(hash);
+}
+
+/* Clear the oracle. */
+void
+Oracle::clear()
+{
+    _dontDemote.reset();
+}
+
+static LIns* demote(LirWriter *out, LInsp i)
+{
+    if (i->isCall())
+        return callArgN(i,0);
+    if (i->isop(LIR_i2f) || i->isop(LIR_u2f))
+        return i->oprnd1();
+    if (i->isconst())
+        return i;
+    AvmAssert(i->isconstq());
+    double cf = i->constvalf();
+    int32_t ci = cf > 0x7fffffff ? uint32_t(cf) : int32_t(cf);
+    return out->insImm(ci);
+}
+
+static bool isPromoteInt(LIns* i)
+{
+    jsdouble d;
+    return i->isop(LIR_i2f) || i->isconst() ||
+        (i->isconstq() && ((d = i->constvalf()) == (jsdouble)(jsint)d));
+}
+
+static bool isPromoteUint(LIns* i)
+{
+    jsdouble d;
+    return i->isop(LIR_u2f) || i->isconst() ||
+        (i->isconstq() && ((d = i->constvalf()) == (jsdouble)(jsuint)d));
+}
+
+static bool isPromote(LIns* i)
+{
+    return isPromoteInt(i) || isPromoteUint(i);
+}
+
+static bool isconst(LIns* i, int32_t c)
+{
+    return i->isconst() && i->constval() == c;
+}
+
+static bool overflowSafe(LIns* i)
+{
+    LIns* c;
+    return (i->isop(LIR_and) && ((c = i->oprnd2())->isconst()) &&
+            ((c->constval() & 0xc0000000) == 0)) ||
+           (i->isop(LIR_rsh) && ((c = i->oprnd2())->isconst()) &&
+            ((c->constval() > 0)));
+}
+
+class FuncFilter: public LirWriter
+{
+    TraceRecorder& recorder;
+public:
+    FuncFilter(LirWriter* out, TraceRecorder& _recorder):
+        LirWriter(out), recorder(_recorder)
+    {
+    }
+
+    LInsp ins1(LOpcode v, LInsp s0)
+    {
+        switch (v) {
+          case LIR_fneg:
+              if (isPromoteInt(s0)) {
+                  LIns* result = out->ins1(LIR_neg, demote(out, s0));
+                  out->insGuard(LIR_xt, out->ins1(LIR_ov, result),
+                                recorder.snapshot(OVERFLOW_EXIT));
+                  return out->ins1(LIR_i2f, result);
+              }
+              break;
+          default:;
+        }
+        return out->ins1(v, s0);
+    }
+
+    LInsp ins2(LOpcode v, LInsp s0, LInsp s1)
+    {
+        if (s0 == s1 && v == LIR_feq) {
+            if (isPromote(s0)) {
+                // double(int) and double(uint) cannot be nan
+                return insImm(1);
+            }
+            if (s0->isop(LIR_fmul) || s0->isop(LIR_fsub) || s0->isop(LIR_fadd)) {
+                LInsp lhs = s0->oprnd1();
+                LInsp rhs = s0->oprnd2();
+                if (isPromote(lhs) && isPromote(rhs)) {
+                    // add/sub/mul promoted ints can't be nan
+                    return insImm(1);
+                }
+            }
+        } else if (LIR_feq <= v && v <= LIR_fge) {
+            if (isPromoteInt(s0) && isPromoteInt(s1)) {
+                // demote fcmp to cmp
+                v = LOpcode(v + (LIR_eq - LIR_feq));
+                return out->ins2(v, demote(out, s0), demote(out, s1));
+            } else if (isPromoteUint(s0) && isPromoteUint(s1)) {
+                // uint compare
+                v = LOpcode(v + (LIR_eq - LIR_feq));
+                if (v != LIR_eq)
+                    v = LOpcode(v + (LIR_ult - LIR_lt)); // cmp -> ucmp
+                return out->ins2(v, demote(out, s0), demote(out, s1));
+            }
+        } else if (v == LIR_fadd || v == LIR_fsub) {
+            /* demoting multiplication seems to be tricky since it can quickly overflow the
+               value range of int32 */
+            if (isPromoteInt(s0) && isPromoteInt(s1)) {
+                // demote fop to op
+                v = (LOpcode)((int)v & ~LIR64);
+                LIns* d0;
+                LIns* d1;
+                LIns* result = out->ins2(v, d0 = demote(out, s0), d1 = demote(out, s1));
+                if (!overflowSafe(d0) || !overflowSafe(d1)) {
+                    out->insGuard(LIR_xt, out->ins1(LIR_ov, result),
+                                  recorder.snapshot(OVERFLOW_EXIT));
+                }
+                return out->ins1(LIR_i2f, result);
+            }
+        } else if (v == LIR_or &&
+                   s0->isop(LIR_lsh) && isconst(s0->oprnd2(), 16) &&
+                   s1->isop(LIR_and) && isconst(s1->oprnd2(), 0xffff)) {
+            LIns* msw = s0->oprnd1();
+            LIns* lsw = s1->oprnd1();
+            LIns* x;
+            LIns* y;
+            if (lsw->isop(LIR_add) &&
+                lsw->oprnd1()->isop(LIR_and) &&
+                lsw->oprnd2()->isop(LIR_and) &&
+                isconst(lsw->oprnd1()->oprnd2(), 0xffff) &&
+                isconst(lsw->oprnd2()->oprnd2(), 0xffff) &&
+                msw->isop(LIR_add) &&
+                msw->oprnd1()->isop(LIR_add) &&
+                msw->oprnd2()->isop(LIR_rsh) &&
+                msw->oprnd1()->oprnd1()->isop(LIR_rsh) &&
+                msw->oprnd1()->oprnd2()->isop(LIR_rsh) &&
+                isconst(msw->oprnd2()->oprnd2(), 16) &&
+                isconst(msw->oprnd1()->oprnd1()->oprnd2(), 16) &&
+                isconst(msw->oprnd1()->oprnd2()->oprnd2(), 16) &&
+                (x = lsw->oprnd1()->oprnd1()) == msw->oprnd1()->oprnd1()->oprnd1() &&
+                (y = lsw->oprnd2()->oprnd1()) == msw->oprnd1()->oprnd2()->oprnd1() &&
+                lsw == msw->oprnd2()->oprnd1()) {
+                return out->ins2(LIR_add, x, y);
+            }
+        }
+        return out->ins2(v, s0, s1);
+    }
+
+    LInsp insCall(uint32_t fid, LInsp args[])
+    {
+        LInsp s0 = args[0];
+        switch (fid) {
+          case F_DoubleToUint32:
+            if (s0->isconstq())
+                return out->insImm(js_DoubleToECMAUint32(s0->constvalf()));
+            if (s0->isop(LIR_i2f) || s0->isop(LIR_u2f)) {
+                return s0->oprnd1();
+            }
+            break;
+          case F_DoubleToInt32:
+            if (s0->isconstq())
+                return out->insImm(js_DoubleToECMAInt32(s0->constvalf()));
+            if (s0->isop(LIR_fadd) || s0->isop(LIR_fsub) || s0->isop(LIR_fmul)) {
+                LInsp lhs = s0->oprnd1();
+                LInsp rhs = s0->oprnd2();
+                if (isPromote(lhs) && isPromote(rhs)) {
+                    LOpcode op = LOpcode(s0->opcode() & ~LIR64);
+                    return out->ins2(op, demote(out, lhs), demote(out, rhs));
+                }
+            }
+            if (s0->isop(LIR_i2f) || s0->isop(LIR_u2f)) {
+                return s0->oprnd1();
+            }
+            if (s0->isCall() && s0->fid() == F_UnboxDouble) {
+                LIns* args2[] = { callArgN(s0, 0) };
+                return out->insCall(F_UnboxInt32, args2);
+            }
+            if (s0->isCall() && s0->fid() == F_StringToNumber) {
+                // callArgN's ordering is that as seen by the builtin, not as stored in args here.
+                // True story!
+                LIns* args2[] = { callArgN(s0, 1), callArgN(s0, 0) };
+                return out->insCall(F_StringToInt32, args2);
+            }
+            break;
+          case F_BoxDouble:
+            JS_ASSERT(s0->isQuad());
+            if (s0->isop(LIR_i2f)) {
+                LIns* args2[] = { s0->oprnd1(), args[1] };
+                return out->insCall(F_BoxInt32, args2);
+            }
+            if (s0->isCall() && s0->fid() == F_UnboxDouble) 
+                return callArgN(s0, 0);
+            break;
+        }
+        return out->insCall(fid, args);
+    }
+};
+
+/* In debug mode vpname contains a textual description of the type of the
+   slot during the forall iteration over al slots. */
+#ifdef DEBUG
+#define DEF_VPNAME          const char* vpname; unsigned vpnum
+#define SET_VPNAME(name)    do { vpname = name; vpnum = 0; } while(0)
+#define INC_VPNUM()         do { ++vpnum; } while(0)
+#else
+#define DEF_VPNAME          do {} while (0)
+#define vpname ""
+#define vpnum 0
+#define SET_VPNAME(name)    ((void)0)
+#define INC_VPNUM()         ((void)0)
+#endif
+
+/* Iterate over all interned global variables. */
+#define FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, code)                        \
+    JS_BEGIN_MACRO                                                            \
+        DEF_VPNAME;                                                           \
+        JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain);  \
+        unsigned n;                                                           \
+        jsval* vp;                                                            \
+        SET_VPNAME("global");                                                 \
+        for (n = 0; n < ngslots; ++n) {                                       \
+            vp = &STOBJ_GET_SLOT(globalObj, gslots[n]);                       \
+            { code; }                                                         \
+            INC_VPNUM();                                                      \
+        }                                                                     \
+    JS_END_MACRO
+
+/* Iterate over all slots in the frame, consisting of args, vars, and stack
+   (except for the top-level frame which does not have args or vars. */
+#define FORALL_FRAME_SLOTS(fp, depth, code)                                   \
+    JS_BEGIN_MACRO                                                            \
+        jsval* vp;                                                            \
+        jsval* vpstop;                                                        \
+        if (fp->callee) {                                                     \
+            if (depth == 0) {                                                 \
+                SET_VPNAME("callee");                                         \
+                vp = &fp->argv[-2];                                           \
+                { code; }                                                     \
+                SET_VPNAME("this");                                           \
+                vp = &fp->argv[-1];                                           \
+                { code; }                                                     \
+                SET_VPNAME("argv");                                           \
+                unsigned nargs = JS_MAX(fp->fun->nargs, fp->argc);            \
+                vp = &fp->argv[0]; vpstop = &fp->argv[nargs];                 \
+                while (vp < vpstop) { code; ++vp; INC_VPNUM(); }              \
+            }                                                                 \
+            SET_VPNAME("vars");                                               \
+            vp = fp->slots; vpstop = &fp->slots[fp->script->nfixed];          \
+            while (vp < vpstop) { code; ++vp; INC_VPNUM(); }                  \
+        }                                                                     \
+        SET_VPNAME("stack");                                                  \
+        vp = StackBase(fp); vpstop = fp->regs->sp;                            \
+        while (vp < vpstop) { code; ++vp; INC_VPNUM(); }                      \
+        if (fsp < fspstop - 1) {                                              \
+            JSStackFrame* fp2 = fsp[1];                                       \
+            int missing = fp2->fun->nargs - fp2->argc;                        \
+            if (missing > 0) {                                                \
+                SET_VPNAME("missing");                                        \
+                vp = fp->regs->sp;                                            \
+                vpstop = vp + missing;                                        \
+                while (vp < vpstop) { code; ++vp; INC_VPNUM(); }              \
+            }                                                                 \
+        }                                                                     \
+    JS_END_MACRO
+
+/* Iterate over all slots in each pending frame. */
+#define FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, code)                   \
+    JS_BEGIN_MACRO                                                            \
+        DEF_VPNAME;                                                           \
+        unsigned n;                                                           \
+        JSStackFrame* currentFrame = cx->fp;                                  \
+        JSStackFrame* entryFrame;                                             \
+        JSStackFrame* fp = currentFrame;                                      \
+        for (n = 0; n < callDepth; ++n) { fp = fp->down; }                    \
+        entryFrame = fp;                                                      \
+        unsigned frames = callDepth+1;                                        \
+        JSStackFrame** fstack =                                               \
+            (JSStackFrame**) alloca(frames * sizeof (JSStackFrame*));         \
+        JSStackFrame** fspstop = &fstack[frames];                             \
+        JSStackFrame** fsp = fspstop-1;                                       \
+        fp = currentFrame;                                                    \
+        for (;; fp = fp->down) { *fsp-- = fp; if (fp == entryFrame) break; }  \
+        unsigned depth;                                                       \
+        for (depth = 0, fsp = fstack; fsp < fspstop; ++fsp, ++depth) {        \
+            fp = *fsp;                                                        \
+            FORALL_FRAME_SLOTS(fp, depth, code);                              \
+        }                                                                     \
+    JS_END_MACRO
+
+#define FORALL_SLOTS(cx, ngslots, gslots, callDepth, code)                    \
+    JS_BEGIN_MACRO                                                            \
+        FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, code);                       \
+        FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, code);                  \
+    JS_END_MACRO
+
+/* Calculate the total number of native frame slots we need from this frame
+   all the way back to the entry frame, including the current stack usage. */
+static unsigned
+nativeStackSlots(JSContext *cx, unsigned callDepth)
+{
+    JSStackFrame* fp = cx->fp;
+    unsigned slots = 0;
+#if defined _DEBUG
+    unsigned int origCallDepth = callDepth;
+#endif
+    for (;;) {
+        unsigned operands = fp->regs->sp - StackBase(fp);
+        JS_ASSERT(operands <= fp->script->nslots - fp->script->nfixed);
+        slots += operands;
+        if (fp->callee)
+            slots += fp->script->nfixed;
+        if (callDepth-- == 0) {
+            if (fp->callee) {
+                unsigned nargs = JS_MAX(fp->fun->nargs, fp->argc);
+                slots += 2/*callee,this*/ + nargs;
+            }
+#if defined _DEBUG
+            unsigned int m = 0;
+            FORALL_SLOTS_IN_PENDING_FRAMES(cx, origCallDepth, m++);
+            JS_ASSERT(m == slots);
+#endif
+            return slots;
+        }
+        JSStackFrame* fp2 = fp;
+        fp = fp->down;
+        int missing = fp2->fun->nargs - fp2->argc;
+        if (missing > 0)
+            slots += missing;
+    }
+    JS_NOT_REACHED("nativeStackSlots");
+}
+
+/* Capture the type map for the selected slots of the global object. */
+void
+TypeMap::captureGlobalTypes(JSContext* cx, SlotList& slots)
+{
+    unsigned ngslots = slots.length();
+    uint16* gslots = slots.data();
+    setLength(ngslots);
+    uint8* map = data();
+    uint8* m = map;
+    FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
+        uint8 type = getCoercedType(*vp);
+        if ((type == JSVAL_INT) && oracle.isGlobalSlotUndemotable(cx->fp->script, gslots[n]))
+            type = JSVAL_DOUBLE;
+        *m++ = type;
+    );
+}
+
+/* Capture the type map for the currently pending stack frames. */
+void
+TypeMap::captureStackTypes(JSContext* cx, unsigned callDepth)
+{
+    setLength(nativeStackSlots(cx, callDepth));
+    uint8* map = data();
+    uint8* m = map;
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
+        uint8 type = getCoercedType(*vp);
+        if ((type == JSVAL_INT) &&
+            oracle.isStackSlotUndemotable(cx->fp->script, cx->fp->regs->pc, unsigned(m - map))) {
+            type = JSVAL_DOUBLE;
+        }
+        *m++ = type;
+    );
+}
+
+/* Compare this type map to another one and see whether they match. */
+bool
+TypeMap::matches(TypeMap& other) const
+{
+    if (length() != other.length())
+        return false;
+    return !memcmp(data(), other.data(), length());
+}
+
+/* Use the provided storage area to create a new type map that contains the partial type map
+   with the rest of it filled up from the complete type map. */
+static void
+mergeTypeMaps(uint8** partial, unsigned* plength, uint8* complete, unsigned clength, uint8* mem)
+{
+    unsigned l = *plength;
+    JS_ASSERT(l < clength);
+    memcpy(mem, *partial, l * sizeof(uint8));
+    memcpy(mem + l, complete + l, (clength - l) * sizeof(uint8));
+    *partial = mem;
+    *plength = clength;
+}
+
+TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor, Fragment* _fragment,
+        TreeInfo* ti, unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
+        GuardRecord* innermostNestedGuard)
+{
+    JS_ASSERT(!_fragment->vmprivate && ti);
+
+    this->cx = cx;
+    this->traceMonitor = &JS_TRACE_MONITOR(cx);
+    this->globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain);
+    this->anchor = _anchor;
+    this->fragment = _fragment;
+    this->lirbuf = _fragment->lirbuf;
+    this->treeInfo = ti;
+    this->callDepth = _fragment->calldepth;
+    JS_ASSERT(!_anchor || _anchor->calldepth == _fragment->calldepth);
+    this->atoms = cx->fp->script->atomMap.vector;
+
+    
+    debug_only_v(printf("recording starting from %s:%u@%u\n", cx->fp->script->filename,
+                        js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc),
+                        cx->fp->regs->pc - cx->fp->script->code););
+
+    lir = lir_buf_writer = new (&gc) LirBufWriter(lirbuf);
+#ifdef DEBUG
+    if (verbose_debug)
+        lir = verbose_filter = new (&gc) VerboseWriter(&gc, lir, lirbuf->names);
+#endif
+    lir = cse_filter = new (&gc) CseFilter(lir, &gc);
+    lir = expr_filter = new (&gc) ExprFilter(lir);
+    lir = func_filter = new (&gc) FuncFilter(lir, *this);
+    lir->ins0(LIR_trace);
+
+    if (!nanojit::AvmCore::config.tree_opt || fragment->root == fragment) {
+        lirbuf->state = addName(lir->insParam(0), "state");
+        lirbuf->param1 = addName(lir->insParam(1), "param1");
+    }
+    lirbuf->sp = addName(lir->insLoad(LIR_ldp, lirbuf->state, (int)offsetof(InterpState, sp)), "sp");
+    lirbuf->rp = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, rp)), "rp");
+    cx_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, cx)), "cx");
+    gp_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, gp)), "gp");
+    eos_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eos)), "eos");
+    eor_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, offsetof(InterpState, eor)), "eor");
+
+    /* read into registers all values on the stack and all globals we know so far */
+    import(treeInfo, lirbuf->sp, ngslots, callDepth, globalTypeMap, stackTypeMap);
+
+    /* If we are attached to a tree call guard, make sure the guard the inner tree exited from
+       is what we expect it to be. */
+    if (_anchor && _anchor->exit->exitType == NESTED_EXIT) {
+        LIns* nested_ins = addName(lir->insLoad(LIR_ldp, lirbuf->state, 
+                                                offsetof(InterpState, nestedExit)), "nestedExit");
+        guard(true, lir->ins2(LIR_eq, nested_ins, lir->insImmPtr(innermostNestedGuard)), NESTED_EXIT);
+    }
+}
+
+TraceRecorder::~TraceRecorder()
+{
+    JS_ASSERT(treeInfo);
+    if (fragment->root == fragment && !fragment->root->code()) {
+        JS_ASSERT(!fragment->root->vmprivate);
+        delete treeInfo;
+    }
+#ifdef DEBUG
+    delete verbose_filter;
+#endif
+    delete cse_filter;
+    delete expr_filter;
+    delete func_filter;
+    delete lir_buf_writer;
+}
+
+/* Add debug information to a LIR instruction as we emit it. */
+inline LIns*
+TraceRecorder::addName(LIns* ins, const char* name)
+{
+#ifdef DEBUG
+    lirbuf->names->addName(ins, name);
+#endif
+    return ins;
+}
+
+/* Determine the current call depth (starting with the entry frame.) */
+unsigned
+TraceRecorder::getCallDepth() const
+{
+    return callDepth;
+}
+
+/* Determine the offset in the native global frame for a jsval we track */
+ptrdiff_t
+TraceRecorder::nativeGlobalOffset(jsval* p) const
+{
+    JS_ASSERT(isGlobal(p));
+    if (size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS)
+        return size_t(p - globalObj->fslots) * sizeof(double);
+    return ((p - globalObj->dslots) + JS_INITIAL_NSLOTS) * sizeof(double);
+}
+
+/* Determine whether a value is a global stack slot */
+bool
+TraceRecorder::isGlobal(jsval* p) const
+{
+    return ((size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) ||
+            (size_t(p - globalObj->dslots) < (STOBJ_NSLOTS(globalObj) - JS_INITIAL_NSLOTS)));
+}
+
+/* Determine the offset in the native stack for a jsval we track */
+ptrdiff_t
+TraceRecorder::nativeStackOffset(jsval* p) const
+{
+#ifdef DEBUG
+    size_t slow_offset = 0;
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
+        if (vp == p) goto done;
+        slow_offset += sizeof(double)
+    );
+
+    /*
+     * If it's not in a pending frame, it must be on the stack of the current frame above
+     * sp but below fp->slots + script->nslots.
+     */
+    JS_ASSERT(size_t(p - cx->fp->slots) < cx->fp->script->nslots);
+    slow_offset += size_t(p - cx->fp->regs->sp) * sizeof(double);
+
+done:
+#define RETURN(offset) { JS_ASSERT((offset) == slow_offset); return offset; }
+#else
+#define RETURN(offset) { return offset; }
+#endif
+    size_t offset = 0;
+    JSStackFrame* currentFrame = cx->fp;
+    JSStackFrame* entryFrame;
+    JSStackFrame* fp = currentFrame;
+    for (unsigned n = 0; n < callDepth; ++n) { fp = fp->down; }
+    entryFrame = fp;
+    unsigned frames = callDepth+1;
+    JSStackFrame** fstack = (JSStackFrame **)alloca(frames * sizeof (JSStackFrame *));
+    JSStackFrame** fspstop = &fstack[frames];
+    JSStackFrame** fsp = fspstop-1;
+    fp = currentFrame;
+    for (;; fp = fp->down) { *fsp-- = fp; if (fp == entryFrame) break; }
+    for (fsp = fstack; fsp < fspstop; ++fsp) {
+        fp = *fsp;
+        if (fp->callee) {
+            if (fsp == fstack) {
+                unsigned nargs = JS_MAX(fp->fun->nargs, fp->argc);
+                if (size_t(p - &fp->argv[-2]) < 2/*callee,this*/ + nargs)
+                    RETURN(offset + size_t(p - &fp->argv[-2]) * sizeof(double));
+                offset += (2/*callee,this*/ + nargs) * sizeof(double);
+            }
+            if (size_t(p - &fp->slots[0]) < fp->script->nfixed)
+                RETURN(offset + size_t(p - &fp->slots[0]) * sizeof(double));
+            offset += fp->script->nfixed * sizeof(double);
+        }
+        jsval* spbase = StackBase(fp);
+        if (size_t(p - spbase) < size_t(fp->regs->sp - spbase))
+            RETURN(offset + size_t(p - spbase) * sizeof(double));
+        offset += size_t(fp->regs->sp - spbase) * sizeof(double);
+        if (fsp < fspstop - 1) {
+            JSStackFrame* fp2 = fsp[1];
+            int missing = fp2->fun->nargs - fp2->argc;
+            if (missing > 0) {
+                if (size_t(p - fp->regs->sp) < size_t(missing))
+                    RETURN(offset + size_t(p - fp->regs->sp) * sizeof(double));
+                offset += size_t(missing) * sizeof(double);
+            }
+        }
+    }
+
+    /*
+     * If it's not in a pending frame, it must be on the stack of the current frame above
+     * sp but below fp->slots + script->nslots.
+     */
+    JS_ASSERT(size_t(p - currentFrame->slots) < currentFrame->script->nslots);
+    offset += size_t(p - currentFrame->regs->sp) * sizeof(double);
+    RETURN(offset);
+#undef RETURN
+}
+
+/* Track the maximum number of native frame slots we need during
+   execution. */
+void
+TraceRecorder::trackNativeStackUse(unsigned slots)
+{
+    if (slots > treeInfo->maxNativeStackSlots)
+        treeInfo->maxNativeStackSlots = slots;
+}
+
+/* Unbox a jsval into a slot. Slots are wide enough to hold double values
+   directly (instead of storing a pointer to them). */
+static bool
+ValueToNative(JSContext* cx, jsval v, uint8 type, double* slot)
+{
+    unsigned tag = JSVAL_TAG(v);
+    switch (type) {
+      case JSVAL_INT:
+        jsint i;
+        if (JSVAL_IS_INT(v))
+            *(jsint*)slot = JSVAL_TO_INT(v);
+        else if ((tag == JSVAL_DOUBLE) && JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(v), i))
+            *(jsint*)slot = i;
+        else if (v == JSVAL_VOID)
+            *(jsint*)slot = 0;
+        else {
+            debug_only_v(printf("int != tag%lu(value=%lu) ", JSVAL_TAG(v), v);)
+            return false;
+        }
+        debug_only_v(printf("int<%d> ", *(jsint*)slot);)
+        return true;
+      case JSVAL_DOUBLE:
+        jsdouble d;
+        if (JSVAL_IS_INT(v))
+            d = JSVAL_TO_INT(v);
+        else if (tag == JSVAL_DOUBLE)
+            d = *JSVAL_TO_DOUBLE(v);
+        else if (v == JSVAL_VOID)
+            d = js_NaN;
+        else {
+            debug_only_v(printf("double != tag%lu ", JSVAL_TAG(v));)
+            return false;
+        }
+        *(jsdouble*)slot = d;
+        debug_only_v(printf("double<%g> ", d);)
+        return true;
+      case JSVAL_BOOLEAN:
+        if (tag != JSVAL_BOOLEAN) {
+             debug_only_v(printf("bool != tag%u ", tag);)
+             return false;
+        }
+        *(JSBool*)slot = JSVAL_TO_BOOLEAN(v);
+        debug_only_v(printf("boolean<%d> ", *(bool*)slot);)
+        return true;
+      case JSVAL_STRING:
+        if (v == JSVAL_VOID) {
+            *(JSString**)slot = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); 
+            return true;
+        } 
+        if (tag != JSVAL_STRING) {
+            debug_only_v(printf("string != tag%u ", tag);)
+            return false;
+        }
+        *(JSString**)slot = JSVAL_TO_STRING(v);
+        debug_only_v(printf("string<%p> ", *(JSString**)slot);)
+        return true;
+      default:
+        JS_ASSERT(type == JSVAL_OBJECT);
+        if (v == JSVAL_VOID) {
+            *(JSObject**)slot = NULL;
+            return true;
+        }
+        if (tag != JSVAL_OBJECT) {
+            debug_only_v(printf("object != tag%u ", tag);)
+            return false;
+        }
+        *(JSObject**)slot = JSVAL_TO_OBJECT(v);
+        debug_only_v(printf("object<%p:%s> ", JSVAL_TO_OBJECT(v),
+                            JSVAL_IS_NULL(v)
+                            ? "null"
+                            : STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v))->name);)
+        return true;
+    }
+}
+
+/* Box a value from the native stack back into the jsval format. Integers
+   that are too large to fit into a jsval are automatically boxed into
+   heap-allocated doubles. */
+static bool
+NativeToValue(JSContext* cx, jsval& v, uint8 type, double* slot)
+{
+    jsint i;
+    jsdouble d;
+    switch (type) {
+      case JSVAL_BOOLEAN:
+        v = BOOLEAN_TO_JSVAL(*(bool*)slot);
+        debug_only_v(printf("boolean<%d> ", *(bool*)slot);)
+        break;
+      case JSVAL_INT:
+        i = *(jsint*)slot;
+        debug_only_v(printf("int<%d> ", i);)
+      store_int:
+        if (INT_FITS_IN_JSVAL(i)) {
+            v = INT_TO_JSVAL(i);
+            break;
+        }
+        d = (jsdouble)i;
+        goto store_double;
+      case JSVAL_DOUBLE:
+        d = *slot;
+        debug_only_v(printf("double<%g> ", d);)
+        if (JSDOUBLE_IS_INT(d, i))
+            goto store_int;
+      store_double:
+        /* Its safe to trigger the GC here since we rooted all strings/objects and all the
+           doubles we already processed. */
+        return js_NewDoubleInRootedValue(cx, d, &v) ? true : false;
+      case JSVAL_STRING:
+        v = STRING_TO_JSVAL(*(JSString**)slot);
+        debug_only_v(printf("string<%p> ", *(JSString**)slot);)
+        break;
+      default:
+        JS_ASSERT(type == JSVAL_OBJECT);
+        v = OBJECT_TO_JSVAL(*(JSObject**)slot);
+        debug_only_v(printf("object<%p:%s> ", JSVAL_TO_OBJECT(v),
+                            JSVAL_IS_NULL(v)
+                            ? "null"
+                            : STOBJ_GET_CLASS(JSVAL_TO_OBJECT(v))->name);)
+        break;
+    }
+    return true;
+}
+
+/* Attempt to unbox the given list of interned globals onto the native global frame, checking
+   along the way that the supplied type-mao holds. */
+static bool
+BuildNativeGlobalFrame(JSContext* cx, unsigned ngslots, uint16* gslots, uint8* mp, double* np)
+{
+    debug_only_v(printf("global: ");)
+    FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
+        if (!ValueToNative(cx, *vp, *mp, np + gslots[n]))
+            return false;
+        ++mp;
+    );
+    debug_only_v(printf("\n");)
+    return true;
+}
+
+/* Attempt to unbox the given JS frame onto a native frame, checking along the way that the
+   supplied type-map holds. */
+static bool
+BuildNativeStackFrame(JSContext* cx, unsigned callDepth, uint8* mp, double* np)
+{
+    debug_only_v(printf("stack: ");)
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
+        debug_only_v(printf("%s%u=", vpname, vpnum);)
+        if (!ValueToNative(cx, *vp, *mp, np))
+            return false;
+        ++mp; ++np;
+    );
+    debug_only_v(printf("\n");)
+    return true;
+}
+
+/* Box the given native frame into a JS frame. This only fails due to a hard error
+   (out of memory for example). */
+static int
+FlushNativeGlobalFrame(JSContext* cx, unsigned ngslots, uint16* gslots, uint8* mp, double* np)
+{
+    uint8* mp_base = mp;
+    /* Root all string and object references first (we don't need to call the GC for this). */
+    FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
+        if ((*mp == JSVAL_STRING || *mp == JSVAL_OBJECT) &&
+            !NativeToValue(cx, *vp, *mp, np + gslots[n])) {
+            return -1;
+        }
+        ++mp;
+    );
+    /* Now do this again but this time for all values (properly quicker than actually checking
+       the type and excluding strings and objects). The GC might kick in when we store doubles,
+       but everything is rooted now (all strings/objects and all doubles we already boxed). */
+    mp = mp_base;
+    FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
+        if (!NativeToValue(cx, *vp, *mp, np + gslots[n]))
+            return -1;
+        ++mp;
+    );
+    debug_only_v(printf("\n");)
+    return mp - mp_base;
+}
+
+/* Box the given native stack frame into the virtual machine stack. This only fails due to a
+   hard error (out of memory for example). */
+static int
+FlushNativeStackFrame(JSContext* cx, unsigned callDepth, uint8* mp, double* np, jsval* stopAt)
+{
+    uint8* mp_base = mp;
+    double* np_base = np;
+    /* Root all string and object references first (we don't need to call the GC for this). */
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
+        if (vp == stopAt) goto skip1;
+        if ((*mp == JSVAL_STRING || *mp == JSVAL_OBJECT) && !NativeToValue(cx, *vp, *mp, np))
+            return -1;
+        ++mp; ++np
+    );
+skip1:
+    // Restore thisp from the now-restored argv[-1] in each pending frame.
+    unsigned n = callDepth;
+    for (JSStackFrame* fp = cx->fp; n-- != 0; fp = fp->down)
+        fp->thisp = JSVAL_TO_OBJECT(fp->argv[-1]);
+
+    /* Now do this again but this time for all values (properly quicker than actually checking
+       the type and excluding strings and objects). The GC might kick in when we store doubles,
+       but everything is rooted now (all strings/objects and all doubles we already boxed). */
+    mp = mp_base;
+    np = np_base;
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
+        if (vp == stopAt) goto skip2;
+        debug_only_v(printf("%s%u=", vpname, vpnum);)
+        if (!NativeToValue(cx, *vp, *mp, np))
+            return -1;
+        ++mp; ++np
+    );
+skip2:
+    debug_only_v(printf("\n");)
+    return mp - mp_base;
+}
+
+/* Emit load instructions onto the trace that read the initial stack state. */
+void
+TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, uint8& t,
+                      const char *prefix, uintN index, JSStackFrame *fp)
+{
+    LIns* ins;
+    if (t == JSVAL_INT) { /* demoted */
+        JS_ASSERT(isInt32(*p));
+        /* Ok, we have a valid demotion attempt pending, so insert an integer
+           read and promote it to double since all arithmetic operations expect
+           to see doubles on entry. The first op to use this slot will emit a
+           f2i cast which will cancel out the i2f we insert here. */
+        ins = lir->insLoadi(base, offset);
+        ins = lir->ins1(LIR_i2f, ins);
+    } else {
+        JS_ASSERT(isNumber(*p) == (t == JSVAL_DOUBLE));
+        if (t == JSVAL_DOUBLE) {
+            ins = lir->insLoad(LIR_ldq, base, offset);
+        } else {
+            ins = lir->insLoad(LIR_ldp, base, offset);
+        }
+    }
+    tracker.set(p, ins);
+#ifdef DEBUG
+    char name[64];
+    JS_ASSERT(strlen(prefix) < 10);
+    void* mark = NULL;
+    jsuword* localNames = NULL;
+    const char* funName = NULL;
+    if (*prefix == 'a' || *prefix == 'v') {
+        mark = JS_ARENA_MARK(&cx->tempPool);
+        localNames = js_GetLocalNameArray(cx, fp->fun, &cx->tempPool);
+        funName = fp->fun->atom ? js_AtomToPrintableString(cx, fp->fun->atom) : "<anonymous>";
+    }
+    if (!strcmp(prefix, "argv")) {
+        if (index < fp->fun->nargs) {
+            JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[index]);
+            JS_snprintf(name, sizeof name, "$%s.%s", funName, js_AtomToPrintableString(cx, atom));
+        } else {
+            JS_snprintf(name, sizeof name, "$%s.<arg%d>", funName, index);
+        }
+    } else if (!strcmp(prefix, "vars")) {
+        JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(localNames[fp->fun->nargs + index]);
+        JS_snprintf(name, sizeof name, "$%s.%s", funName, js_AtomToPrintableString(cx, atom));
+    } else {
+        JS_snprintf(name, sizeof name, "$%s%d", prefix, index);
+    }
+
+    if (mark)
+        JS_ARENA_RELEASE(&cx->tempPool, mark);
+    addName(ins, name);
+
+    static const char* typestr[] = {
+        "object", "int", "double", "3", "string", "5", "boolean", "any"
+    };
+    debug_only_v(printf("import vp=%p name=%s type=%s flags=%d\n", p, name, typestr[t & 7], t >> 3););
+#endif
+}
+
+void
+TraceRecorder::import(TreeInfo* treeInfo, LIns* sp, unsigned ngslots, unsigned callDepth,
+                      uint8* globalTypeMap, uint8* stackTypeMap)
+{
+    /* If we get a partial list that doesn't have all the types (i.e. recording from a side
+       exit that was recorded but we added more global slots later), merge the missing types
+       from the entry type map. This is safe because at the loop edge we verify that we
+       have compatible types for all globals (entry type and loop edge type match). While
+       a different trace of the tree might have had a guard with a different type map for
+       these slots we just filled in here (the guard we continue from didn't know about them),
+       since we didn't take that particular guard the only way we could have ended up here
+       is if that other trace had at its end a compatible type distribution with the entry
+       map. Since thats exactly what we used to fill in the types our current side exit
+       didn't provide, this is always safe to do. */
+    unsigned length;
+    if (ngslots < (length = traceMonitor->globalTypeMap->length()))
+        mergeTypeMaps(&globalTypeMap, &ngslots,
+                      traceMonitor->globalTypeMap->data(), length,
+                      (uint8*)alloca(sizeof(uint8) * length));
+    JS_ASSERT(ngslots == traceMonitor->globalTypeMap->length());
+
+    /* the first time we compile a tree this will be empty as we add entries lazily */
+    uint16* gslots = traceMonitor->globalSlots->data();
+    uint8* m = globalTypeMap;
+    FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
+        import(gp_ins, nativeGlobalOffset(vp), vp, *m, vpname, vpnum, NULL);
+        m++;
+    );
+    ptrdiff_t offset = -treeInfo->nativeStackBase;
+    m = stackTypeMap;
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
+        import(sp, offset, vp, *m, vpname, vpnum, fp);
+        m++; offset += sizeof(double);
+    );
+}
+
+/* Lazily import a global slot if we don't already have it in the tracker. */
+bool
+TraceRecorder::lazilyImportGlobalSlot(unsigned slot)
+{
+    if (slot != (uint16)slot) /* we use a table of 16-bit ints, bail out if that's not enough */
+        return false;
+    jsval* vp = &STOBJ_GET_SLOT(globalObj, slot);
+    if (tracker.has(vp))
+        return true; /* we already have it */
+    unsigned index = traceMonitor->globalSlots->length();
+    /* If this the first global we are adding, remember the shape of the global object. */
+    if (index == 0)
+        traceMonitor->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape;
+    /* Add the slot to the list of interned global slots. */
+    traceMonitor->globalSlots->add(slot);
+    uint8 type = getCoercedType(*vp);
+    if ((type == JSVAL_INT) && oracle.isGlobalSlotUndemotable(cx->fp->script, slot))
+        type = JSVAL_DOUBLE;
+    traceMonitor->globalTypeMap->add(type);
+    import(gp_ins, slot*sizeof(double), vp, type, "global", index, NULL);
+    return true;
+}
+
+/* Write back a value onto the stack or global frames. */
+LIns*
+TraceRecorder::writeBack(LIns* i, LIns* base, ptrdiff_t offset)
+{
+    /* Sink all type casts targeting the stack into the side exit by simply storing the original
+       (uncasted) value. Each guard generates the side exit map based on the types of the
+       last stores to every stack location, so its safe to not perform them on-trace. */
+    if (isPromoteInt(i))
+        i = ::demote(lir, i);
+    return lir->insStorei(i, base, offset);
+}
+
+/* Update the tracker, then issue a write back store. */
+void
+TraceRecorder::set(jsval* p, LIns* i, bool initializing)
+{
+    JS_ASSERT(initializing || tracker.has(p));
+    tracker.set(p, i);
+    /* If we are writing to this location for the first time, calculate the offset into the
+       native frame manually, otherwise just look up the last load or store associated with
+       the same source address (p) and use the same offset/base. */
+    LIns* x;
+    if ((x = nativeFrameTracker.get(p)) == NULL) {
+        if (isGlobal(p))
+            x = writeBack(i, gp_ins, nativeGlobalOffset(p));
+        else
+            x = writeBack(i, lirbuf->sp, -treeInfo->nativeStackBase + nativeStackOffset(p));
+        nativeFrameTracker.set(p, x);
+    } else {
+#define ASSERT_VALID_CACHE_HIT(base, offset)                                  \
+    JS_ASSERT(base == lirbuf->sp || base == gp_ins);                          \
+    JS_ASSERT(offset == ((base == lirbuf->sp)                                 \
+        ? -treeInfo->nativeStackBase + nativeStackOffset(p)                   \
+        : nativeGlobalOffset(p)));                                            \
+
+        if (x->isop(LIR_st) || x->isop(LIR_stq)) {
+            ASSERT_VALID_CACHE_HIT(x->oprnd2(), x->oprnd3()->constval());
+            writeBack(i, x->oprnd2(), x->oprnd3()->constval());
+        } else {
+            JS_ASSERT(x->isop(LIR_sti) || x->isop(LIR_stqi));
+            ASSERT_VALID_CACHE_HIT(x->oprnd2(), x->immdisp());
+            writeBack(i, x->oprnd2(), x->immdisp());
+        }
+    }
+#undef ASSERT_VALID_CACHE_HIT
+}
+
+LIns*
+TraceRecorder::get(jsval* p)
+{
+    return tracker.get(p);
+}
+
+/* Determine whether a bytecode location (pc) terminates a loop or is a path within the loop. */
+static bool
+js_IsLoopExit(JSContext* cx, JSScript* script, jsbytecode* pc)
+{
+    switch (*pc) {
+      case JSOP_LT:
+      case JSOP_GT:
+      case JSOP_LE:
+      case JSOP_GE:
+      case JSOP_NE:
+      case JSOP_EQ:
+        JS_ASSERT(js_CodeSpec[*pc].length == 1);
+        pc++;
+        /* FALL THROUGH */
+
+      case JSOP_IFEQ:
+      case JSOP_IFEQX:
+      case JSOP_IFNE:
+      case JSOP_IFNEX:
+        /*
+         * Forward jumps are usually intra-branch, but for-in loops jump to the trailing enditer to
+         * clean up, so check for that case here.
+         */
+        if (pc[GET_JUMP_OFFSET(pc)] == JSOP_ENDITER)
+            return true;
+        return GET_JUMP_OFFSET(pc) < 0;
+
+      default:;
+    }
+    return false;
+}
+
+struct FrameInfo {
+    JSObject*       callee;     // callee function object
+    jsbytecode*     callpc;     // pc of JSOP_CALL in caller script
+    union {
+        struct {
+            uint16  spdist;     // distance from fp->slots to fp->regs->sp at JSOP_CALL
+            uint16  argc;       // actual argument count, may be < fun->nargs
+        } s;
+        uint32      word;       // for spdist/argc LIR store in record_JSOP_CALL
+    };
+};
+
+/* Promote slots if necessary to match the called tree' type map and report error if thats
+   impossible. */
+bool
+TraceRecorder::adjustCallerTypes(Fragment* f)
+{
+    JSTraceMonitor* tm = traceMonitor;
+    uint8* m = tm->globalTypeMap->data();
+    uint16* gslots = traceMonitor->globalSlots->data();
+    unsigned ngslots = traceMonitor->globalSlots->length();
+    FORALL_GLOBAL_SLOTS(cx, ngslots, gslots, 
+        LIns* i = get(vp);
+        bool isPromote = isPromoteInt(i);
+        if (isPromote && *m == JSVAL_DOUBLE) 
+            lir->insStorei(get(vp), gp_ins, nativeGlobalOffset(vp));
+        ++m;
+    );
+    m = ((TreeInfo*)f->vmprivate)->stackTypeMap.data();
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0,
+        LIns* i = get(vp);
+        bool isPromote = isPromoteInt(i);
+        if (isPromote && *m == JSVAL_DOUBLE) 
+            lir->insStorei(get(vp), lirbuf->sp, 
+                           -treeInfo->nativeStackBase + nativeStackOffset(vp));
+        ++m;
+    );
+    return true;
+}
+
+/* Find a peer fragment that we can call, considering our current type distribution. */
+bool TraceRecorder::selectCallablePeerFragment(Fragment** first)
+{
+    /* Until we have multiple trees per start point this is always the first fragment. */
+    return (*first)->code();
+}
+
+SideExit*
+TraceRecorder::snapshot(ExitType exitType)
+{
+    JSStackFrame* fp = cx->fp;
+    if (exitType == BRANCH_EXIT && js_IsLoopExit(cx, fp->script, fp->regs->pc))
+        exitType = LOOP_EXIT;
+    /* Generate the entry map and stash it in the trace. */
+    unsigned stackSlots = nativeStackSlots(cx, callDepth);
+    /* It's sufficient to track the native stack use here since all stores above the
+       stack watermark defined by guards are killed. */
+    trackNativeStackUse(stackSlots + 1);
+    /* reserve space for the type map */
+    unsigned ngslots = traceMonitor->globalSlots->length();
+    LIns* data = lir_buf_writer->skip((stackSlots + ngslots) * sizeof(uint8));
+    /* setup side exit structure */
+    memset(&exit, 0, sizeof(exit));
+    exit.from = fragment;
+    exit.calldepth = callDepth;
+    exit.numGlobalSlots = ngslots;
+    exit.numStackSlots = stackSlots;
+    exit.exitType = exitType;
+    exit.ip_adj = fp->regs->pc - (jsbytecode*)fragment->root->ip;
+    exit.sp_adj = (stackSlots * sizeof(double)) - treeInfo->nativeStackBase;
+    exit.rp_adj = exit.calldepth * sizeof(FrameInfo);
+    uint8* m = exit.typeMap = (uint8 *)data->payload();
+    /* Determine the type of a store by looking at the current type of the actual value the
+       interpreter is using. For numbers we have to check what kind of store we used last
+       (integer or double) to figure out what the side exit show reflect in its typemap. */
+    FORALL_SLOTS(cx, ngslots, traceMonitor->globalSlots->data(), callDepth,
+        LIns* i = get(vp);
+        *m = isNumber(*vp)
+               ? (isPromoteInt(i) ? JSVAL_INT : JSVAL_DOUBLE)
+               : JSVAL_TAG(*vp);
+        JS_ASSERT((*m != JSVAL_INT) || isInt32(*vp));
+        ++m;
+    );
+    JS_ASSERT(unsigned(m - exit.typeMap) == ngslots + stackSlots);
+    return &exit;
+}
+
+/* Emit a guard for condition (cond), expecting to evaluate to boolean result (expected). */
+LIns*
+TraceRecorder::guard(bool expected, LIns* cond, ExitType exitType)
+{
+    return lir->insGuard(expected ? LIR_xf : LIR_xt,
+                         cond,
+                         snapshot(exitType));
+}
+
+/* Try to match the type of a slot to type t. checkType is used to verify that the type of
+   values flowing into the loop edge is compatible with the type we expect in the loop header. */
+bool
+TraceRecorder::checkType(jsval& v, uint8 t, bool& unstable)
+{
+    if (t == JSVAL_INT) { /* initially all whole numbers cause the slot to be demoted */
+        if (!isNumber(v))
+            return false; /* not a number? type mismatch */
+        LIns* i = get(&v);
+        if (!i->isop(LIR_i2f)) {
+            debug_only_v(printf("int slot is !isInt32, slot #%d, triggering re-compilation\n",
+                                !isGlobal(&v)
+                                ? nativeStackOffset(&v)
+                                : nativeGlobalOffset(&v)););
+            AUDIT(slotPromoted);
+            unstable = true;
+            return true; /* keep checking types, but request re-compilation */
+        }
+        /* Looks good, slot is an int32, the last instruction should be i2f. */
+        JS_ASSERT(isInt32(v) && i->isop(LIR_i2f));
+        /* We got the final LIR_i2f as we expected. Overwrite the value in that
+           slot with the argument of i2f since we want the integer store to flow along
+           the loop edge, not the casted value. */
+        set(&v, i->oprnd1());
+        return true;
+    }
+    if (t == JSVAL_DOUBLE) {
+        if (!isNumber(v))
+            return false; /* not a number? type mismatch */
+        LIns* i = get(&v);
+        /* We sink i2f conversions into the side exit, but at the loop edge we have to make
+           sure we promote back to double if at loop entry we want a double. */
+        if (isPromoteInt(i)) 
+            set(&v, lir->ins1(LIR_i2f, i));
+        return true;
+    }
+    /* for non-number types we expect a precise match of the type */
+#ifdef DEBUG
+    if (JSVAL_TAG(v) != t) {
+        debug_only_v(printf("Type mismatch: val %c, map %c ", "OID?S?B"[JSVAL_TAG(v)],
+                            "OID?S?B"[t]););
+    }
+#endif
+    return JSVAL_TAG(v) == t;
+}
+
+static void
+js_TrashTree(JSContext* cx, Fragment* f);
+
+/* Make sure that the current values in the given stack frame and all stack frames
+   up and including entryFrame are type-compatible with the entry map. */
+bool
+TraceRecorder::verifyTypeStability()
+{
+    unsigned ngslots = traceMonitor->globalSlots->length();
+    uint16* gslots = traceMonitor->globalSlots->data();
+    uint8* typemap = traceMonitor->globalTypeMap->data();
+    JS_ASSERT(traceMonitor->globalTypeMap->length() == ngslots);
+    bool recompile = false;
+    uint8* m = typemap;
+    FORALL_GLOBAL_SLOTS(cx, ngslots, gslots,
+        bool demote = false;
+        if (!checkType(*vp, *m, demote))
+            return false;
+        if (demote) {
+            oracle.markGlobalSlotUndemotable(cx->fp->script, gslots[n]);
+            recompile = true;
+        }
+        ++m
+    );
+    typemap = treeInfo->stackTypeMap.data();
+    m = typemap;
+    FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
+        bool demote = false;
+        if (!checkType(*vp, *m, demote))
+            return false;
+        if (demote) {
+            oracle.markStackSlotUndemotable(cx->fp->script, (jsbytecode*)fragment->ip,
+                    unsigned(m - typemap));
+            recompile = true;
+        }
+        ++m
+    );
+    if (recompile)
+        js_TrashTree(cx, fragment);
+    return !recompile;
+}
+
+/* Check whether the current pc location is the loop header of the loop this recorder records. */
+bool
+TraceRecorder::isLoopHeader(JSContext* cx) const
+{
+    return cx->fp->regs->pc == fragment->root->ip;
+}
+
+/* Complete and compile a trace and link it to the existing tree if appropriate. */
+void
+TraceRecorder::closeLoop(Fragmento* fragmento)
+{
+    if (!verifyTypeStability()) {
+        AUDIT(unstableLoopVariable);
+        debug_only_v(printf("Trace rejected: unstable loop variables.\n");)
+        return;
+    }
+    if (treeInfo->maxNativeStackSlots >= MAX_NATIVE_STACK_SLOTS) {
+        debug_only_v(printf("Trace rejected: excessive stack use.\n"));
+        fragment->blacklist();
+        return;
+    }
+    SideExit *exit = snapshot(LOOP_EXIT);
+    exit->target = fragment->root;
+    if (fragment == fragment->root) {
+        fragment->lastIns = lir->insGuard(LIR_loop, lir->insImm(1), exit);
+    } else {
+        fragment->lastIns = lir->insGuard(LIR_x, lir->insImm(1), exit);
+    }
+    compile(fragmento->assm(), fragment);
+    if (anchor) {
+        fragment->addLink(anchor);
+        fragmento->assm()->patch(anchor);
+    }
+    JS_ASSERT(fragment->code());
+    JS_ASSERT(!fragment->vmprivate);
+    if (fragment == fragment->root)
+        fragment->vmprivate = treeInfo;
+	/* :TODO: windows support */
+#if defined DEBUG && !defined WIN32
+    char* label = (char*)malloc(strlen(cx->fp->script->filename) + 64);
+    sprintf(label, "%s:%u", cx->fp->script->filename,
+            js_PCToLineNumber(cx, cx->fp->script, cx->fp->regs->pc));
+    fragmento->labels->add(fragment, sizeof(Fragment), 0, label);
+    free(label);
+#endif
+}
+
+/* Emit code to adjust the stack to match the inner tree's stack expectations. */
+void
+TraceRecorder::prepareTreeCall(Fragment* inner)
+{
+    TreeInfo* ti = (TreeInfo*)inner->vmprivate;
+    inner_sp_ins = lirbuf->sp;
+    /* The inner tree expects to be ca