Backout 6bbf3f22bb5d (bug 753158), 38a703b244c2 (bug 753145), c9a5dfa1b07d (bug 767750), cd782fd66995 & 6cf7aa93994c (bug 765956), 0253f34f6bc2 & 41d5c8529748 (bug 771039),94f6bf99a4aa (bug 766447),fad7d06d7dd5 (bug 772303) for winxp pgo-only jsreftest failures (caused by fad7d06d7dd5) and the rest for conflicts, on a CLOSED TREE
authorEd Morley <emorley@mozilla.com>
Thu, 12 Jul 2012 13:04:51 +0100
changeset 99058 f0be4b70b814d6cd310667b309d2d80859aad71e
parent 99057 64cff7aafcc474aa245963d9bc318bf57a599e39
child 99059 ed4888197cb523d994b540a247ccc78347baf171
child 99133 f9499238bd4b82cb34b2ab2fd1aafde29ea3007e
push id11805
push useremorley@mozilla.com
push dateThu, 12 Jul 2012 12:05:05 +0000
treeherdermozilla-inbound@f0be4b70b814 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs753158, 753145, 767750, 765956, 771039, 766447, 772303
milestone16.0a1
backs out6bbf3f22bb5dfee937c386a3e6004df46ff02203
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout 6bbf3f22bb5d (bug 753158), 38a703b244c2 (bug 753145), c9a5dfa1b07d (bug 767750), cd782fd66995 & 6cf7aa93994c (bug 765956), 0253f34f6bc2 & 41d5c8529748 (bug 771039),94f6bf99a4aa (bug 766447),fad7d06d7dd5 (bug 772303) for winxp pgo-only jsreftest failures (caused by fad7d06d7dd5) and the rest for conflicts, on a CLOSED TREE
dom/bindings/DOMJSClass.h
js/src/builtin/Eval.cpp
js/src/builtin/RegExp.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/TreeContext-inl.h
js/src/jit-test/tests/basic/testImplicitArgumentsInGenExprs.js
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdbgapi.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsproxy.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameState-inl.h
js/src/methodjit/FrameState.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PolyIC.h
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/tests/js1_5/extensions/regress-300079.js
js/src/tests/js1_8_1/regress/regress-452498-108.js
js/src/vm/ArgumentsObject-inl.h
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
js/src/vm/GlobalObject.cpp
js/src/vm/ObjectImpl-inl.h
js/src/vm/ObjectImpl.h
js/src/vm/SPSProfiler.h
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/Xdr.cpp
js/src/vm/Xdr.h
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -16,17 +16,18 @@
 #define DOM_OBJECT_SLOT 0
 
 // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to
 // start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses
 // that one.
 #define DOM_PROTOTYPE_SLOT (JSCLASS_GLOBAL_SLOT_COUNT + 1)
 
 // We use these flag bits for the new bindings.
-#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
+#define JSCLASS_IS_DOMJSCLASS JSCLASS_USERBIT1
+#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT2
 
 namespace mozilla {
 namespace dom {
 
 typedef bool
 (* ResolveProperty)(JSContext* cx, JSObject* wrapper, jsid id, bool set,
                     JSPropertyDescriptor* desc);
 typedef bool
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -5,17 +5,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jscntxt.h"
 #include "jsonparser.h"
 
 #include "builtin/Eval.h"
 #include "frontend/BytecodeCompiler.h"
-#include "mozilla/HashFunctions.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinterpinlines.h"
 
 using namespace js;
 
 // We should be able to assert this for *any* fp->scopeChain().
 static void
@@ -26,100 +25,160 @@ AssertInnerizedScopeChain(JSContext *cx,
         if (JSObjectOp op = o->getClass()->ext.innerObject) {
             Rooted<JSObject*> obj(cx, o);
             JS_ASSERT(op(cx, obj) == o);
         }
     }
 #endif
 }
 
-static bool
-IsEvalCacheCandidate(JSScript *script)
+void
+EvalCache::purge()
 {
-    // Make sure there are no inner objects which might use the wrong parent
-    // and/or call scope by reusing the previous eval's script. Skip the
-    // script's first object, which entrains the eval's scope.
-    return script->savedCallerFun &&
-           !script->hasSingletons &&
-           script->objects()->length == 1 &&
-           !script->hasRegexps();
+    // Purge all scripts from the eval cache. In addition to removing them from
+    // table_, null out the evalHashLink field of any script removed. Since
+    // evalHashLink is in a union with globalObject, this allows the GC to
+    // indiscriminately use the union as a nullable globalObject pointer.
+    for (size_t i = 0; i < ArrayLength(table_); ++i) {
+        for (JSScript **listHeadp = &table_[i]; *listHeadp; ) {
+            JSScript *script = *listHeadp;
+            JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
+            *listHeadp = script->evalHashLink();
+            script->evalHashLink() = NULL;
+        }
+    }
+}
+
+JSScript **
+EvalCache::bucket(JSLinearString *str)
+{
+    const jschar *s = str->chars();
+    size_t n = str->length();
+
+    if (n > 100)
+        n = 100;
+    uint32_t h;
+    for (h = 0; n; s++, n--)
+        h = JS_ROTATE_LEFT32(h, 4) ^ *s;
+
+    h *= JS_GOLDEN_RATIO;
+    h >>= 32 - SHIFT;
+    JS_ASSERT(h < ArrayLength(table_));
+    return &table_[h];
 }
 
-/* static */ HashNumber
-EvalCacheHashPolicy::hash(const EvalCacheLookup &l)
+static JSScript *
+EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, unsigned staticLevel,
+                JSPrincipals *principals, JSObject &scopeobj, JSScript **bucket)
 {
-    return AddToHash(HashString(l.str->chars(), l.str->length()),
-                     l.caller,
-                     l.staticLevel,
-                     l.version,
-                     l.compartment);
-}
+    // Cache local eval scripts indexed by source qualified by scope.
+    // 
+    // An eval cache entry should never be considered a hit unless its
+    // strictness matches that of the new eval code. The existing code takes
+    // care of this, because hits are qualified by the function from which
+    // eval was called, whose strictness doesn't change. (We don't cache evals
+    // in eval code, so the calling function corresponds to the calling script,
+    // and its strictness never varies.) Scripts produced by calls to eval from
+    // global code aren't cached.
+    // 
+    // FIXME bug 620141: Qualify hits by calling script rather than function.
+    // Then we wouldn't need the unintuitive !isEvalFrame() hack in EvalKernel
+    // to avoid caching nested evals in functions (thus potentially mismatching
+    // on strict mode), and we could cache evals in global code if desired.
+    unsigned count = 0;
+    JSScript **scriptp = bucket;
 
-/* static */ bool
-EvalCacheHashPolicy::match(JSScript *script, const EvalCacheLookup &l)
-{
-    JS_ASSERT(IsEvalCacheCandidate(script));
+    JSVersion version = cx->findVersion();
+    JSScript *script;
+    JSSubsumePrincipalsOp subsume = cx->runtime->securityCallbacks->subsumePrincipals;
+    while ((script = *scriptp) != NULL) {
+        if (script->savedCallerFun &&
+            script->staticLevel == staticLevel &&
+            script->getVersion() == version &&
+            !script->hasSingletons &&
+            (!subsume || script->principals == principals ||
+             (subsume(principals, script->principals) &&
+              subsume(script->principals, principals))))
+        {
+            // Get the prior (cache-filling) eval's saved caller function.
+            // See frontend::CompileScript.
+            JSFunction *fun = script->getCallerFunction();
+
+            if (fun == caller->fun()) {
+                /*
+                 * Get the source string passed for safekeeping in the atom map
+                 * by the prior eval to frontend::CompileScript.
+                 */
+                JSAtom *src = script->atoms[0];
 
-    // Get the source string passed for safekeeping in the atom map
-    // by the prior eval to frontend::CompileScript.
-    JSAtom *keyStr = script->atoms[0];
+                if (src == str || EqualStrings(src, str)) {
+                    // Source matches. Make sure there are no inner objects
+                    // which might use the wrong parent and/or call scope by
+                    // reusing the previous eval's script. Skip the script's
+                    // first object, which entrains the eval's scope.
+                    JS_ASSERT(script->objects()->length >= 1);
+                    if (script->objects()->length == 1 &&
+                        !script->hasRegexps()) {
+                        JS_ASSERT(staticLevel == script->staticLevel);
+                        *scriptp = script->evalHashLink();
+                        script->evalHashLink() = NULL;
+                        return script;
+                    }
+                }
+            }
+        }
 
-    return EqualStrings(keyStr, l.str) &&
-           script->getCallerFunction() == l.caller &&
-           script->staticLevel == l.staticLevel &&
-           script->getVersion() == l.version &&
-           script->compartment() == l.compartment;
+        static const unsigned EVAL_CACHE_CHAIN_LIMIT = 4;
+        if (++count == EVAL_CACHE_CHAIN_LIMIT)
+            return NULL;
+        scriptp = &script->evalHashLink();
+    }
+    return NULL;
 }
 
 // There are two things we want to do with each script executed in EvalKernel:
 //  1. notify jsdbgapi about script creation/destruction
 //  2. add the script to the eval cache when EvalKernel is finished
 //
 // NB: Although the eval cache keeps a script alive wrt to the JS engine, from
 // a jsdbgapi user's perspective, we want each eval() to create and destroy a
 // script. This hides implementation details and means we don't have to deal
-// with calls to JS_GetScriptObject for scripts in the eval cache.
+// with calls to JS_GetScriptObject for scripts in the eval cache (currently,
+// script->object aliases script->evalHashLink()).
 class EvalScriptGuard
 {
     JSContext *cx_;
+    JSLinearString *str_;
+    JSScript **bucket_;
     Rooted<JSScript*> script_;
 
-    /* These fields are only valid if lookup_.str is non-NULL. */
-    EvalCacheLookup lookup_;
-    EvalCache::AddPtr p_;
-
   public:
-    EvalScriptGuard(JSContext *cx)
-      : cx_(cx), script_(cx)
-    {
-        lookup_.str = NULL;
+    EvalScriptGuard(JSContext *cx, JSLinearString *str)
+      : cx_(cx),
+        str_(str),
+        script_(cx) {
+        bucket_ = cx->runtime->evalCache.bucket(str);
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
-            if (lookup_.str && IsEvalCacheCandidate(script_))
-                cx_->runtime->evalCache.relookupOrAdd(p_, lookup_, script_);
+            script_->evalHashLink() = *bucket_;
+            *bucket_ = script_;
         }
     }
 
-    void lookupInEvalCache(JSLinearString *str, JSFunction *caller, unsigned staticLevel)
-    {
-        lookup_.str = str;
-        lookup_.caller = caller;
-        lookup_.staticLevel = staticLevel;
-        lookup_.version = cx_->findVersion();
-        lookup_.compartment = cx_->compartment;
-        p_ = cx_->runtime->evalCache.lookupForAdd(lookup_);
-        if (p_) {
-            script_ = *p_;
-            cx_->runtime->evalCache.remove(p_);
-            js_CallNewScriptHook(cx_, script_, NULL);
+    void lookupInEvalCache(StackFrame *caller, unsigned staticLevel,
+                           JSPrincipals *principals, JSObject &scopeobj) {
+        if (JSScript *found = EvalCacheLookup(cx_, str_, caller, staticLevel,
+                                              principals, scopeobj, bucket_)) {
+            js_CallNewScriptHook(cx_, found, NULL);
+            script_ = found;
             script_->isCachedEval = false;
             script_->isActiveEval = true;
         }
     }
 
     void setNewScript(JSScript *script) {
         // JSScript::initFromEmitter has already called js_CallNewScriptHook.
         JS_ASSERT(!script_ && script);
@@ -183,16 +242,21 @@ EvalKernel(JSContext *cx, const CallArgs
         staticLevel = caller->script()->staticLevel + 1;
 
         // Direct calls to eval are supposed to see the caller's |this|. If we
         // haven't wrapped that yet, do so now, before we make a copy of it for
         // the eval code to use.
         if (!ComputeThis(cx, caller))
             return false;
         thisv = caller->thisValue();
+
+#ifdef DEBUG
+        jsbytecode *callerPC = caller->pcQuadratic(cx);
+        JS_ASSERT(callerPC && JSOp(*callerPC) == JSOP_EVAL);
+#endif
     } else {
         JS_ASSERT(args.callee().global() == *scopeobj);
         staticLevel = 0;
 
         // Use the global as 'this', modulo outerization.
         JSObject *thisobj = scopeobj->thisObject(cx);
         if (!thisobj)
             return false;
@@ -241,36 +305,37 @@ EvalKernel(JSContext *cx, const CallArgs
                 if (tmp.isUndefined())
                     break;
                 args.rval() = tmp;
                 return true;
             }
         }
     }
 
-    EvalScriptGuard esg(cx);
+    EvalScriptGuard esg(cx, linearStr);
 
     JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
 
     if (evalType == DIRECT_EVAL && caller->isNonEvalFunctionFrame())
-        esg.lookupInEvalCache(linearStr, caller->fun(), staticLevel);
+        esg.lookupInEvalCache(caller, staticLevel, principals, *scopeobj);
 
     if (!esg.foundScript()) {
         unsigned lineno;
         const char *filename;
         JSPrincipals *originPrincipals;
         CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals,
                                     evalType == DIRECT_EVAL ? CALLED_FROM_JSOP_EVAL
                                                             : NOT_CALLED_FROM_JSOP_EVAL);
 
         bool compileAndGo = true;
         bool noScriptRval = false;
+        bool needScriptGlobal = false;
         JSScript *compiled = frontend::CompileScript(cx, scopeobj, caller,
                                                      principals, originPrincipals,
-                                                     compileAndGo, noScriptRval,
+                                                     compileAndGo, noScriptRval, needScriptGlobal,
                                                      chars, length, filename,
                                                      lineno, cx->findVersion(), linearStr,
                                                      staticLevel);
         if (!compiled)
             return false;
 
         esg.setNewScript(compiled);
     }
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -571,29 +571,29 @@ ExecuteRegExp(JSContext *cx, Native nati
         return false;
 
     /* Step 3. */
     Rooted<JSLinearString*> linearInput(cx, input->ensureLinear(cx));
     if (!linearInput)
         return false;
 
     /* Step 4. */
-    Value lastIndex = reobj->getLastIndex();
+    const Value &lastIndex = reobj->getLastIndex();
 
     /* Step 5. */
     double i;
     if (!ToInteger(cx, lastIndex, &i))
         return false;
 
     /* Steps 6-7 (with sticky extension). */
     if (!re->global() && !re->sticky())
         i = 0;
 
     const jschar *chars = linearInput->chars();
-    size_t length = linearInput->length();
+    size_t length = input->length();
 
     /* Step 9a. */
     if (i < 0 || i > length) {
         reobj->zeroLastIndex();
         args.rval() = NullValue();
         return true;
     }
 
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -16,20 +16,64 @@
 
 #include "jsinferinlines.h"
 
 #include "frontend/TreeContext-inl.h"
 
 using namespace js;
 using namespace js::frontend;
 
+bool
+MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script)
+{
+    AssertRootingUnnecessary safe(cx);
+
+    Vector<JSScript *, 16> worklist(cx);
+    if (!worklist.append(script))
+        return false;
+
+    while (worklist.length()) {
+        JSScript *outer = worklist.back();
+        worklist.popBack();
+
+        if (outer->hasObjects()) {
+            ObjectArray *arr = outer->objects();
+
+            /*
+             * If this is an eval script, don't treat the saved caller function
+             * stored in the first object slot as an inner function.
+             */
+            size_t start = outer->savedCallerFun ? 1 : 0;
+
+            for (size_t i = start; i < arr->length; i++) {
+                JSObject *obj = arr->vector[i];
+                if (!obj->isFunction())
+                    continue;
+                JSFunction *fun = obj->toFunction();
+                JS_ASSERT(fun->isInterpreted());
+                JSScript *inner = fun->script();
+                if (outer->function() && outer->function()->isHeavyweight()) {
+                    outer->isOuterFunction = true;
+                    inner->isInnerFunction = true;
+                }
+                if (!inner->hasObjects())
+                    continue;
+                if (!worklist.append(inner))
+                    return false;
+            }
+        }
+    }
+
+    return true;
+}
+
 JSScript *
 frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
                         JSPrincipals *principals, JSPrincipals *originPrincipals,
-                        bool compileAndGo, bool noScriptRval,
+                        bool compileAndGo, bool noScriptRval, bool needScriptGlobal,
                         const jschar *chars, size_t length,
                         const char *filename, unsigned lineno, JSVersion version,
                         JSString *source_ /* = NULL */,
                         unsigned staticLevel /* = 0 */)
 {
     RootedString source(cx, source_);
 
     class ProbesManager
@@ -59,23 +103,24 @@ frontend::CompileScript(JSContext *cx, H
 
     SharedContext sc(cx, scopeChain, /* fun = */ NULL, /* funbox = */ NULL, StrictModeFromContext(cx));
 
     TreeContext tc(&parser, &sc, staticLevel, /* bodyid = */ 0);
     if (!tc.init())
         return NULL;
 
     bool savedCallerFun = compileAndGo && callerFrame && callerFrame->isFunctionFrame();
+    GlobalObject *globalObject = needScriptGlobal ? GetCurrentGlobal(cx) : NULL;
     Rooted<JSScript*> script(cx, JSScript::Create(cx,
-                                                  /* enclosingScope = */ NullPtr(),
                                                   savedCallerFun,
                                                   principals,
                                                   originPrincipals,
                                                   compileAndGo,
                                                   noScriptRval,
+                                                  globalObject,
                                                   version,
                                                   staticLevel));
     if (!script)
         return NULL;
 
     // We can specialize a bit for the given scope chain if that scope chain is the global object.
     JSObject *globalScope = scopeChain && scopeChain == &scopeChain->global() ? (JSObject*) scopeChain : NULL;
     JS_ASSERT_IF(globalScope, globalScope->isNative());
@@ -199,16 +244,19 @@ frontend::CompileScript(JSContext *cx, H
     if (Emit1(cx, &bce, JSOP_STOP) < 0)
         return NULL;
 
     if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
         return NULL;
 
     bce.tellDebuggerAboutCompiledScript(cx);
 
+    if (!MarkInnerAndOuterFunctions(cx, script))
+        return NULL;
+
     return script;
 }
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 bool
 frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun,
                               JSPrincipals *principals, JSPrincipals *originPrincipals,
@@ -226,23 +274,24 @@ frontend::CompileFunctionBody(JSContext 
     funsc.bindings.transfer(bindings);
     fun->setArgCount(funsc.bindings.numArgs());
 
     unsigned staticLevel = 0;
     TreeContext funtc(&parser, &funsc, staticLevel, /* bodyid = */ 0);
     if (!funtc.init())
         return false;
 
+    GlobalObject *globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
     Rooted<JSScript*> script(cx, JSScript::Create(cx,
-                                                  /* enclosingScope = */ NullPtr(),
                                                   /* savedCallerFun = */ false,
                                                   principals,
                                                   originPrincipals,
                                                   /* compileAndGo = */ false,
                                                   /* noScriptRval = */ false,
+                                                  globalObject,
                                                   version,
                                                   staticLevel));
     if (!script)
         return false;
 
     StackFrame *nullCallerFrame = NULL;
     BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, nullCallerFrame,
                            /* hasGlobalScope = */ false, lineno);
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -11,17 +11,17 @@
 #include "frontend/Parser.h"
 
 namespace js {
 namespace frontend {
 
 JSScript *
 CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
               JSPrincipals *principals, JSPrincipals *originPrincipals,
-              bool compileAndGo, bool noScriptRval,
+              bool compileAndGo, bool noScriptRval, bool needScriptGlobal,
               const jschar *chars, size_t length,
               const char *filename, unsigned lineno, JSVersion version,
               JSString *source_ = NULL, unsigned staticLevel = 0);
 
 bool
 CompileFunctionBody(JSContext *cx, HandleFunction fun,
                     JSPrincipals *principals, JSPrincipals *originPrincipals,
                     Bindings *bindings, const jschar *chars, size_t length,
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -668,41 +668,22 @@ BackPatch(JSContext *cx, BytecodeEmitter
 
 static void
 PushStatementBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StmtType type, ptrdiff_t top)
 {
     SET_STATEMENT_TOP(stmt, top);
     PushStatement(bce, stmt, type);
 }
 
-/*
- * Return the enclosing lexical scope, which is the innermost enclosing static
- * block object or compiler created function.
- */
-static JSObject *
-EnclosingStaticScope(BytecodeEmitter *bce)
-{
-    if (bce->blockChain)
-        return bce->blockChain;
-
-    if (!bce->sc->inFunction()) {
-        JS_ASSERT(!bce->parent);
-        return NULL;
-    }
-
-    return bce->sc->fun();
-}
-
 // Push a block scope statement and link blockObj into bce->blockChain.
 static void
 PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj,
                   ptrdiff_t top)
 {
     PushStatementBCE(bce, stmt, STMT_BLOCK, top);
-    blockObj.initEnclosingStaticScope(EnclosingStaticScope(bce));
     FinishPushBlockScope(bce, stmt, blockObj);
 }
 
 // Patches |breaks| and |continues| unless the top statement info record
 // represents a try-catch-finally suite. May fail if a jump offset overflows.
 static bool
 PopStatementBCE(JSContext *cx, BytecodeEmitter *bce)
 {
@@ -868,17 +849,16 @@ EmitAliasedVarOp(JSContext *cx, JSOp op,
         return false;
 
     jsbytecode *pc = bce->code(off);
     SET_UINT16(pc, sc.hops);
     pc += sizeof(uint16_t);
     SET_UINT16(pc, sc.slot);
     pc += sizeof(uint16_t);
     SET_UINT32_INDEX(pc, maybeBlockIndex);
-    CheckTypeSet(cx, bce, op);
     return true;
 }
 
 static unsigned
 ClonedBlockDepth(BytecodeEmitter *bce)
 {
     unsigned clonedBlockDepth = 0;
     for (StaticBlockObject *b = bce->blockChain; b; b = b->enclosingBlock()) {
@@ -887,77 +867,60 @@ ClonedBlockDepth(BytecodeEmitter *bce)
     }
 
     return clonedBlockDepth;
 }
 
 static bool
 EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce)
 {
-    unsigned skippedScopes = 0;
-    BytecodeEmitter *bceOfDef = bce;
-    if (pn->isUsed()) {
-        /*
-         * As explained in BindNameToSlot, the 'level' of a use indicates how
-         * many function scopes (i.e., BytecodeEmitters) to skip to find the
-         * enclosing function scope of the definition being accessed.
-         */
-        for (unsigned i = pn->pn_cookie.level(); i; i--) {
-            skippedScopes += ClonedBlockDepth(bceOfDef);
-            if (bceOfDef->sc->funIsHeavyweight()) {
-                skippedScopes++;
-                if (bceOfDef->sc->fun()->isNamedLambda())
-                    skippedScopes++;
-            }
-            bceOfDef = bceOfDef->parent;
-        }
-    } else {
-        JS_ASSERT(pn->isDefn());
-        JS_ASSERT(pn->pn_cookie.level() == bce->script->staticLevel);
-    }
-
+    /*
+     * The contents of the dynamic scope chain (fp->scopeChain) exactly reflect
+     * the needsClone-subset of the block chain. Use this to determine the
+     * number of ClonedBlockObjects on fp->scopeChain to skip to find the scope
+     * object containing the var to which pn is bound. ALIASEDVAR ops cannot
+     * reach across with scopes so ClonedBlockObjects is the only NestedScope
+     * on the scope chain.
+     */
     ScopeCoordinate sc;
     if (JOF_OPTYPE(pn->getOp()) == JOF_QARG) {
-        sc.hops = skippedScopes + ClonedBlockDepth(bceOfDef);
-        sc.slot = bceOfDef->sc->bindings.formalIndexToSlot(pn->pn_cookie.slot());
+        sc.hops = ClonedBlockDepth(bce);
+        sc.slot = bce->sc->bindings.formalIndexToSlot(pn->pn_cookie.slot());
     } else {
         JS_ASSERT(JOF_OPTYPE(pn->getOp()) == JOF_LOCAL || pn->isKind(PNK_FUNCTION));
         unsigned local = pn->pn_cookie.slot();
-        if (local < bceOfDef->sc->bindings.numVars()) {
-            sc.hops = skippedScopes + ClonedBlockDepth(bceOfDef);
-            sc.slot = bceOfDef->sc->bindings.varIndexToSlot(local);
+        if (local < bce->sc->bindings.numVars()) {
+            sc.hops = ClonedBlockDepth(bce);
+            sc.slot = bce->sc->bindings.varIndexToSlot(local);
         } else {
-            unsigned depth = local - bceOfDef->sc->bindings.numVars();
-            StaticBlockObject *b = bceOfDef->blockChain;
+            unsigned depth = local - bce->sc->bindings.numVars();
+            unsigned hops = 0;
+            StaticBlockObject *b = bce->blockChain;
             while (!b->containsVarAtDepth(depth)) {
                 if (b->needsClone())
-                    skippedScopes++;
+                    hops++;
                 b = b->enclosingBlock();
             }
-            sc.hops = skippedScopes;
-            sc.slot = b->localIndexToSlot(bceOfDef->sc->bindings, local);
+            sc.hops = hops;
+            sc.slot = b->localIndexToSlot(bce->sc->bindings, local);
         }
     }
 
     return EmitAliasedVarOp(cx, op, sc, bce);
 }
 
 static bool
 EmitVarOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
 {
     JS_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME));
     JS_ASSERT_IF(pn->isKind(PNK_NAME), JOF_OPTYPE(op) == JOF_QARG || JOF_OPTYPE(op) == JOF_LOCAL);
     JS_ASSERT(!pn->pn_cookie.isFree());
 
-    if (!bce->isAliasedName(pn)) {
-        JS_ASSERT(pn->isUsed() || pn->isDefn());
-        JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0);
-        JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel);
+    if (!bce->isAliasedName(pn))
         return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), bce);
-    }
 
     switch (op) {
       case JSOP_GETARG: case JSOP_GETLOCAL: op = JSOP_GETALIASEDVAR; break;
       case JSOP_SETARG: case JSOP_SETLOCAL: op = JSOP_SETALIASEDVAR; break;
       case JSOP_CALLARG: case JSOP_CALLLOCAL: op = JSOP_CALLALIASEDVAR; break;
       default: JS_NOT_REACHED("unexpected var op");
     }
 
@@ -1203,83 +1166,93 @@ TryConvertToGname(BytecodeEmitter *bce, 
  *
  * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget
  * to update the special cases in EmitFor (for-in) and EmitAssignment (= and
  * op=, e.g. +=).
  */
 static bool
 BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
+    Definition *dn;
+    JSOp op;
+    Definition::Kind dn_kind;
+
     JS_ASSERT(pn->isKind(PNK_NAME));
 
-    /* Don't attempt if 'pn' is already bound, deoptimized, or a nop. */
-    if ((pn->pn_dflags & PND_BOUND) || pn->isDeoptimized() || pn->getOp() == JSOP_NOP)
+    /* Idempotency tests come first, since we may be called more than once. */
+    if (pn->pn_dflags & PND_BOUND)
         return true;
 
-    /* JSOP_CALLEE is pre-bound by definition. */
+    /* No cookie initialized for callee; it is pre-bound by definition. */
     JS_ASSERT(!pn->isOp(JSOP_CALLEE));
 
     /*
-     * The parser already linked name uses to definitions when (where not
-     * prevented by non-lexical constructs like 'with' and 'eval').
+     * The parser linked all uses (including forward references) to their
+     * definitions, unless a with statement or direct eval intervened.
      */
-    Definition *dn;
     if (pn->isUsed()) {
         JS_ASSERT(pn->pn_cookie.isFree());
         dn = pn->pn_lexdef;
         JS_ASSERT(dn->isDefn());
+        if (pn->isDeoptimized())
+            return true;
         pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
-    } else if (pn->isDefn()) {
+    } else {
+        if (!pn->isDefn())
+            return true;
         dn = (Definition *) pn;
-    } else {
+    }
+
+    op = pn->getOp();
+    if (op == JSOP_NOP)
         return true;
-    }
-
-    JSOp op = pn->getOp();
+
     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
-    JS_ASSERT_IF(dn->kind() == Definition::CONST, pn->pn_dflags & PND_CONST);
+    RootedAtom atom(cx, pn->pn_atom);
+    UpvarCookie cookie = dn->pn_cookie;
+    dn_kind = dn->kind();
 
     /*
      * Turn attempts to mutate const-declared bindings into get ops (for
      * pre-increment and pre-decrement ops, our caller will have to emit
      * JSOP_POS, JSOP_ONE, and JSOP_ADD as well).
      *
      * Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
      * bindings visible to the compiler are permanent in JS unless the
      * declaration originates at top level in eval code.
      */
     switch (op) {
       case JSOP_NAME:
       case JSOP_SETCONST:
         break;
       case JSOP_DELNAME:
-        if (dn->kind() != Definition::UNKNOWN) {
+        if (dn_kind != Definition::UNKNOWN) {
             if (bce->callerFrame && dn->isTopLevel())
                 JS_ASSERT(bce->script->compileAndGo);
             else
                 pn->setOp(JSOP_FALSE);
             pn->pn_dflags |= PND_BOUND;
             return true;
         }
         break;
       default:
         if (pn->isConst()) {
             if (bce->sc->needStrictChecks()) {
                 JSAutoByteString name;
-                if (!js_AtomToPrintableString(cx, pn->pn_atom, &name) ||
+                if (!js_AtomToPrintableString(cx, atom, &name) ||
                     !bce->reportStrictModeError(pn, JSMSG_READ_ONLY, name.ptr()))
                 {
                     return false;
                 }
             }
             pn->setOp(op = JSOP_NAME);
         }
     }
 
-    if (dn->pn_cookie.isFree()) {
+    if (cookie.isFree()) {
         StackFrame *caller = bce->callerFrame;
         if (caller) {
             JS_ASSERT(bce->script->compileAndGo);
 
             /*
              * Don't generate upvars on the left side of a for loop. See
              * bug 470758.
              */
@@ -1310,70 +1283,61 @@ BindNameToSlot(JSContext *cx, BytecodeEm
             return true;
 
         pn->setOp(op);
         pn->pn_dflags |= PND_BOUND;
 
         return true;
     }
 
-    /*
-     * At this point, we are only dealing with uses that have already been
-     * bound to definitions via pn_lexdef. The rest of this routine converts
-     * the parse node of the use from its initial JSOP_*NAME* op to a LOCAL/ARG
-     * op. This requires setting the node's pn_cookie with a pair (level, slot)
-     * where 'level' is the number of function scopes between the use and the
-     * def and 'slot' is the index to emit as the immediate of the ARG/LOCAL
-     * op. For example, in this code:
-     *
-     *   function(a,b,x) { return x }
-     *   function(y) { function() { return y } }
-     *
-     * x will get (level = 0, slot = 2) and y will get (level = 1, slot = 0).
-     */
-    JS_ASSERT(!pn->isDefn());
-    JS_ASSERT(pn->isUsed());
-    JS_ASSERT(pn->pn_lexdef);
-    JS_ASSERT(pn->pn_cookie.isFree());
+    uint16_t level = cookie.level();
+    JS_ASSERT(bce->script->staticLevel >= level);
+
+    const unsigned skip = bce->script->staticLevel - level;
+    if (skip != 0)
+        return true;
 
     /*
      * We are compiling a function body and may be able to optimize name
      * to stack slot. Look for an argument or variable in the function and
      * rewrite pn_op and update pn accordingly.
      */
-    switch (dn->kind()) {
+    switch (dn_kind) {
       case Definition::UNKNOWN:
         return true;
 
+      case Definition::LET:
+        switch (op) {
+          case JSOP_NAME:     op = JSOP_GETLOCAL; break;
+          case JSOP_SETNAME:  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;
+          default: JS_NOT_REACHED("let");
+        }
+        break;
+
       case Definition::ARG:
         switch (op) {
           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;
           default: JS_NOT_REACHED("arg");
         }
         JS_ASSERT(!pn->isConst());
         break;
 
       case Definition::VAR:
         if (dn->isOp(JSOP_CALLEE)) {
             JS_ASSERT(op != JSOP_CALLEE);
-
-            /*
-             * Currently, the ALIASEDVAR ops do not support accessing the
-             * callee of a DeclEnvObject, so use NAME.
-             */
-            if (dn->pn_cookie.level() != bce->script->staticLevel)
-                return true;
-
-            JS_ASSERT(bce->sc->fun()->flags & JSFUN_LAMBDA);
-            JS_ASSERT(pn->pn_atom == bce->sc->fun()->atom);
+            JS_ASSERT((bce->sc->fun()->flags & JSFUN_LAMBDA) && atom == bce->sc->fun()->atom);
 
             /*
              * Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to
              * address two cases: a new binding introduced by eval, and
              * assignment to the name in strict mode.
              *
              *   var fun = (function f(s) { eval(s); return f; });
              *   assertEq(fun("var f = 42"), 42);
@@ -1401,65 +1365,38 @@ BindNameToSlot(JSContext *cx, BytecodeEm
             }
 
             pn->setOp(op);
             pn->pn_dflags |= PND_BOUND;
             return true;
         }
         /* FALL THROUGH */
 
-      case Definition::FUNCTION:
-      case Definition::CONST:
-      case Definition::LET:
+      default:
+        JS_ASSERT_IF(dn_kind != Definition::FUNCTION,
+                     dn_kind == Definition::VAR ||
+                     dn_kind == Definition::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;
           default: JS_NOT_REACHED("local");
         }
+        JS_ASSERT_IF(dn_kind == Definition::CONST, pn->pn_dflags & PND_CONST);
         break;
-
-      default:
-        JS_NOT_REACHED("unexpected dn->kind()");
-    }
-
-    /*
-     * The difference between the current static level and the static level of
-     * the definition is the number of function scopes between the current
-     * scope and dn's scope.
-     */
-    unsigned skip = bce->script->staticLevel - dn->pn_cookie.level();
-    JS_ASSERT_IF(skip, dn->isClosed());
-
-    /*
-     * Explicitly disallow accessing var/let bindings in global scope from
-     * nested functions. The reason for this limitation is that, since the
-     * global script is not included in the static scope chain (1. because it
-     * has no object to stand in the static scope chain, 2. to minimize memory
-     * bloat where a single live function keeps its whole global script
-     * alive.), ScopeCoordinateToTypeSet is not able to find the var/let's
-     * associated types::TypeSet.
-     */
-    if (skip) {
-        BytecodeEmitter *bceSkipped = bce;
-        for (unsigned i = 0; i < skip; i++)
-            bceSkipped = bceSkipped->parent;
-        if (!bceSkipped->sc->inFunction())
-            return true;
     }
 
     JS_ASSERT(!pn->isOp(op));
     pn->setOp(op);
-    if (!pn->pn_cookie.set(bce->sc->context, skip, dn->pn_cookie.slot()))
-        return false;
-
+    if (!pn->pn_cookie.set(bce->sc->context, 0, cookie.slot()))
+        return false;
     pn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 /*
  * If pn contains a useful expression, return true with *answer set to true.
  * If pn contains a useless expression, return true with *answer set to false.
  * Return false on error.
@@ -1700,18 +1637,21 @@ BytecodeEmitter::needsImplicitThis()
 }
 
 void
 BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext *cx)
 {
     js_CallNewScriptHook(cx, script, script->function());
     if (!parent) {
         GlobalObject *compileAndGoGlobal = NULL;
-        if (script->compileAndGo)
-            compileAndGoGlobal = &script->global();
+        if (script->compileAndGo) {
+            compileAndGoGlobal = script->globalObject;
+            if (!compileAndGoGlobal)
+                compileAndGoGlobal = &sc->scopeChain()->global();
+        }
         Debugger::onNewScript(cx, script, compileAndGoGlobal);
     }
 }
 
 bool
 BytecodeEmitter::reportError(ParseNode *pn, unsigned errorNumber, ...)
 {
     va_list args;
@@ -3487,24 +3427,27 @@ EmitAssignment(JSContext *cx, BytecodeEm
 {
     ptrdiff_t top = bce->offset();
 
     /*
      * Check left operand type and generate specialized code for it.
      * Specialize to avoid ECMA "reference type" values on the operand
      * stack, which impose pervasive runtime "GetValue" costs.
      */
-    jsatomid atomIndex = (jsatomid) -1;
+    jsatomid atomIndex = (jsatomid) -1;              /* quell GCC overwarning */
     jsbytecode offset = 1;
 
     switch (lhs->getKind()) {
       case PNK_NAME:
         if (!BindNameToSlot(cx, bce, lhs))
             return false;
-        if (lhs->pn_cookie.isFree()) {
+        if (!lhs->pn_cookie.isFree()) {
+            JS_ASSERT(lhs->pn_cookie.level() == 0);
+            atomIndex = lhs->pn_cookie.slot();
+        } else {
             if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex))
                 return false;
             if (!lhs->isConst()) {
                 JSOp op = lhs->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME;
                 if (!EmitIndex32(cx, op, atomIndex, bce))
                     return false;
                 offset++;
             }
@@ -4269,16 +4212,17 @@ EmitIf(JSContext *cx, BytecodeEmitter *b
  *
  *  bytecode          stackDepth  srcnotes
  *  evaluate a        +1
  *  evaluate b        +1
  *  dup               +1          SRC_DESTRUCTLET + offset to enterlet0
  *  destructure y
  *  pick 1
  *  dup               +1          SRC_DESTRUCTLET + offset to enterlet0
+ *  pick
  *  destructure z
  *  pick 1
  *  pop               -1
  *  enterlet0                     SRC_DECL + offset to leaveblockexpr
  *  evaluate e        +1
  *  leaveblockexpr    -3          SRC_PCBASE + offset to evaluate a
  *
  * Note that, since enterlet0 simply changes fp->blockChain and does not
@@ -4875,25 +4819,25 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
         SharedContext sc(cx, /* scopeChain = */ NULL, fun, funbox, funbox->strictModeState);
         sc.cxFlags = funbox->cxFlags;
         if (bce->sc->funMightAliasLocals())
             sc.setFunMightAliasLocals();  // inherit funMightAliasLocals from parent
         sc.bindings.transfer(&funbox->bindings);
         JS_ASSERT_IF(bce->sc->inStrictMode(), sc.inStrictMode());
 
         // Inherit most things (principals, version, etc) from the parent.
+        GlobalObject *globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
         Rooted<JSScript*> parent(cx, bce->script);
-        Rooted<JSObject*> enclosingScope(cx, EnclosingStaticScope(bce));
         Rooted<JSScript*> script(cx, JSScript::Create(cx,
-                                                      enclosingScope,
                                                       /* savedCallerFun = */ false,
                                                       parent->principals,
                                                       parent->originPrincipals,
                                                       parent->compileAndGo,
                                                       /* noScriptRval = */ false,
+                                                      globalObject,
                                                       parent->getVersion(),
                                                       parent->staticLevel + 1));
         if (!script)
             return false;
 
         BytecodeEmitter bce2(bce, bce->parser, &sc, script, bce->callerFrame, bce->hasGlobalScope,
                              pn->pn_pos.begin.lineno);
         if (!bce2.init())
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -731,20 +731,16 @@ struct ParseNode {
 #define PND_BLOCKCHILD  0x20            /* use or def is direct block child */
 #define PND_PLACEHOLDER 0x40            /* placeholder definition for lexdep */
 #define PND_BOUND       0x80            /* bound to a stack or global slot */
 #define PND_DEOPTIMIZED 0x100           /* former pn_used name node, pn_lexdef
                                            still valid, but this use no longer
                                            optimizable via an upvar opcode */
 #define PND_CLOSED      0x200           /* variable is closed over */
 #define PND_DEFAULT     0x400           /* definition is an arg with a default */
-#define PND_IMPLICITARGUMENTS 0x800     /* the definition is a placeholder for
-                                           'arguments' that has been converted
-                                           into a definition after the function
-                                           body has been parsed. */
 
 /* Flags to propagate from uses to definition. */
 #define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_CLOSED)
 
 /* PN_LIST pn_xflags bits. */
 #define PNX_STRCAT      0x01            /* PNK_ADD list has string term */
 #define PNX_CANTFOLD    0x02            /* PNK_ADD list has unfoldable term */
 #define PNX_POPVAR      0x04            /* PNK_VAR or PNK_CONST last result
@@ -781,17 +777,16 @@ struct ParseNode {
     bool isLet() const          { return test(PND_LET); }
     bool isConst() const        { return test(PND_CONST); }
     bool isInitialized() const  { return test(PND_INITIALIZED); }
     bool isBlockChild() const   { return test(PND_BLOCKCHILD); }
     bool isPlaceholder() const  { return test(PND_PLACEHOLDER); }
     bool isDeoptimized() const  { return test(PND_DEOPTIMIZED); }
     bool isAssigned() const     { return test(PND_ASSIGNED); }
     bool isClosed() const       { return test(PND_CLOSED); }
-    bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); }
 
     /*
      * True iff this definition creates a top-level binding in the overall
      * script being compiled -- that is, it affects the whole program's
      * bindings, not bindings for a specific function (unless this definition
      * is in the outermost scope in eval code, executed within a function) or
      * the properties of a specific object (through the with statement).
      *
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -97,16 +97,24 @@ StrictModeGetter::setQueuedStrictModeErr
 static void
 PushStatementTC(TreeContext *tc, StmtInfoTC *stmt, StmtType type)
 {
     stmt->blockid = tc->blockid();
     PushStatement(tc, stmt, type);
     stmt->isFunctionBodyBlock = false;
 }
 
+// Push a block scope statement and link blockObj into tc->blockChain.
+static void
+PushBlockScopeTC(TreeContext *tc, StmtInfoTC *stmt, StaticBlockObject &blockObj)
+{
+    PushStatementTC(tc, stmt, STMT_BLOCK);
+    FinishPushBlockScope(tc, stmt, blockObj);
+}
+
 Parser::Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
                const jschar *chars, size_t length, const char *fn, unsigned ln, JSVersion v,
                bool foldConstants, bool compileAndGo)
   : AutoGCRooter(cx, PARSER),
     context(cx),
     strictModeGetter(this),
     tokenStream(cx, prin, originPrin, chars, length, fn, ln, v, &strictModeGetter),
     tempPoolMark(NULL),
@@ -511,20 +519,17 @@ CheckStrictParameters(JSContext *cx, Par
     JSAtom *evalAtom = cx->runtime->atomState.evalAtom;
 
     /* name => whether we've warned about the name already */
     HashMap<JSAtom *, bool> parameters(cx);
     if (!parameters.init(sc->bindings.numArgs()))
         return false;
 
     // Start with lastVariable(), not the last argument, for destructuring.
-    Shape::Range r = sc->bindings.lastVariable();
-    Shape::Range::AutoRooter root(cx, &r);
-
-    for (; !r.empty(); r.popFront()) {
+    for (Shape::Range r = sc->bindings.lastVariable(); !r.empty(); r.popFront()) {
         jsid id = r.front().propid();
         if (!JSID_IS_ATOM(id))
             continue;
 
         JSAtom *name = JSID_TO_ATOM(id);
 
         if (name == argumentsAtom || name == evalAtom) {
             if (!ReportBadParameter(cx, parser, name, JSMSG_BAD_BINDING))
@@ -660,25 +665,22 @@ Parser::functionBody(FunctionBodyType ty
      */
     for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) {
         JSAtom *atom = r.front().key();
         Definition *dn = r.front().value();
         JS_ASSERT(dn->isPlaceholder());
         if (atom == arguments) {
             /*
              * Turn 'dn' into a proper definition so uses will be bound as
-             * GETLOCAL in the emitter. The PND_IMPLICITARGUMENTS flag informs
-             * CompExprTransplanter (and anyone else) that this definition node
-             * has no proper declaration in the parse tree.
+             * GETLOCAL in the emitter.
              */
             if (!BindLocalVariable(context, tc, dn, VARIABLE))
                 return NULL;
             dn->setOp(JSOP_GETLOCAL);
             dn->pn_dflags &= ~PND_PLACEHOLDER;
-            dn->pn_dflags |= PND_IMPLICITARGUMENTS;
 
             /* NB: this leaves r invalid so we must break immediately. */
             tc->lexdeps->remove(arguments);
             break;
         }
     }
 
     bool hasRest = tc->sc->fun()->hasRest();
@@ -2134,26 +2136,22 @@ struct RemoveDecl {
         tc->decls.remove(atom);
         return true;
     }
 };
 
 static void
 PopStatementTC(TreeContext *tc)
 {
-    StaticBlockObject *blockObj = tc->topStmt->blockObj;
-    JS_ASSERT(!!blockObj == (tc->topStmt->isBlockScope));
-
+    if (tc->topStmt->isBlockScope) {
+        StaticBlockObject &blockObj = *tc->topStmt->blockObj;
+        JS_ASSERT(!blockObj.inDictionaryMode());
+        ForEachLetDef(tc, blockObj, RemoveDecl());
+    }
     FinishPopStatement(tc);
-
-    if (blockObj) {
-        JS_ASSERT(!blockObj->inDictionaryMode());
-        ForEachLetDef(tc, *blockObj, RemoveDecl());
-        blockObj->resetPrevBlockChainFromParser();
-    }
 }
 
 static inline bool
 OuterLet(TreeContext *tc, StmtInfoTC *stmt, HandleAtom atom)
 {
     while (stmt->downScope) {
         stmt = LexicalLookup(tc, atom, NULL, stmt->downScope);
         if (!stmt)
@@ -2752,37 +2750,32 @@ Parser::returnOrYield(bool useAssignExpr
     {
         return NULL;
     }
 
     return pn;
 }
 
 static ParseNode *
-PushLexicalScope(JSContext *cx, Parser *parser, StaticBlockObject &blockObj, StmtInfoTC *stmt)
+PushLexicalScope(JSContext *cx, Parser *parser, StaticBlockObject &obj, StmtInfoTC *stmt)
 {
     ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, parser);
     if (!pn)
         return NULL;
 
-    ObjectBox *blockbox = parser->newObjectBox(&blockObj);
+    ObjectBox *blockbox = parser->newObjectBox(&obj);
     if (!blockbox)
         return NULL;
 
-    TreeContext *tc = parser->tc;
-
-    PushStatementTC(tc, stmt, STMT_BLOCK);
-    blockObj.initPrevBlockChainFromParser(tc->blockChain);
-    FinishPushBlockScope(tc, stmt, blockObj);
-
+    PushBlockScopeTC(parser->tc, stmt, obj);
     pn->setOp(JSOP_LEAVEBLOCK);
     pn->pn_objbox = blockbox;
     pn->pn_cookie.makeFree();
     pn->pn_dflags = 0;
-    if (!GenerateBlockId(tc, stmt->blockid))
+    if (!GenerateBlockId(parser->tc, stmt->blockid))
         return NULL;
     pn->pn_blockid = stmt->blockid;
     return pn;
 }
 
 static ParseNode *
 PushLexicalScope(JSContext *cx, Parser *parser, StmtInfoTC *stmt)
 {
@@ -3774,17 +3767,17 @@ Parser::letStatement()
              * list stack, if it isn't already there.  If it is there, but it
              * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
              * block.
              */
             stmt->isBlockScope = true;
             stmt->downScope = tc->topScopeStmt;
             tc->topScopeStmt = stmt;
 
-            blockObj->initPrevBlockChainFromParser(tc->blockChain);
+            blockObj->setEnclosingBlock(tc->blockChain);
             tc->blockChain = blockObj;
             stmt->blockObj = blockObj;
 
 #ifdef DEBUG
             ParseNode *tmp = tc->blockNode;
             JS_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
 #endif
 
@@ -4903,26 +4896,21 @@ Parser::unaryExpr()
  * the one or more bindings induced by V have not yet been created.
  */
 class CompExprTransplanter {
     ParseNode       *root;
     Parser          *parser;
     bool            genexp;
     unsigned        adjust;
     unsigned        funcLevel;
-    HashSet<Definition *> visitedImplicitArguments;
 
   public:
     CompExprTransplanter(ParseNode *pn, Parser *parser, bool ge, unsigned adj)
-      : root(pn), parser(parser), genexp(ge), adjust(adj), funcLevel(0),
-        visitedImplicitArguments(parser->context)
-    {}
-
-    bool init() {
-        return visitedImplicitArguments.init();
+      : root(pn), parser(parser), genexp(ge), adjust(adj), funcLevel(0)
+    {
     }
 
     bool transplant(ParseNode *pn);
 };
 
 /*
  * A helper for lazily checking for the presence of illegal |yield| or |arguments|
  * tokens inside of generator expressions. This must be done lazily since we don't
@@ -5187,31 +5175,16 @@ CompExprTransplanter::transplant(ParseNo
                     /*
                      * The variable first occurs free in the 'yield' expression;
                      * move the existing placeholder node (and all its uses)
                      * from the parent's lexdeps into the generator's lexdeps.
                      */
                     tc->parent->lexdeps->remove(atom);
                     if (!tc->lexdeps->put(atom, dn))
                         return false;
-                } else if (dn->isImplicitArguments()) {
-                    /*
-                     * Implicit 'arguments' Definition nodes (see
-                     * PND_IMPLICITARGUMENTS in Parser::functionBody) are only
-                     * reachable via the lexdefs of their uses. Unfortunately,
-                     * there may be multiple uses, so we need to maintain a set
-                     * to only bump the definition once.
-                     */
-                    if (genexp && !visitedImplicitArguments.has(dn)) {
-                        if (!BumpStaticLevel(dn, tc))
-                            return false;
-                        AdjustBlockId(dn, adjust, tc);
-                        if (!visitedImplicitArguments.put(dn))
-                            return false;
-                    }
                 }
             }
         }
 
         if (pn->pn_pos >= root->pn_pos)
             AdjustBlockId(pn, adjust, tc);
         break;
 
@@ -5284,19 +5257,16 @@ Parser::comprehensionTail(ParseNode *kid
         pn->pn_blockid = stmtInfo.blockid = blockid;
         JS_ASSERT(adjust < blockid);
         adjust = blockid - adjust;
     }
 
     pnp = &pn->pn_expr;
 
     CompExprTransplanter transplanter(kid, this, kind == PNK_SEMI, adjust);
-    if (!transplanter.init())
-        return NULL;
-
     transplanter.transplant(kid);
 
     JS_ASSERT(tc->blockChain && tc->blockChain == pn->pn_objbox->object);
     data.initLet(HoistVars, *tc->blockChain, JSMSG_ARRAY_INIT_TOO_BIG);
 
     do {
         /*
          * FOR node is binary, left is loop control and right is body.  Use
--- a/js/src/frontend/TreeContext-inl.h
+++ b/js/src/frontend/TreeContext-inl.h
@@ -140,16 +140,17 @@ frontend::PushStatement(ContextT *ct, ty
 }
 
 template <class ContextT>
 void
 frontend::FinishPushBlockScope(ContextT *ct, typename ContextT::StmtInfo *stmt,
                                StaticBlockObject &blockObj)
 {
     stmt->isBlockScope = true;
+    blockObj.setEnclosingBlock(ct->blockChain);
     stmt->downScope = ct->topScopeStmt;
     ct->topScopeStmt = stmt;
     ct->blockChain = &blockObj;
     stmt->blockObj = &blockObj;
 }
 
 template <class ContextT>
 void
deleted file mode 100644
--- a/js/src/jit-test/tests/basic/testImplicitArgumentsInGenExprs.js
+++ /dev/null
@@ -1,5 +0,0 @@
-assertEq(((function() arguments) for (x in [1])).next()(42)[0], 42);
-assertEq(((function() {return arguments}) for (x in [1])).next()(42)[0], 42);
-assertEq(((function() {return arguments[0] + arguments[1]}) for (x in [1])).next()(41,1), 42);
-assertEq(((function() {return arguments[0] + (function() { return arguments[0]})(arguments[1])}) for (x in [1])).next()(41,1), 42);
-assertEq(((function() { var arguments = 3; return arguments}) for (x in [1])).next()(42), 3);
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -309,42 +309,51 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_QNAMECONST:
             isJaegerCompileable = false;
             /* FALL THROUGH */
           case JSOP_NAME:
           case JSOP_CALLNAME:
           case JSOP_BINDNAME:
           case JSOP_SETNAME:
           case JSOP_DELNAME:
-          case JSOP_GETALIASEDVAR:
-          case JSOP_CALLALIASEDVAR:
-          case JSOP_SETALIASEDVAR:
             usesScopeChain_ = true;
             isInlineable = false;
             break;
 
+          case JSOP_GETALIASEDVAR:
+          case JSOP_CALLALIASEDVAR:
+          case JSOP_SETALIASEDVAR: {
+            JS_ASSERT(!isInlineable);
+            usesScopeChain_ = true;
+            break;
+          }
+
           case JSOP_DEFFUN:
           case JSOP_DEFVAR:
           case JSOP_DEFCONST:
           case JSOP_SETCONST:
+            extendsScope_ = true;
             isInlineable = canTrackVars = false;
             break;
 
           case JSOP_EVAL:
+            extendsScope_ = true;
             isInlineable = canTrackVars = false;
             break;
 
           case JSOP_ENTERWITH:
+            addsScopeObjects_ = true;
             isJaegerCompileable = isInlineable = canTrackVars = false;
             break;
 
           case JSOP_ENTERLET0:
           case JSOP_ENTERLET1:
           case JSOP_ENTERBLOCK:
           case JSOP_LEAVEBLOCK:
+            addsScopeObjects_ = true;
             isInlineable = false;
             break;
 
           case JSOP_THIS:
             usesThisValue_ = true;
             break;
 
           case JSOP_CALL:
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -354,16 +354,26 @@ static inline uint32_t GetBytecodeSlot(J
       case JSOP_CALLLOCAL:
       case JSOP_SETLOCAL:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC:
         return LocalSlot(script, GET_SLOTNO(pc));
 
+      case JSOP_GETALIASEDVAR:
+      case JSOP_CALLALIASEDVAR:
+      case JSOP_SETALIASEDVAR:
+      {
+        unsigned index;
+        return ScopeCoordinateToFrameIndex(script, pc, &index) == FrameIndex_Local
+               ? LocalSlot(script, index)
+               : ArgSlot(index);
+      }
+
       case JSOP_THIS:
         return ThisSlot();
 
       default:
         JS_NOT_REACHED("Bad slot opcode");
         return 0;
     }
 }
@@ -828,16 +838,18 @@ class ScriptAnalysis
 
     /* --------- Bytecode analysis --------- */
 
     bool usesReturnValue_:1;
     bool usesScopeChain_:1;
     bool usesThisValue_:1;
     bool hasFunctionCalls_:1;
     bool modifiesArguments_:1;
+    bool extendsScope_:1;
+    bool addsScopeObjects_:1;
     bool localsAliasStack_:1;
     bool isInlineable:1;
     bool isJaegerCompileable:1;
     bool canTrackVars:1;
 
     uint32_t numReturnSites_;
 
     /* --------- Lifetime analysis --------- */
@@ -884,16 +896,25 @@ class ScriptAnalysis
 
     /*
      * True if all named formal arguments are not modified. If the arguments
      * object cannot escape, the arguments are never modified within the script.
      */
     bool modifiesArguments() { return modifiesArguments_; }
 
     /*
+     * True if the script may extend declarations in its top level scope with
+     * dynamic fun/var declarations or through eval.
+     */
+    bool extendsScope() { return extendsScope_; }
+
+    /* True if the script may add block or with objects to its scope chain. */
+    bool addsScopeObjects() { return addsScopeObjects_; }
+
+    /*
      * True if there are any LOCAL opcodes aliasing values on the stack (above
      * script->nfixed).
      */
     bool localsAliasStack() { return localsAliasStack_; }
 
     /* Accessors for bytecode information. */
 
     Bytecode& getCode(uint32_t offset) {
@@ -1091,16 +1112,35 @@ class ScriptAnalysis
     bool trackSlot(uint32_t slot) { return !slotEscapes(slot) && canTrackVars && slot < 1000; }
 
     const LifetimeVariable & liveness(uint32_t slot) {
         JS_ASSERT(script->compartment()->activeAnalysis);
         JS_ASSERT(!slotEscapes(slot));
         return lifetimes[slot];
     }
 
+    /*
+     * If a NAME or similar opcode is definitely accessing a particular slot
+     * of a script this one is nested in, get that script/slot.
+     */
+    struct NameAccess {
+        JSScript *script;
+        types::TypeScriptNesting *nesting;
+        uint32_t slot;
+
+        /* Decompose the slot above. */
+        bool arg;
+        uint32_t index;
+
+        const Value **basePointer() const {
+            return arg ? &nesting->argArray : &nesting->varArray;
+        }
+    };
+    NameAccess resolveNameAccess(JSContext *cx, jsid id, bool addDependency = false);
+
     void printSSA(JSContext *cx);
     void printTypes(JSContext *cx);
 
     void clearAllocations();
 
   private:
     void setOOM(JSContext *cx) {
         if (!outOfMemory)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -871,19 +871,16 @@ JSRuntime::init(uint32_t maxbytes)
         return false;
 
     if (!stackSpace.init())
         return false;
 
     if (!scriptFilenameTable.init())
         return false;
 
-    if (!evalCache.init())
-        return false;
-
     debugScopes = this->new_<DebugScopes>(this);
     if (!debugScopes || !debugScopes->init()) {
         Foreground::delete_(debugScopes);
         return false;
     }
 
     nativeStackBase = GetNativeStackBase();
     return true;
@@ -3364,21 +3361,25 @@ JS_NewObject(JSContext *cx, JSClass *jsc
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
+    if (proto && !proto->setNewTypeUnknown(cx))
+        return NULL;
+
     JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
     AssertRootingUnnecessary safe(cx);
     if (obj) {
         if (clasp->ext.equality)
             MarkTypeObjectFlags(cx, obj, OBJECT_FLAG_SPECIAL_EQUALITY);
+        MarkTypeObjectUnknownProperties(cx, obj->type());
     }
 
     JS_ASSERT_IF(obj, obj->getParent());
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
@@ -4657,25 +4658,18 @@ JS_CloneFunctionObject(JSContext *cx, JS
         JS_ASSERT(parent);
     }
 
     if (!funobj->isFunction()) {
         ReportIsNotFunction(cx, ObjectValue(*funobj));
         return NULL;
     }
 
-    /*
-     * If a function was compiled as compile-and-go or was compiled to be
-     * lexically nested inside some other script, we cannot clone it without
-     * breaking the compiler's assumptions.
-     */
     RootedFunction fun(cx, funobj->toFunction());
-    if (fun->isInterpreted() &&
-        (fun->script()->compileAndGo || fun->script()->enclosingStaticScope()))
-    {
+    if (fun->isInterpreted() && fun->script()->compileAndGo) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
         return NULL;
     }
 
     if (fun->isBoundFunction()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_CANT_CLONE_OBJECT);
@@ -4903,19 +4897,20 @@ CompileUCScriptForPrincipalsCommon(JSCon
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     AutoLastFrameCheck lfc(cx);
 
     bool compileAndGo = cx->hasRunOption(JSOPTION_COMPILE_N_GO);
     bool noScriptRval = cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL);
+    bool needScriptGlobal = true;
     return frontend::CompileScript(cx, obj, NULL, principals, originPrincipals,
-                                   compileAndGo, noScriptRval, chars, length,
-                                   filename, lineno, version);
+                                   compileAndGo, noScriptRval, needScriptGlobal,
+                                   chars, length, filename, lineno, version);
 }
 
 extern JS_PUBLIC_API(JSScript *)
 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
                                        JSPrincipals *principals,
                                        const jschar *chars, size_t length,
                                        const char *filename, unsigned lineno,
                                        JSVersion version)
@@ -5108,19 +5103,20 @@ CompileUTF8FileHelper(JSContext *cx, JSO
 
     JS_ASSERT(i <= len);
     len = i;
     size_t decodelen = len;
     jschar *decodebuf = (jschar *)cx->malloc_(decodelen * sizeof(jschar));
     if (JS_DecodeUTF8(cx, buf, len, decodebuf, &decodelen)) {
         bool compileAndGo = cx->hasRunOption(JSOPTION_COMPILE_N_GO);
         bool noScriptRval = cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL);
+        bool needScriptGlobal = true;
         script = frontend::CompileScript(cx, obj, NULL, principals, NULL,
-                                         compileAndGo, noScriptRval, decodebuf, decodelen,
-                                         filename, 1, cx->findVersion());
+                                         compileAndGo, noScriptRval, needScriptGlobal,
+                                         decodebuf, decodelen, filename, 1, cx->findVersion());
     } else {
         script = NULL;
     }
     cx->free_(buf);
     cx->free_(decodebuf);
     return script;
 }
 
@@ -5180,17 +5176,19 @@ JS_CompileUTF8FileHandle(JSContext *cx, 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     return JS_CompileUTF8FileHandleForPrincipals(cx, obj, filename, file, NULL);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalFromScript(JSScript *script)
 {
     JS_ASSERT(!script->isCachedEval);
-    return &script->global();
+    JS_ASSERT(script->globalObject);
+
+    return script->globalObject;
 }
 
 static JSFunction *
 CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj_,
                                      JSPrincipals *principals, const char *name,
                                      unsigned nargs, const char **argnames,
                                      const jschar *chars, size_t length,
                                      const char *filename, unsigned lineno, JSVersion version)
@@ -5375,17 +5373,17 @@ JS_ExecuteScript(JSContext *cx, JSObject
      * Mozilla caches pre-compiled scripts (e.g., in the XUL prototype cache)
      * and runs them against multiple globals. With a compartment per global,
      * this requires cloning the pre-compiled script into each new global.
      * Since each script gets run once, there is no point in trying to cache
      * this clone. Ideally, this would be handled at some pinch point in
      * mozilla, but there doesn't seem to be one, so we handle it here.
      */
     if (scriptArg->compartment() != obj->compartment()) {
-        script = CloneScript(cx, NullPtr(), NullPtr(), scriptArg);
+        script = CloneScript(cx, scriptArg);
         if (!script.get())
             return false;
     } else {
         script = scriptArg;
     }
 
     return Execute(cx, script.get(), *obj, rval);
 }
@@ -5406,22 +5404,23 @@ EvaluateUCScriptForPrincipalsCommon(JSCo
                                     jsval *rval, JSVersion compileVersion)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
 
     RootedObject obj(cx, obj_);
 
     bool compileAndGo = true;
     bool noScriptRval = !rval;
+    bool needScriptGlobal = true;
 
     CHECK_REQUEST(cx);
     AutoLastFrameCheck lfc(cx);
     JSScript *script = frontend::CompileScript(cx, obj, NULL, principals, originPrincipals,
-                                               compileAndGo, noScriptRval, chars, length,
-                                               filename, lineno, compileVersion);
+                                               compileAndGo, noScriptRval, needScriptGlobal,
+                                               chars, length, filename, lineno, compileVersion);
     if (!script)
         return false;
 
     JS_ASSERT(script->getVersion() == compileVersion);
 
     return Execute(cx, script, *obj, rval);
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3835,17 +3835,17 @@ struct JSClass {
 
     void                *reserved[40];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  /* objects have private slot */
 #define JSCLASS_NEW_ENUMERATE           (1<<1)  /* has JSNewEnumerateOp hook */
 #define JSCLASS_NEW_RESOLVE             (1<<2)  /* has JSNewResolveOp hook */
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  /* private is (nsISupports *) */
-#define JSCLASS_IS_DOMJSCLASS           (1<<4)  /* objects are DOM */
+/* (1<<4) is unused */
 #define JSCLASS_IMPLEMENTS_BARRIERS     (1<<5)  /* Correctly implements GC read
                                                    and write barriers */
 #define JSCLASS_DOCUMENT_OBSERVER       (1<<6)  /* DOM document observer */
 #define JSCLASS_USERBIT1                (1<<7)  /* Reserved for embeddings. */
 
 /*
  * To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
  * JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
@@ -4640,20 +4640,16 @@ extern JS_PUBLIC_API(JSFunction *)
 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
                     const jschar *name, size_t namelen, JSNative call,
                     unsigned nargs, unsigned attrs);
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
                       unsigned nargs, unsigned attrs);
 
-/*
- * Clone a top-level function into a new scope. This function will dynamically
- * fail if funobj was lexically nested inside some other function.
- */
 extern JS_PUBLIC_API(JSObject *)
 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
 
 /*
  * Methods usually act upon |this| objects only from a single global object and
  * compartment.  Sometimes, however, a method must act upon |this| values from
  * multiple global objects or compartments.  In such cases the |this| value a
  * method might see will be wrapped, such that various access to the object --
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -168,35 +168,28 @@ class ToSourceCache
     Map *map_;
   public:
     ToSourceCache() : map_(NULL) {}
     JSString *lookup(JSFunction *fun);
     void put(JSFunction *fun, JSString *);
     void purge();
 };
 
-struct EvalCacheLookup
+class EvalCache
 {
-    JSLinearString *str;
-    JSFunction *caller;
-    unsigned staticLevel;
-    JSVersion version;
-    JSCompartment *compartment;
-};
+    static const unsigned SHIFT = 6;
+    static const unsigned LENGTH = 1 << SHIFT;
+    JSScript *table_[LENGTH];
 
-struct EvalCacheHashPolicy
-{
-    typedef EvalCacheLookup Lookup;
-
-    static HashNumber hash(const Lookup &l);
-    static bool match(JSScript *script, const EvalCacheLookup &l);
+  public:
+    EvalCache() { PodArrayZero(table_); }
+    JSScript **bucket(JSLinearString *str);
+    void purge();
 };
 
-typedef HashSet<JSScript *, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
-
 class NativeIterCache
 {
     static const size_t SIZE = size_t(1) << 8;
 
     /* Cached native iterators. */
     JSObject            *data[SIZE];
 
     static size_t getIndex(uint32_t key) {
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -288,18 +288,21 @@ class CompartmentChecker
             for (int i = 0; i < ida->length; i++) {
                 if (JSID_IS_OBJECT(ida->vector[i]))
                     check(ida->vector[i]);
             }
         }
     }
 
     void check(JSScript *script) {
-        if (script)
+        if (script) {
             check(script->compartment());
+            if (!script->isCachedEval && script->globalObject)
+                check(script->globalObject);
+        }
     }
 
     void check(StackFrame *fp) {
         if (fp)
             check(fp->scopeChain());
     }
 };
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -530,16 +530,17 @@ JSCompartment::sweep(FreeOp *fop, bool r
             for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
                 JSScript *script = i.get<JSScript>();
                 if (script->types) {
                     types::TypeScript::Sweep(fop, script);
 
                     if (releaseTypes) {
                         script->types->destroy();
                         script->types = NULL;
+                        script->typesPurged = true;
                     }
                 }
             }
         }
 
         {
             gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES);
             types.sweep(fop);
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -123,17 +123,17 @@ struct JSCompartment
     // Nb: global_ might be NULL, if (a) it's the atoms compartment, or (b) the
     // compartment's global has been collected.  The latter can happen if e.g.
     // a string in a compartment is rooted but no object is, and thus the
     // global isn't rooted, and thus the global can be finalized while the
     // compartment lives on.
     //
     // In contrast, JSObject::global() is infallible because marking a JSObject
     // always marks its global as well.
-    // TODO: add infallible JSScript::global()
+    // TODO: add infallible JSScript::global() and JSContext::global()
     //
     js::GlobalObject *maybeGlobal() const {
         JS_ASSERT_IF(global_, global_->compartment() == this);
         return global_;
     }
 
     void initGlobal(js::GlobalObject &global) {
         JS_ASSERT(global.compartment() == this);
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -180,17 +180,17 @@ JS_SetSingleStepMode(JSContext *cx, JSSc
 JS_PUBLIC_API(JSBool)
 JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handler, jsval closure)
 {
     assertSameCompartment(cx, script, closure);
 
     if (!CheckDebugMode(cx))
         return false;
 
-    BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc);
+    BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, NULL);
     if (!site)
         return false;
     site->setTrap(cx->runtime->defaultFreeOp(), handler, closure);
     return true;
 }
 
 JS_PUBLIC_API(void)
 JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -331,18 +331,17 @@ fun_resolve(JSContext *cx, HandleObject 
         }
     }
 
     return true;
 }
 
 template<XDRMode mode>
 bool
-js::XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
-                           JSObject **objp)
+js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript)
 {
     /* NB: Keep this in sync with CloneInterpretedFunction. */
     JSAtom *atom;
     uint32_t firstword;           /* flag telling whether fun->atom is non-null,
                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
                                    and 14 bits reserved for future use */
     uint32_t flagsword;           /* word for argument count and fun->flags */
 
@@ -378,17 +377,17 @@ js::XDRInterpretedFunction(XDRState<mode
 
     if (!xdr->codeUint32(&firstword))
         return false;
     if ((firstword & 1U) && !XDRAtom(xdr, &atom))
         return false;
     if (!xdr->codeUint32(&flagsword))
         return false;
 
-    if (!XDRScript(xdr, enclosingScope, enclosingScript, fun, &script))
+    if (!XDRScript(xdr, &script, parentScript))
         return false;
 
     if (mode == XDR_DECODE) {
         fun->nargs = flagsword >> 16;
         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         fun->flags = uint16_t(flagsword);
         fun->atom.init(atom);
         fun->initScript(script);
@@ -399,37 +398,37 @@ js::XDRInterpretedFunction(XDRState<mode
         js_CallNewScriptHook(cx, fun->script(), fun);
         *objp = fun;
     }
 
     return true;
 }
 
 template bool
-js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, JSObject **);
+js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *xdr, JSObject **objp, JSScript *parentScript);
 
 template bool
-js::XDRInterpretedFunction(XDRState<XDR_DECODE> *, HandleObject, HandleScript, JSObject **);
+js::XDRInterpretedFunction(XDRState<XDR_DECODE> *xdr, JSObject **objp, JSScript *parentScript);
 
 JSObject *
-js::CloneInterpretedFunction(JSContext *cx, HandleObject enclosingScope, HandleFunction srcFun)
+js::CloneInterpretedFunction(JSContext *cx, HandleFunction srcFun)
 {
     /* NB: Keep this in sync with XDRInterpretedFunction. */
 
     RootedObject parent(cx, NULL);
     RootedFunction clone(cx, js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL));
     if (!clone)
         return NULL;
     if (!JSObject::clearParent(cx, clone))
         return NULL;
     if (!JSObject::clearType(cx, clone))
         return NULL;
 
     Rooted<JSScript*> srcScript(cx, srcFun->script());
-    JSScript *clonedScript = CloneScript(cx, enclosingScope, clone, srcScript);
+    JSScript *clonedScript = CloneScript(cx, srcScript);
     if (!clonedScript)
         return NULL;
 
     clone->nargs = srcFun->nargs;
     clone->flags = srcFun->flags;
     clone->atom.init(srcFun->atom);
     clone->initScript(clonedScript);
     clonedScript->setFunction(clone);
@@ -1277,33 +1276,30 @@ js_CloneFunctionObject(JSContext *cx, Ha
          * will have been caught by CloneFunctionObject coming from function
          * definitions or read barriers, so will not get here.
          */
         if (fun->getProto() == proto && !fun->hasSingletonType())
             clone->setType(fun->type());
     } else {
         /*
          * Across compartments we have to clone the script for interpreted
-         * functions. Cross-compartment cloning only happens via JSAPI
-         * (JS_CloneFunctionObject) which dynamically ensures that 'script' has
-         * no enclosing lexical scope (only the global scope).
+         * functions.
          */
         if (clone->isInterpreted()) {
             RootedScript script(cx, clone->script());
             JS_ASSERT(script);
             JS_ASSERT(script->compartment() == fun->compartment());
             JS_ASSERT(script->compartment() != cx->compartment);
-            JS_ASSERT(!script->enclosingStaticScope());
 
             clone->mutableScript().init(NULL);
-
-            JSScript *cscript = CloneScript(cx, NullPtr(), clone, script);
+            JSScript *cscript = CloneScript(cx, script);
             if (!cscript)
                 return NULL;
 
+            cscript->globalObject = &clone->global();
             clone->setScript(cscript);
             cscript->setFunction(clone);
             if (!clone->setTypeForScriptedFunction(cx))
                 return NULL;
 
             js_CallNewScriptHook(cx, clone->script(), clone);
             Debugger::onNewScript(cx, clone->script(), NULL);
         }
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -67,17 +67,16 @@ struct JSFunction : public JSObject
     bool hasRest()           const { return flags & JSFUN_HAS_REST; }
     bool isInterpreted()     const { return kind() >= JSFUN_INTERPRETED; }
     bool isNative()          const { return !isInterpreted(); }
     bool isNativeConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
     bool isHeavyweight()     const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
     bool isNullClosure()     const { return kind() == JSFUN_NULL_CLOSURE; }
     bool isFunctionPrototype() const { return flags & JSFUN_PROTOTYPE; }
     bool isInterpretedConstructor() const { return isInterpreted() && !isFunctionPrototype(); }
-    bool isNamedLambda()     const { return (flags & JSFUN_LAMBDA) && atom; }
 
     uint16_t kind()          const { return flags & JSFUN_KINDMASK; }
     void setKind(uint16_t k) {
         JS_ASSERT(!(k & ~JSFUN_KINDMASK));
         flags = (flags & ~JSFUN_KINDMASK) | k;
     }
 
     /* Returns the strictness of this function, which must be interpreted. */
@@ -249,25 +248,27 @@ JSFunction::toExtended()
 
 inline const js::FunctionExtended *
 JSFunction::toExtended() const
 {
     JS_ASSERT(isExtended());
     return static_cast<const js::FunctionExtended *>(this);
 }
 
+inline bool
+js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
+
 namespace js {
 
 template<XDRMode mode>
 bool
-XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope,
-                       HandleScript enclosingScript, JSObject **objp);
+XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
 
 extern JSObject *
-CloneInterpretedFunction(JSContext *cx, HandleObject enclosingScope, HandleFunction fun);
+CloneInterpretedFunction(JSContext *cx, HandleFunction fun);
 
 } /* namespace js */
 
 extern JSBool
 js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern JSBool
 js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3051,17 +3051,17 @@ PurgeRuntime(JSTracer *trc)
 
     rt->tempLifoAlloc.freeUnused();
 
     rt->gsnCache.purge();
     rt->propertyCache.purge(rt);
     rt->newObjectCache.purge();
     rt->nativeIterCache.purge();
     rt->toSourceCache.purge();
-    rt->evalCache.clear();
+    rt->evalCache.purge();
 
     for (ContextIter acx(rt); !acx.done(); acx.next())
         acx->purge();
 }
 
 static bool
 ShouldPreserveJITCode(JSCompartment *c, int64_t currentTime)
 {
@@ -4322,28 +4322,16 @@ JS::CheckStackRoots(JSContext *cx)
     // should be modified to properly root any gcthings, and very possibly any
     // code calling that function should also be modified if it was improperly
     // assuming that GC could not happen at all within the called function.
     // (The latter may not apply if the AssertRootingUnnecessary only protected
     // a portion of a function, so the callers were already assuming that GC
     // could happen.)
     JS_ASSERT(!cx->rootingUnnecessary);
 
-    // GCs can't happen when analysis/inference/compilation are active.
-    if (cx->compartment->activeAnalysis)
-        return;
-
-    // Can switch to the atoms compartment during analysis.
-    if (IsAtomsCompartment(cx->compartment)) {
-        for (CompartmentsIter c(rt); !c.done(); c.next()) {
-            if (c.get()->activeAnalysis)
-                return;
-        }
-    }
-
     AutoCopyFreeListToArenas copy(rt);
 
     JSTracer checker;
     JS_TracerInit(&checker, rt, EmptyMarkCallback);
 
     ConservativeGCData *cgcd = &rt->conservativeGC;
     cgcd->recordStackTop();
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1825,36 +1825,28 @@ TypeCompartment::init(JSContext *cx)
         if (masm.supportsFloatingPoint())
 #endif
             inferenceEnabled = true;
     }
 }
 
 TypeObject *
 TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
-                               JSProtoKey key, JSObject *proto_, bool unknown,
-                               bool isDOM)
+                               JSProtoKey key, JSObject *proto_, bool unknown)
 {
     RootedObject proto(cx, proto_);
     TypeObject *object = gc::NewGCThing<TypeObject>(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject));
     if (!object)
         return NULL;
     new(object) TypeObject(proto, key == JSProto_Function, unknown);
 
-    if (!cx->typeInferenceEnabled()) {
+    if (!cx->typeInferenceEnabled())
         object->flags |= OBJECT_FLAG_UNKNOWN_MASK;
-    } else {
-        if (isDOM) {
-            object->setFlags(cx, OBJECT_FLAG_NON_DENSE_ARRAY
-                               | OBJECT_FLAG_NON_TYPED_ARRAY
-                               | OBJECT_FLAG_NON_PACKED_ARRAY);
-        } else {
-            object->setFlagsFromKey(cx, key);
-        }
-    }
+    else
+        object->setFlagsFromKey(cx, key);
 
     return object;
 }
 
 TypeObject *
 TypeCompartment::newAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key)
 {
     AutoEnterTypeInference enter(cx);
@@ -1866,17 +1858,17 @@ TypeCompartment::newAllocationSiteTypeOb
             return NULL;
         }
     }
 
     AllocationSiteTable::AddPtr p = allocationSiteTable->lookupForAdd(key);
     JS_ASSERT(!p);
 
     RootedObject proto(cx);
-    RootedObject global(cx, &key.script->global());
+    RootedObject global(cx, key.script->global());
     if (!js_GetClassPrototype(cx, global, key.kind, &proto, NULL))
         return NULL;
 
     RootedScript keyScript(cx, key.script);
     TypeObject *res = newTypeObject(cx, key.script, key.kind, proto);
     if (!res) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return NULL;
@@ -1958,29 +1950,29 @@ types::UseNewTypeForInitializer(JSContex
     if (!cx->typeInferenceEnabled() || script->function())
         return false;
 
     if (key != JSProto_Object && !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray))
         return false;
 
     AutoEnterTypeInference enter(cx);
 
-    if (!script->ensureRanAnalysis(cx))
+    if (!script->ensureRanAnalysis(cx, NULL))
         return false;
 
     return !script->analysis()->getCode(pc).inLoop;
 }
 
 bool
 types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
 {
     if (!cx->typeInferenceEnabled() || !script->hasGlobal())
         return true;
 
-    JSObject *proto = script->global().getOrCreateArrayPrototype(cx);
+    JSObject *proto = script->global()->getOrCreateArrayPrototype(cx);
     if (!proto)
         return true;
 
     do {
         TypeObject *type = proto->getType(cx);
         if (type->unknownProperties())
             return true;
         TypeSet *indexTypes = type->getProperty(cx, JSID_VOID, false);
@@ -2892,16 +2884,18 @@ TypeObject::setFlags(JSContext *cx, Type
         return;
 
     AutoEnterTypeInference enter(cx);
 
     if (singleton) {
         /* Make sure flags are consistent with persistent object state. */
         JS_ASSERT_IF(flags & OBJECT_FLAG_UNINLINEABLE,
                      interpretedFunction->script()->uninlineable);
+        JS_ASSERT_IF(flags & OBJECT_FLAG_REENTRANT_FUNCTION,
+                     interpretedFunction->script()->reentrantOuterFunction);
         JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
                      singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
     }
 
     this->flags |= flags;
 
     InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
 
@@ -3143,16 +3137,115 @@ GetInitializerType(JSContext *cx, JSScri
     JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
 
     if (UseNewTypeForInitializer(cx, script, pc, key))
         return NULL;
 
     return TypeScript::InitObject(cx, script, pc, key);
 }
 
+/*
+ * Detach nesting state for script from its parent, removing it entirely if it
+ * has no children of its own. This happens when walking type information while
+ * initially resolving NAME accesses, thus will not invalidate any compiler
+ * dependencies.
+ */
+static void
+DetachNestingParent(JSScript *script)
+{
+    TypeScriptNesting *nesting = script->nesting();
+
+    if (!nesting || !nesting->parent)
+        return;
+
+    /* Remove from parent's list of children. */
+    JSScript **pscript = &nesting->parent->nesting()->children;
+    while ((*pscript)->nesting() != nesting)
+        pscript = &(*pscript)->nesting()->next;
+    *pscript = nesting->next;
+
+    nesting->parent = NULL;
+
+    /* If this nesting can have no children of its own, destroy it. */
+    if (!script->isOuterFunction)
+        script->clearNesting();
+}
+
+ScriptAnalysis::NameAccess
+ScriptAnalysis::resolveNameAccess(JSContext *cx, jsid id, bool addDependency)
+{
+    JS_ASSERT(cx->typeInferenceEnabled());
+
+    NameAccess access;
+    PodZero(&access);
+
+    if (!JSID_IS_ATOM(id))
+        return access;
+    JSAtom *atom = JSID_TO_ATOM(id);
+
+    JSScript *script = this->script;
+    while (script->function() && script->nesting()) {
+        if (!script->ensureRanInference(cx))
+            return access;
+
+        /*
+         * Don't resolve names in scripts which use 'let' or 'with'. New names
+         * bound here can mask variables of the script itself.
+         *
+         * Also, don't resolve names in scripts which are generators. Frame
+         * balancing works differently for generators and we do not maintain
+         * active frame counts for such scripts.
+         */
+        if (script->analysis()->addsScopeObjects() || script->isGenerator)
+            return access;
+
+        /* Check if the script definitely binds the identifier. */
+        unsigned index;
+        BindingKind kind = script->bindings.lookup(cx, atom, &index);
+        if (kind == ARGUMENT || kind == VARIABLE) {
+            TypeObject *obj = script->function()->getType(cx);
+
+            if (addDependency) {
+                /*
+                 * Record the dependency which compiled code has on the outer
+                 * function being non-reentrant.
+                 */
+                if (TypeSet::HasObjectFlags(cx, obj, OBJECT_FLAG_REENTRANT_FUNCTION))
+                    return access;
+            }
+
+            if (!script->isOuterFunction)
+                return access;
+
+            access.script = script;
+            access.nesting = script->nesting();
+            access.slot = (kind == ARGUMENT) ? ArgSlot(index) : LocalSlot(script, index);
+            access.arg = (kind == ARGUMENT);
+            access.index = index;
+            return access;
+        } else if (kind != NONE) {
+            return access;
+        }
+
+        /*
+         * The script's bindings do not contain a name for the function itself,
+         * don't resolve name accesses on lambdas in DeclEnv objects on the
+         * scope chain.
+         */
+        if (atom == CallObjectLambdaName(*script->function()))
+            return access;
+
+        if (!script->nesting()->parent)
+            return access;
+        script = script->nesting()->parent;
+    }
+
+    return access;
+}
+
 /* Analyze type information for a single bytecode. */
 bool
 ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
                                      TypeInferenceState &state)
 {
     jsbytecode *pc = script->code + offset;
     JSOp op = (JSOp)*pc;
 
@@ -3368,61 +3461,91 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         if (id == NameToId(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]))
             seen->addType(cx, Type::UndefinedType());
         if (id == NameToId(cx->runtime->atomState.NaNAtom))
             seen->addType(cx, Type::DoubleType());
         if (id == NameToId(cx->runtime->atomState.InfinityAtom))
             seen->addType(cx, Type::DoubleType());
 
         /* Handle as a property access. */
-        PropertyAccess(cx, script, pc, script->global().getType(cx), false, seen, id);
+        PropertyAccess(cx, script, pc, script->global()->getType(cx), false, seen, id);
 
         if (op == JSOP_CALLGNAME)
             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
 
         if (CheckNextTest(pc))
             pushed[0].addType(cx, Type::UndefinedType());
         break;
       }
 
       case JSOP_NAME:
       case JSOP_CALLNAME: {
         TypeSet *seen = bytecodeTypes(pc);
-        addTypeBarrier(cx, pc, seen, Type::UnknownType());
         seen->addSubset(cx, &pushed[0]);
+
+        /*
+         * Try to resolve this name by walking the function's scope nesting.
+         * If we succeed but the accessed script has had its TypeScript purged
+         * in the past, we still must use a type barrier: the name access can
+         * be on a call object which predated the purge, and whose types might
+         * not be reflected in the reconstructed information.
+         */
+        jsid id = GetAtomId(cx, script, pc, 0);
+        NameAccess access = resolveNameAccess(cx, id);
+        if (access.script && !access.script->typesPurged) {
+            TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
+            types->addSubsetBarrier(cx, script, pc, seen);
+        } else {
+            addTypeBarrier(cx, pc, seen, Type::UnknownType());
+        }
+
         if (op == JSOP_CALLNAME)
             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
         break;
       }
 
       case JSOP_BINDGNAME:
       case JSOP_BINDNAME:
         break;
 
       case JSOP_SETGNAME: {
         jsid id = GetAtomId(cx, script, pc, 0);
-        PropertyAccess(cx, script, pc, script->global().getType(cx),
+        PropertyAccess(cx, script, pc, script->global()->getType(cx),
                        true, poppedTypes(pc, 0), id);
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
       }
 
-      case JSOP_SETNAME:
+      case JSOP_SETNAME: {
+        jsid id = GetAtomId(cx, script, pc, 0);
+        NameAccess access = resolveNameAccess(cx, id);
+        if (access.script) {
+            TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
+            poppedTypes(pc, 0)->addSubset(cx, types);
+        } else {
+            cx->compartment->types.monitorBytecode(cx, script, offset);
+        }
+        poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
+        break;
+      }
+
       case JSOP_SETCONST:
         cx->compartment->types.monitorBytecode(cx, script, offset);
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_GETXPROP: {
         TypeSet *seen = bytecodeTypes(pc);
         addTypeBarrier(cx, pc, seen, Type::UnknownType());
         seen->addSubset(cx, &pushed[0]);
         break;
       }
 
+      case JSOP_GETALIASEDVAR:
+      case JSOP_CALLALIASEDVAR:
       case JSOP_GETARG:
       case JSOP_CALLARG:
       case JSOP_GETLOCAL:
       case JSOP_CALLLOCAL: {
         uint32_t slot = GetBytecodeSlot(script, pc);
         if (trackSlot(slot)) {
             /*
              * Normally these opcodes don't pop anything, but they are given
@@ -3432,21 +3555,22 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
             poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         } else if (slot < TotalSlots(script)) {
             TypeSet *types = TypeScript::SlotTypes(script, slot);
             types->addSubset(cx, &pushed[0]);
         } else {
             /* Local 'let' variable. Punt on types for these, for now. */
             pushed[0].addType(cx, Type::UnknownType());
         }
-        if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL)
+        if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL || op == JSOP_CALLALIASEDVAR)
             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
         break;
       }
 
+      case JSOP_SETALIASEDVAR:
       case JSOP_SETARG:
       case JSOP_SETLOCAL: {
         uint32_t slot = GetBytecodeSlot(script, pc);
         if (!trackSlot(slot) && slot < TotalSlots(script)) {
             TypeSet *types = TypeScript::SlotTypes(script, slot);
             poppedTypes(pc, 0)->addSubset(cx, types);
         }
 
@@ -3454,34 +3578,16 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
          * For assignments to non-escaping locals/args, we don't need to update
          * the possible types of the var, as for each read of the var SSA gives
          * us the writes that could have produced that read.
          */
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
       }
 
-      case JSOP_GETALIASEDVAR:
-      case JSOP_CALLALIASEDVAR:
-        /*
-         * Every aliased variable will contain 'undefined' in addition to the
-         * type of whatever value is written to it. Thus, a dynamic barrier is
-         * necessary. Since we don't expect the to observe more than 1 type,
-         * there is little benefit to maintaining a TypeSet for the aliased
-         * variable. Instead, we monitor/barrier all reads unconditionally.
-         */
-        bytecodeTypes(pc)->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLALIASEDVAR)
-            pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
-        break;
-
-      case JSOP_SETALIASEDVAR:
-        poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
-        break;
-
       case JSOP_INCARG:
       case JSOP_DECARG:
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC: {
@@ -3861,17 +3967,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       case JSOP_CASE:
         poppedTypes(pc, 1)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_GENERATOR:
           if (script->function()) {
             if (script->hasGlobal()) {
-                JSObject *proto = script->global().getOrCreateGeneratorPrototype(cx);
+                JSObject *proto = script->global()->getOrCreateGeneratorPrototype(cx);
                 if (!proto)
                     return false;
                 TypeObject *object = proto->getNewType(cx);
                 if (!object)
                     return false;
                 TypeScript::ReturnTypes(script)->addType(cx, Type::ObjectType(object));
             } else {
                 TypeScript::ReturnTypes(script)->addType(cx, Type::UnknownType());
@@ -3964,16 +4070,55 @@ ScriptAnalysis::analyzeTypes(JSContext *
      * all types in the compartment.
      */
     ranInference_ = true;
 
     /* Make sure the initial type set of all local vars includes void. */
     for (unsigned i = 0; i < script->nfixed; i++)
         TypeScript::LocalTypes(script, i)->addType(cx, Type::UndefinedType());
 
+    TypeScriptNesting *nesting = script->function() ? script->nesting() : NULL;
+    if (nesting && nesting->parent) {
+        /*
+         * Check whether NAME accesses can be resolved in parent scopes, and
+         * detach from the parent if so. Even if outdated activations of this
+         * function are live when the parent is called again, we do not need to
+         * consider this reentrance as no state in the parent will be used.
+         */
+        if (!nesting->parent->ensureRanInference(cx))
+            return;
+
+        bool detached = false;
+
+        /* Don't track for leaf scripts which have no free variables. */
+        if (!usesScopeChain() && !script->isOuterFunction) {
+            DetachNestingParent(script);
+            detached = true;
+        }
+
+        /*
+         * If the names bound by the script are extensible (DEFFUN, EVAL, ...),
+         * don't resolve NAME accesses into the parent.
+         */
+        if (!detached && extendsScope()) {
+            DetachNestingParent(script);
+            detached = true;
+        }
+
+
+        if (!detached) {
+            /*
+             * Don't track for parents which add call objects or are generators,
+             * don't resolve NAME accesses into the parent.
+             */
+            if (nesting->parent->analysis()->addsScopeObjects() || nesting->parent->isGenerator)
+                DetachNestingParent(script);
+        }
+    }
+
     TypeInferenceState state(cx);
 
     unsigned offset = 0;
     while (offset < script->length) {
         Bytecode *code = maybeCode(offset);
 
         jsbytecode *pc = script->code + offset;
 
@@ -4127,17 +4272,19 @@ AnalyzeNewScriptProperties(JSContext *cx
         /*
          * Bail out on really long initializer lists (far longer than maximum
          * number of properties we can track), we may be recursing.
          */
         return false;
     }
 
     JSScript *script = fun->script();
-    if (!script->ensureRanAnalysis(cx) || !script->ensureRanInference(cx)) {
+    JS_ASSERT(!script->isInnerFunction);
+
+    if (!script->ensureRanAnalysis(cx, fun) || !script->ensureRanInference(cx)) {
         *pbaseobj = NULL;
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
 
     if (script->hasClearedGlobal())
         return false;
 
@@ -4363,16 +4510,17 @@ AnalyzePoppedThis(JSContext *cx, Vector<
             JSObject *funcallObj = funcallTypes->getSingleton(cx, false);
             JSObject *scriptObj = scriptTypes->getSingleton(cx, false);
             if (!funcallObj || !scriptObj || !scriptObj->isFunction() ||
                 !scriptObj->toFunction()->isInterpreted()) {
                 return false;
             }
 
             JSFunction *function = scriptObj->toFunction();
+            JS_ASSERT(!function->script()->isInnerFunction);
 
             /*
              * Generate constraints to clear definite properties from the type
              * should the Function.call or callee itself change in the future.
              */
             funcallTypes->add(cx,
                 cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
             scriptTypes->add(cx,
@@ -4413,17 +4561,17 @@ AnalyzePoppedThis(JSContext *cx, Vector<
 /*
  * Either make the newScript information for type when it is constructed
  * by the specified script, or regenerate the constraints for an existing
  * newScript on the type after they were cleared by a GC.
  */
 static void
 CheckNewScriptProperties(JSContext *cx, HandleTypeObject type, JSFunction *fun)
 {
-    if (type->unknownProperties())
+    if (type->unknownProperties() || fun->script()->isInnerFunction)
         return;
 
     /* Strawman object to add properties to and watch for duplicates. */
     RootedObject baseobj(cx, NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16));
     if (!baseobj) {
         if (type->newScript)
             type->clearNewScript(cx);
         return;
@@ -4455,18 +4603,18 @@ CheckNewScriptProperties(JSContext *cx, 
 
     TypeNewScript::Initializer done(TypeNewScript::Initializer::DONE, 0);
 
     /*
      * The base object may have been created with a different finalize kind
      * than we will use for subsequent new objects. Generate an object with the
      * appropriate final shape.
      */
-    RootedShape shape(cx, baseobj->lastProperty());
-    baseobj = NewReshapedObject(cx, type, baseobj->getParent(), kind, shape);
+    baseobj = NewReshapedObject(cx, type, baseobj->getParent(), kind,
+                                baseobj->lastProperty());
     if (!baseobj ||
         !type->addDefiniteProperties(cx, baseobj) ||
         !initializerList.append(done)) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
     size_t numBytes = sizeof(TypeNewScript)
@@ -4729,17 +4877,17 @@ IsAboutToBeFinalized(TypeObjectKey *key)
 void
 TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     AutoEnterTypeInference enter(cx);
 
     /* Directly update associated type sets for applicable bytecodes. */
     if (js_CodeSpec[*pc].format & JOF_TYPESET) {
-        if (!script->ensureRanAnalysis(cx)) {
+        if (!script->ensureRanAnalysis(cx, NULL)) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
         TypeSet *types = script->analysis()->bytecodeTypes(pc);
         if (!types->hasType(type)) {
             InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
                       script->id(), pc - script->code, TypeString(type));
             types->addType(cx, type);
@@ -4835,31 +4983,280 @@ void
 TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
 {
     /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
     if (!(js_CodeSpec[*pc].format & JOF_TYPESET))
         return;
 
     AutoEnterTypeInference enter(cx);
 
-    if (!script->ensureRanAnalysis(cx)) {
+    if (!script->ensureRanAnalysis(cx, NULL)) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
     Type type = GetValueType(cx, rval);
     TypeSet *types = script->analysis()->bytecodeTypes(pc);
     if (types->hasType(type))
         return;
 
     InferSpew(ISpewOps, "bytecodeType: #%u:%05u: %s",
               script->id(), pc - script->code, TypeString(type));
     types->addType(cx, type);
 }
 
+bool
+TypeScript::SetScope(JSContext *cx, JSScript *script_, JSObject *scope_)
+{
+    Rooted<JSScript*> script(cx, script_);
+    RootedObject scope(cx, scope_);
+
+    JS_ASSERT(script->types && !script->types->hasScope());
+
+    JSFunction *fun = script->function();
+    bool nullClosure = fun && fun->isNullClosure();
+
+    JS_ASSERT_IF(!fun, !script->isOuterFunction && !script->isInnerFunction);
+    JS_ASSERT_IF(!scope, fun && !script->isInnerFunction);
+
+    /*
+     * The scope object must be the initial one for the script, before any call
+     * object has been created in the heavyweight case.
+     */
+    JS_ASSERT_IF(scope && scope->isCall() && !scope->asCall().isForEval(),
+                 &scope->asCall().callee() != fun);
+
+    if (!script->compileAndGo) {
+        script->types->global = NULL;
+        return true;
+    }
+
+    JS_ASSERT_IF(fun && scope, fun->global() == scope->global());
+    script->types->global = fun ? &fun->global() : &scope->global();
+
+    /*
+     * Update the parent in the script's bindings. The bindings are created
+     * with a NULL parent, and fixing the parent now avoids the need to reshape
+     * every time a call object is created from the bindings.
+     */
+    if (!script->bindings.setParent(cx, script->types->global))
+        return false;
+
+    if (!cx->typeInferenceEnabled())
+        return true;
+
+    if (!script->isInnerFunction || nullClosure) {
+        /*
+         * Outermost functions need nesting information if there are inner
+         * functions directly nested in them.
+         */
+        if (script->isOuterFunction) {
+            script->types->nesting = cx->new_<TypeScriptNesting>();
+            if (!script->types->nesting)
+                return false;
+        }
+        return true;
+    }
+
+    /*
+     * Walk the scope chain to the next call object, which will be the function
+     * the script is nested inside.
+     */
+    while (!scope->isCall())
+        scope = &scope->asScope().enclosingScope();
+
+    CallObject &call = scope->asCall();
+
+    /* The isInnerFunction test ensures there is no intervening strict eval call object. */
+    JS_ASSERT(!call.isForEval());
+
+    /* Don't track non-heavyweight parents, NAME ops won't reach into them. */
+    JSFunction *parentFun = &call.callee();
+    if (!parentFun || !parentFun->isHeavyweight())
+        return true;
+    JSScript *parent = parentFun->script();
+    JS_ASSERT(parent->isOuterFunction);
+
+    /*
+     * We only need the nesting in the child if it has NAME accesses going
+     * into the parent. We won't know for sure whether this is the case until
+     * analyzing the script's types, which we don't want to do yet. The nesting
+     * info we make here may get pruned if/when we eventually do such analysis.
+     */
+
+    /*
+     * Scopes are set when scripts first execute, and the parent script must
+     * have executed first. It is still possible for the parent script to not
+     * have a scope, however, as we occasionally purge all TypeScripts from the
+     * compartment and there may be inner function objects parented to an
+     * activation of the outer function sticking around. In such cases, treat
+     * the parent's call object as the most recent one, so that it is not
+     * marked as reentrant.
+     */
+    if (!parent->ensureHasTypes(cx))
+        return false;
+    if (!parent->types->hasScope()) {
+        if (!SetScope(cx, parent, &call.enclosingScope()))
+            return false;
+        parent->nesting()->activeCall = &call;
+        parent->nesting()->argArray = Valueify(call.argArray());
+        parent->nesting()->varArray = Valueify(call.varArray());
+    }
+
+    JS_ASSERT(!script->types->nesting);
+
+    /* Construct and link nesting information for the two functions. */
+
+    script->types->nesting = cx->new_<TypeScriptNesting>();
+    if (!script->types->nesting)
+        return false;
+
+    script->nesting()->parent = parent;
+    script->nesting()->next = parent->nesting()->children;
+    parent->nesting()->children = script;
+
+    return true;
+}
+
+TypeScriptNesting::~TypeScriptNesting()
+{
+    /*
+     * Unlink from any parent/child. Nesting info on a script does not keep
+     * either the parent or children live during GC.
+     */
+
+    if (parent) {
+        JSScript **pscript = &parent->nesting()->children;
+        while ((*pscript)->nesting() != this)
+            pscript = &(*pscript)->nesting()->next;
+        *pscript = next;
+    }
+
+    while (children) {
+        TypeScriptNesting *child = children->nesting();
+        children = child->next;
+        child->parent = NULL;
+        child->next = NULL;
+    }
+}
+
+bool
+ClearActiveNesting(JSScript *start)
+{
+    /*
+     * Clear active call information for script and any outer functions
+     * inner to it. Return false if an inner function has frames on the stack.
+     */
+
+    /* Traverse children, then parent, avoiding recursion. */
+    JSScript *script = start;
+    bool traverseChildren = true;
+    while (true) {
+        TypeScriptNesting *nesting = script->nesting();
+        if (nesting->children && traverseChildren) {
+            script = nesting->children;
+            continue;
+        }
+        if (nesting->activeFrames)
+            return false;
+        if (script->isOuterFunction) {
+            nesting->activeCall = NULL;
+            nesting->argArray = NULL;
+            nesting->varArray = NULL;
+        }
+        if (script == start)
+            break;
+        if (nesting->next) {
+            script = nesting->next;
+            traverseChildren = true;
+        } else {
+            script = nesting->parent;
+            traverseChildren = false;
+        }
+    }
+
+    return true;
+}
+
+/*
+ * For the specified scope and script with an outer function, check if the
+ * scope represents a reentrant activation on an inner function of the parent
+ * or any of its transitive parents.
+ */
+static void
+CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
+{
+  restart:
+    JSScript *parent = script->nesting()->parent;
+    JS_ASSERT(parent);
+
+    while (!scope->isCall() || scope->asCall().callee().script() != parent)
+        scope = &scope->asScope().enclosingScope();
+
+    if (scope != parent->nesting()->activeCall) {
+        parent->reentrantOuterFunction = true;
+        MarkTypeObjectFlags(cx, parent->function(), OBJECT_FLAG_REENTRANT_FUNCTION);
+
+        /*
+         * Continue checking parents to see if this is reentrant for them too.
+         * We don't need to check this in for non-reentrant calls on the outer
+         * function: when we entered any outer function to the immediate parent
+         * we cleared the active call for its transitive children, so a
+         * non-reentrant call on a child is also a non-reentrant call on the
+         * parent.
+         */
+        if (parent->nesting()->parent) {
+            scope = &scope->asScope().enclosingScope();
+            script = parent;
+            goto restart;
+        }
+    }
+}
+
+void
+NestingPrologue(JSContext *cx, StackFrame *fp)
+{
+    JSScript *script = fp->fun()->script();
+    TypeScriptNesting *nesting = script->nesting();
+
+    if (nesting->parent)
+        CheckNestingParent(cx, fp->scopeChain(), script);
+
+    if (script->isOuterFunction) {
+        /*
+         * Check the stack has no frames for this activation, any of its inner
+         * functions or any of their transitive inner functions.
+         *
+         * Also, if the script has an extensible scope, then the arg/var array
+         * can be moved unexpectedly, so abort the optimization.
+         */
+        if (!ClearActiveNesting(script) || script->funHasExtensibleScope) {
+            script->reentrantOuterFunction = true;
+            MarkTypeObjectFlags(cx, fp->fun(), OBJECT_FLAG_REENTRANT_FUNCTION);
+        }
+
+        nesting->activeCall = &fp->callObj();
+        nesting->argArray = Valueify(nesting->activeCall->argArray());
+        nesting->varArray = Valueify(nesting->activeCall->varArray());
+    }
+
+    /* Maintain stack frame count for the function. */
+    nesting->activeFrames++;
+}
+
+void
+NestingEpilogue(StackFrame *fp)
+{
+    JSScript *script = fp->fun()->script();
+    TypeScriptNesting *nesting = script->nesting();
+
+    JS_ASSERT(nesting->activeFrames != 0);
+    nesting->activeFrames--;
+}
+
 } } /* namespace js::types */
 
 /////////////////////////////////////////////////////////////////////
 // TypeScript
 /////////////////////////////////////////////////////////////////////
 
 /*
  * Returns true if we don't expect to compute the correct types for some value
@@ -5026,25 +5423,23 @@ JSFunction::setTypeForScriptedFunction(J
 
     if (!cx->typeInferenceEnabled())
         return true;
 
     if (singleton) {
         if (!setSingletonType(cx))
             return false;
     } else {
-        RootedFunction self(cx, this);
-
         TypeObject *type = cx->compartment->types.newTypeObject(cx, script(),
                                                                 JSProto_Function, getProto());
         if (!type)
             return false;
 
-        self->setType(type);
-        type->interpretedFunction = self;
+        setType(type);
+        type->interpretedFunction = this;
     }
 
     return true;
 }
 
 #ifdef DEBUG
 
 /* static */ void
@@ -5186,16 +5581,18 @@ JSObject::makeLazyType(JSContext *cx)
 
     type->singleton = self;
 
     if (self->isFunction() && self->toFunction()->isInterpreted()) {
         type->interpretedFunction = self->toFunction();
         JSScript *script = type->interpretedFunction->script();
         if (script->uninlineable)
             type->flags |= OBJECT_FLAG_UNINLINEABLE;
+        if (script->reentrantOuterFunction)
+            type->flags |= OBJECT_FLAG_REENTRANT_FUNCTION;
     }
 
     if (self->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
         type->flags |= OBJECT_FLAG_ITERATED;
 
 #if JS_HAS_XML_SUPPORT
     /*
      * XML objects do not have equality hooks but are treated special by EQ/NE
@@ -5208,20 +5605,20 @@ JSObject::makeLazyType(JSContext *cx)
     if (self->getClass()->ext.equality)
         type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
 
     /*
      * Adjust flags for objects which will have the wrong flags set by just
      * looking at the class prototype key.
      */
 
-    if (self->isSlowArray())
+    if (isSlowArray())
         type->flags |= OBJECT_FLAG_NON_DENSE_ARRAY | OBJECT_FLAG_NON_PACKED_ARRAY;
 
-    if (IsTypedArrayProto(self))
+    if (IsTypedArrayProto(this))
         type->flags |= OBJECT_FLAG_NON_TYPED_ARRAY;
 
     self->type_ = type;
 }
 
 /* static */ inline HashNumber
 TypeObjectEntry::hash(JSObject *proto)
 {
@@ -5264,17 +5661,17 @@ JSObject::setNewTypeUnknown(JSContext *c
         if (TypeObjectSet::Ptr p = table.lookup(this))
             MarkTypeObjectUnknownProperties(cx, *p);
     }
 
     return true;
 }
 
 TypeObject *
-JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
+JSObject::getNewType(JSContext *cx, JSFunction *fun)
 {
     TypeObjectSet &table = cx->compartment->newTypeObjects;
 
     if (!table.initialized() && !table.init())
         return NULL;
 
     TypeObjectSet::AddPtr p = table.lookupForAdd(this);
     if (p) {
@@ -5286,36 +5683,31 @@ JSObject::getNewType(JSContext *cx, JSFu
          * in existence which are not created by calling 'new' on newScript,
          * we must clear the new script information from the type and will not
          * be able to assume any definite properties for instances of the type.
          * This case is rare, but can happen if, for example, two scripted
          * functions have the same value for their 'prototype' property, or if
          * Object.create is called with a prototype object that is also the
          * 'prototype' property of some scripted function.
          */
-        if (type->newScript && type->newScript->fun != fun_)
+        if (type->newScript && type->newScript->fun != fun)
             type->clearNewScript(cx);
 
-        if (!isDOM && !type->hasAnyFlags(OBJECT_FLAG_NON_DOM))
-            type->setFlags(cx, OBJECT_FLAG_NON_DOM);
-
         return type;
     }
 
     RootedObject self(cx, this);
-    RootedFunction fun(cx, fun_);
 
     if (!setDelegate(cx))
         return NULL;
 
     bool markUnknown = self->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN);
 
     RootedTypeObject type(cx);
-    type = cx->compartment->types.newTypeObject(cx, NULL, JSProto_Object, self,
-                                                markUnknown, isDOM);
+    type = cx->compartment->types.newTypeObject(cx, NULL, JSProto_Object, self, markUnknown);
     if (!type)
         return NULL;
 
     if (!table.relookupOrAdd(p, self, type.get()))
         return NULL;
 
     if (!cx->typeInferenceEnabled())
         return type;
@@ -5691,27 +6083,39 @@ TypeScript::Sweep(FreeOp *fop, JSScript 
             IsAboutToBeFinalized(type.objectKey()))
         {
             *presult = result->next;
             fop->delete_(result);
         } else {
             presult = &result->next;
         }
     }
+
+    /*
+     * If the script has nesting state with a most recent activation, we do not
+     * need either to mark the call object or clear it if not live. Even with
+     * a dead pointer in the nesting, we can't get a spurious match while
+     * testing for reentrancy: if previous activations are still live, they
+     * cannot alias the most recent one, and future activations will overwrite
+     * activeCall on creation.
+     */
 }
 
 void
 TypeScript::destroy()
 {
     while (dynamicList) {
         TypeResult *next = dynamicList->next;
         Foreground::delete_(dynamicList);
         dynamicList = next;
     }
 
+    if (nesting)
+        Foreground::delete_(nesting);
+
     Foreground::free_(this);
 }
 
 inline size_t
 TypeSet::computedSizeOfExcludingThis()
 {
     /*
      * This memory is allocated within the temp pool (but accounted for
@@ -5757,16 +6161,18 @@ SizeOfScriptTypeInferenceData(JSScript *
         return;
 
     /* If TI is disabled, a single TypeScript is still present. */
     if (!script->compartment()->types.inferenceEnabled) {
         sizes->scripts += mallocSizeOf(typeScript);
         return;
     }
 
+    sizes->scripts += mallocSizeOf(typeScript->nesting);
+
     unsigned count = TypeScript::NumTypeSets(script);
     sizes->scripts += mallocSizeOf(typeScript);
 
     TypeResult *result = typeScript->dynamicList;
     while (result) {
         sizes->scripts += mallocSizeOf(result);
         result = result->next;
     }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -272,27 +272,27 @@ enum {
     OBJECT_FLAG_NON_DENSE_ARRAY       = 0x00010000,
 
     /* Whether any objects this represents are not packed arrays. */
     OBJECT_FLAG_NON_PACKED_ARRAY      = 0x00020000,
 
     /* Whether any objects this represents are not typed arrays. */
     OBJECT_FLAG_NON_TYPED_ARRAY       = 0x00040000,
 
-    /* Whether any objects this represents are not DOM objects */
-    OBJECT_FLAG_NON_DOM               = 0x00080000,
-
     /* Whether any represented script is considered uninlineable. */
-    OBJECT_FLAG_UNINLINEABLE          = 0x00100000,
+    OBJECT_FLAG_UNINLINEABLE          = 0x00080000,
 
     /* Whether any objects have an equality hook. */
-    OBJECT_FLAG_SPECIAL_EQUALITY      = 0x00200000,
+    OBJECT_FLAG_SPECIAL_EQUALITY      = 0x00100000,
 
     /* Whether any objects have been iterated over. */
-    OBJECT_FLAG_ITERATED              = 0x00400000,
+    OBJECT_FLAG_ITERATED              = 0x00200000,
+
+    /* Outer function which has been marked reentrant. */
+    OBJECT_FLAG_REENTRANT_FUNCTION    = 0x00400000,
 
     /* For a global object, whether flags were set on the RegExpStatics. */
     OBJECT_FLAG_REGEXP_FLAGS_SET      = 0x00800000,
 
     /* Flags which indicate dynamic properties of represented objects. */
     OBJECT_FLAG_DYNAMIC_MASK          = 0x00ff0000,
 
     /*
@@ -797,17 +797,17 @@ struct TypeObject : gc::Cell
 
     /* Set flags on this object which are implied by the specified key. */
     inline void setFlagsFromKey(JSContext *cx, JSProtoKey kind);
 
     /*
      * Get the global object which all objects of this type are parented to,
      * or NULL if there is none known.
      */
-    //inline JSObject *getGlobal();
+    inline JSObject *getGlobal();
 
     /* Helpers */
 
     bool addProperty(JSContext *cx, jsid id, Property **pprop);
     bool addDefiniteProperties(JSContext *cx, JSObject *obj);
     bool matchDefiniteProperties(JSObject *obj);
     void addPrototype(JSContext *cx, TypeObject *proto);
     void addPropertyType(JSContext *cx, jsid id, Type type);
@@ -902,28 +902,129 @@ struct TypeCallsite
 
     /* Type set receiving the return value of this call. */
     TypeSet *returnTypes;
 
     inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
                         bool isNew, unsigned argumentCount);
 };
 
+/*
+ * Information attached to outer and inner function scripts nested in one
+ * another for tracking the reentrance state for outer functions. This state is
+ * used to generate fast accesses to the args and vars of the outer function.
+ *
+ * A function is non-reentrant if, at any point in time, only the most recent
+ * activation (i.e. call object) is live. An activation is live if either the
+ * activation is on the stack, or a transitive inner function parented to the
+ * activation is on the stack.
+ *
+ * Because inner functions can be (and, quite often, are) stored in object
+ * properties and it is difficult to build a fast and robust escape analysis
+ * to cope with such flow, we detect reentrance dynamically. For the outer
+ * function, we keep track of the call object for the most recent activation,
+ * and the number of frames for the function and its inner functions which are
+ * on the stack.
+ *
+ * If the outer function is called while frames associated with a previous
+ * activation are on the stack, the outer function is reentrant. If an inner
+ * function is called whose scope does not match the most recent activation,
+ * the outer function is reentrant.
+ *
+ * The situation gets trickier when there are several levels of nesting.
+ *
+ * function foo() {
+ *   var a;
+ *   function bar() {
+ *     var b;
+ *     function baz() { return a + b; }
+ *   }
+ * }
+ *
+ * At calls to 'baz', we don't want to do the scope check for the activations
+ * of both 'foo' and 'bar', but rather 'bar' only. For this to work, a call to
+ * 'baz' which is a reentrant call on 'foo' must also be a reentrant call on
+ * 'bar'. When 'foo' is called, we clear the most recent call object for 'bar'.
+ */
+struct TypeScriptNesting
+{
+    /*
+     * If this is an inner function, the outer function. If non-NULL, this will
+     * be the immediate nested parent of the script (even if that parent has
+     * been marked reentrant). May be NULL even if the script has a nested
+     * parent, if NAME accesses cannot be tracked into the parent (either the
+     * script extends its scope with eval() etc., or the parent can make new
+     * scope chain objects with 'let' or 'with').
+     */
+    JSScript *parent;
+
+    /* If this is an outer function, list of inner functions. */
+    JSScript *children;
+
+    /* Link for children list of parent. */
+    JSScript *next;
+
+    /* If this is an outer function, the most recent activation. */
+    CallObject *activeCall;
+
+    /*
+     * If this is an outer function, pointers to the most recent activation's
+     * arguments and variables arrays. These could be referring either to stack
+     * values in activeCall's frame (if it has not finished yet) or to the
+     * internal slots of activeCall (if the frame has finished). Pointers to
+     * these fields can be embedded directly in JIT code (though remember to
+     * use 'addDependency == true' when calling resolveNameAccess).
+     */
+    const Value *argArray;
+    const Value *varArray;
+
+    /* Number of frames for this function on the stack. */
+    uint32_t activeFrames;
+
+    TypeScriptNesting() { PodZero(this); }
+    ~TypeScriptNesting();
+};
+
+/* Construct nesting information for script wrt its parent. */
+bool CheckScriptNesting(JSContext *cx, JSScript *script);
+
+/* Track nesting state when calling or finishing an outer/inner function. */
+void NestingPrologue(JSContext *cx, StackFrame *fp);
+void NestingEpilogue(StackFrame *fp);
+
 /* Persistent type information for a script, retained across GCs. */
 class TypeScript
 {
     friend struct ::JSScript;
 
     /* Analysis information for the script, cleared on each GC. */
     analyze::ScriptAnalysis *analysis;
 
+    /*
+     * Information about the scope in which a script executes. This information
+     * is not set until the script has executed at least once and SetScope
+     * called, before that 'global' will be poisoned per GLOBAL_MISSING_SCOPE.
+     */
+    static const size_t GLOBAL_MISSING_SCOPE = 0x1;
+
+    /* Global object for the script, if compileAndGo. */
+    HeapPtr<GlobalObject> global;
+
   public:
+
+    /* Nesting state for outer or inner function scripts. */
+    TypeScriptNesting *nesting;
+
     /* Dynamic types generated at points within this script. */
     TypeResult *dynamicList;
 
+    inline TypeScript();
+
+    bool hasScope() { return size_t(global.get()) != GLOBAL_MISSING_SCOPE; }
+
     /* Array of type type sets for variables and JOF_TYPESET ops. */
     TypeSet *typeArray() { return (TypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
 
     static inline unsigned NumTypeSets(JSScript *script);
 
     static bool SetScope(JSContext *cx, JSScript *script, JSObject *scope);
 
     static inline TypeSet *ReturnTypes(JSScript *script);
@@ -976,16 +1077,17 @@ class TypeScript
     static inline void SetThis(JSContext *cx, JSScript *script, Type type);
     static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
     static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type);
     static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value);
     static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
     static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
 
     static void Sweep(FreeOp *fop, JSScript *script);
+    inline void trace(JSTracer *trc);
     void destroy();
 };
 
 struct ArrayTableKey;
 typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
 
 struct ObjectTableKey;
 struct ObjectTableEntry;
@@ -1096,18 +1198,17 @@ struct TypeCompartment
 
     /*
      * Make a function or non-function object associated with an optional
      * script. The 'key' parameter here may be an array, typed array, function
      * or JSProto_Object to indicate a type whose class is unknown (not just
      * js_ObjectClass).
      */
     TypeObject *newTypeObject(JSContext *cx, JSScript *script,
-                              JSProtoKey kind, JSObject *proto,
-                              bool unknown = false, bool isDOM = false);
+                              JSProtoKey kind, JSObject *proto, bool unknown = false);
 
     /* Make an object for an allocation site. */
     TypeObject *newAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
 
     void nukeTypes(FreeOp *fop);
     void processPendingRecompiles(FreeOp *fop);
 
     /* Mark all types as needing destruction once inference has 'finished'. */
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -7,16 +7,17 @@
 /* Inline members for javascript type inference. */
 
 #include "jsarray.h"
 #include "jsanalyze.h"
 #include "jscompartment.h"
 #include "jsinfer.h"
 #include "jsprf.h"
 
+#include "gc/Marking.h"
 #include "gc/Root.h"
 #include "vm/GlobalObject.h"
 
 #include "vm/Stack-inl.h"
 
 #ifndef jsinferinlines_h___
 #define jsinferinlines_h___
 
@@ -306,17 +307,17 @@ TypeMonitorCall(JSContext *cx, const js:
     extern void TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
                                     const CallArgs &args, bool constructing);
 
     RootedObject callee(cx, &args.callee());
     if (callee->isFunction()) {
         JSFunction *fun = callee->toFunction();
         if (fun->isInterpreted()) {
             RootedScript script(cx, fun->script());
-            if (!script->ensureRanAnalysis(cx))
+            if (!script->ensureRanAnalysis(cx, fun->environment()))
                 return false;
             if (cx->typeInferenceEnabled())
                 TypeMonitorCallSlow(cx, callee, args, constructing);
         }
     }
 
     return true;
 }
@@ -443,16 +444,22 @@ UseNewTypeAtEntry(JSContext *cx, StackFr
            fp->prev() && fp->prev()->isScriptFrame() &&
            UseNewType(cx, fp->prev()->script(), fp->prevpc());
 }
 
 /////////////////////////////////////////////////////////////////////
 // Script interface functions
 /////////////////////////////////////////////////////////////////////
 
+inline
+TypeScript::TypeScript()
+{
+    this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
+}
+
 /* static */ inline unsigned
 TypeScript::NumTypeSets(JSScript *script)
 {
     return script->nTypeSets + analyze::TotalSlots(script);
 }
 
 /* static */ inline TypeSet *
 TypeScript::ReturnTypes(JSScript *script)
@@ -492,17 +499,17 @@ TypeScript::SlotTypes(JSScript *script, 
     JS_ASSERT(slot < js::analyze::TotalSlots(script));
     return script->types->typeArray() + script->nTypeSets + slot;
 }
 
 /* static */ inline TypeObject *
 TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
 {
     RootedObject proto(cx);
-    RootedObject global(cx, &script->global());
+    RootedObject global(cx, script->global());
     if (!js_GetClassPrototype(cx, global, key, &proto, NULL))
         return NULL;
     return proto->getNewType(cx);
 }
 
 struct AllocationSiteKey {
     JSScript *script;
 
@@ -682,17 +689,17 @@ TypeScript::SetThis(JSContext *cx, JSScr
 
     if (!ThisTypes(script)->hasType(type) || analyze) {
         AutoEnterTypeInference enter(cx);
 
         InferSpew(ISpewOps, "externalType: setThis #%u: %s",
                   script->id(), TypeString(type));
         ThisTypes(script)->addType(cx, type);
 
-        if (analyze)
+        if (analyze && script->types->hasScope())
             script->ensureRanInference(cx);
     }
 }
 
 /* static */ inline void
 TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
 {
     if (cx->typeInferenceEnabled())
@@ -744,16 +751,25 @@ TypeScript::SetArgument(JSContext *cx, J
 TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
 {
     if (cx->typeInferenceEnabled()) {
         Type type = GetValueType(cx, value);
         SetArgument(cx, script, arg, type);
     }
 }
 
+void
+TypeScript::trace(JSTracer *trc)
+{
+    if (hasScope() && global)
+        gc::MarkObject(trc, &global, "script_global");
+
+    /* Note: nesting does not keep anything alive. */
+}
+
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
 inline JSCompartment *
 TypeCompartment::compartment()
 {
     return (JSCompartment *)((char *)this - offsetof(JSCompartment, types));
@@ -1318,47 +1334,54 @@ TypeObject::getProperty(unsigned i)
 
 inline void
 TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
 {
     TypeObjectFlags flags = 0;
 
     switch (key) {
       case JSProto_Array:
-        flags = OBJECT_FLAG_NON_TYPED_ARRAY
-              | OBJECT_FLAG_NON_DOM;
+        flags = OBJECT_FLAG_NON_TYPED_ARRAY;
         break;
 
       case JSProto_Int8Array:
       case JSProto_Uint8Array:
       case JSProto_Int16Array:
       case JSProto_Uint16Array:
       case JSProto_Int32Array:
       case JSProto_Uint32Array:
       case JSProto_Float32Array:
       case JSProto_Float64Array:
       case JSProto_Uint8ClampedArray:
       case JSProto_DataView:
         flags = OBJECT_FLAG_NON_DENSE_ARRAY
-              | OBJECT_FLAG_NON_PACKED_ARRAY
-              | OBJECT_FLAG_NON_DOM;
+              | OBJECT_FLAG_NON_PACKED_ARRAY;
         break;
 
       default:
         flags = OBJECT_FLAG_NON_DENSE_ARRAY
               | OBJECT_FLAG_NON_PACKED_ARRAY
-              | OBJECT_FLAG_NON_TYPED_ARRAY
-              | OBJECT_FLAG_NON_DOM;
+              | OBJECT_FLAG_NON_TYPED_ARRAY;
         break;
     }
 
     if (!hasAllFlags(flags))
         setFlags(cx, flags);
 }
 
+inline JSObject *
+TypeObject::getGlobal()
+{
+    if (singleton)
+        return &singleton->global();
+    if (interpretedFunction && interpretedFunction->script()->compileAndGo)
+        return &interpretedFunction->global();
+    return NULL;
+}
+
 inline void
 TypeObject::writeBarrierPre(TypeObject *type)
 {
 #ifdef JSGC_INCREMENTAL
     if (!type)
         return;
 
     JSCompartment *comp = type->compartment();
@@ -1424,35 +1447,41 @@ Property::Property(const Property &o)
 
 inline bool
 JSScript::ensureHasTypes(JSContext *cx)
 {
     return types || makeTypes(cx);
 }
 
 inline bool
-JSScript::ensureRanAnalysis(JSContext *cx)
+JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
 {
     js::analyze::AutoEnterAnalysis aea(cx->compartment);
     JSScript *self = this;
     JS::SkipRoot root(cx, &self);
 
     if (!self->ensureHasTypes(cx))
         return false;
+    if (!self->types->hasScope()) {
+        js::RootedObject scopeRoot(cx, scope);
+        if (!js::types::TypeScript::SetScope(cx, self, scope))
+            return false;
+        scope = scopeRoot;
+    }
     if (!self->hasAnalysis() && !self->makeAnalysis(cx))
         return false;
     JS_ASSERT(self->analysis()->ranBytecode());
     return true;
 }
 
 inline bool
 JSScript::ensureRanInference(JSContext *cx)
 {
     JS::RootedScript self(cx, this);
-    if (!ensureRanAnalysis(cx))
+    if (!ensureRanAnalysis(cx, NULL))
         return false;
     if (!self->analysis()->ranInference()) {
         js::types::AutoEnterTypeInference enter(cx);
         self->analysis()->analyzeTypes(cx);
     }
     return !self->analysis()->OOM() &&
         !cx->compartment->types.pendingNukeTypes;
 }
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -474,17 +474,17 @@ js::ExecuteKernel(JSContext *cx, JSScrip
             result->setUndefined();
         return true;
     }
 
     ExecuteFrameGuard efg;
     if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
         return false;
 
-    if (!script->ensureRanAnalysis(cx))
+    if (!script->ensureRanAnalysis(cx, &scopeChain))
         return false;
     TypeScript::SetThis(cx, script, efg.fp()->thisValue());
 
     Probes::startExecution(cx, script);
     bool ok = RunScript(cx, script, efg.fp());
     Probes::stopExecution(cx, script);
 
     /* Propgate the return value out. */
@@ -834,17 +834,17 @@ TryNoteIter::settle()
 }
 
 /*
  * Increment/decrement the value 'v'. The resulting value is stored in *slot.
  * The result of the expression (taking into account prefix/postfix) is stored
  * in *expr.
  */
 static bool
-DoIncDec(JSContext *cx, HandleScript script, jsbytecode *pc, const Value &v, Value *slot, Value *expr)
+DoIncDec(JSContext *cx, JSScript *script, jsbytecode *pc, const Value &v, Value *slot, Value *expr)
 {
     const JSCodeSpec &cs = js_CodeSpec[*pc];
 
     if (v.isInt32()) {
         int32_t i = v.toInt32();
         if (i > JSVAL_INT_MIN && i < JSVAL_INT_MAX) {
             int32_t sum = i + (cs.format & JOF_INC ? 1 : -1);
             *slot = Int32Value(sum);
@@ -2760,17 +2760,16 @@ BEGIN_CASE(JSOP_REST)
 }
 END_CASE(JSOP_REST)
 
 BEGIN_CASE(JSOP_CALLALIASEDVAR)
 BEGIN_CASE(JSOP_GETALIASEDVAR)
 {
     ScopeCoordinate sc = ScopeCoordinate(regs.pc);
     PUSH_COPY(regs.fp()->aliasedVarScope(sc).aliasedVar(sc));
-    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 }
 END_CASE(JSOP_GETALIASEDVAR)
 
 BEGIN_CASE(JSOP_SETALIASEDVAR)
 {
     ScopeCoordinate sc = ScopeCoordinate(regs.pc);
     regs.fp()->aliasedVarScope(sc).setAliasedVar(sc, regs.sp[-1]);
 }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2178,34 +2178,34 @@ JSObject::sealOrFreeze(JSContext *cx, Im
             if (!self->setGenericAttributes(cx, id, &attrs))
                 return false;
         }
     }
 
     return true;
 }
 
-/* static */ bool
-JSObject::isSealedOrFrozen(JSContext *cx, HandleObject obj, ImmutabilityType it, bool *resultp)
-{
-    if (obj->isExtensible()) {
+bool
+JSObject::isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp)
+{
+    if (isExtensible()) {
         *resultp = false;
         return true;
     }
 
     AutoIdVector props(cx);
-    if (!GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props))
+    if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props))
         return false;
 
     RootedId id(cx);
     for (size_t i = 0, len = props.length(); i < len; i++) {
         id = props[i];
 
         unsigned attrs;
-        if (!obj->getGenericAttributes(cx, id, &attrs))
+        if (!getGenericAttributes(cx, id, &attrs))
             return false;
 
         /*
          * If the property is configurable, this object is neither sealed nor
          * frozen. If the property is a writable data property, this object is
          * not frozen.
          */
         if (!(attrs & JSPROP_PERMANENT) ||
@@ -2236,17 +2236,17 @@ obj_freeze(JSContext *cx, unsigned argc,
 static JSBool
 obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
         return false;
 
     bool frozen;
-    if (!JSObject::isFrozen(cx, obj, &frozen))
+    if (!obj->isFrozen(cx, &frozen))
         return false;
     vp->setBoolean(frozen);
     return true;
 }
 
 static JSBool
 obj_seal(JSContext *cx, unsigned argc, Value *vp)
 {
@@ -2262,17 +2262,17 @@ obj_seal(JSContext *cx, unsigned argc, V
 static JSBool
 obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
 {
     RootedObject obj(cx);
     if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isSealed", &obj))
         return false;
 
     bool sealed;
-    if (!JSObject::isSealed(cx, obj, &sealed))
+    if (!obj->isSealed(cx, &sealed))
         return false;
     vp->setBoolean(sealed);
     return true;
 }
 
 JSFunctionSpec object_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,             obj_toSource,                0,0),
@@ -2395,19 +2395,17 @@ js::NewObjectWithGivenProto(JSContext *c
     if (proto && (!parent || parent == proto->getParent()) && !proto->isGlobal()) {
         if (cache.lookupProto(clasp, proto, kind, &entry)) {
             JSObject *obj = cache.newObjectFromHit(cx, entry);
             if (obj)
                 return obj;
         }
     }
 
-    bool isDOM = (clasp->flags & JSCLASS_IS_DOMJSCLASS);
-    types::TypeObject *type = proto ? proto->getNewType(cx, NULL, isDOM)
-                                    : cx->compartment->getEmptyType(cx);
+    types::TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
     if (!type)
         return NULL;
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
     if (!parent && proto)
@@ -2506,17 +2504,17 @@ js::NewObjectWithType(JSContext *cx, Han
     if (entry != -1 && !obj->hasDynamicSlots())
         cache.fillType(entry, &ObjectClass, type, kind, obj);
 
     return obj;
 }
 
 JSObject *
 js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
-                      gc::AllocKind kind, HandleShape shape)
+                      gc::AllocKind kind, Shape *shape)
 {
     RootedObject res(cx, NewObjectWithType(cx, type, parent, kind));
     if (!res)
         return NULL;
 
     if (shape->isEmptyShape())
         return res;
 
@@ -2609,30 +2607,26 @@ js_CreateThisForFunction(JSContext *cx, 
     JSObject *proto;
     if (protov.isObject())
         proto = &protov.toObject();
     else
         proto = NULL;
     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
 
     if (obj && newType) {
-        RootedObject nobj(cx, obj);
-
         /*
          * Reshape the object and give it a (lazily instantiated) singleton
          * type before passing it as the 'this' value for the call.
          */
-        nobj->clear(cx);
-        if (!nobj->setSingletonType(cx))
+        obj->clear(cx);
+        if (!obj->setSingletonType(cx))
             return NULL;
 
         JSScript *calleeScript = callee->toFunction()->script();
-        TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
-
-        return nobj;
+        TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(obj));
     }
 
     return obj;
 }
 
 /*
  * Given pc pointing after a property accessing bytecode, return true if the
  * access is "object-detecting" in the sense used by web scripts, e.g., when
@@ -3528,22 +3522,20 @@ JSObject::growSlots(JSContext *cx, uint3
      * by calling 'new' on a particular script, bump the GC kind for that
      * type to give these objects a larger number of fixed slots when future
      * objects are constructed.
      */
     if (!hasLazyType() && !oldCount && type()->newScript) {
         gc::AllocKind kind = type()->newScript->allocKind;
         unsigned newScriptSlots = gc::GetGCKindSlots(kind);
         if (newScriptSlots == numFixedSlots() && gc::TryIncrementAllocKind(&kind)) {
-            AutoEnterTypeInference enter(cx);
-
             Rooted<TypeObject*> typeObj(cx, type());
-            RootedShape shape(cx, typeObj->newScript->shape);
             JSObject *obj = NewReshapedObject(cx, typeObj,
-                                              getParent(), kind, shape);
+                                              getParent(), kind,
+                                              typeObj->newScript->shape);
             if (!obj)
                 return false;
 
             typeObj->newScript->allocKind = kind;
             typeObj->newScript->shape = obj->lastProperty();
             typeObj->markStateChange(cx);
         }
     }
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -437,18 +437,17 @@ struct JSObject : public js::ObjectImpl
 
     const js::HeapPtr<js::types::TypeObject> &typeFromGC() const {
         /* Direct field access for use by GC. */
         return type_;
     }
 
     inline void setType(js::types::TypeObject *newType);
 
-    js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL,
-                                      bool isDOM = false);
+    js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL);
 
 #ifdef DEBUG
     bool hasNewType(js::types::TypeObject *newType);
 #endif
 
     /*
      * Mark an object that has been iterated over and is a singleton. We need
      * to recover this information in the object's type information after it
@@ -527,34 +526,30 @@ struct JSObject : public js::ObjectImpl
     /*
      * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the
      * object as non-extensible, and adjust each property's attributes appropriately: each
      * property becomes non-configurable, and if |freeze|, data properties become
      * read-only as well.
      */
     bool sealOrFreeze(JSContext *cx, ImmutabilityType it);
 
-    static bool isSealedOrFrozen(JSContext *cx, js::HandleObject obj, ImmutabilityType it, bool *resultp);
+    bool isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp);
 
     static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it);
 
   public:
     bool preventExtensions(JSContext *cx);
 
     /* ES5 15.2.3.8: non-extensible, all props non-configurable */
     inline bool seal(JSContext *cx) { return sealOrFreeze(cx, SEAL); }
     /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
     bool freeze(JSContext *cx) { return sealOrFreeze(cx, FREEZE); }
 
-    static inline bool isSealed(JSContext *cx, js::HandleObject obj, bool *resultp) {
-        return isSealedOrFrozen(cx, obj, SEAL, resultp);
-    }
-    static inline bool isFrozen(JSContext *cx, js::HandleObject obj, bool *resultp) {
-        return isSealedOrFrozen(cx, obj, FREEZE, resultp);
-    }
+    bool isSealed(JSContext *cx, bool *resultp) { return isSealedOrFrozen(cx, SEAL, resultp); }
+    bool isFrozen(JSContext *cx, bool *resultp) { return isSealedOrFrozen(cx, FREEZE, resultp); }
 
     /* Accessors for elements. */
 
     inline bool ensureElements(JSContext *cx, unsigned cap);
     bool growElements(JSContext *cx, unsigned cap);
     void shrinkElements(JSContext *cx, unsigned cap);
 
     inline js::ElementIteratorObject *asElementIterator();
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1547,17 +1547,17 @@ CopyInitializerObject(JSContext *cx, Han
     if (!obj->setLastProperty(cx, baseobj->lastProperty()))
         return NULL;
 
     return obj;
 }
 
 JSObject *
 NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
-                  gc::AllocKind kind, HandleShape shape);
+                  gc::AllocKind kind, Shape *shape);
 
 /*
  * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of
  * the object, zero if the final size is unknown. This should only be used for
  * objects that do not require any fixed slots.
  */
 static inline gc::AllocKind
 GuessObjectGCKind(size_t numSlots)
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -6374,17 +6374,17 @@ GetPCCountScriptContents(JSContext *cx, 
 
     StringBuffer buf(cx);
 
     if (!script->function() && !script->compileAndGo)
         return buf.finishString();
 
     {
         JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, &script->global()))
+        if (!ac.enter(cx, script->function() ? (JSObject *) script->function() : script->global()))
             return NULL;
 
         if (!GetPCCountJSON(cx, sac, buf))
             return NULL;
     }
 
     return buf.finishString();
 }
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -337,18 +337,18 @@ OPDEF(JSOP_FINALLY,     135,"finally",  
  * An ALIASEDVAR opcode contains the following immediates:
  *  uint16 hops:  the number of scope objects to skip to find the ScopeObject
  *                containing the variable being accessed
  *  uint16 slot:  the slot containing the variable in the ScopeObject (this
  *                'slot' does not include RESERVED_SLOTS).
  *  uint32 block: the index (into the script object table) of the block chain
  *                at the point of the variable access.
  */
-OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL,   9,  0,  1, 19,  JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
-OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL,  9,  0,  1, 19,  JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
+OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL,   9,  0,  1, 19,  JOF_SCOPECOORD|JOF_NAME)
+OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL,  9,  0,  1, 19,  JOF_SCOPECOORD|JOF_NAME)
 OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL,   9,  1,  1,  3,  JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING)
 OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 
 /* Unused. */
 OPDEF(JSOP_UNUSED8,       143,"unused8",  NULL,       1,  0,  0,  0,  JOF_BYTE)
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -362,17 +362,17 @@ IndirectProxyHandler::getPropertyDescrip
                                             jsid id, bool set,
                                             PropertyDescriptor *desc)
 {
     return JS_GetPropertyDescriptorById(cx, GetProxyTargetObject(proxy), id,
                                         JSRESOLVE_QUALIFIED, desc);
 }
 
 static bool
-GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, jsid id, unsigned flags,
+GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
                          JSPropertyDescriptor *desc)
 {
     // If obj is a proxy, we can do better than just guessing. This is
     // important for certain types of wrappers that wrap other wrappers.
     if (obj->isProxy())
         return Proxy::getOwnPropertyDescriptor(cx, obj, id,
                                                flags & JSRESOLVE_ASSIGNING,
                                                desc);
@@ -384,18 +384,17 @@ GetOwnPropertyDescriptor(JSContext *cx, 
     return true;
 }
 
 bool
 IndirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
                                                jsid id, bool set,
                                                PropertyDescriptor *desc)
 {
-    RootedObject target(cx, GetProxyTargetObject(proxy));
-    return GetOwnPropertyDescriptor(cx, target, id,
+    return GetOwnPropertyDescriptor(cx, GetProxyTargetObject(proxy), id,
                                     JSRESOLVE_QUALIFIED, desc);
 }
 
 bool
 IndirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
                                      PropertyDescriptor *desc)
 {
     RootedObject obj(cx, GetProxyTargetObject(proxy));
@@ -1763,20 +1762,16 @@ js::NewProxyObject(JSContext *cx, BasePr
         if (construct) {
             obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
         }
     }
 
     /* Don't track types of properties of proxies. */
     MarkTypeObjectUnknownProperties(cx, obj->type());
 
-    /* Mark the new proxy as having singleton type. */
-    if (clasp == &OuterWindowProxyClass && !obj->setSingletonType(cx))
-        return NULL;
-
     return obj;
 }
 
 static JSBool
 proxy_create(JSContext *cx, unsigned argc, Value *vp)
 {
     if (argc < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -273,22 +273,45 @@ ShapeTable::grow(JSContext *cx)
     return true;
 }
 
 Shape *
 Shape::getChildBinding(JSContext *cx, const StackShape &child)
 {
     JS_ASSERT(!inDictionary());
 
-    /* Try to allocate all slots inline. */
-    uint32_t slots = child.slotSpan();
-    gc::AllocKind kind = gc::GetGCObjectKind(slots);
-    uint32_t nfixed = gc::GetGCKindSlots(kind);
+    Shape *shape = cx->propertyTree().getChild(cx, this, numFixedSlots(), child);
+    if (shape) {
+        //JS_ASSERT(shape->parent == this); // XXX 'this' is not rooted here
+
+        /*
+         * Update the number of fixed slots which bindings of this shape will
+         * have. Bindings are constructed as new properties come in, so the
+         * call object allocation class is not known ahead of time. Compute
+         * the fixed slot count here, which will feed into call objects created
+         * off of the bindings.
+         */
+        uint32_t slots = child.slotSpan();
+        gc::AllocKind kind = gc::GetGCObjectKind(slots);
 
-    return cx->propertyTree().getChild(cx, this, nfixed, child);
+        /*
+         * Make sure that the arguments and variables in the call object all
+         * end up in a contiguous range of slots. We need this to be able to
+         * embed the args/vars arrays in the TypeScriptNesting for the function
+         * after the call object's frame has finished.
+         */
+        uint32_t nfixed = gc::GetGCKindSlots(kind);
+        if (nfixed < slots) {
+            nfixed = CallObject::RESERVED_SLOTS;
+            JS_ASSERT(gc::GetGCKindSlots(gc::GetGCObjectKind(nfixed)) == CallObject::RESERVED_SLOTS);
+        }
+
+        shape->setNumFixedSlots(nfixed);
+    }
+    return shape;
 }
 
 /* static */ Shape *
 Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base, JSObject *proto, Shape *shape_)
 {
     RootedShape shape(cx, shape_);
 
     JS_ASSERT(!shape->inDictionary());
@@ -1179,16 +1202,41 @@ Bindings::setExtensibleParents(JSContext
         return false;
     Shape *newShape = Shape::setExtensibleParents(cx, lastBinding);
     if (!newShape)
         return false;
     lastBinding = newShape;
     return true;
 }
 
+bool
+Bindings::setParent(JSContext *cx, JSObject *obj_)
+{
+    RootedObject obj(cx, obj_);
+
+    /*
+     * This may be invoked on GC heap allocated bindings, in which case this
+     * is pointing to an internal value of a JSScript that can't itself be
+     * relocated. The script itself will be rooted, and will not be moved, so
+     * mark the stack value as non-relocatable for the stack root analysis.
+     */
+    Bindings *self = this;
+    SkipRoot root(cx, &self);
+
+    if (!ensureShape(cx))
+        return false;
+
+    /* This is only used for Block objects, which have a NULL proto. */
+    Shape *newShape = Shape::setObjectParent(cx, obj, NULL, self->lastBinding);
+    if (!newShape)
+        return false;
+    self->lastBinding = newShape;
+    return true;
+}
+
 inline
 InitialShapeEntry::InitialShapeEntry() : shape(NULL), proto(NULL)
 {
 }
 
 inline
 InitialShapeEntry::InitialShapeEntry(const ReadBarriered<Shape> &shape, JSObject *proto)
   : shape(shape), proto(proto)
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -46,16 +46,18 @@
 #include "vm/RegExpObject-inl.h"
 
 #include "frontend/TreeContext-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
+namespace js {
+
 BindingKind
 Bindings::lookup(JSContext *cx, JSAtom *name, unsigned *indexp) const
 {
     if (!lastBinding)
         return NONE;
 
     Shape **spp;
     Shape *shape = Shape::search(cx, lastBinding, AtomToId(name), &spp);
@@ -117,17 +119,17 @@ Bindings::add(JSContext *cx, HandleAtom 
     RootedId id(cx);
     if (!name) {
         JS_ASSERT(kind == ARGUMENT); /* destructuring */
         id = INT_TO_JSID(nargs);
     } else {
         id = AtomToId(name);
     }
 
-    StackBaseShape base(&CallClass, cx->global(), BaseShape::VAROBJ);
+    StackBaseShape base(&CallClass, NULL, BaseShape::VAROBJ);
     base.updateGetterSetter(attrs, getter, setter);
 
     UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
     if (!nbase)
         return false;
 
     StackShape child(nbase, id, slot, 0, attrs, Shape::HAS_SHORTID, *indexp);
 
@@ -240,16 +242,18 @@ Bindings::lastVariable() const
 
 void
 Bindings::trace(JSTracer *trc)
 {
     if (lastBinding)
         MarkShape(trc, &lastBinding, "shape");
 }
 
+} /* namespace js */
+
 template<XDRMode mode>
 static bool
 XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
 {
     /*
      * A script constant can be an arbitrary primitive value as they are used
      * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
      * bug 407186.
@@ -333,35 +337,19 @@ XDRScriptConst(XDRState<mode> *xdr, Heap
       case SCRIPT_VOID:
         if (mode == XDR_DECODE)
             vp->init(UndefinedValue());
         break;
     }
     return true;
 }
 
-static inline uint32_t
-FindBlockIndex(JSScript *script, StaticBlockObject &block)
-{
-    ObjectArray *objects = script->objects();
-    HeapPtrObject *vector = objects->vector;
-    unsigned length = objects->length;
-    for (unsigned i = 0; i < length; ++i) {
-        if (vector[i] == &block)
-            return i;
-    }
-
-    JS_NOT_REACHED("Block not found");
-    return UINT32_MAX;
-}
-
 template<XDRMode mode>
 bool
-js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
-              HandleFunction fun, JSScript **scriptp)
+js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
 {
     /* NB: Keep this in sync with CloneScript. */
 
     enum ScriptBits {
         NoScriptRval,
         SavedCallerFun,
         StrictModeCode,
         ContainsDynamicNameAccess,
@@ -379,22 +367,26 @@ js::XDRScript(XDRState<mode> *xdr, Handl
     uint32_t nTypeSets = 0;
     uint32_t scriptBits = 0;
 
     JSContext *cx = xdr->cx();
     Rooted<JSScript*> script(cx);
     nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = nClosedArgs = nClosedVars = 0;
     jssrcnote *notes = NULL;
 
-    /* XDR arguments and vars. */
-    uint16_t nargs = 0, nvars = 0;
-    uint32_t argsVars = 0;
+    /* XDR arguments, var vars, and upvars. */
+    uint16_t nargs, nvars;
+#if defined(DEBUG) || defined(__GNUC__) /* quell GCC overwarning */
+    script = NULL;
+    nargs = nvars = Bindings::BINDING_COUNT_LIMIT;
+#endif
+    uint32_t argsVars;
     if (mode == XDR_ENCODE) {
         script = *scriptp;
-        JS_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment());
+        JS_ASSERT_IF(parentScript, parentScript->compartment() == script->compartment());
 
         nargs = script->bindings.numArgs();
         nvars = script->bindings.numVars();
         argsVars = (nargs << 16) | nvars;
     }
     if (!xdr->codeUint32(&argsVars))
         return false;
     if (mode == XDR_DECODE) {
@@ -518,17 +510,17 @@ js::XDRScript(XDRState<mode> *xdr, Handl
             scriptBits |= (1 << ContainsDynamicNameAccess);
         if (script->funHasExtensibleScope)
             scriptBits |= (1 << FunHasExtensibleScope);
         if (script->argumentsHasVarBinding())
             scriptBits |= (1 << ArgumentsHasVarBinding);
         if (script->analyzedArgsUsage() && script->needsArgsObj())
             scriptBits |= (1 << NeedsArgsObj);
         if (script->filename) {
-            scriptBits |= (enclosingScript && enclosingScript->filename == script->filename)
+            scriptBits |= (parentScript && parentScript->filename == script->filename)
                           ? (1 << ParentFilename)
                           : (1 << OwnFilename);
         }
         if (script->isGenerator)
             scriptBits |= (1 << IsGenerator);
 
         JS_ASSERT(!script->compileAndGo);
         JS_ASSERT(!script->hasSingletons);
@@ -567,22 +559,22 @@ js::XDRScript(XDRState<mode> *xdr, Handl
     if (mode == XDR_DECODE) {
         /* Note: version is packed into the 32b space with another 16b value. */
         JSVersion version_ = JSVersion(version & JS_BITMASK(16));
         JS_ASSERT((version_ & VersionFlags::FULL_MASK) == unsigned(version_));
 
         // principals and originPrincipals are set with xdr->initScriptPrincipals(script) below.
         // staticLevel is set below.
         script = JSScript::Create(cx,
-                                  enclosingScope,
                                   !!(scriptBits & (1 << SavedCallerFun)),
                                   /* principals = */ NULL,
                                   /* originPrincipals = */ NULL,
                                   /* compileAndGo = */ false,
                                   !!(scriptBits & (1 << NoScriptRval)),
+                                  /* globalObject = */ NULL,
                                   version_,
                                   /* staticLevel = */ 0);
         if (!script || !JSScript::partiallyInit(cx, script,
                                                 length, nsrcnotes, natoms, nobjects,
                                                 nregexps, ntrynotes, nconsts, nClosedArgs,
                                                 nClosedVars, nTypeSets))
             return JS_FALSE;
 
@@ -625,19 +617,19 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         if (!xdr->codeCString(&filename))
             return false;
         if (mode == XDR_DECODE) {
             script->filename = SaveScriptFilename(cx, filename);
             if (!script->filename)
                 return false;
         }
     } else if (scriptBits & (1 << ParentFilename)) {
-        JS_ASSERT(enclosingScript);
+        JS_ASSERT(parentScript);
         if (mode == XDR_DECODE)
-            script->filename = enclosingScript->filename;
+            script->filename = parentScript->filename;
     }
 
     if (mode == XDR_DECODE) {
         script->lineno = lineno;
         script->nslots = uint16_t(nslots);
         script->staticLevel = uint16_t(nslots >> 16);
         xdr->initScriptPrincipals(script);
     }
@@ -651,83 +643,40 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         } else {
             JSAtom *tmp = script->atoms[i];
             if (!XDRAtom(xdr, &tmp))
                 return false;
         }
     }
 
     /*
-     * Here looping from 0-to-length to xdr objects is essential to ensure that
-     * all references to enclosing blocks (via FindBlockIndex below) happen
-     * after the enclosing block has been XDR'd.
+     * Here looping from 0-to-length to xdr objects is essential. It ensures
+     * that block objects from the script->objects array will be written and
+     * restored in the outer-to-inner order. js_XDRBlockObject relies on this
+     * to restore the parent chain.
      */
     for (i = 0; i != nobjects; ++i) {
         HeapPtr<JSObject> *objp = &script->objects()->vector[i];
         uint32_t isBlock;
         if (mode == XDR_ENCODE) {
             JSObject *obj = *objp;
             JS_ASSERT(obj->isFunction() || obj->isStaticBlock());
             isBlock = obj->isBlock() ? 1 : 0;
         }
         if (!xdr->codeUint32(&isBlock))
             return false;
         if (isBlock == 0) {
-            /* Code the nested function's enclosing scope. */
-            uint32_t funEnclosingScopeIndex = 0;
-            if (mode == XDR_ENCODE) {
-                StaticScopeIter ssi((*objp)->toFunction()->script()->enclosingStaticScope());
-                if (ssi.done() || ssi.type() == StaticScopeIter::FUNCTION) {
-                    JS_ASSERT(ssi.done() == !fun);
-                    funEnclosingScopeIndex = UINT32_MAX;
-                } else {
-                    funEnclosingScopeIndex = FindBlockIndex(script, ssi.block());
-                    JS_ASSERT(funEnclosingScopeIndex < i);
-                }
-            }
-            if (!xdr->codeUint32(&funEnclosingScopeIndex))
-                return false;
-            Rooted<JSObject*> funEnclosingScope(cx);
-            if (mode == XDR_DECODE) {
-                if (funEnclosingScopeIndex == UINT32_MAX) {
-                    funEnclosingScope = fun;
-                } else {
-                    JS_ASSERT(funEnclosingScopeIndex < i);
-                    funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex];
-                }
-            }
-
             JSObject *tmp = *objp;
-            if (!XDRInterpretedFunction(xdr, funEnclosingScope, script, &tmp))
+            if (!XDRInterpretedFunction(xdr, &tmp, parentScript))
                 return false;
             *objp = tmp;
         } else {
-            /* Code the nested block's enclosing scope. */
             JS_ASSERT(isBlock == 1);
-            uint32_t blockEnclosingScopeIndex = 0;
-            if (mode == XDR_ENCODE) {
-                if (StaticBlockObject *block = (*objp)->asStaticBlock().enclosingBlock())
-                    blockEnclosingScopeIndex = FindBlockIndex(script, *block);
-                else
-                    blockEnclosingScopeIndex = UINT32_MAX;
-            }
-            if (!xdr->codeUint32(&blockEnclosingScopeIndex))
-                return false;
-            Rooted<JSObject*> blockEnclosingScope(cx);
-            if (mode == XDR_DECODE) {
-                if (blockEnclosingScopeIndex != UINT32_MAX) {
-                    JS_ASSERT(blockEnclosingScopeIndex < i);
-                    blockEnclosingScope = script->objects()->vector[blockEnclosingScopeIndex];
-                } else {
-                    blockEnclosingScope = fun;
-                }
-            }
-
             StaticBlockObject *tmp = static_cast<StaticBlockObject *>(objp->get());
-            if (!XDRStaticBlockObject(xdr, blockEnclosingScope, script, &tmp))
+            if (!XDRStaticBlockObject(xdr, script, &tmp))
                 return false;
             *objp = tmp;
         }
     }
     for (i = 0; i != nregexps; ++i) {
         if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
             return false;
     }
@@ -784,20 +733,20 @@ js::XDRScript(XDRState<mode> *xdr, Handl
             (void) script->initScriptCounts(cx);
         *scriptp = script;
     }
 
     return true;
 }
 
 template bool
-js::XDRScript(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, HandleFunction, JSScript **);
+js::XDRScript(XDRState<XDR_ENCODE> *xdr, JSScript **scriptp, JSScript *parentScript);
 
 template bool
-js::XDRScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript, HandleFunction, JSScript **);
+js::XDRScript(XDRState<XDR_DECODE> *xdr, JSScript **scriptp, JSScript *parentScript);
 
 bool
 JSScript::initScriptCounts(JSContext *cx)
 {
     JS_ASSERT(!hasScriptCounts);
 
     size_t n = 0;
 
@@ -1120,42 +1069,44 @@ ScriptDataSize(uint32_t length, uint32_t
         size += sizeof(ClosedSlotArray) + nClosedVars * sizeof(uint32_t);
 
     size += length * sizeof(jsbytecode);
     size += nsrcnotes * sizeof(jssrcnote);
     return size;
 }
 
 JSScript *
-JSScript::Create(JSContext *cx, HandleObject enclosingScope, bool savedCallerFun,
-                 JSPrincipals *principals, JSPrincipals *originPrincipals,
-                 bool compileAndGo, bool noScriptRval, JSVersion version, unsigned staticLevel)
+JSScript::Create(JSContext *cx, bool savedCallerFun, JSPrincipals *principals,
+                 JSPrincipals *originPrincipals, bool compileAndGo, bool noScriptRval,
+                 GlobalObject *globalObject_, JSVersion version, unsigned staticLevel)
 {
+    Rooted<GlobalObject*> globalObject(cx, globalObject_);
     JSScript *script = js_NewGCScript(cx);
     if (!script)
         return NULL;
 
     PodZero(script);
 
-    script->enclosingScope_ = enclosingScope;
     script->savedCallerFun = savedCallerFun;
 
     /* Establish invariant: principals implies originPrincipals. */
     if (principals) {
         script->principals = principals;
         script->originPrincipals = originPrincipals ? originPrincipals : principals;
         JS_HoldPrincipals(script->principals);
         JS_HoldPrincipals(script->originPrincipals);
     } else if (originPrincipals) {
         script->originPrincipals = originPrincipals;
         JS_HoldPrincipals(script->originPrincipals);
     }
 
     script->compileAndGo = compileAndGo;
     script->noScriptRval = noScriptRval;
+ 
+    script->globalObject = globalObject;
 
     script->version = version;
     JS_ASSERT(script->getVersion() == version);     // assert that no overflow occurred
 
     // This is an unsigned-to-uint16_t conversion, test for too-high values.
     // In practice, recursion in Parser and/or BytecodeEmitter will blow the
     // stack if we nest functions more than a few hundred deep, so this will
     // never trigger.  Oh well.
@@ -1362,17 +1313,17 @@ JSScript::fullyInitFromEmitter(JSContext
     if (cx->compartment->debugMode())
         script->debugMode = true;
 #endif
 
     if (bce->sc->inFunction()) {
         if (bce->sc->funArgumentsHasLocalBinding()) {
             // This must precede the script->bindings.transfer() call below
             script->setArgumentsHasVarBinding();
-            if (bce->sc->funDefinitelyNeedsArgsObj())
+            if (bce->sc->funDefinitelyNeedsArgsObj())        
                 script->setNeedsArgsObj(true);
         } else {
             JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj());
         }
     }
 
     if (nClosedArgs)
         PodCopy<uint32_t>(script->closedArgs()->vector, &bce->closedArgs[0], nClosedArgs);
@@ -1694,17 +1645,17 @@ template <class T>
 static inline T *
 Rebase(JSScript *dst, JSScript *src, T *srcp)
 {
     size_t off = reinterpret_cast<uint8_t *>(srcp) - src->data;
     return reinterpret_cast<T *>(dst->data + off);
 }
 
 JSScript *
-js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src)
+js::CloneScript(JSContext *cx, HandleScript src)
 {
     /* NB: Keep this in sync with XDRScript. */
 
     uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
     uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
     uint32_t nregexps  = src->hasRegexps()  ? src->regexps()->length  : 0;
     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
     uint32_t nClosedArgs = src->numClosedArgs();
@@ -1743,39 +1694,23 @@ js::CloneScript(JSContext *cx, HandleObj
         return NULL;
 
     /* Objects */
 
     AutoObjectVector objects(cx);
     if (nobjects != 0) {
         HeapPtrObject *vector = src->objects()->vector;
         for (unsigned i = 0; i < nobjects; i++) {
-            JSObject &obj = *vector[i];
             JSObject *clone;
-            if (obj.isStaticBlock()) {
-                Rooted<StaticBlockObject*> innerBlock(cx, &obj.asStaticBlock());
-
-                Rooted<JSObject*> enclosingScope(cx);
-                if (StaticBlockObject *enclosingBlock = innerBlock->enclosingBlock())
-                    enclosingScope = objects[FindBlockIndex(src, *enclosingBlock)];
-                else
-                    enclosingScope = fun;
-
-                clone = CloneStaticBlockObject(cx, enclosingScope, innerBlock);
+            if (vector[i]->isStaticBlock()) {
+                Rooted<StaticBlockObject*> block(cx, &vector[i]->asStaticBlock());
+                clone = CloneStaticBlockObject(cx, block, objects, src);
             } else {
-                Rooted<JSFunction*> innerFun(cx, obj.toFunction());
-
-                StaticScopeIter ssi(innerFun->script()->enclosingStaticScope());
-                Rooted<JSObject*> enclosingScope(cx);
-                if (!ssi.done() && ssi.type() == StaticScopeIter::BLOCK)
-                    enclosingScope = objects[FindBlockIndex(src, ssi.block())];
-                else
-                    enclosingScope = fun;
-
-                clone = CloneInterpretedFunction(cx, enclosingScope, innerFun);
+                RootedFunction fun(cx, vector[i]->toFunction());
+                clone = CloneInterpretedFunction(cx, fun);
             }
             if (!clone || !objects.append(clone))
                 return NULL;
         }
     }
 
     /* RegExps */
 
@@ -1786,20 +1721,21 @@ js::CloneScript(JSContext *cx, HandleObj
             JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->asRegExp());
             if (!clone || !regexps.append(clone))
                 return NULL;
         }
     }
 
     /* Now that all fallible allocation is complete, create the GC thing. */
 
-    JSScript *dst = JSScript::Create(cx, enclosingScope, src->savedCallerFun,
+    JSScript *dst = JSScript::Create(cx, src->savedCallerFun,
                                      cx->compartment->principals, src->originPrincipals,
                                      src->compileAndGo, src->noScriptRval,
-                                     src->getVersion(), src->staticLevel);
+                                     /* globalObject = */ NULL, src->getVersion(),
+                                     src->staticLevel);
     if (!dst) {
         Foreground::free_(data);
         return NULL;
     }
 
     new (&dst->bindings) Bindings;
     dst->bindings.transfer(&bindings);
 
@@ -2008,17 +1944,18 @@ JSScript::changeStepModeCount(JSContext 
     uint32_t count = debug->stepMode & stepCountMask;
     JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
     return tryNewStepMode(cx,
                           (debug->stepMode & stepFlagMask) |
                           ((count + delta) & stepCountMask));
 }
 
 BreakpointSite *
-JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc)
+JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
+                                    GlobalObject *scriptGlobal)
 {
     JS_ASSERT(size_t(pc - code) < length);
 
     if (!ensureHasDebugScript(cx))
         return NULL;
 
     DebugScript *debug = debugScript();
     BreakpointSite *&site = debug->breakpoints[pc - code];
@@ -2027,16 +1964,21 @@ JSScript::getOrCreateBreakpointSite(JSCo
         site = cx->runtime->new_<BreakpointSite>(this, pc);
         if (!site) {
             js_ReportOutOfMemory(cx);
             return NULL;
         }
         debug->numSites++;
     }
 
+    if (site->scriptGlobal)
+        JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
+    else
+        site->scriptGlobal = scriptGlobal;
+
     return site;
 }
 
 void
 JSScript::destroyBreakpointSite(FreeOp *fop, jsbytecode *pc)
 {
     JS_ASSERT(unsigned(pc - code) < length);
 
@@ -2113,24 +2055,27 @@ JSScript::markChildren(JSTracer *trc)
     if (hasConsts()) {
         ConstArray *constarray = consts();
         MarkValueRange(trc, constarray->length, constarray->vector, "consts");
     }
 
     if (function())
         MarkObject(trc, &function_, "function");
 
-    if (enclosingScope_)
-        MarkObject(trc, &enclosingScope_, "enclosing");
+    if (!isCachedEval && globalObject)
+        MarkObject(trc, &globalObject, "object");
 
     if (IS_GC_MARKING_TRACER(trc) && filename)
         MarkScriptFilename(trc->runtime, filename);
 
     bindings.trace(trc);
 
+    if (types)
+        types->trace(trc);
+
 #ifdef JS_METHODJIT
     for (int constructing = 0; constructing <= 1; constructing++) {
         for (int barriers = 0; barriers <= 1; barriers++) {
             mjit::JITScript *jit = getJIT((bool) constructing, (bool) barriers);
             if (jit)
                 jit->trace(trc);
         }
     }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -98,19 +98,16 @@ class Bindings
      * not be used again.
      */
     inline void transfer(Bindings *bindings);
 
     uint16_t numArgs() const { return nargs; }
     uint16_t numVars() const { return nvars; }
     unsigned count() const { return nargs + nvars; }
 
-    /* Convert a CallObject slot to either a formal or local variable index. */
-    inline BindingKind slotToFrameIndex(unsigned slot, unsigned *index);
-
     /*
      * The VM's StackFrame allocates a Value for each formal and variable.
      * A (formal|var)Index is the index passed to fp->unaliasedFormal/Var to
      * access this variable. These two functions convert between formal/var
      * indices and the corresponding slot in the CallObject.
      */
     inline uint16_t formalIndexToSlot(uint16_t i);
     inline uint16_t varIndexToSlot(uint16_t i);
@@ -126,16 +123,18 @@ class Bindings
      * The result is guaranteed not to have duplicate property names.
      */
     Shape *callObjectShape(JSContext *cx) const;
 
     /* See Scope::extensibleParents */
     inline bool extensibleParents();
     bool setExtensibleParents(JSContext *cx);
 
+    bool setParent(JSContext *cx, JSObject *obj);
+
     enum {
         /* A script may have no more than this many arguments or variables. */
         BINDING_COUNT_LIMIT = 0xFFFF
     };
 
     /*
      * Add a local binding for the given name, of the given type, for the code
      * being compiled.  If fun is non-null, this binding set is being created
@@ -405,25 +404,38 @@ struct JSScript : public js::gc::Cell
                                    comment above Create() for details) */
 
     const char      *filename;  /* source filename or null */
     js::HeapPtrAtom *atoms;     /* maps immediate index to literal struct */
 
     JSPrincipals    *principals;/* principals for this script */
     JSPrincipals    *originPrincipals; /* see jsapi.h 'originPrincipals' comment */
 
+    /*
+     * A global object for the script.
+     * - All scripts returned by JSAPI functions (JS_CompileScript,
+     *   JS_CompileUTF8File, etc.) have a non-null globalObject.
+     * - A function script has a globalObject if the function comes from a
+     *   compile-and-go script.
+     * - Temporary scripts created by obj_eval, JS_EvaluateScript, and
+     *   similar functions never have the globalObject field set; for such
+     *   scripts the global should be extracted from the JS frame that
+     *   execute scripts.
+     */
+    js::HeapPtr<js::GlobalObject, JSScript*> globalObject;
+
     /* Persistent type information retained across GCs. */
     js::types::TypeScript *types;
 
   private:
 #ifdef JS_METHODJIT
     JITScriptSet *jitInfo;
 #endif
+
     js::HeapPtrFunction function_;
-    js::HeapPtrObject   enclosingScope_;
 
     // 32-bit fields.
 
   public:
     uint32_t        length;     /* length of code vector */
 
     uint32_t        lineno;     /* base line number of script */
 
@@ -493,19 +505,24 @@ struct JSScript : public js::gc::Cell
     bool            funHasExtensibleScope:1;       /* see ContextFlags' field of the same name */
     bool            warnedAboutTwoArgumentEval:1; /* have warned about use of
                                                      obsolete eval(s, o) in
                                                      this script */
     bool            warnedAboutUndefinedProp:1; /* have warned about uses of
                                                    undefined properties in this
                                                    script */
     bool            hasSingletons:1;  /* script has singleton objects */
+    bool            isOuterFunction:1; /* function is heavyweight, with inner functions */
+    bool            isInnerFunction:1; /* function is directly nested in a heavyweight
+                                        * outer function */
     bool            isActiveEval:1;   /* script came from eval(), and is still active */
     bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
     bool            uninlineable:1;   /* script is considered uninlineable by analysis */
+    bool            reentrantOuterFunction:1; /* outer function marked reentrant */
+    bool            typesPurged:1;    /* TypeScript has been purged at some point */
 #ifdef JS_METHODJIT
     bool            debugMode:1;      /* script was compiled in debug mode */
     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
 #endif
     bool            callDestroyHook:1;/* need to call destroy hook */
     bool            isGenerator:1;    /* is a generator */
     bool            hasScriptCounts:1;/* script has an entry in
                                          JSCompartment::scriptCountsMap */
@@ -520,20 +537,21 @@ struct JSScript : public js::gc::Cell
     bool            needsArgsAnalysis_:1;
     bool            needsArgsObj_:1;
 
     //
     // End of fields.  Start methods.
     //
 
   public:
-    static JSScript *Create(JSContext *cx, js::HandleObject enclosingScope, bool savedCallerFun,
+    static JSScript *Create(JSContext *cx, bool savedCallerFun,
                             JSPrincipals *principals, JSPrincipals *originPrincipals,
                             bool compileAndGo, bool noScriptRval,
-                            JSVersion version, unsigned staticLevel);
+                            js::GlobalObject *globalObject, JSVersion version,
+                            unsigned staticLevel);
 
     // Three ways ways to initialize a JSScript.  Callers of partiallyInit()
     // and fullyInitTrivial() are responsible for notifying the debugger after
     // successfully creating any kind (function or other) of new JSScript.
     // However, callers of fullyInitFromEmitter() do not need to do this.
     static bool partiallyInit(JSContext *cx, JS::Handle<JSScript*> script,
                               uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
                               uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes, uint32_t nconsts,
@@ -571,55 +589,62 @@ struct JSScript : public js::gc::Cell
      * canonical location for the arguments. Note: if a formal is aliased
      * through the scope chain, then script->argLivesInCallObject and
      * JSOP_*ARG* opcodes won't be emitted at all.
      */
     bool argsObjAliasesFormals() const {
         return needsArgsObj() && !strictModeCode;
     }
 
+    /* Hash table chaining for JSCompartment::evalCache. */
+    JSScript *&evalHashLink() { return *globalObject.unsafeGetUnioned(); }
+
     /*
      * Original compiled function for the script, if it has a function.
      * NULL for global and eval scripts.
      */
     JSFunction *function() const { return function_; }
     void setFunction(JSFunction *fun);
 
-    /* Return whether this script was compiled for 'eval' */
-    bool isForEval() { return isCachedEval || isActiveEval; }
-
 #ifdef DEBUG
     unsigned id();
 #else
     unsigned id() { return 0; }
 #endif
 
     /* Ensure the script has a TypeScript. */
     inline bool ensureHasTypes(JSContext *cx);
 
     /*
-     * Ensure the script has bytecode analysis information. Performed when the
-     * script first runs, or first runs after a TypeScript GC purge.
+     * Ensure the script has scope and bytecode analysis information.
+     * Performed when the script first runs, or first runs after a TypeScript
+     * GC purge. If scope is NULL then the script must already have types with
+     * scope information.
      */
-    inline bool ensureRanAnalysis(JSContext *cx);
+    inline bool ensureRanAnalysis(JSContext *cx, JSObject *scope);
 
     /* Ensure the script has type inference analysis information. */
     inline bool ensureRanInference(JSContext *cx);
 
     inline bool hasAnalysis();
     inline void clearAnalysis();
     inline js::analyze::ScriptAnalysis *analysis();
 
     inline bool hasGlobal() const;
     inline bool hasClearedGlobal() const;
 
-    inline js::GlobalObject &global() const;
+    inline js::GlobalObject * global() const;
+    inline js::types::TypeScriptNesting *nesting() const;
+
+    inline void clearNesting();
 
-    /* See StaticScopeIter comment. */
-    JSObject *enclosingStaticScope() const { return enclosingScope_; }
+    /* Return creation time global or null. */
+    js::GlobalObject *getGlobalObjectOrNull() const {
+        return (isCachedEval || isActiveEval) ? NULL : globalObject.get();
+    }
 
   private:
     bool makeTypes(JSContext *cx);
     bool makeAnalysis(JSContext *cx);
 
 #ifdef JS_METHODJIT
   private:
     // CallCompiler must be a friend because it generates code that directly
@@ -845,17 +870,18 @@ struct JSScript : public js::gc::Cell
     bool hasAnyBreakpointsOrStepMode() { return hasDebugScript; }
 
     js::BreakpointSite *getBreakpointSite(jsbytecode *pc)
     {
         JS_ASSERT(size_t(pc - code) < length);
         return hasDebugScript ? debugScript()->breakpoints[pc - code] : NULL;
     }
 
-    js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc);
+    js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
+                                                  js::GlobalObject *scriptGlobal);
 
     void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc);
 
     void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
     void clearTraps(js::FreeOp *fop);
 
     void markTrapClosures(JSTracer *trc);
 
@@ -1004,23 +1030,22 @@ enum LineOption {
     CALLED_FROM_JSOP_EVAL,
     NOT_CALLED_FROM_JSOP_EVAL
 };
 
 inline void
 CurrentScriptFileLineOrigin(JSContext *cx, unsigned *linenop, LineOption = NOT_CALLED_FROM_JSOP_EVAL);
 
 extern JSScript *
-CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script);
+CloneScript(JSContext *cx, HandleScript script);
 
 /*
  * NB: after a successful XDR_DECODE, XDRScript callers must do any required
  * subsequent set-up of owning function or script object and then call
  * js_CallNewScriptHook.
  */
 template<XDRMode mode>
 bool
-XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
-          HandleFunction fun, JSScript **scriptp);
+XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript);
 
 } /* namespace js */
 
 #endif /* jsscript_h___ */
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -10,42 +10,29 @@
 
 #include "jsautooplen.h"
 #include "jscntxt.h"
 #include "jsfun.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jsscope.h"
 
+#include "vm/ScopeObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/RegExpObject.h"
 
 #include "jsscopeinlines.h"
 
 namespace js {
 
 inline
 Bindings::Bindings()
     : lastBinding(NULL), nargs(0), nvars(0), hasDup_(false)
 {}
 
-inline BindingKind
-Bindings::slotToFrameIndex(unsigned slot, unsigned *index)
-{
-    slot -= CallObject::RESERVED_SLOTS;
-    if (slot < numArgs()) {
-        *index = slot;
-        return ARGUMENT;
-    }
-
-    *index = slot - numArgs();
-    JS_ASSERT(*index < numVars());
-    return VARIABLE;
-}
-
 inline void
 Bindings::transfer(Bindings *bindings)
 {
     JS_ASSERT(!lastBinding);
     JS_ASSERT(!bindings->lastBinding || !bindings->lastBinding->inDictionary());
 
     *this = *bindings;
 #ifdef DEBUG
@@ -63,18 +50,18 @@ Bindings::lastShape() const
 
 Shape *
 Bindings::initialShape(JSContext *cx) const
 {
     /* Get an allocation kind to match an empty call object. */
     gc::AllocKind kind = gc::FINALIZE_OBJECT2_BACKGROUND;
     JS_ASSERT(gc::GetGCKindSlots(kind) == CallObject::RESERVED_SLOTS);
 
-    return EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(),
-                                       kind, BaseShape::VAROBJ);
+    return EmptyShape::getInitialShape(cx, &CallClass, NULL, NULL, kind,
+                                       BaseShape::VAROBJ);
 }
 
 bool
 Bindings::ensureShape(JSContext *cx)
 {
     if (!lastBinding) {
         lastBinding = initialShape(cx);
         if (!lastBinding)
@@ -199,34 +186,51 @@ JSScript::isEmpty() const
 inline bool
 JSScript::hasGlobal() const
 {
     /*
      * Make sure that we don't try to query information about global objects
      * which have had their scopes cleared. compileAndGo code should not run
      * anymore against such globals.
      */
-    return compileAndGo && !global().isCleared();
+    JS_ASSERT(types && types->hasScope());
+    js::GlobalObject *obj = types->global;
+    return obj && !obj->isCleared();
 }
 
-inline js::GlobalObject &
+inline js::GlobalObject *
 JSScript::global() const
 {
-    /*
-     * A JSScript always marks its compartment's global (via bindings) so we
-     * can assert that maybeGlobal is non-null here.
-     */
-    return *compartment()->maybeGlobal();
+    JS_ASSERT(hasGlobal());
+    return types->global;
 }
 
 inline bool
 JSScript::hasClearedGlobal() const
 {
-    JS_ASSERT(types);
-    return global().isCleared();
+    JS_ASSERT(types && types->hasScope());
+    js::GlobalObject *obj = types->global;
+    return obj && obj->isCleared();
+}
+
+inline js::types::TypeScriptNesting *
+JSScript::nesting() const
+{
+    JS_ASSERT(function() && types && types->hasScope());
+    return types->nesting;
+}
+
+inline void
+JSScript::clearNesting()
+{
+    js::types::TypeScriptNesting *nesting = this->nesting();
+    if (nesting) {
+        js::Foreground::delete_(nesting);
+        types->nesting = NULL;
+    }
 }
 
 #ifdef JS_METHODJIT
 inline bool
 JSScript::ensureHasJITInfo(JSContext *cx)
 {
     if (jitInfo)
         return true;
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -1712,17 +1712,17 @@ static JSObject *
 GetCurrentScopeChain(JSContext *cx)
 {
     if (cx->hasfp())
         return cx->fp()->scopeChain();
     return JS_ObjectToInnerObject(cx, cx->globalObject);
 }
 
 static JSXML *
-ParseXMLSource(JSContext *cx, HandleString src)
+ParseXMLSource(JSContext *cx, JSString *src)
 {
     jsval nsval;
     JSLinearString *uri;
     size_t urilen, srclen, length, offset, dstlen;
     jschar *chars;
     const jschar *srcp, *endp;
     JSXML *xml;
     const char *filename;
@@ -1851,17 +1851,17 @@ OrphanXMLChild(JSContext *cx, JSXML *xml
 }
 
 static JSObject *
 ToXML(JSContext *cx, jsval v)
 {
     JSObject *obj;
     JSXML *xml;
     Class *clasp;
-    RootedString str(cx);
+    JSString *str;
     uint32_t length;
 
     if (JSVAL_IS_PRIMITIVE(v)) {
         if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v))
             goto bad;
     } else {
         obj = JSVAL_TO_OBJECT(v);
         if (obj->isXML()) {
@@ -1932,17 +1932,17 @@ static JSBool
 Append(JSContext *cx, JSXML *list, JSXML *kid);
 
 static JSObject *
 ToXMLList(JSContext *cx, jsval v)
 {
     JSObject *obj, *listobj;
     JSXML *xml, *list, *kid;
     Class *clasp;
-    RootedString str(cx);
+    JSString *str;
     uint32_t i, length;
 
     if (JSVAL_IS_PRIMITIVE(v)) {
         if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v))
             goto bad;
     } else {
         obj = JSVAL_TO_OBJECT(v);
         if (obj->isXML()) {
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -1370,17 +1370,17 @@ static const JSC::MacroAssembler::Regist
             bumpCount(count, scratch);
         }
     }
 
     static const double oneDouble;
 };
 
 /* Return f<true> if the script is strict mode code, f<false> otherwise. */
-#define STRICT_VARIANT(script, f)                                             \
+#define STRICT_VARIANT(f)                                                     \
     (FunctionTemplateConditional(script->strictModeCode,                      \
                                  f<true>, f<false>))
 
 /* Save some typing. */
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Type = Assembler::JSReturnReg_Type;
 static const JSC::MacroAssembler::RegisterID JSReturnReg_Data = Assembler::JSReturnReg_Data;
 static const JSC::MacroAssembler::RegisterID JSParamReg_Argc  = Assembler::JSParamReg_Argc;
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -54,17 +54,17 @@ static const size_t USES_BEFORE_INLINING
 mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript,
                          unsigned chunkIndex, bool isConstructing)
   : BaseCompiler(cx),
     outerScript(cx, outerScript),
     chunkIndex(chunkIndex),
     isConstructing(isConstructing),
     outerChunk(outerJIT()->chunkDescriptor(chunkIndex)),
     ssa(cx, outerScript),
-    globalObj(cx, outerScript->hasGlobal() ? &outerScript->global() : NULL),
+    globalObj(cx, outerScript->hasGlobal() ? outerScript->global() : NULL),
     globalSlots(globalObj ? globalObj->getRawSlots() : NULL),
     frame(cx, *thisFromCtor(), masm, stubcc),
     a(NULL), outer(NULL), script(NULL), PC(NULL), loop(NULL),
     inlineFrames(CompilerAllocPolicy(cx, *thisFromCtor())),
     branchPatches(CompilerAllocPolicy(cx, *thisFromCtor())),
 #if defined JS_MONOIC
     getGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
     setGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
@@ -130,17 +130,17 @@ mjit::Compiler::compile()
 CompileStatus
 mjit::Compiler::checkAnalysis(HandleScript script)
 {
     if (script->hasClearedGlobal()) {
         JaegerSpew(JSpew_Abort, "script has a cleared global\n");
         return Compile_Abort;
     }
 
-    if (!script->ensureRanAnalysis(cx))
+    if (!script->ensureRanAnalysis(cx, NULL))
         return Compile_Error;
 
     if (!script->analysis()->jaegerCompileable()) {
         JaegerSpew(JSpew_Abort, "script has uncompileable opcodes\n");
         return Compile_Abort;
     }
 
     if (cx->typeInferenceEnabled() && !script->ensureRanInference(cx))
@@ -185,17 +185,17 @@ mjit::Compiler::scanInlineCalls(uint32_t
     if (isConstructing)
         return Compile_Okay;
 
     JSScript *script = ssa.getFrame(index).script;
     ScriptAnalysis *analysis = script->analysis();
 
     /* Don't inline from functions which could have a non-global scope object. */
     if (!script->hasGlobal() ||
-        &script->global() != globalObj ||
+        script->global() != globalObj ||
         (script->function() && script->function()->getParent() != globalObj) ||
         (script->function() && script->function()->isHeavyweight()) ||
         script->isActiveEval) {
         return Compile_Okay;
     }
 
     uint32_t nextOffset = 0;
     uint32_t lastOffset = script->length;
@@ -311,17 +311,17 @@ mjit::Compiler::scanInlineCalls(uint32_t
                 break;
 
             /* Watch for excessively deep nesting of inlined frames. */
             if (nextDepth + script->nslots >= stackLimit) {
                 okay = false;
                 break;
             }
 
-            if (!script->types) {
+            if (!script->types || !script->types->hasScope()) {
                 okay = false;
                 break;
             }
 
             CompileStatus status = checkAnalysis(script);
             if (status != Compile_Okay)
                 return status;
 
@@ -628,17 +628,17 @@ mjit::SetChunkLimit(uint32_t limit)
 {
     if (limit)
         CHUNK_LIMIT = limit;
 }
 
 JITScript *
 MakeJITScript(JSContext *cx, JSScript *script)
 {
-    if (!script->ensureRanAnalysis(cx))
+    if (!script->ensureRanAnalysis(cx, NULL))
         return NULL;
 
     ScriptAnalysis *analysis = script->analysis();
 
     Vector<ChunkDescriptor> chunks(cx);
     Vector<CrossChunkEdge> edges(cx);
 
     if (script->length < CHUNK_LIMIT || !cx->typeInferenceEnabled()) {
@@ -1092,17 +1092,19 @@ mjit::Compiler::generatePrologue()
         markUndefinedLocals();
 
         /*
          * Load the scope chain into the frame if it will be needed by NAME
          * opcodes or by the nesting prologue below. The scope chain is always
          * set for global and eval frames, and will have been set by
          * HeavyweightFunctionPrologue for heavyweight function frames.
          */
-        if (!script->function()->isHeavyweight() && analysis->usesScopeChain()) {
+        if (!script->function()->isHeavyweight() &&
+            (analysis->usesScopeChain() || script->nesting()))
+        {
             RegisterID t0 = Registers::ReturnReg;
             Jump hasScope = masm.branchTest32(Assembler::NonZero,
                                               FrameFlagsAddress(), Imm32(StackFrame::HAS_SCOPECHAIN));
             masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script->function())), t0);
             masm.loadPtr(Address(t0, JSFunction::offsetOfEnvironment()), t0);
             masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain()));
             hasScope.linkTo(masm.label(), &masm);
         }
@@ -1138,20 +1140,52 @@ mjit::Compiler::generatePrologue()
     /* Inline StackFrame::prologue. */
     if (script->isActiveEval && script->strictModeCode) {
         prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::StrictEvalPrologue, REJOIN_EVAL_PROLOGUE);
     } else if (script->function()) {
         if (script->function()->isHeavyweight()) {
             prepareStubCall(Uses(0));
             INLINE_STUBCALL(stubs::HeavyweightFunctionPrologue, REJOIN_FUNCTION_PROLOGUE);
+        } else if (types::TypeScriptNesting *nesting = script->nesting()) {
+            /*
+             * Inline the common case for the nesting prologue: the
+             * function is a non-heavyweight inner function with no
+             * children of its own. We ensure during inference that the
+             * outer function does not add scope objects for 'let' or
+             * 'with', so that the frame's scope chain will be
+             * the parent's call object, and if it differs from the
+             * parent's current activation then the parent is reentrant.
+             */
+            JSScript *parent = nesting->parent;
+            JS_ASSERT(parent);
+            JS_ASSERT_IF(parent->hasAnalysis() && parent->analysis()->ranBytecode(),
+                         !parent->analysis()->addsScopeObjects());
+
+            RegisterID t0 = Registers::ReturnReg;
+            masm.move(ImmPtr(&parent->nesting()->activeCall), t0);
+            masm.loadPtr(Address(t0), t0);
+
+            Address scopeChain(JSFrameReg, StackFrame::offsetOfScopeChain());
+            Jump mismatch = masm.branchPtr(Assembler::NotEqual, t0, scopeChain);
+            masm.add32(Imm32(1), AbsoluteAddress(&nesting->activeFrames));
+
+            masm.load32(FrameFlagsAddress(), t0);
+            masm.or32(Imm32(StackFrame::HAS_NESTING), t0);
+            masm.store32(t0, FrameFlagsAddress());
+
+            stubcc.linkExitDirect(mismatch, stubcc.masm.label());
+            OOL_STUBCALL(stubs::TypeNestingPrologue, REJOIN_FUNCTION_PROLOGUE);
+            stubcc.crossJump(stubcc.masm.jump(), masm.label());
         }
 
-        if (isConstructing && !constructThis())
-            return Compile_Error;
+        if (isConstructing) {
+            if (!constructThis())
+                return Compile_Error;
+        }
     }
 
     CompileStatus status = methodEntryHelper();
     if (status == Compile_Okay)
         recompileCheckHelper();
 
     return status;
 }
@@ -2518,26 +2552,26 @@ mjit::Compiler::generateMethod()
 
           BEGIN_CASE(JSOP_DELPROP)
           {
             uint32_t index = GET_UINT32_INDEX(PC);
             PropertyName *name = script->getName(index);
 
             prepareStubCall(Uses(1));
             masm.move(ImmPtr(name), Registers::ArgReg1);
-            INLINE_STUBCALL(STRICT_VARIANT(script, stubs::DelProp), REJOIN_FALLTHROUGH);
+            INLINE_STUBCALL(STRICT_VARIANT(stubs::DelProp), REJOIN_FALLTHROUGH);
             frame.pop();
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELPROP)
 
           BEGIN_CASE(JSOP_DELELEM)
           {
             prepareStubCall(Uses(2));
-            INLINE_STUBCALL(STRICT_VARIANT(script, stubs::DelElem), REJOIN_FALLTHROUGH);
+            INLINE_STUBCALL(STRICT_VARIANT(stubs::DelElem), REJOIN_FALLTHROUGH);
             frame.popn(2);
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELELEM)
 
           BEGIN_CASE(JSOP_TYPEOF)
           BEGIN_CASE(JSOP_TYPEOFEXPR)
             jsop_typeof();
@@ -2821,48 +2855,49 @@ mjit::Compiler::generateMethod()
                 PC += JSOP_SETARG_LENGTH + JSOP_POP_LENGTH;
                 break;
             }
           }
           END_CASE(JSOP_SETARG)
 
           BEGIN_CASE(JSOP_GETLOCAL)
           BEGIN_CASE(JSOP_CALLLOCAL)
+          BEGIN_CASE(JSOP_GETALIASEDVAR)
+          BEGIN_CASE(JSOP_CALLALIASEDVAR)
           {
             /*
              * Update the var type unless we are about to pop the variable.
              * Sync is not guaranteed for types of dead locals, and GETLOCAL
              * followed by POP is not regarded as a use of the variable.
              */
             jsbytecode *next = &PC[JSOP_GETLOCAL_LENGTH];
             if (JSOp(*next) != JSOP_POP || analysis->jumpTarget(next))
                 restoreVarType();
             if (JSObject *singleton = pushedSingleton(0))
                 frame.push(ObjectValue(*singleton));
+            else if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD)
+                jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ true);
             else
                 frame.pushLocal(GET_SLOTNO(PC));
+
+            PC += GetBytecodeLength(PC);
+            break;
           }
           END_CASE(JSOP_GETLOCAL)
 
-          BEGIN_CASE(JSOP_GETALIASEDVAR)
-          BEGIN_CASE(JSOP_CALLALIASEDVAR)
-            jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ true);
-          END_CASE(JSOP_GETALIASEDVAR);
-
           BEGIN_CASE(JSOP_SETLOCAL)
           BEGIN_CASE(JSOP_SETALIASEDVAR)
           {
             jsbytecode *next = &PC[GetBytecodeLength(PC)];
             bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
-            if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD) {
+            if (JOF_OPTYPE(*PC) == JOF_SCOPECOORD)
                 jsop_aliasedVar(ScopeCoordinate(PC), /* get = */ false, pop);
-            } else {
+            else
                 frame.storeLocal(GET_SLOTNO(PC), pop);
-                updateVarType();
-            }
+            updateVarType();
 
             if (pop) {
                 frame.pop();
                 PC = next + JSOP_POP_LENGTH;
                 break;
             }
 
             PC = next;
@@ -3027,17 +3062,17 @@ mjit::Compiler::generateMethod()
           END_CASE(JSOP_LABEL)
 
           BEGIN_CASE(JSOP_DEFFUN)
           {
             JSFunction *innerFun = script->getFunction(GET_UINT32_INDEX(PC));
 
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(innerFun), Registers::ArgReg1);
-            INLINE_STUBCALL(STRICT_VARIANT(script, stubs::DefFun), REJOIN_FALLTHROUGH);
+            INLINE_STUBCALL(STRICT_VARIANT(stubs::DefFun), REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_DEFFUN)
 
           BEGIN_CASE(JSOP_DEFVAR)
           BEGIN_CASE(JSOP_DEFCONST)
           {
             PropertyName *name = script->getName(GET_UINT32_INDEX(PC));
 
@@ -3768,16 +3803,20 @@ mjit::Compiler::emitReturn(FrameEntry *f
     }
 
     /* Inline StackFrame::epilogue. */
     if (debugMode()) {
         prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::Epilogue, REJOIN_NONE);
     } else {
         profilingPopHelper();
+
+        if (script->function() && script->nesting()) {
+            masm.sub32(Imm32(1), AbsoluteAddress(&script->nesting()->activeFrames));
+        }
     }
 
     emitReturnValue(&masm, fe);
     emitFinalReturn(masm);
 
     /*
      * After we've placed the call object, all tracked state can be
      * thrown away. This will happen anyway because the next live opcode (if
@@ -4195,18 +4234,28 @@ mjit::Compiler::inlineCallHelper(uint32_
 
     callIC.typeMonitored = monitored(PC) || hasTypeBarriers(PC);
 
     /* Test the type if necessary. Failing this always takes a really slow path. */
     MaybeJump notObjectJump;
     if (icCalleeType.isSet())
         notObjectJump = masm.testObject(Assembler::NotEqual, icCalleeType.reg());
 
+    /*
+     * For an optimized apply, keep icCalleeData in a callee-saved register for
+     * the subsequent ic::SplatApplyArgs call.
+     */
     Registers tempRegs(Registers::AvailRegs);
-    tempRegs.takeReg(icCalleeData);
+    if (callIC.frameSize.isDynamic() && !Registers::isSaved(icCalleeData)) {
+        RegisterID x = tempRegs.takeAnyReg(Registers::SavedRegs).reg();
+        masm.move(icCalleeData, x);
+        icCalleeData = x;
+    } else {
+        tempRegs.takeReg(icCalleeData);
+    }
 
     /* Reserve space just before initialization of funGuard. */
     RESERVE_IC_SPACE(masm);
 
     /*
      * Guard on the callee identity. This misses on the first run. If the
      * callee is scripted, compiled/compilable, and argc == nargs, then this
      * guard is patched, and the compiled code address is baked in.
@@ -4237,26 +4286,19 @@ mjit::Compiler::inlineCallHelper(uint32_
         Jump isNative = stubcc.masm.branch32(Assembler::Below, tmp, Imm32(JSFUN_INTERPRETED));
         tempRegs.putReg(tmp);
 
         /*
          * N.B. After this call, the frame will have a dynamic frame size.
          * Check after the function is known not to be a native so that the
          * catch-all/native path has a static depth.
          */
-        if (callIC.frameSize.isDynamic()) {
+        if (callIC.frameSize.isDynamic())
             OOL_STUBCALL(ic::SplatApplyArgs, REJOIN_CALL_SPLAT);
 
-            /*
-             * Restore identity of callee after SplatApplyArgs, which may
-             * have been clobbered (not callee save reg or changed by moving GC).
-             */
-            stubcc.masm.loadPayload(frame.addressOf(origThis), icCalleeData);
-        }
-
         /*
          * No-op jump that gets patched by ic::New/Call to the stub generated
          * by generateFullCallStub.
          */
         Jump toPatch = stubcc.masm.jump();
         toPatch.linkTo(stubcc.masm.label(), &stubcc.masm);
         callIC.oolJump = toPatch;
         callIC.icCall = stubcc.masm.label();
@@ -4689,17 +4731,17 @@ mjit::Compiler::emitStubCmpOp(BoolStub s
     return jumpAndRun(j, target);
 }
 
 void
 mjit::Compiler::jsop_setprop_slow(PropertyName *name)
 {
     prepareStubCall(Uses(2));
     masm.move(ImmPtr(name), Registers::ArgReg1);
-    INLINE_STUBCALL(STRICT_VARIANT(script, stubs::SetName), REJOIN_FALLTHROUGH);
+    INLINE_STUBCALL(STRICT_VARIANT(stubs::SetName), REJOIN_FALLTHROUGH);
     JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
     frame.shimmy(1);
     if (script->hasScriptCounts)
         bumpPropCount(PC, PCCounts::PROP_OTHER);
 }
 
 void
 mjit::Compiler::jsop_getprop_slow(PropertyName *name, bool forPrototype)
@@ -5351,16 +5393,52 @@ mjit::Compiler::jsop_setprop(PropertyNam
 
     /* If the incoming type will never PIC, take slow path. */
     if (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_OBJECT) {
         jsop_setprop_slow(name);
         return true;
     }
 
     /*
+     * If this is a SETNAME to a variable of a non-reentrant outer function,
+     * set the variable's slot directly for the active call object.
+     */
+    if (cx->typeInferenceEnabled() && js_CodeSpec[*PC].format & JOF_NAME) {
+        ScriptAnalysis::NameAccess access =
+            analysis->resolveNameAccess(cx, NameToId(name), true);
+        if (access.nesting) {
+            /* Use a SavedReg so it isn't clobbered by the stub call. */
+            RegisterID nameReg = frame.allocReg(Registers::SavedRegs).reg();
+            Address address = frame.loadNameAddress(access, nameReg);
+
+#ifdef JSGC_INCREMENTAL_MJ
+            /* Write barrier. */
+            if (cx->compartment->needsBarrier()) {
+                stubcc.linkExit(masm.jump(), Uses(0));
+                stubcc.leave();
+
+                /* sync() may have overwritten nameReg, so we reload its data. */
+                JS_ASSERT(address.base == nameReg);
+                stubcc.masm.move(ImmPtr(access.basePointer()), nameReg);
+                stubcc.masm.loadPtr(Address(nameReg), nameReg);
+                stubcc.masm.addPtr(Imm32(address.offset), nameReg, Registers::ArgReg1);
+
+                OOL_STUBCALL(stubs::WriteBarrier, REJOIN_NONE);
+                stubcc.rejoin(Changes(0));
+            }
+#endif
+
+            frame.storeTo(rhs, address, popGuaranteed);
+            frame.shimmy(1);
+            frame.freeReg(address.base);
+            return true;
+        }
+    }
+
+    /*
      * Set the property directly if we are accessing a known object which
      * always has the property in a particular inline slot.
      */
     jsid id = NameToId(name);
     types::TypeSet *types = frame.extra(lhs).types;
     if (JSOp(*PC) == JSOP_SETPROP && id == types::MakeTypeId(cx, id) &&
         types && !types->unknownObject() &&
         types->getObjectCount() == 1 &&
@@ -5391,17 +5469,17 @@ mjit::Compiler::jsop_setprop(PropertyNam
                 OOL_STUBCALL(stubs::GCThingWriteBarrier, REJOIN_NONE);
                 stubcc.rejoin(Changes(0));
             }
 #endif
             if (!isObject) {
                 stubcc.linkExit(notObject.get(), Uses(2));
                 stubcc.leave();
                 stubcc.masm.move(ImmPtr(name), Registers::ArgReg1);
-                OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetName), REJOIN_FALLTHROUGH);
+                OOL_STUBCALL(STRICT_VARIANT(stubs::SetName), REJOIN_FALLTHROUGH);
             }
             frame.storeTo(rhs, Address(reg, JSObject::getFixedSlotOffset(slot)), popGuaranteed);
             frame.unpinReg(reg);
             frame.shimmy(1);
             if (!isObject)
                 stubcc.rejoin(Changes(1));
             if (script->hasScriptCounts)
                 bumpPropCount(PC, PCCounts::PROP_DEFINITE);
@@ -5455,17 +5533,17 @@ mjit::Compiler::jsop_setprop(PropertyNam
         /* Start the hot path where it's easy to patch it. */
         pic.fastPathStart = masm.label();
         Jump j = masm.testObject(Assembler::NotEqual, reg);
 
         pic.typeCheck = stubcc.linkExit(j, Uses(2));
         stubcc.leave();
 
         stubcc.masm.move(ImmPtr(name), Registers::ArgReg1);
-        OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetName), REJOIN_FALLTHROUGH);
+        OOL_STUBCALL(STRICT_VARIANT(stubs::SetName), REJOIN_FALLTHROUGH);
 
         typeCheck = stubcc.masm.jump();
         pic.hasTypeCheck = true;
     } else {
         pic.fastPathStart = masm.label();
         pic.hasTypeCheck = false;
         pic.typeReg = Registers::ReturnReg;
     }
@@ -5536,16 +5614,34 @@ mjit::Compiler::jsop_setprop(PropertyNam
 
     pics.append(pic);
     return true;
 }
 
 void
 mjit::Compiler::jsop_name(PropertyName *name, JSValueType type)
 {
+    /*
+     * If this is a NAME for a variable of a non-reentrant outer function, get
+     * the variable's slot directly for the active call object. We always need
+     * to check for undefined, however.
+     */
+    if (cx->typeInferenceEnabled()) {
+        ScriptAnalysis::NameAccess access =
+            analysis->resolveNameAccess(cx, NameToId(name), true);
+        if (access.nesting) {
+            Address address = frame.loadNameAddress(access);
+            JSValueType type = knownPushedType(0);
+            BarrierState barrier = pushAddressMaybeBarrier(address, type, true,
+                                                           /* testUndefined = */ true);
+            finishBarrier(barrier, REJOIN_GETTER, 0);
+            return;
+        }
+    }
+
     PICGenInfo pic(ic::PICInfo::NAME, JSOp(*PC));
 
     RESERVE_IC_SPACE(masm);
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
     pic.name = name;
@@ -5592,16 +5688,34 @@ mjit::Compiler::jsop_name(PropertyName *
     pics.append(pic);
 
     finishBarrier(barrier, REJOIN_GETTER, 0);
 }
 
 bool
 mjit::Compiler::jsop_xname(PropertyName *name)
 {
+    /*
+     * If this is a GETXPROP for a variable of a non-reentrant outer function,
+     * treat in the same way as a NAME.
+     */
+    if (cx->typeInferenceEnabled()) {
+        ScriptAnalysis::NameAccess access =
+            analysis->resolveNameAccess(cx, NameToId(name), true);
+        if (access.nesting) {
+            frame.pop();
+            Address address = frame.loadNameAddress(access);
+            JSValueType type = knownPushedType(0);
+            BarrierState barrier = pushAddressMaybeBarrier(address, type, true,
+                                                           /* testUndefined = */ true);
+            finishBarrier(barrier, REJOIN_GETTER, 0);
+            return true;
+        }
+    }
+
     PICGenInfo pic(ic::PICInfo::XNAME, JSOp(*PC));
 
     FrameEntry *fe = frame.peek(-1);
     if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
         return jsop_getprop(name, knownPushedType(0));
     }
 
     if (!fe->isTypeKnown()) {
@@ -5654,16 +5768,33 @@ mjit::Compiler::jsop_xname(PropertyName 
 
     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
     return true;
 }
 
 void
 mjit::Compiler::jsop_bindname(PropertyName *name)
 {
+    /*
+     * If this is a BINDNAME for a variable of a non-reentrant outer function,
+     * the object is definitely the outer function's active call object.
+     */
+    if (cx->typeInferenceEnabled()) {
+        ScriptAnalysis::NameAccess access =
+            analysis->resolveNameAccess(cx, NameToId(name), true);
+        if (access.nesting) {
+            RegisterID reg = frame.allocReg();
+            CallObject **pobj = &access.nesting->activeCall;
+            masm.move(ImmPtr(pobj), reg);
+            masm.loadPtr(Address(reg), reg);
+            frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
+            return;
+        }
+    }
+
     PICGenInfo pic(ic::PICInfo::BIND, JSOp(*PC));
 
     // This code does not check the frame flags to see if scopeChain has been
     // set. Rather, it relies on the up-front analysis statically determining
     // whether BINDNAME can be used, which reifies the scope chain at the
     // prologue.
     JS_ASSERT(analysis->usesScopeChain());
 
@@ -5794,35 +5925,57 @@ mjit::Compiler::jsop_aliasedArg(unsigned
 void
 mjit::Compiler::jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter)
 {
     RegisterID reg = frame.allocReg(Registers::SavedRegs).reg();
     masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfScopeChain()), reg);
     for (unsigned i = 0; i < sc.hops; i++)
         masm.loadPayload(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
 
-    Shape *shape = ScopeCoordinateToStaticScope(script, PC).scopeShape();
+    /*
+     * TODO bug 753158: Call and Block objects should use the same layout
+     * strategy: up to the maximum numFixedSlots and overflow (if any) in
+     * dynamic slots. For now, we special case for different layouts:
+     */
     Address addr;
-    if (shape->numFixedSlots() <= sc.slot) {
-        masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
-        addr = Address(reg, (sc.slot - shape->numFixedSlots()) * sizeof(Value));
+    StaticBlockObject *block = ScopeCoordinateBlockChain(script, PC);
+    if (block) {
+        /*
+         * Block objects use a fixed AllocKind which means an invariant number
+         * of fixed slots. Any slot below the fixed slot count is inline, any
+         * slot over is in the dynamic slots.
+         */
+        uint32_t nfixed = gc::GetGCKindSlots(BlockObject::FINALIZE_KIND);
+        if (nfixed <= sc.slot) {
+            masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
+            addr = Address(reg, (sc.slot - nfixed) * sizeof(Value));
+        } else {
+            addr = Address(reg, JSObject::getFixedSlotOffset(sc.slot));
+        }
     } else {
-        addr = Address(reg, JSObject::getFixedSlotOffset(sc.slot));
+        /*
+         * Using special-case hackery in Shape::getChildBinding, CallObject
+         * slots are either altogether in fixed slots or altogether in dynamic
+         * slots (by having numFixed == RESERVED_SLOTS).
+         */
+        if (script->bindings.lastShape()->numFixedSlots() <= sc.slot) {
+            masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
+            addr = Address(reg, (sc.slot - CallObject::RESERVED_SLOTS) * sizeof(Value));
+        } else {
+            addr = Address(reg, JSObject::getFixedSlotOffset(sc.slot));
+        }
     }
 
     if (get) {
-        JSValueType type = knownPushedType(0);
-        RegisterID typeReg, dataReg;
-        frame.loadIntoRegisters(addr, /* reuseBase = */ true, &typeReg, &dataReg);
-        frame.pushRegs(typeReg, dataReg, type);
-        BarrierState barrier = testBarrier(typeReg, dataReg,
-                                           /* testUndefined = */ false,
-                                           /* testReturn */ false,
-                                           /* force */ true);
-        finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
+        unsigned index;
+        FrameEntry *fe = ScopeCoordinateToFrameIndex(script, PC, &index) == FrameIndex_Local
+                         ? frame.getLocal(index)
+                         : frame.getArg(index);
+        JSValueType type = fe->isTypeKnown() ? fe->getKnownType() : JSVAL_TYPE_UNKNOWN;
+        frame.push(addr, type, true /* = reuseBase */);
     } else {
 #ifdef JSGC_INCREMENTAL_MJ
         if (cx->compartment->needsBarrier()) {
             /* Write barrier. */
             stubcc.linkExit(masm.testGCThing(addr), Uses(0));
             stubcc.leave();
             stubcc.masm.addPtr(Imm32(addr.offset), addr.base, Registers::ArgReg1);
             OOL_STUBCALL(stubs::GCThingWriteBarrier, REJOIN_NONE);
@@ -6308,17 +6461,17 @@ mjit::Compiler::jsop_getgname(uint32_t i
     return true;
 }
 
 void
 mjit::Compiler::jsop_setgname_slow(PropertyName *name)
 {
     prepareStubCall(Uses(2));
     masm.move(ImmPtr(name), Registers::ArgReg1);
-    INLINE_STUBCALL(STRICT_VARIANT(script, stubs::SetGlobalName), REJOIN_FALLTHROUGH);
+    INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalName), REJOIN_FALLTHROUGH);
     frame.popn(2);
     pushSyncedEntry(0);
 }
 
 bool
 mjit::Compiler::jsop_setgname(PropertyName *name, bool popGuaranteed)
 {
     if (monitored(PC)) {
@@ -6445,17 +6598,17 @@ mjit::Compiler::jsop_setgname(PropertyNa
 #endif
     return true;
 }
 
 void
 mjit::Compiler::jsop_setelem_slow()
 {
     prepareStubCall(Uses(3));
-    INLINE_STUBCALL(STRICT_VARIANT(script, stubs::SetElem), REJOIN_FALLTHROUGH);
+    INLINE_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
     frame.popn(3);
     frame.pushSynced(JSVAL_TYPE_UNKNOWN);
 }
 
 void
 mjit::Compiler::jsop_getelem_slow()
 {
     prepareStubCall(Uses(2));
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1207,17 +1207,17 @@ mjit::Compiler::jsop_setelem_dense()
     // Fully store the value. :TODO: don't need to do this in the non-initlen case
     // if the array is packed and monomorphic.
     if (key.isConstant())
         masm.storeValue(vr, Address(slotsReg, key.index() * sizeof(Value)));
     else
         masm.storeValue(vr, BaseIndex(slotsReg, key.reg(), masm.JSVAL_SCALE));
 
     stubcc.leave();
-    OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetElem), REJOIN_FALLTHROUGH);
+    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
 
     if (!hoisted)
         frame.freeReg(slotsReg);
     frame.shimmy(2);
     stubcc.rejoin(Changes(2));
 }
 
 #ifdef JS_METHODJIT_TYPED_ARRAY
@@ -1481,17 +1481,17 @@ mjit::Compiler::jsop_setelem_typed(int a
     if (pinKey)
         frame.unpinReg(key.reg());
     if (hoisted)
         frame.unpinReg(objReg);
     else
         frame.freeReg(objReg);
 
     stubcc.leave();
-    OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetElem), REJOIN_FALLTHROUGH);
+    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
 
     frame.shimmy(2);
     stubcc.rejoin(Changes(2));
 }
 #endif /* JS_METHODJIT_TYPED_ARRAY */
 
 void
 mjit::Compiler::tryConvertInteger(FrameEntry *fe, Uses uses)
@@ -1682,19 +1682,19 @@ mjit::Compiler::jsop_setelem(bool popGua
         ic.holeGuard = masm.guardNotHole(slot);
         masm.storeValue(ic.vr, slot);
     }
     stubcc.linkExitDirect(ic.holeGuard, ic.slowPathStart);
 
     stubcc.leave();
 #if defined JS_POLYIC
     passICAddress(&ic);
-    ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(script, ic::SetElement), REJOIN_FALLTHROUGH);
+    ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(ic::SetElement), REJOIN_FALLTHROUGH);
 #else
-    OOL_STUBCALL(STRICT_VARIANT(script, stubs::SetElem), REJOIN_FALLTHROUGH);
+    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
 #endif
 
     ic.fastPathRejoin = masm.label();
 
     // When generating typed array stubs, it may be necessary to call
     // ToInt32(), which would clobber registers. To deal with this, we tell the
     // IC exactly which registers need to be saved across calls.
     ic.volatileMask = frame.regsInUse();
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -877,16 +877,34 @@ FrameState::syncAndForgetFe(FrameEntry *
     }
 
     syncFe(fe);
     forgetAllRegs(fe);
     fe->type.setMemory();
     fe->data.setMemory();
 }
 
+inline JSC::MacroAssembler::Address
+FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access, RegisterID reg)
+{
+    JS_ASSERT(access.script && access.nesting);
+
+    masm.move(ImmPtr(access.basePointer()), reg);
+    masm.loadPtr(Address(reg), reg);
+
+    return Address(reg, access.index * sizeof(Value));
+}
+
+inline JSC::MacroAssembler::Address
+FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access)
+{
+    RegisterID reg = allocReg();
+    return loadNameAddress(access, reg);
+}
+
 inline void
 FrameState::forgetLoopReg(FrameEntry *fe)
 {
     /*
      * Don't use a loop register for fe in the active loop, as its underlying
      * representation may have changed since the start of the loop.
      */
     if (loop)
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -924,16 +924,24 @@ class FrameState
      * Return NULL or a new vector with all current copies of temporaries,
      * excluding those about to be popped per 'uses'.
      */
     Vector<TemporaryCopy> *getTemporaryCopies(Uses uses);
 
     inline void syncAndForgetFe(FrameEntry *fe, bool markSynced = false);
     inline void forgetLoopReg(FrameEntry *fe);
 
+    /*
+     * Get an address for the specified name access in another script.
+     * The compiler owns the result's base register.
+     */
+    inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access);
+    inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access,
+                                   RegisterID reg);
+
   private:
     inline AnyRegisterID allocAndLoadReg(FrameEntry *fe, bool fp, RematInfo::RematType type);
     inline void forgetReg(AnyRegisterID reg);
     AnyRegisterID evictSomeReg(uint32_t mask);
     void evictReg(AnyRegisterID reg);
     inline FrameEntry *rawPush();
     inline void addToTracker(FrameEntry *fe);
 
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -557,17 +557,17 @@ js_InternalThrow(VMFrame &f)
      * Fall back to EnterMethodJIT and finish the frame in the interpreter.
      * With type inference enabled, we may wipe out all JIT code on the
      * stack without patching ncode values to jump to the interpreter, and
      * thus can only enter JIT code via EnterMethodJIT (which overwrites
      * its entry frame's ncode). See ClearAllFrames.
      */
     cx->jaegerRuntime().setLastUnfinished(Jaeger_Unfinished);
 
-    if (!script->ensureRanAnalysis(cx)) {
+    if (!script->ensureRanAnalysis(cx, NULL)) {
         js_ReportOutOfMemory(cx);
         return NULL;
     }
 
     analyze::AutoEnterAnalysis enter(cx);
 
     /*
      * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
@@ -731,17 +731,17 @@ js_InternalInterpret(void *returnData, v
     StackFrame *fp = f.regs.fp();
     JSScript *script = fp->script();
 
     jsbytecode *pc = f.regs.pc;
 
     JSOp op = JSOp(*pc);
     const JSCodeSpec *cs = &js_CodeSpec[op];
 
-    if (!script->ensureRanAnalysis(cx)) {
+    if (!script->ensureRanAnalysis(cx, NULL)) {
         js_ReportOutOfMemory(cx);
         return js_InternalThrow(f);
     }
 
     analyze::AutoEnterAnalysis enter(cx);
     analyze::ScriptAnalysis *analysis = script->analysis();
 
     /*
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -53,22 +53,22 @@ PatchGetFallback(VMFrame &f, ic::GetGlob
     Repatcher repatch(f.chunk());
     JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stubs::Name));
     repatch.relink(ic->slowPathCall, fptr);
 }
 
 void JS_FASTCALL
 ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic)
 {
-    RootedObject obj(f.cx, &f.fp()->global());
+    JSObject &obj = f.fp()->global();
     PropertyName *name = f.script()->getName(GET_UINT32_INDEX(f.pc()));
 
     RecompilationMonitor monitor(f.cx);
 
-    Shape *shape = obj->nativeLookup(f.cx, NameToId(name));
+    Shape *shape = obj.nativeLookup(f.cx, NameToId(name));
 
     if (monitor.recompiled()) {
         stubs::Name(f);
         return;
     }
 
     if (!shape ||
         !shape->hasDefaultGetter() ||
@@ -78,20 +78,20 @@ ic::GetGlobalName(VMFrame &f, ic::GetGlo
             PatchGetFallback(f, ic);
         stubs::Name(f);
         return;
     }
     uint32_t slot = shape->slot();
 
     /* Patch shape guard. */
     Repatcher repatcher(f.chunk());
-    repatcher.repatch(ic->fastPathStart.dataLabelPtrAtOffset(ic->shapeOffset), obj->lastProperty());
+    repatcher.repatch(ic->fastPathStart.dataLabelPtrAtOffset(ic->shapeOffset), obj.lastProperty());
 
     /* Patch loads. */
-    uint32_t index = obj->dynamicSlotIndex(slot);
+    uint32_t index = obj.dynamicSlotIndex(slot);
     JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset);
     repatcher.patchAddressOffsetForValueLoad(label, index * sizeof(Value));
 
     /* Do load anyway... this time. */
     stubs::Name(f);
 }
 
 template <JSBool strict>
@@ -102,18 +102,19 @@ DisabledSetGlobal(VMFrame &f, ic::SetGlo
 }
 
 template void JS_FASTCALL DisabledSetGlobal<true>(VMFrame &f, ic::SetGlobalNameIC *ic);
 template void JS_FASTCALL DisabledSetGlobal<false>(VMFrame &f, ic::SetGlobalNameIC *ic);
 
 static void
 PatchSetFallback(VMFrame &f, ic::SetGlobalNameIC *ic)
 {
+    JSScript *script = f.script();
     Repatcher repatch(f.chunk());
-    VoidStubSetGlobal stub = STRICT_VARIANT(f.script(), DisabledSetGlobal);
+    VoidStubSetGlobal stub = STRICT_VARIANT(DisabledSetGlobal);
     JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stub));
     repatch.relink(ic->slowPathCall, fptr);
 }
 
 void
 SetGlobalNameIC::patchInlineShapeGuard(Repatcher &repatcher, Shape *shape)
 {
     JSC::CodeLocationDataLabelPtr label = fastPathStart.dataLabelPtrAtOffset(shapeOffset);
@@ -147,30 +148,31 @@ UpdateSetGlobalName(VMFrame &f, ic::SetG
                                               ic->vr.isTypeKnown());
 
     return Lookup_Cacheable;
 }
 
 void JS_FASTCALL
 ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic)
 {
-    RootedObject obj(f.cx, &f.fp()->global());
-    RootedPropertyName name(f.cx, f.script()->getName(GET_UINT32_INDEX(f.pc())));
+    JSObject &obj = f.fp()->global();
+    JSScript *script = f.script();
+    PropertyName *name = script->getName(GET_UINT32_INDEX(f.pc()));
 
     RecompilationMonitor monitor(f.cx);
 
-    Shape *shape = obj->nativeLookup(f.cx, NameToId(name));
+    Shape *shape = obj.nativeLookup(f.cx, NameToId(name));
 
     if (!monitor.recompiled()) {
-        LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape);
+        LookupStatus status = UpdateSetGlobalName(f, ic, &obj, shape);
         if (status == Lookup_Error)
             THROW();
     }
 
-    STRICT_VARIANT(f.script(), stubs::SetGlobalName)(f, name);
+    STRICT_VARIANT(stubs::SetGlobalName)(f, name);
 }
 
 class EqualityICLinker : public LinkerHelper
 {
     VMFrame &f;
 
   public:
     EqualityICLinker(Assembler &masm, VMFrame &f)
@@ -757,18 +759,18 @@ class CallCompiler : public BaseCompiler
         } else {
             JS_ASSERT(!f.regs.inlined());
             JS_ASSERT(*f.regs.pc == JSOP_FUNAPPLY && GET_ARGC(f.regs.pc) == 2);
             if (!ic::SplatApplyArgs(f))       /* updates regs.sp */
                 THROWV(true);
             args = CallArgsFromSp(f.u.call.dynamicArgc, f.regs.sp);
         }
 
-        RootedFunction fun(cx);
-        if (!IsFunctionObject(args.calleev(), fun.address()))
+        JSFunction *fun;
+        if (!IsFunctionObject(args.calleev(), &fun))
             return false;
 
         if ((!callingNew && !fun->isNative()) || (callingNew && !fun->isNativeConstructor()))
             return false;
 
         if (callingNew)
             args.thisv().setMagic(JS_IS_CONSTRUCTING);
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -63,25 +63,26 @@ class PICLinker : public LinkerHelper
     }
 };
 
 class PICStubCompiler : public BaseCompiler
 {
   protected:
     const char *type;
     VMFrame &f;
+    JSScript *script;
     ic::PICInfo &pic;
     void *stub;
     uint64_t gcNumber;
 
   public:
     bool canCallHook;
 
-    PICStubCompiler(const char *type, VMFrame &f, ic::PICInfo &pic, void *stub)
-      : BaseCompiler(f.cx), type(type), f(f), pic(pic), stub(stub),
+    PICStubCompiler(const char *type, VMFrame &f, JSScript *script, ic::PICInfo &pic, void *stub)
+      : BaseCompiler(f.cx), type(type), f(f), script(script), pic(pic), stub(stub),
         gcNumber(f.cx->runtime->gcNumber), canCallHook(pic.canCallHook)
     { }
 
     LookupStatus error() {
         /*
          * N.B. Do not try to disable the IC, we do not want to guard on
          * whether the IC has been recompiled when propagating errors.
          */
@@ -107,17 +108,17 @@ class PICStubCompiler : public BaseCompi
     bool hadGC() {
         return gcNumber != f.cx->runtime->gcNumber;
     }
 
   protected:
     void spew(const char *event, const char *op) {
 #ifdef JS_METHODJIT_SPEW
         JaegerSpew(JSpew_PICs, "%s %s: %s (%s: %d)\n",
-                   type, event, op, f.script()->filename, CurrentLine(cx));
+                   type, event, op, script->filename, CurrentLine(cx));
 #endif
     }
 };
 
 static bool
 GeneratePrototypeGuards(JSContext *cx, Vector<JSC::MacroAssembler::Jump,8> &mismatches, Assembler &masm,
                         JSObject *obj, JSObject *holder,
                         JSC::MacroAssembler::RegisterID objReg,
@@ -159,25 +160,25 @@ GeneratePrototypeGuards(JSContext *cx, V
         pobj = pobj->getProto();
     }
 
     return true;
 }
 
 class SetPropCompiler : public PICStubCompiler
 {
-    RootedObject obj;
-    RootedPropertyName name;
+    JSObject *obj;
+    PropertyName *name;
     int lastStubSecondShapeGuard;
 
   public:
-    SetPropCompiler(VMFrame &f, JSObject *obj, ic::PICInfo &pic, PropertyName *name,
+    SetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, PropertyName *name,
                     VoidStubPIC stub)
-      : PICStubCompiler("setprop", f, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
-        obj(f.cx, obj), name(f.cx, name), lastStubSecondShapeGuard(pic.secondShapeGuard)
+      : PICStubCompiler("setprop", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
+        obj(obj), name(name), lastStubSecondShapeGuard(pic.secondShapeGuard)
     { }
 
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
     {
         SetPropLabels &labels = pic.setPropLabels();
         repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr));
         repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard),
                           NULL);
@@ -745,27 +746,27 @@ struct GetPropHelper {
     }
 };
 
 namespace js {
 namespace mjit {
 
 class GetPropCompiler : public PICStubCompiler
 {
-    RootedObject obj;
-    RootedPropertyName name;
-    int lastStubSecondShapeGuard;
+    JSObject    *obj;
+    PropertyName *name;
+    int         lastStubSecondShapeGuard;
 
   public:
-    GetPropCompiler(VMFrame &f, JSObject *obj, ic::PICInfo &pic, PropertyName *name,
+    GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, PropertyName *name,
                     VoidStubPIC stub)
-      : PICStubCompiler("getprop", f, pic,
+      : PICStubCompiler("getprop", f, script, pic,
                         JS_FUNC_TO_DATA_PTR(void *, stub)),
-        obj(f.cx, obj),
-        name(f.cx, name),
+        obj(obj),
+        name(name),
         lastStubSecondShapeGuard(pic.secondShapeGuard)
     { }
 
     int getLastStubSecondShapeGuard() const {
         return lastStubSecondShapeGuard ? POST_INST_OFFSET(lastStubSecondShapeGuard) : 0;
     }
 
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
@@ -866,17 +867,17 @@ class GetPropCompiler : public PICStubCo
 
     LookupStatus generateStringPropertyStub()
     {
         if (!f.fp()->script()->hasGlobal())
             return disable("String.prototype without compile-and-go global");
 
         RecompilationMonitor monitor(f.cx);
 
-        RootedObject obj(f.cx, f.fp()->global().getOrCreateStringPrototype(f.cx));
+        JSObject *obj = f.fp()->global().getOrCreateStringPrototype(f.cx);
         if (!obj)
             return error();
 
         if (monitor.recompiled())
             return Lookup_Uncacheable;
 
         GetPropHelper<GetPropCompiler> getprop(cx, obj, name, *this, f);
         LookupStatus status = getprop.lookupAndTest();
@@ -1211,25 +1212,22 @@ class GetPropCompiler : public PICStubCo
             return;
         }
 
         linker.patchJump(pic.fastPathRejoin);
 
         linkerEpilogue(linker, start, shapeMismatches);
     }
 
-    LookupStatus generateStub(JSObject *holder, HandleShape shape)
+    LookupStatus generateStub(JSObject *holder, Shape *shape)
     {
         Vector<Jump, 8> shapeMismatches(cx);
 
         Assembler masm;
 
-        // Ignore GC pointers baked into assembly visible on the stack.
-        SkipRoot skip(cx, &masm);
-
         Label start;
         Jump shapeGuardJump;
         Jump argsLenGuard;
 
         bool setStubShapeOffset = true;
         if (obj->isDenseArray()) {
             start = masm.label();
             shapeGuardJump = masm.branchPtr(Assembler::NotEqual,
@@ -1442,19 +1440,19 @@ class ScopeNameCompiler : public PICStub
 
         if (tobj != getprop.holder)
             return disable("scope chain walk terminated early");
 
         return Lookup_Cacheable;
     }
 
   public:
-    ScopeNameCompiler(VMFrame &f, JSObject *scopeChain, ic::PICInfo &pic,
+    ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
                       PropertyName *name, VoidStubPIC stub)
-      : PICStubCompiler("name", f, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
+      : PICStubCompiler("name", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
         scopeChain(f.cx, scopeChain), name(f.cx, name),
         getprop(f.cx, NULL, name, *thisFromCtor(), f)
     { }
 
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
     {
         ScopeNameLabels &labels = pic.scopeNameLabels();
 
@@ -1710,19 +1708,19 @@ class ScopeNameCompiler : public PICStub
 };
 
 class BindNameCompiler : public PICStubCompiler
 {
     RootedObject scopeChain;
     RootedPropertyName name;
 
   public:
-    BindNameCompiler(VMFrame &f, JSObject *scopeChain, ic::PICInfo &pic,
+    BindNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
                      PropertyName *name, VoidStubPIC stub)
-      : PICStubCompiler("bind", f, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
+      : PICStubCompiler("bind", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
         scopeChain(f.cx, scopeChain), name(f.cx, name)
     { }
 
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
     {
         BindNameLabels &labels = pic.bindNameLabels();
 
         /* Link the inline jump back to the slow path. */
@@ -1857,26 +1855,28 @@ DisabledGetPropNoCacheIC(VMFrame &f, ic:
 }
 
 void JS_FASTCALL
 ic::GetProp(VMFrame &f, ic::PICInfo *pic)
 {
     bool cached = pic->cached;
     VoidStubPIC stub = cached ? DisabledGetPropIC : DisabledGetPropNoCacheIC;
 
-    RootedPropertyName name(f.cx, pic->name);
+    JSScript *script = f.fp()->script();
+
+    PropertyName *name = pic->name;
     if (name == f.cx->runtime->atomState.lengthAtom) {
         if (IsOptimizedArguments(f.fp(), &f.regs.sp[-1])) {
             f.regs.sp[-1].setInt32(f.regs.fp()->numActualArgs());
             return;
         }
         if (!f.regs.sp[-1].isPrimitive()) {
             JSObject *obj = &f.regs.sp[-1].toObject();
             if (obj->isArray() || obj->isString()) {
-                GetPropCompiler cc(f, obj, *pic, NULL, stub);
+                GetPropCompiler cc(f, script, obj, *pic, NULL, stub);
                 if (obj->isArray()) {
                     LookupStatus status = cc.generateArrayLengthStub();
                     if (status == Lookup_Error)
                         THROW();
                     f.regs.sp[-1].setNumber(obj->getArrayLength());
                 } else {
                     LookupStatus status = cc.generateStringObjLengthStub();
                     if (status == Lookup_Error)
@@ -1885,17 +1885,17 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
                     f.regs.sp[-1].setInt32(str->length());
                 }
                 return;
             }
         }
     }
 
     if (f.regs.sp[-1].isString()) {
-        GetPropCompiler cc(f, NULL, *pic, name, stub);
+        GetPropCompiler cc(f, script, NULL, *pic, name, stub);
         if (name == f.cx->runtime->atomState.lengthAtom) {
             LookupStatus status = cc.generateStringLengthStub();
             if (status == Lookup_Error)
                 THROW();
             JSString *str = f.regs.sp[-1].toString();
             f.regs.sp[-1].setInt32(str->length());
         } else {
             LookupStatus status = cc.generateStringPropertyStub();
@@ -1907,66 +1907,67 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
             if (!obj->getProperty(f.cx, name, &f.regs.sp[-1]))
                 THROW();
         }
         return;
     }
 
     RecompilationMonitor monitor(f.cx);
 
-    RootedObject obj(f.cx, ValueToObject(f.cx, f.regs.sp[-1]));
+    JSObject *obj = ValueToObject(f.cx, f.regs.sp[-1]);
     if (!obj)
         THROW();
 
     if (!monitor.recompiled() && pic->shouldUpdate(f.cx)) {
-        GetPropCompiler cc(f, obj, *pic, name, stub);
+        GetPropCompiler cc(f, script, obj, *pic, name, stub);
         if (!cc.update())
             THROW();
     }
 
-    RootedValue v(f.cx);
+    Value v;
     if (cached) {
-        if (!GetPropertyOperation(f.cx, f.script(), f.pc(), f.regs.sp[-1], v.address()))
+        if (!GetPropertyOperation(f.cx, f.script(), f.pc(), f.regs.sp[-1], &v))
             THROW();
     } else {
-        if (!obj->getProperty(f.cx, name, v.address()))
+        if (!obj->getProperty(f.cx, name, &v))
             THROW();
     }
 
     f.regs.sp[-1] = v;
 }
 
 template <JSBool strict>
 static void JS_FASTCALL
 DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::SetName<strict>(f, pic->name);
 }
 
 void JS_FASTCALL
 ic::SetProp(VMFrame &f, ic::PICInfo *pic)
 {
+    JSScript *script = f.fp()->script();
     JS_ASSERT(pic->isSet());
 
-    VoidStubPIC stub = STRICT_VARIANT(f.script(), DisabledSetPropIC);
+    VoidStubPIC stub = STRICT_VARIANT(DisabledSetPropIC);
 
     // Save this in case the compiler triggers a recompilation of this script.
-    RootedPropertyName name(f.cx, pic->name);
-    VoidStubName nstub = STRICT_VARIANT(f.script(), stubs::SetName);
+    PropertyName *name = pic->name;
+    VoidStubName nstub = STRICT_VARIANT(stubs::SetName);
 
     RecompilationMonitor monitor(f.cx);
 
     JSObject *obj = ValueToObject(f.cx, f.regs.sp[-2]);
     if (!obj)
         THROW();
 
     // Note, we can't use SetName for PROPINC PICs because the property
     // cache can't handle a GET and SET from the same scripted PC.
     if (!monitor.recompiled() && pic->shouldUpdate(f.cx)) {
-        SetPropCompiler cc(f, obj, *pic, name, stub);
+        SetPropCompiler cc(f, script, obj, *pic, name, stub);
         LookupStatus status = cc.update();
         if (status == Lookup_Error)
             THROW();
     }
 
     nstub(f, name);
 }
 
@@ -1980,57 +1981,63 @@ static void JS_FASTCALL
 DisabledXNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::GetProp(f, pic->name);
 }
 
 void JS_FASTCALL
 ic::XName(VMFrame &f, ic::PICInfo *pic)
 {
+    JSScript *script = f.fp()->script();
+
     /* GETXPROP is guaranteed to have an object. */
     JSObject *obj = &f.regs.sp[-1].toObject();
 
-    ScopeNameCompiler cc(f, obj, *pic, pic->name, DisabledXNameIC);
+    ScopeNameCompiler cc(f, script, obj, *pic, pic->name, DisabledXNameIC);
 
     LookupStatus status = cc.updateForXName();
     if (status == Lookup_Error)
         THROW();
 
     Value rval;
     if (!cc.retrieve(&rval, PICInfo::XNAME))
         THROW();
     f.regs.sp[-1] = rval;
 }
 
 void JS_FASTCALL
 ic::Name(VMFrame &f, ic::PICInfo *pic)
 {
-    ScopeNameCompiler cc(f, f.fp()->scopeChain(), *pic, pic->name, DisabledNameIC);
+    JSScript *script = f.fp()->script();
+
+    ScopeNameCompiler cc(f, script, f.fp()->scopeChain(), *pic, pic->name, DisabledNameIC);
 
     LookupStatus status = cc.updateForName();
     if (status == Lookup_Error)
         THROW();
 
-    RootedValue rval(f.cx);
-    if (!cc.retrieve(rval.address(), PICInfo::NAME))
+    Value rval;
+    if (!cc.retrieve(&rval, PICInfo::NAME))
         THROW();
     f.regs.sp[0] = rval;
 }
 
 static void JS_FASTCALL
 DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::BindName(f, pic->name);
 }
 
 void JS_FASTCALL
 ic::BindName(VMFrame &f, ic::PICInfo *pic)
 {
+    JSScript *script = f.fp()->script();
+
     VoidStubPIC stub = DisabledBindNameIC;
-    BindNameCompiler cc(f, f.fp()->scopeChain(), *pic, pic->name, stub);
+    BindNameCompiler cc(f, script, f.fp()->scopeChain(), *pic, pic->name, stub);
 
     JSObject *obj = cc.update();
     if (!obj)
         THROW();
 
     f.regs.sp[0].setObject(*obj);
 }
 
@@ -2169,17 +2176,17 @@ GetElementIC::purge(Repatcher &repatcher
         repatcher.relink(slowPathCall,
                          FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::GetElement)));
     }
 
     reset();
 }
 
 LookupStatus
-GetElementIC::attachGetProp(VMFrame &f, HandleObject obj, HandleValue v, HandlePropertyName name,
+GetElementIC::attachGetProp(VMFrame &f, JSObject *obj, const Value &v, PropertyName *name,
                             Value *vp)
 {
     JS_ASSERT(v.isString());
     JSContext *cx = f.cx;
 
     GetPropHelper<GetElementIC> getprop(cx, obj, name, *this, f);
     LookupStatus status = getprop.lookupAndTest();
     if (status != Lookup_Cacheable)
@@ -2350,17 +2357,17 @@ GetElementIC::attachGetProp(VMFrame &f, 
     // Finally, fetch the value to avoid redoing the property lookup.
     *vp = holder->getSlot(shape->slot());
 
     return Lookup_Cacheable;
 }
 
 #if defined JS_METHODJIT_TYPED_ARRAY
 LookupStatus
-GetElementIC::attachTypedArray(VMFrame &f, HandleObject obj, HandleValue v, HandleId id, Value *vp)
+GetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
 {
     JSContext *cx = f.cx;
 
     if (!v.isInt32())
         return disable(f, "typed array with string key");
 
     if (op == JSOP_CALLELEM)
         return disable(f, "typed array with call");
@@ -2443,28 +2450,26 @@ GetElementIC::attachTypedArray(VMFrame &
     if (!obj->getGeneric(cx, idRoot, vp))
         return Lookup_Error;
 
     return Lookup_Cacheable;
 }
 #endif /* JS_METHODJIT_TYPED_ARRAY */
 
 LookupStatus
-GetElementIC::update(VMFrame &f, HandleObject obj, HandleValue v, HandleId id, Value *vp)
+GetElementIC::update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp)
 {
-    /*JSObject *obj, const Value &v, jsid id, Value *vp)
+    /*
      * Only treat this as a GETPROP for non-numeric string identifiers. The
      * GETPROP IC assumes the id has already gone through filtering for string
      * indexes in the emitter.
      */
     uint32_t dummy;
-    if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy)) {
-        RootedPropertyName name(f.cx, JSID_TO_ATOM(id)->asPropertyName());
-        return attachGetProp(f, obj, v, name, vp);
-    }
+    if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy))
+        return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);
 
 #if defined JS_METHODJIT_TYPED_ARRAY
     /*
      * Typed array ICs can make stub calls, and need to know which registers
      * are in use and need to be restored after the call. If type inference is
      * enabled then we don't necessarily know the full set of such registers
      * when generating the IC (loop-carried registers may be allocated later),
      * and additionally the push/pop instructions used to save/restore in the
@@ -2486,18 +2491,17 @@ ic::GetElement(VMFrame &f, ic::GetElemen
 
     // Right now, we don't optimize for strings or lazy arguments.
     if (!f.regs.sp[-2].isObject()) {
         ic->disable(f, "non-object");
         stubs::GetElem(f);
         return;
     }
 
-    RootedValue idval_(cx, f.regs.sp[-1]);
-    Value &idval = idval_.get();
+    Value idval = f.regs.sp[-1];
 
     RecompilationMonitor monitor(cx);
 
     RootedObject obj(cx, ValueToObject(cx, f.regs.sp[-2]));
     if (!obj)
         THROW();
 
 #if JS_HAS_XML_SUPPORT
@@ -2517,17 +2521,17 @@ ic::GetElement(VMFrame &f, ic::GetElemen
         if (!InternNonIntElementId(cx, obj, idval, id.address()))
             THROW();
     }
 
     if (!monitor.recompiled() && ic->shouldUpdate(cx)) {
 #ifdef DEBUG
         f.regs.sp[-2] = MagicValue(JS_GENERIC_MAGIC);
 #endif
-        LookupStatus status = ic->update(f, obj, idval_, id, &f.regs.sp[-2]);
+        LookupStatus status = ic->update(f, obj, idval, id, &f.regs.sp[-2]);
         if (status != Lookup_Uncacheable) {
             if (status == Lookup_Error)
                 THROW();
 
             // If the result can be cached, the value was already retrieved.
             JS_ASSERT(!f.regs.sp[-2].isMagic());
             return;
         }
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -238,20 +238,20 @@ struct GetElementIC : public BasePolyIC 
         // The shape guard is only unconditional if the type is known to not
         // be an int32.
         if (idRemat.isTypeKnown() && idRemat.knownType() != JSVAL_TYPE_INT32)
             return !inlineShapeGuardPatched;
         return false;
     }
 
     void purge(Repatcher &repatcher);
-    LookupStatus update(VMFrame &f, HandleObject obj, HandleValue v, HandleId id, Value *vp);
-    LookupStatus attachGetProp(VMFrame &f, HandleObject obj, HandleValue v, HandlePropertyName name,
+    LookupStatus update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
+    LookupStatus attachGetProp(VMFrame &f, JSObject *obj, const Value &v, PropertyName *name,
                                Value *vp);
-    LookupStatus attachTypedArray(VMFrame &f, HandleObject obj, HandleValue v, HandleId id, Value *vp);
+    LookupStatus attachTypedArray(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *vp);
     LookupStatus disable(VMFrame &f, const char *reason);
     LookupStatus error(JSContext *cx);
     bool shouldUpdate(JSContext *cx);
 
   protected:
     void reset() {
         BasePolyIC::reset();
         inlineTypeGuardPatched = false;
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -118,17 +118,17 @@ template<JSBool strict>
 void JS_FASTCALL
 stubs::SetElem(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
     Value &objval = regs.sp[-3];
     Value &idval  = regs.sp[-2];
-    RootedValue rval(cx, regs.sp[-1]);
+    Value rval    = regs.sp[-1];
 
     RootedId id(cx);
 
     Rooted<JSObject*> obj(cx, ValueToObject(cx, objval));
     if (!obj)
         THROW();
 
     if (!FetchElementId(f.cx, obj, idval, id.address(), &regs.sp[-2]))
@@ -150,17 +150,17 @@ stubs::SetElem(VMFrame &f)
                 obj->setDenseArrayElementWithType(cx, i, rval);
                 goto end_setelem;
             } else {
                 if (f.script()->hasAnalysis())
                     f.script()->analysis()->getCode(f.pc()).arrayWriteHole = true;
             }
         }
     } while (0);
-    if (!obj->setGeneric(cx, obj, id, rval.address(), strict))
+    if (!obj->setGeneric(cx, obj, id, &rval, strict))
         THROW();
   end_setelem:
     /* :FIXME: Moving the assigned object into the lowest stack slot
      * is a temporary hack. What we actually want is an implementation
      * of popAfterSet() that allows popping more than one value;
      * this logic can then be handled in Compiler.cpp. */
     regs.sp[-3] = regs.sp[-1];
 }
@@ -332,23 +332,23 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
     /*
      * 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.
      */
     Rooted<JSObject*> parent(cx, &fp->varObj());
 
     /* ES5 10.5 (NB: with subsequent errata). */
-    RootedPropertyName name(cx, fun->atom->asPropertyName());
+    PropertyName *name = fun->atom->asPropertyName();
     RootedShape shape(cx);
     RootedObject pobj(cx);
     if (!parent->lookupProperty(cx, name, &pobj, &shape))
         THROW();
 
-    RootedValue rval(cx, ObjectValue(*fun));
+    Value rval = ObjectValue(*fun);
 
     do {
         /* Steps 5d, 5f. */
         if (!shape || pobj != parent) {
             if (!parent->defineProperty(cx, name, rval,
                                         JS_PropertyStub, JS_StrictPropertyStub, attrs))
             {
                 THROW();
@@ -381,17 +381,17 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
         /*
          * Non-global properties, and global properties which we aren't simply
          * redefining, must be set.  First, this preserves their attributes.
          * Second, this will produce warnings and/or errors as necessary if the
          * specified Call object property is not writable (const).
          */
 
         /* Step 5f. */
-        if (!parent->setProperty(cx, parent, name, rval.address(), strict))
+        if (!parent->setProperty(cx, parent, name, &rval, strict))
             THROW();
     } while (false);
 }
 
 template void JS_FASTCALL stubs::DefFun<true>(VMFrame &f, JSFunction *fun);
 template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
 
 #define RELATIONAL(OP)                                                        \
@@ -460,19 +460,18 @@ stubs::Not(VMFrame &f)
 
 template <bool EQ>
 static inline bool
 StubEqualityOp(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
-    RootedValue rval_(cx, regs.sp[-1]);
-    RootedValue lval_(cx, regs.sp[-2]);
-    Value &rval = rval_.get(), &lval = lval_.get();
+    Value rval = regs.sp[-1];
+    Value lval = regs.sp[-2];
 
     bool cond;
 
     /* The string==string case is easily the hottest;  try it first. */
     if (lval.isString() && rval.isString()) {
         JSString *l = lval.toString();
         JSString *r = rval.toString();
         bool equal;
@@ -571,19 +570,18 @@ stubs::NotEqual(VMFrame &f)
     return f.regs.sp[-2].toBoolean();
 }
 
 void JS_FASTCALL
 stubs::Add(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
-    RootedValue rval_(cx, regs.sp[-1]);
-    RootedValue lval_(cx, regs.sp[-2]);
-    Value &rval = rval_.get(), &lval = lval_.get();
+    Value rval = regs.sp[-1];
+    Value lval = regs.sp[-2];
 
     /* The string + string case is easily the hottest;  try it first. */
     bool lIsString = lval.isString();
     bool rIsString = rval.isString();
     RootedString lstr(cx), rstr(cx);
     if (lIsString && rIsString) {
         lstr = lval.toString();
         rstr = rval.toString();
@@ -858,37 +856,37 @@ stubs::Neg(VMFrame &f)
     d = -d;
     if (!f.regs.sp[-1].setNumber(d))
         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
 stubs::NewInitArray(VMFrame &f, uint32_t count)
 {
-    Rooted<TypeObject*> type(f.cx, (TypeObject *) f.scratch);
     RootedObject obj(f.cx, NewDenseAllocatedArray(f.cx, count));
     if (!obj)
         THROW();
 
+    TypeObject *type = (TypeObject *) f.scratch;
     if (type) {
         obj->setType(type);
     } else {
         RootedScript script(f.cx, f.script());
         if (!SetInitializerObjectType(f.cx, script, f.pc(), obj))
             THROW();
     }
 
     f.regs.sp[0].setObject(*obj);
 }
 
 void JS_FASTCALL
 stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
 {
     JSContext *cx = f.cx;
-    Rooted<TypeObject*> type(f.cx, (TypeObject *) f.scratch);
+    TypeObject *type = (TypeObject *) f.scratch;
 
     RootedObject obj(cx);
     if (baseobj) {
         Rooted<JSObject*> base(cx, baseobj);
         obj = CopyInitializerObject(cx, base);
     } else {
         gc::AllocKind kind = GuessObjectGCKind(0);
         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
@@ -916,17 +914,17 @@ stubs::InitElem(VMFrame &f, uint32_t las
 
     /* Pop the element's value into rval. */
     JS_ASSERT(regs.stackDepth() >= 3);
     const Value &rref = regs.sp[-1];
 
     /* Find the object being initialized at top of stack. */
     const Value &lref = regs.sp[-3];
     JS_ASSERT(lref.isObject());
-    RootedObject obj(cx, &lref.toObject());
+    JSObject *obj = &lref.toObject();
 
     /* Fetch id now that we have obj. */
     RootedId id(cx);
     const Value &idval = regs.sp[-2];
     if (!FetchElementId(f.cx, obj, idval, id.address(), &regs.sp[-2]))
         THROW();
 
     /*
@@ -975,18 +973,18 @@ stubs::Lambda(VMFrame &f, JSFunction *fu
 }
 
 void JS_FASTCALL
 stubs::GetProp(VMFrame &f, PropertyName *name)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
-    RootedValue rval(cx);
-    if (!GetPropertyOperation(cx, f.script(), f.pc(), f.regs.sp[-1], rval.address()))
+    Value rval;
+    if (!GetPropertyOperation(cx, f.script(), f.pc(), f.regs.sp[-1], &rval))
         THROW();
 
     regs.sp[-1] = rval;
 }
 
 void JS_FASTCALL
 stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
 {
@@ -1019,27 +1017,28 @@ stubs::Iter(VMFrame &f, uint32_t flags)
 static void
 InitPropOrMethod(VMFrame &f, PropertyName *name, JSOp op)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
     /* Load the property's initial value into rval. */
     JS_ASSERT(regs.stackDepth() >= 2);
-    RootedValue rval(f.cx, regs.sp[-1]);
+    Value rval;
+    rval = regs.sp[-1];
 
     /* Load the object being initialized into lval/obj. */
     RootedObject obj(cx, &regs.sp[-2].toObject());
     JS_ASSERT(obj->isNative());
 
     /* Get the immediate property name into id. */
     RootedId id(cx, NameToId(name));
 
     if (JS_UNLIKELY(name == cx->runtime->atomState.protoAtom)
-        ? !baseops::SetPropertyHelper(cx, obj, obj, id, 0, rval.address(), false)
+        ? !baseops::SetPropertyHelper(cx, obj, obj, id, 0, &rval, false)
         : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
                                 JSPROP_ENUMERATE, 0, 0, 0)) {
         THROW();
     }
 }
 
 void JS_FASTCALL
 stubs::InitProp(VMFrame &f, PropertyName *name)
@@ -1430,17 +1429,17 @@ stubs::In(VMFrame &f)
     JSContext *cx = f.cx;
 
     const Value &rref = f.regs.sp[-1];
     if (!rref.isObject()) {
         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
         THROWV(JS_FALSE);
     }
 
-    RootedObject obj(cx, &rref.toObject());
+    JSObject *obj = &rref.toObject();
     RootedId id(cx);
     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id.address(), &f.regs.sp[-2]))
         THROWV(JS_FALSE);
 
     RootedObject obj2(cx);
     RootedShape prop(cx);
     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
         THROWV(JS_FALSE);
@@ -1615,16 +1614,22 @@ stubs::StrictEvalPrologue(VMFrame &f)
 void JS_FASTCALL
 stubs::HeavyweightFunctionPrologue(VMFrame &f)
 {
     if (!f.fp()->jitHeavyweightFunctionPrologue(f.cx))
         THROW();
 }
 
 void JS_FASTCALL
+stubs::TypeNestingPrologue(VMFrame &f)
+{
+    f.fp()->jitTypeNestingPrologue(f.cx);
+}
+
+void JS_FASTCALL
 stubs::Epilogue(VMFrame &f)
 {
     f.fp()->epilogue(f.cx);
 }
 
 void JS_FASTCALL
 stubs::AnyFrameEpilogue(VMFrame &f)
 {
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -165,16 +165,17 @@ void * JS_FASTCALL InvariantFailure(VMFr
 
 template <bool strict> int32_t JS_FASTCALL ConvertToTypedInt(JSContext *cx, Value *vp);
 void JS_FASTCALL ConvertToTypedFloat(JSContext *cx, Value *vp);
 
 void JS_FASTCALL Exception(VMFrame &f);
 
 void JS_FASTCALL StrictEvalPrologue(VMFrame &f);
 void JS_FASTCALL HeavyweightFunctionPrologue(VMFrame &f);
+void JS_FASTCALL TypeNestingPrologue(VMFrame &f);
 
 void JS_FASTCALL AnyFrameEpilogue(VMFrame &f);
 void JS_FASTCALL Epilogue(VMFrame &f);
 
 JSObject * JS_FASTCALL
 NewDenseUnallocatedArray(VMFrame &f, uint32_t length);
 
 void JS_FASTCALL ArrayConcatTwoArrays(VMFrame &f);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1467,17 +1467,17 @@ SetThrowHook(JSContext *cx, unsigned arg
     JS_SetThrowHook(cx->runtime, DebuggerAndThrowHandler, str);
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
 static JSBool
 LineToPC(JSContext *cx, unsigned argc, jsval *vp)
 {
-    RootedScript script(cx);
+    JSScript *script;
     int32_t lineArg = 0;
     uint32_t lineno;
     jsbytecode *pc;
 
     if (argc == 0) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
         return false;
     }
--- a/js/src/tests/js1_5/extensions/regress-300079.js
+++ b/js/src/tests/js1_5/extensions/regress-300079.js
@@ -22,17 +22,17 @@ function test()
 
   if (typeof clone == 'undefined') {
     expect = 'SKIPPED';
     actual = 'SKIPPED';
   }
   else {
     expect = 'PASSED';
 
-    f = Function("return a * a;");
+    f = Function("a", "return (function () { return a * a;});")();
     g = clone(f, {a: 3});
     f = null;
     gc();
     try {
       a_squared = g(2);
       if (a_squared != 9)
         throw "Unexpected return from g: a_squared == " + a_squared;
       actual = "PASSED";
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_1/regress/regress-452498-108.js
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 452498;
+var summary = 'TM: upvar2 regression tests';
+var actual = '';
+var expect = '';
+
+
+//-----------------------------------------------------------------------------
+test();
+//-----------------------------------------------------------------------------
+
+function test()
+{
+  enterFunc ('test');
+  printBugNumber(BUGNUMBER);
+  printStatus (summary);
+
+// ------- Comment #108 From Jesse Ruderman
+
+  function p(){p}
+
+  expect = 'function p(){p;}';
+  actual = p + '';
+
+  compareSource(expect, actual, summary);
+
+  exitFunc ('test');
+}
--- a/js/src/vm/ArgumentsObject-inl.h
+++ b/js/src/vm/ArgumentsObject-inl.h
@@ -67,27 +67,27 @@ ArgumentsObject::setArg(unsigned i, cons
 }
 
 inline const Value &
 ArgumentsObject::element(uint32_t i) const
 {
     JS_ASSERT(!isElementDeleted(i));
     const Value &v = data()->args[i];
     if (v.isMagic(JS_FORWARD_TO_CALL_OBJECT))
-        return getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().formal(i);
+        return getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().arg(i);
     return v;
 }
 
 inline void
 ArgumentsObject::setElement(uint32_t i, const Value &v)
 {
     JS_ASSERT(!isElementDeleted(i));
     HeapValue &lhs = data()->args[i];
     if (lhs.isMagic(JS_FORWARD_TO_CALL_OBJECT))
-        getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().setFormal(i, v);
+        getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall().setArg(i, v);
     else
         lhs = v;
 }
 
 inline bool
 ArgumentsObject::isElementDeleted(uint32_t i) const
 {
     JS_ASSERT(i < data()->numArgs);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -216,17 +216,17 @@ class Debugger::FrameRange
         }
     }
 };
 
 
 /*** Breakpoints *********************************************************************************/
 
 BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc)
-  : script(script), pc(pc), enabledCount(0),
+  : script(script), pc(pc), scriptGlobal(NULL), enabledCount(0),
     trapHandler(NULL), trapClosure(UndefinedValue())
 {
     JS_ASSERT(!script->hasBreakpointsAt(pc));
     JS_INIT_CLIST(&breakpoints);
 }
 
 void
 BreakpointSite::recompile(FreeOp *fop)
@@ -2100,36 +2100,36 @@ class Debugger::ScriptQuery {
     bool findScripts(AutoScriptVector *vector) {
         if (!prepareQuery())
             return false;
 
         /* Search each compartment for debuggee scripts. */
         for (CompartmentSet::Range r = compartments.all(); !r.empty(); r.popFront()) {
             for (gc::CellIter i(r.front(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
                 JSScript *script = i.get<JSScript>();
-                if (script->hasGlobal() && !script->isForEval()) {
-                    if (!consider(script, &script->global(), vector))
-                        return false;
-                }
+                GlobalObject *global = script->getGlobalObjectOrNull();
+                if (global && !consider(script, global, vector))
+                    return false;
             }
         }
 
         /*
          * Since eval scripts have no global, we need to find them via the call
          * stack, where frame's scope tells us the global in use.
          */
         for (ScriptFrameIter fri(cx); !fri.done(); ++fri) {
             if (fri.isEvalFrame()) {
                 JSScript *script = fri.script();
 
                 /*
-                 * Eval scripts were not considered above so we don't need to
-                 * check the existing script vector for duplicates.
+                 * If eval scripts never have global objects set, then we don't need
+                 * to check the existing script vector for duplicates, since we only
+                 * include scripts with globals above.
                  */
-                JS_ASSERT(script->isForEval());
+                JS_ASSERT(!script->getGlobalObjectOrNull());
 
                 GlobalObject *global = &fri.fp()->global();
                 if (!consider(script, global, vector))
                     return false;
             }
         }
 
         /*
@@ -2856,17 +2856,29 @@ DebuggerScript_getLineOffsets(JSContext 
     return true;
 }
 
 bool
 Debugger::observesScript(JSScript *script) const
 {
     if (!enabled)
         return false;
-    return observesGlobal(&script->global());
+
+    /* Does the script have a global stored in it? */
+    if (GlobalObject *global = script->getGlobalObjectOrNull())
+        return observesGlobal(global);
+
+    /* Is the script in a compartment this Debugger is debugging? */
+    JSCompartment *comp = script->compartment();
+    for (GlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
+        if (r.front()->compartment() == comp)
+            return true;
+    }
+
+    return false;
 }
 
 static JSBool
 DebuggerScript_setBreakpoint(JSContext *cx, unsigned argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.Script.setBreakpoint", 2);
     THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "setBreakpoint", args, obj, script);
     Debugger *dbg = Debugger::fromChildJSObject(obj);
@@ -2880,17 +2892,18 @@ DebuggerScript_setBreakpoint(JSContext *
     if (!ScriptOffset(cx, script, args[0], &offset))
         return false;
 
     JSObject *handler = NonNullObject(cx, args[1]);
     if (!handler)
         return false;
 
     jsbytecode *pc = script->code + offset;
-    BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc);
+    Rooted<GlobalObject *> scriptGlobal(cx, script->getGlobalObjectOrNull());
+    BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, scriptGlobal);
     if (!site)
         return false;
     site->inc(cx->runtime->defaultFreeOp());
     if (cx->runtime->new_<Breakpoint>(dbg, site, handler)) {
         args.rval().setUndefined();
         return true;
     }
     site->dec(cx->runtime->defaultFreeOp());
@@ -3172,17 +3185,17 @@ DebuggerArguments_getArg(JSContext *cx, 
     /*
      * Since getters can be extracted and applied to other objects,
      * there is no guarantee this object has an ith argument.
      */
     JS_ASSERT(i >= 0);
     Value arg;
     if (unsigned(i) < fp->numActualArgs()) {
         if (unsigned(i) < fp->numFormalArgs() && fp->script()->formalLivesInCallObject(i))
-            arg = fp->callObj().formal(i);
+            arg = fp->callObj().arg(i);
         else if (fp->script()->argsObjAliasesFormals() && fp->hasArgsObj())
             arg = fp->argsObj().arg(i);
         else
             arg = fp->unaliasedActual(i, DONT_CHECK_ALIASING);
     } else {
         arg.setUndefined();
     }
 
@@ -3404,18 +3417,19 @@ js::EvaluateInEnv(JSContext *cx, Handle<
     /*
      * NB: This function breaks the assumption that the compiler can see all
      * calls and properly compute a static level. In practice, any non-zero
      * static level will suffice.
      */
     JSPrincipals *prin = fp->scopeChain()->principals(cx);
     bool compileAndGo = true;
     bool noScriptRval = false;
+    bool needScriptGlobal = true;
     JSScript *script = frontend::CompileScript(cx, env, fp, prin, prin,
-                                               compileAndGo, noScriptRval,
+                                               compileAndGo, noScriptRval, needScriptGlobal,
                                                chars, length, filename, lineno,
                                                cx->findVersion(), NULL, /* staticLimit = */ 1);
     if (!script)
         return false;
 
     script->isActiveEval = true;
     return ExecuteKernel(cx, script, *env, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
 }
@@ -4021,20 +4035,20 @@ DebuggerObject_isSealedHelper(JSContext 
 
     AutoCompartment ac(cx, obj);
     if (!ac.enter())
         return false;
 
     ErrorCopier ec(ac, dbg->toJSObject());
     bool r;
     if (op == Seal) {
-        if (!JSObject::isSealed(cx, obj, &r))
+        if (!obj->isSealed(cx, &r))
             return false;
     } else if (op == Freeze) {
-        if (!JSObject::isFrozen(cx, obj, &r))
+        if (!obj->isFrozen(cx, &r))
             return false;
     } else {
         r = obj->isExtensible();
     }
     args.rval().setBoolean(r);
     return true;
 }
 
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -350,28 +350,36 @@ class BreakpointSite {
     friend struct ::JSScript;
     friend class Debugger;
 
   public:
     JSScript *script;
     jsbytecode * const pc;
 
   private:
+    /*
+     * The holder object for script, if known, else NULL.  This is NULL for
+     * cached eval scripts and for JSD1 traps. It is always non-null for JSD2
+     * breakpoints in held scripts.
+     */
+    GlobalObject *scriptGlobal;
+
     JSCList breakpoints;  /* cyclic list of all js::Breakpoints at this instruction */
     size_t enabledCount;  /* number of breakpoints in the list that are enabled */
     JSTrapHandler trapHandler;  /* jsdbgapi trap state */
     HeapValue trapClosure;
 
     void recompile(FreeOp *fop);
 
   public:
     BreakpointSite(JSScript *script, jsbytecode *pc);
     Breakpoint *firstBreakpoint() const;
     bool hasBreakpoint(Breakpoint *bp);
     bool hasTrap() const { return !!trapHandler; }
+    GlobalObject *getScriptGlobal() const { return scriptGlobal; }
 
     void inc(FreeOp *fop);
     void dec(FreeOp *fop);
     void setTrap(FreeOp *fop, JSTrapHandler handler, const Value &closure);
     void clearTrap(FreeOp *fop, JSTrapHandler *handlerp = NULL, Value *closurep = NULL);
     void destroyIfEmpty(FreeOp *fop);
 };
 
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -109,22 +109,22 @@ GlobalObject::initFunctionAndObjectClass
         JSObject *proto = js_NewFunction(cx, functionProto,
                                          NULL, 0, JSFUN_INTERPRETED, self, NULL);
         if (!proto)
             return NULL;
         JS_ASSERT(proto == functionProto);
         functionProto->flags |= JSFUN_PROTOTYPE;
 
         Rooted<JSScript*> script(cx, JSScript::Create(cx,
-                                                      /* enclosingScope = */ NullPtr(),
                                                       /* savedCallerFun = */ false,
                                                       /* principals = */ NULL,
                                                       /* originPrincipals = */ NULL,
                                                       /* compileAndGo = */ false,
                                                       /* noScriptRval = */ true,
+                                                      /* globalObject = */ NULL,
                                                       JSVERSION_DEFAULT,
                                                       /* staticLevel = */ 0));
         if (!script || !JSScript::fullyInitTrivial(cx, script))
             return NULL;
 
         functionProto->initScript(script);
         functionProto->getType(cx)->interpretedFunction = functionProto;
         script->setFunction(functionProto);
--- a/js/src/vm/ObjectImpl-inl.h
+++ b/js/src/vm/ObjectImpl-inl.h
@@ -145,16 +145,27 @@ inline void
 js::ObjectImpl::getSlotRange(uint32_t start, uint32_t length,
                              HeapSlot **fixedStart, HeapSlot **fixedEnd,
                              HeapSlot **slotsStart, HeapSlot **slotsEnd)
 {
     MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
     getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
 }
 
+inline bool
+js::ObjectImpl::hasContiguousSlots(uint32_t start, uint32_t count) const
+{
+    /*
+     * Check that the range [start, start+count) is either all inline or all
+     * out of line.
+     */
+    MOZ_ASSERT(slotInRange(start + count, SENTINEL_ALLOWED));
+    return start + count <= numFixedSlots() || start >= numFixedSlots();
+}
+
 inline void
 js::ObjectImpl::invalidateSlotRange(uint32_t start, uint32_t length)
 {
 #ifdef DEBUG
     MOZ_ASSERT(!isDenseArray());
 
     HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -1038,16 +1038,18 @@ class ObjectImpl : public gc::Cell
                              HeapSlot **fixedStart, HeapSlot **fixedEnd,
                              HeapSlot **slotsStart, HeapSlot **slotsEnd);
 
   protected:
     friend struct GCMarker;
     friend struct Shape;
     friend class NewObjectCache;
 
+    inline bool hasContiguousSlots(uint32_t start, uint32_t count) const;
+
     inline void invalidateSlotRange(uint32_t start, uint32_t count);
     inline void initializeSlotRange(uint32_t start, uint32_t count);
 
     /*
      * Initialize a flat array of slots to this object at a start slot.  The
      * caller must ensure that are enough slots.
      */
     void initSlotRange(uint32_t start, const Value *vector, uint32_t length);
--- a/js/src/vm/SPSProfiler.h
+++ b/js/src/vm/SPSProfiler.h
@@ -140,17 +140,17 @@ class SPSProfiler
 /*
  * This class is used in RunScript() to push the marker onto the sampling stack
  * that we're about to enter JS function calls. This is the only time in which a
  * valid stack pointer is pushed to the sampling stack.
  */
 class SPSEntryMarker
 {
     SPSProfiler *profiler;
-    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER;
   public:
     SPSEntryMarker(JSRuntime *rt JS_GUARD_OBJECT_NOTIFIER_PARAM);
     ~SPSEntryMarker();
 };
 
 } /* namespace js */
 
 #endif /* SPSProfiler_h__ */
--- a/js/src/vm/ScopeObject-inl.h
+++ b/js/src/vm/ScopeObject-inl.h
@@ -5,18 +5,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ScopeObject_inl_h___
 #define ScopeObject_inl_h___
 
 #include "ScopeObject.h"
 
-#include "jsscriptinlines.h"
-
 namespace js {
 
 inline
 ScopeCoordinate::ScopeCoordinate(jsbytecode *pc)
   : hops(GET_UINT16(pc)), slot(GET_UINT16(pc + 2))
 {
     JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
 }
@@ -69,24 +67,24 @@ CallObject::isForEval() const
 
 inline JSFunction &
 CallObject::callee() const
 {
     return *getReservedSlot(CALLEE_SLOT).toObject().toFunction();
 }
 
 inline const Value &
-CallObject::formal(unsigned i, MaybeCheckAliasing checkAliasing) const
+CallObject::arg(unsigned i, MaybeCheckAliasing checkAliasing) const
 {
     JS_ASSERT_IF(checkAliasing, callee().script()->formalLivesInCallObject(i));
     return getSlot(RESERVED_SLOTS + i);
 }
 
 inline void
-CallObject::setFormal(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing)
+CallObject::setArg(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing)
 {
     JS_ASSERT_IF(checkAliasing, callee().script()->formalLivesInCallObject(i));
     setSlot(RESERVED_SLOTS + i, v);
 }
 
 inline const Value &
 CallObject::var(unsigned i, MaybeCheckAliasing checkAliasing) const
 {
@@ -98,16 +96,35 @@ CallObject::var(unsigned i, MaybeCheckAl
 inline void
 CallObject::setVar(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing)
 {
     JSFunction &fun = callee();
     JS_ASSERT_IF(checkAliasing, fun.script()->varIsAliased(i));
     setSlot(RESERVED_SLOTS + fun.nargs + i, v);
 }
 
+inline HeapSlotArray
+CallObject::argArray()
+{
+#ifdef DEBUG
+    JSFunction &fun = callee();
+    JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS, fun.nargs));
+#endif
+    return HeapSlotArray(getSlotAddress(RESERVED_SLOTS));
+}
+
+inline HeapSlotArray
+CallObject::varArray()
+{
+    JSFunction &fun = callee();
+    JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS + fun.nargs,
+                                 fun.script()->bindings.numVars()));
+    return HeapSlotArray(getSlotAddress(RESERVED_SLOTS + fun.nargs));
+}
+
 inline uint32_t
 NestedScopeObject::stackDepth() const
 {
     return getReservedSlot(DEPTH_SLOT).toPrivateUint32();
 }
 
 inline JSObject &
 WithObject::withThis() const
@@ -149,46 +166,27 @@ BlockObject::slotValue(unsigned i)
 
 inline void
 BlockObject::setSlotValue(unsigned i, const Value &v)
 {
     JS_ASSERT(i < slotCount());
     setSlot(RESERVED_SLOTS + i, v);
 }
 
-inline void
-StaticBlockObject::initPrevBlockChainFromParser(StaticBlockObject *prev)
-{
-    setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(prev));
-}
-
-inline void
-StaticBlockObject::resetPrevBlockChainFromParser()
-{
-    setReservedSlot(SCOPE_CHAIN_SLOT, UndefinedValue());
-}
-
-inline void
-StaticBlockObject::initEnclosingStaticScope(JSObject *obj)
-{
-    JS_ASSERT(getReservedSlot(SCOPE_CHAIN_SLOT).isUndefined());
-    setReservedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(obj));
-}
-
 inline StaticBlockObject *
 StaticBlockObject::enclosingBlock() const
 {
     JSObject *obj = getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
-    return obj && obj->isStaticBlock() ? &obj->asStaticBlock() : NULL;
+    return obj ? &obj->asStaticBlock() : NULL;
 }
 
-inline JSObject *
-StaticBlockObject::enclosingStaticScope() const
+inline void
+StaticBlockObject::setEnclosingBlock(StaticBlockObject *blockObj)
 {
-    return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
+    setFixedSlot(SCOPE_CHAIN_SLOT, ObjectOrNullValue(blockObj));
 }
 
 inline void
 StaticBlockObject::setStackDepth(uint32_t depth)
 {
     JS_ASSERT(getReservedSlot(DEPTH_SLOT).isUndefined());
     initReservedSlot(DEPTH_SLOT, PrivateUint32Value(depth));
 }
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -18,124 +18,73 @@
 
 #include "ScopeObject-inl.h"
 
 using namespace js;
 using namespace js::types;
 
 /*****************************************************************************/
 
-StaticScopeIter::StaticScopeIter(JSObject *obj)
-  : obj(obj), onNamedLambda(false)
-{
-    JS_ASSERT_IF(obj, obj->isStaticBlock() || obj->isFunction());
-}
-
-bool
-StaticScopeIter::done() const
-{
-    return obj == NULL;
-}
-
-void
-StaticScopeIter::operator++(int)
-{
-    if (obj->isStaticBlock()) {
-        obj = obj->asStaticBlock().enclosingStaticScope();
-    } else if (onNamedLambda || !obj->toFunction()->isNamedLambda()) {
-        onNamedLambda = false;
-        obj = obj->toFunction()->script()->enclosingStaticScope();
-    } else {
-        onNamedLambda = true;
-    }
-    JS_ASSERT_IF(obj, obj->isStaticBlock() || obj->isFunction());
-    JS_ASSERT_IF(onNamedLambda, obj->isFunction());
-}
-
-bool
-StaticScopeIter::hasDynamicScopeObject() const
+StaticBlockObject *
+js::ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc)
 {
-    return obj->isStaticBlock()
-           ? obj->asStaticBlock().needsClone()
-           : obj->toFunction()->isHeavyweight();
-}
-
-Shape *
-StaticScopeIter::scopeShape() const
-{
-    JS_ASSERT(hasDynamicScopeObject());
-    JS_ASSERT(type() != NAMED_LAMBDA);
-    return type() == BLOCK ? block().lastProperty() : funScript()->bindings.lastShape();
-}
-
-StaticScopeIter::Type
-StaticScopeIter::type() const
-{
-    if (onNamedLambda)
-        return NAMED_LAMBDA;
-    return obj->isStaticBlock() ? BLOCK : FUNCTION;
-}
-
-StaticBlockObject &
-StaticScopeIter::block() const
-{
-    JS_ASSERT(type() == BLOCK);
-    return obj->asStaticBlock();
-}
-
-JSScript *
-StaticScopeIter::funScript() const
-{
-    JS_ASSERT(type() == FUNCTION);
-    return obj->toFunction()->script();
-}
-
-/*****************************************************************************/
-
-StaticScopeIter
-js::ScopeCoordinateToStaticScope(JSScript *script, jsbytecode *pc)
-{
-    JS_ASSERT(pc >= script->code && pc < script->code + script->length);
-    JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD);
+    ScopeCoordinate sc(pc);
 
     uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t));
-    JSObject *innermostStaticScope;
     if (blockIndex == UINT32_MAX)
-        innermostStaticScope = script->function();
-    else
-        innermostStaticScope = &script->getObject(blockIndex)->asStaticBlock();
+        return NULL;
 
-    StaticScopeIter ssi(innermostStaticScope);
-    ScopeCoordinate sc(pc);
+    StaticBlockObject *block = &script->getObject(blockIndex)->asStaticBlock();
+    unsigned i = 0;
     while (true) {
-        if (ssi.hasDynamicScopeObject()) {
-            if (!sc.hops)
-                break;
-            sc.hops--;
-        }
-        ssi++;
+        while (block && !block->needsClone())
+            block = block->enclosingBlock();
+        if (i++ == sc.hops)
+            break;
+        block = block->enclosingBlock();
     }
-    return ssi;
+    return block;
 }
 
 PropertyName *
 js::ScopeCoordinateName(JSRuntime *rt, JSScript *script, jsbytecode *pc)
 {
-    Shape::Range r = ScopeCoordinateToStaticScope(script, pc).scopeShape()->all();
+    StaticBlockObject *maybeBlock = ScopeCoordinateBlockChain(script, pc);
     ScopeCoordinate sc(pc);
+    Shape *shape = maybeBlock ? maybeBlock->lastProperty() : script->bindings.lastShape();
+    Shape::Range r = shape->all();
     while (r.front().slot() != sc.slot)
         r.popFront();
     jsid id = r.front().propid();
-
     /* Beware nameless destructuring formal. */
     if (!JSID_IS_ATOM(id))
         return rt->atomState.emptyAtom;
     return JSID_TO_ATOM(id)->asPropertyName();
 }
 
+FrameIndexType
+js::ScopeCoordinateToFrameIndex(JSScript *script, jsbytecode *pc, unsigned *index)
+{
+    ScopeCoordinate sc(pc);
+    if (StaticBlockObject *block = ScopeCoordinateBlockChain(script, pc)) {
+        *index = block->slotToLocalIndex(script->bindings, sc.slot);
+        return FrameIndex_Local;
+    }
+
+    unsigned i = sc.slot - CallObject::RESERVED_SLOTS;
+    if (i < script->bindings.numArgs()) {
+        *index = i;
+        return FrameIndex_Arg;
+    }
+
+    *index = i - script->bindings.numArgs();
+    JS_ASSERT(*index < script->bindings.numVars());
+    return FrameIndex_Local;
+}
+
 /*****************************************************************************/
 
 /*
  * Construct a call object for the given bindings.  If this is a call object
  * for a function invocation, callee should be the function being called.
  * Otherwise it must be a call object for eval of strict mode code, and callee
  * must be null.
  */
@@ -157,17 +106,28 @@ CallObject::create(JSContext *cx, JSScri
     HeapSlot *slots;
     if (!PreallocateObjectDynamicSlots(cx, shape, &slots))
         return NULL;
 
     RootedObject obj(cx, JSObject::create(cx, kind, shape, type, slots));
     if (!obj)
         return NULL;
 
-    JS_ASSERT(enclosing->global() == obj->global());
+    /*
+     * Update the parent for bindings associated with non-compileAndGo scripts,
+     * whose call objects do not have a consistent global variable and need
+     * to be updated dynamically.
+     */
+    if (&enclosing->global() != obj->getParent()) {
+        JS_ASSERT(obj->getParent() == NULL);
+        Rooted<GlobalObject*> global(cx, &enclosing->global());
+        if (!JSObject::setParent(cx, obj, global))
+            return NULL;
+    }
+
     if (!obj->asScope().setEnclosingScope(cx, enclosing))
         return NULL;
 
     obj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
 
     /*
      * If |bindings| is for a function that has extensible parents, that means
      * its Call should have its own shape; see BaseShape::extensibleParents.
@@ -186,38 +146,38 @@ CallObject::createForFunction(JSContext 
     JS_ASSERT(fp->isNonEvalFunctionFrame());
 
     RootedObject scopeChain(cx, fp->scopeChain());
 
     /*
      * For a named function expression Call's parent points to an environment
      * object holding function's name.
      */
-    if (fp->fun()->isNamedLambda()) {
+    if (js_IsNamedLambda(fp->fun())) {
         scopeChain = DeclEnvObject::create(cx, fp);
         if (!scopeChain)
             return NULL;
     }
 
     RootedScript script(cx, fp->script());
     Rooted<JSFunction*> callee(cx, &fp->callee());
     CallObject *callobj = create(cx, script, scopeChain, callee);
     if (!callobj)
         return NULL;
 
     /* Copy in the closed-over formal arguments. */
     if (script->bindingsAccessedDynamically) {
         Value *formals = fp->formals();
         for (unsigned slot = 0, n = fp->fun()->nargs; slot < n; ++slot)
-            callobj->setFormal(slot, formals[slot]);
+            callobj->setArg(slot, formals[slot]);
     } else if (unsigned n = script->numClosedArgs()) {
         Value *formals = fp->formals();
         for (unsigned i = 0; i < n; ++i) {
             uint32_t slot = script->getClosedArg(i);
-            callobj->setFormal(slot, formals[slot]);
+            callobj->setArg(slot, formals[slot]);
         }
     }
 
     return callobj;
 }
 
 void
 CallObject::copyUnaliasedValues(StackFrame *fp)
@@ -228,19 +188,19 @@ CallObject::copyUnaliasedValues(StackFra
     /* If bindings are accessed dynamically, everything is aliased. */
     if (script->bindingsAccessedDynamically)
         return;
 
     /* Copy the unaliased formals. */
     for (unsigned i = 0; i < script->bindings.numArgs(); ++i) {
         if (!script->formalLivesInCallObject(i)) {
             if (script->argsObjAliasesFormals() && fp->hasArgsObj())
-                setFormal(i, fp->argsObj().arg(i), DONT_CHECK_ALIASING);
+                setArg(i, fp->argsObj().arg(i), DONT_CHECK_ALIASING);
             else
-                setFormal(i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING), DONT_CHECK_ALIASING);
+                setArg(i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING), DONT_CHECK_ALIASING);
         }
     }
 
     /* Copy the unaliased var/let bindings. */
     for (unsigned i = 0; i < script->bindings.numVars(); ++i) {
         if (!script->varIsAliased(i))
             setVar(i, fp->unaliasedLocal(i), DONT_CHECK_ALIASING);
     }
@@ -255,30 +215,50 @@ CallObject::createForStrictEval(JSContex
 
     Rooted<JSFunction*> callee(cx, NULL);
     return create(cx, fp->script(), fp->scopeChain(), callee);
 }
 
 JSBool
 CallObject::setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp)
 {
-    /* TODO: this can totally be a data property now. */
+    CallObject &callobj = obj->asCall();
+
     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     unsigned i = (uint16_t) JSID_TO_INT(id);
-    obj->asCall().setFormal(i, *vp);
+
+    JSScript *script = callobj.callee().script();
+    JS_ASSERT(script->formalLivesInCallObject(i));
+
+    callobj.setArg(i, *vp);
+
+    if (!script->ensureHasTypes(cx))
+        return false;
+
+    TypeScript::SetArgument(cx, script, i, *vp);
     return true;
 }
 
 JSBool
 CallObject::setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp)
 {
-    /* TODO: this can totally be a data property now. */
+    CallObject &callobj = obj->asCall();
+
     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     unsigned i = (uint16_t) JSID_TO_INT(id);
-    obj->asCall().setVar(i, *vp);
+
+    JSScript *script = callobj.callee().script();
+    JS_ASSERT(script->varIsAliased(i));
+
+    callobj.setVar(i, *vp);
+
+    if (!script->ensureHasTypes(cx))
+        return false;
+
+    TypeScript::SetLocal(cx, script, i, *vp);
     return true;
 }
 
 JS_PUBLIC_DATA(Class) js::CallClass = {
     "Call",
     JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
@@ -707,46 +687,79 @@ Class js::BlockClass = {
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
+#define NO_PARENT_INDEX UINT32_MAX
+
+/*
+ * If there's a parent id, then get the parent out of our script's object
+ * array. We know that we clone block objects in outer-to-inner order, which
+ * means that getting the parent now will work.
+ */
+static uint32_t
+FindObjectIndex(JSScript *script, StaticBlockObject *maybeBlock)
+{
+    if (!maybeBlock || !script->hasObjects())
+        return NO_PARENT_INDEX;
+
+    ObjectArray *objects = script->objects();
+    HeapPtrObject *vector = objects->vector;
+    unsigned length = objects->length;
+    for (unsigned i = 0; i < length; ++i) {
+        if (vector[i] == maybeBlock)
+            return i;
+    }
+
+    return NO_PARENT_INDEX;
+}
+
 template<XDRMode mode>
 bool
-js::XDRStaticBlockObject(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript script,
-                         StaticBlockObject **objp)
+js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp)
 {
     /* NB: Keep this in sync with CloneStaticBlockObject. */
 
     JSContext *cx = xdr->cx();
 
     Rooted<StaticBlockObject*> obj(cx);
+    uint32_t parentId = 0;
     uint32_t count = 0;
     uint32_t depthAndCount = 0;
-
     if (mode == XDR_ENCODE) {
         obj = *objp;
+        parentId = FindObjectIndex(script, obj->enclosingBlock());
         uint32_t depth = obj->stackDepth();
         JS_ASSERT(depth <= UINT16_MAX);
         count = obj->slotCount();
         JS_ASSERT(count <= UINT16_MAX);
         depthAndCount = (depth << 16) | uint16_t(count);
     }
 
+    /* First, XDR the parent atomid. */
+    if (!xdr->codeUint32(&parentId))
+        return false;
+
     if (mode == XDR_DECODE) {
         obj = StaticBlockObject::create(cx);
         if (!obj)
             return false;
-        obj->initEnclosingStaticScope(enclosingScope);
         *objp = obj;
+
+        obj->setEnclosingBlock(parentId == NO_PARENT_INDEX
+                               ? NULL
+                               : &script->getObject(parentId)->asStaticBlock());
     }
 
+    AutoObjectRooter tvr(cx, obj);
+
     if (!xdr->codeUint32(&depthAndCount))
         return false;
 
     if (mode == XDR_DECODE) {
         uint32_t depth = uint16_t(depthAndCount >> 16);
         count = uint16_t(depthAndCount);
         obj->setStackDepth(depth);
 
@@ -811,31 +824,36 @@ js::XDRStaticBlockObject(XDRState<mode> 
             if (!xdr->codeUint32(&aliased))
                 return false;
         }
     }
     return true;
 }
 
 template bool
-js::XDRStaticBlockObject(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, StaticBlockObject **);
+js::XDRStaticBlockObject(XDRState<XDR_ENCODE> *xdr, JSScript *script, StaticBlockObject **objp);
 
 template bool
-js::XDRStaticBlockObject(XDRState<XDR_DECODE> *, HandleObject, HandleScript, StaticBlockObject **);
+js::XDRStaticBlockObject(XDRState<XDR_DECODE> *xdr, JSScript *script, StaticBlockObject **objp);
 
 JSObject *
-js::CloneStaticBlockObject(JSContext *cx, HandleObject enclosingScope, Handle<StaticBlockObject*> srcBlock)
+js::CloneStaticBlockObject(JSContext *cx, Handle<StaticBlockObject*> srcBlock,
+                           const AutoObjectVector &objects, JSScript *src)
 {
     /* NB: Keep this in sync with XDRStaticBlockObject. */
 
     Rooted<StaticBlockObject*> clone(cx, StaticBlockObject::create(cx));
     if (!clone)
         return NULL;
 
-    clone->initEnclosingStaticScope(enclosingScope);
+    uint32_t parentId = FindObjectIndex(src, srcBlock->enclosingBlock());
+    clone->setEnclosingBlock(parentId == NO_PARENT_INDEX
+                             ? NULL
+                             : &objects[parentId]->asStaticBlock());
+
     clone->setStackDepth(srcBlock->stackDepth());
 
     /* Shape::Range is reverse order, so build a list in forward order. */
     AutoShapeVector shapes(cx);
     if (!shapes.growBy(srcBlock->slotCount()))
         return NULL;
     for (Shape::Range r = srcBlock->lastProperty()->all(); !r.empty(); r.popFront())
         shapes[r.front().shortid()] = &r.front();
@@ -1160,19 +1178,19 @@ class DebugScopeProxy : public BaseProxy
                     } else {
                         if (action == GET)
                             *vp = maybefp->unaliasedFormal(i, DONT_CHECK_ALIASING);
                         else
                             maybefp->unaliasedFormal(i, DONT_CHECK_ALIASING) = *vp;
                     }
                 } else {
                     if (action == GET)
-                        *vp = callobj.formal(i, DONT_CHECK_ALIASING);
+                        *vp = callobj.arg(i, DONT_CHECK_ALIASING);
                     else
-                        callobj.setFormal(i, *vp, DONT_CHECK_ALIASING);
+                        callobj.setArg(i, *vp, DONT_CHECK_ALIASING);
                 }
 
                 if (action == SET)
                     TypeScript::SetArgument(cx, script, i, *vp);
 
                 return true;
             }
 
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -14,102 +14,52 @@
 
 #include "gc/Barrier.h"
 
 namespace js {
 
 /*****************************************************************************/
 
 /*
- * All function scripts have an "enclosing static scope" that refers to the
- * innermost enclosing let or function in the program text. This allows full
- * reconstruction of the lexical scope for debugging or compiling efficient
- * access to variables in enclosing scopes. The static scope is represented at
- * runtime by a tree of compiler-created objects representing each scope:
- *  - a StaticBlockObject is created for 'let' and 'catch' scopes
- *  - a JSFunction+JSScript+Bindings trio is created for function scopes
- * (These objects are primarily used to clone objects scopes for the
- * dynamic scope chain.)
- *
- * There is an additional scope for named lambdas. E.g., in:
- *
- *   (function f() { var x; function g() { } })
- *
- * g's innermost enclosing scope will first be the function scope containing
- * 'x', enclosed by a scope containing only the name 'f'. (This separate scope
- * is necessary due to the fact that declarations in the function scope shadow
- * (dynamically, in the case of 'eval') the lambda name.)
- *
- * There are two limitations to the current lexical nesting information:
- *
- *  - 'with' is completely absent; this isn't a problem for the current use
- *    cases since 'with' causes every static scope to be on the dynamic scope
- *    chain (so the debugger can find everything) and inhibits all upvar
- *    optimization.
- *
- *  - The "enclosing static scope" chain stops at 'eval'. For example in:
- *      let (x) { eval("function f() {}") }
- *    f does not have an enclosing static scope. This is fine for current uses
- *    for the same reason as 'with'.
- *
- * (See also AssertDynamicScopeMatchesStaticScope.)
- */
-class StaticScopeIter
-{
-    JSObject *obj;
-    bool onNamedLambda;
-
-  public:
-    explicit StaticScopeIter(JSObject *obj);
-
-    bool done() const;
-    void operator++(int);
-
-    /* Return whether this static scope will be on the dynamic scope chain. */
-    bool hasDynamicScopeObject() const;
-    Shape *scopeShape() const;
-
-    enum Type { BLOCK, FUNCTION, NAMED_LAMBDA };
-    Type type() const;
-
-    StaticBlockObject &block() const;
-    JSScript *funScript() const;
-};
-
-/*****************************************************************************/
-
-/*
  * A "scope coordinate" describes how to get from head of the scope chain to a
  * given lexically-enclosing variable. A scope coordinate has two dimensions:
  *  - hops: the number of scope objects on the scope chain to skip
- *  - slot: the slot on the scope object holding the variable's value
+ *  - binding: which binding on the scope object
  * Additionally (as described in jsopcode.tbl) there is a 'block' index, but
  * this is only needed for decompilation/inference so it is not included in the
- * main ScopeCoordinate struct: use ScopeCoordinate{BlockChain,Name} instead.
+ * main ScopeCoordinate struct: use ScopeCoordinate{BlockChain,Atom} instead.
  */
 struct ScopeCoordinate
 {
     uint16_t hops;
     uint16_t slot;
 
     inline ScopeCoordinate(jsbytecode *pc);
     inline ScopeCoordinate() {}
 };
 
-/*
- * Return a scope iterator pointing at the static scope containing the variable
- * accessed by the ALIASEDVAR op at 'pc'.
- */
-extern StaticScopeIter
-ScopeCoordinateToStaticScope(JSScript *script, jsbytecode *pc);
+/* Return the static block chain (or null) accessed by *pc. */
+extern StaticBlockObject *
+ScopeCoordinateBlockChain(JSScript *script, jsbytecode *pc);
 
 /* Return the name being accessed by the given ALIASEDVAR op. */
 extern PropertyName *
 ScopeCoordinateName(JSRuntime *rt, JSScript *script, jsbytecode *pc);
 
+/*
+ * The 'slot' of a ScopeCoordinate is relative to the scope object. Type
+ * inference and jit compilation are instead relative to frame values (even if
+ * these values are aliased and thus never accessed, the the index of the
+ * variable is used to refer to the jit/inference information). This function
+ * maps from the ScopeCoordinate space to the StackFrame variable space.
+ */
+enum FrameIndexType { FrameIndex_Local, FrameIndex_Arg };
+extern FrameIndexType
+ScopeCoordinateToFrameIndex(JSScript *script, jsbytecode *pc, unsigned *index);
+
 /*****************************************************************************/
 
 /*
  * Scope objects
  *
  * Scope objects are technically real JSObjects but only belong on the scope
  * chain (that is, fp->scopeChain() or fun->environment()). The hierarchy of
  * scope objects is:
@@ -189,25 +139,32 @@ class CallObject : public ScopeObject
     inline bool isForEval() const;
 
     /*
      * Returns the function for which this CallObject was created. (This may
      * only be called if !isForEval.)
      */
     inline JSFunction &callee() const;
 
-    /* Get/set the formal argument at the given index. */
-    inline const Value &formal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
-    inline void setFormal(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
+    /* Returns the formal argument at the given index. */
+    inline const Value &arg(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
+    inline void setArg(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
 
-    /* Get/set the variable at the given index. */
+    /* Returns the variable at the given index. */
     inline const Value &var(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
     inline void setVar(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
 
-    /* Internal property ops for CallObject dynamic access via scope chain. */
+    /*
+     * Get the actual arrays of arguments and variables. Only call if type
+     * inference is enabled, where we ensure that call object variables are in
+     * contiguous slots (see NewCallObject).
+     */
+    inline HeapSlotArray argArray();
+    inline HeapSlotArray varArray();
+
     static JSBool setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp);
     static JSBool setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp);
 
     /* Copy in all the unaliased formals and locals. */
     void copyUnaliasedValues(StackFrame *fp);
 };
 
 class DeclEnvObject : public ScopeObject
@@ -274,65 +231,41 @@ class BlockObject : public NestedScopeOb
     inline void setSlotValue(unsigned i, const Value &v);
 };
 
 class StaticBlockObject : public BlockObject
 {
   public:
     static StaticBlockObject *create(JSContext *cx);
 
-    /* See StaticScopeIter comment. */
-    inline JSObject *enclosingStaticScope() const;
-
-    /*
-     * A refinement of enclosingStaticScope that returns NULL if the enclosing
-     * static scope is a JSFunction.
-     */
     inline StaticBlockObject *enclosingBlock() const;
-
-    /*
-     * Return whether this StaticBlockObject contains a variable stored at
-     * the given stack depth (i.e., fp->base()[depth]).
-     */
-    bool containsVarAtDepth(uint32_t depth);
+    inline void setEnclosingBlock(StaticBlockObject *blockObj);
 
-    /*
-     * A let binding is aliased if accessed lexically by nested functions or
-     * dynamically through dynamic name lookup (eval, with, function::, etc).
-     */
-    bool isAliased(unsigned i);
-
-    /*
-     * A static block object is cloned (when entering the block) iff some
-     * variable of the block isAliased.
-     */
-    bool needsClone();
-
-    /* Frontend-only functions ***********************************************/
-
-    /* Initialization functions for above fields. */
-    void setAliased(unsigned i, bool aliased);
     void setStackDepth(uint32_t depth);
-    void initEnclosingStaticScope(JSObject *obj);
+    bool containsVarAtDepth(uint32_t depth);
 
     /*
      * Frontend compilation temporarily uses the object's slots to link
      * a let var to its associated Definition parse node.
      */
     void setDefinitionParseNode(unsigned i, Definition *def);
     Definition *maybeDefinitionParseNode(unsigned i);
 
     /*
-     * The parser uses 'enclosingBlock' as the prev-link in the tc->blockChain
-     * stack. Note: in the case of hoisting, this prev-link will not ultimately
-     * be the same as enclosingBlock, initEnclosingStaticScope must be called
-     * separately in the emitter. 'reset' is just for asserting stackiness.
+     * A let binding is aliased is accessed lexically by nested functions or
+     * dynamically through dynamic name lookup (eval, with, function::, etc).
      */
-    void initPrevBlockChainFromParser(StaticBlockObject *prev);
-    void resetPrevBlockChainFromParser();
+    void setAliased(unsigned i, bool aliased);
+    bool isAliased(unsigned i);
+
+    /*
+     * A static block object is cloned (when entering the block) iff some
+     * variable of the block isAliased.
+     */
+    bool needsClone();
 
     static Shape *addVar(JSContext *cx, Handle<StaticBlockObject*> block, HandleId id,
                          int index, bool *redeclared);
 };
 
 class ClonedBlockObject : public BlockObject
 {
   public:
@@ -347,21 +280,21 @@ class ClonedBlockObject : public BlockOb
     void setVar(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
 
     /* Copy in all the unaliased formals and locals. */
     void copyUnaliasedValues(StackFrame *fp);
 };
 
 template<XDRMode mode>
 bool
-XDRStaticBlockObject(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript script,
-                     StaticBlockObject **objp);
+XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp);
 
 extern JSObject *
-CloneStaticBlockObject(JSContext *cx, HandleObject enclosingScope, Handle<StaticBlockObject*> src);
+CloneStaticBlockObject(JSContext *cx, Handle<StaticBlockObject*> srcBlock,
+                       const AutoObjectVector &objects, JSScript *src);
 
 /*****************************************************************************/
 
 class ScopeIterKey;
 
 /*
  * A scope iterator describes the active scopes enclosing the current point of
  * execution for a single frame, proceeding from inner to outer. Here, "frame"
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -181,20 +181,32 @@ StackFrame::jitHeavyweightFunctionProlog
 
     CallObject *callobj = CallObject::createForFunction(cx, this);
     if (!callobj)
         return false;
 
     pushOnScopeChain(*callobj);
     flags_ |= HAS_CALL_OBJ;
 
+    if (script()->nesting()) {
+        types::NestingPrologue(cx, this);
+        flags_ |= HAS_NESTING;
+    }
+
     return true;
 }
 
 inline void
+StackFrame::jitTypeNestingPrologue(JSContext *cx)
+{
+    types::NestingPrologue(cx, this);
+    flags_ |= HAS_NESTING;
+}
+
+inline void
 StackFrame::initVarsToUndefined()
 {
     SetValueRangeToUndefined(slots(), script()->nfixed);
 }
 
 inline JSObject *
 StackFrame::createRestParameter(JSContext *cx)
 {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -217,52 +217,16 @@ StackFrame::pcQuadratic(const ContextSta
      */
     if (StackFrame *next = seg.computeNextFrame(this, maxDepth))
         return next->prevpc();
 
     /* If we hit the limit, just return the beginning of the script. */
     return regs.fp()->script()->code;
 }
 
-static inline void
-AssertDynamicScopeMatchesStaticScope(JSScript *script, JSObject *scope)
-{
-#ifdef DEBUG
-    for (StaticScopeIter i(script->enclosingStaticScope()); !i.done(); i++) {
-        if (i.hasDynamicScopeObject()) {
-            /*
-             * 'with' does not participate in the static scope of the script,
-             * but it does in the dynamic scope, so skip them here.
-             */
-            while (scope->isWith())
-                scope = &scope->asWith().enclosingScope();
-
-            switch (i.type()) {
-              case StaticScopeIter::BLOCK:
-                JS_ASSERT(i.block() == scope->asClonedBlock().staticBlock());
-                scope = &scope->asClonedBlock().enclosingScope();
-                break;
-              case StaticScopeIter::FUNCTION:
-                JS_ASSERT(i.funScript() == scope->asCall().callee().script());
-                scope = &scope->asCall().enclosingScope();
-                break;
-              case StaticScopeIter::NAMED_LAMBDA:
-                scope = &scope->asDeclEnv().enclosingScope();
-                break;
-            }
-        }
-    }
-
-    /*
-     * Ideally, we'd JS_ASSERT(!scope->isScope()) but the enclosing lexical
-     * scope chain stops at eval() boundaries. See StaticScopeIter comment.
-     */
-#endif
-}
-
 bool
 StackFrame::prologue(JSContext *cx, bool newType)
 {
     JS_ASSERT(!isDummyFrame());
     JS_ASSERT(!isGeneratorFrame());
     JS_ASSERT(cx->regs().pc == script()->code);
 
     if (isEvalFrame()) {
@@ -278,26 +242,30 @@ StackFrame::prologue(JSContext *cx, bool
     }
 
     if (isGlobalFrame()) {
         Probes::enterScript(cx, script(), NULL, this);
         return true;
     }
 
     JS_ASSERT(isNonEvalFunctionFrame());
-    AssertDynamicScopeMatchesStaticScope(script(), scopeChain());
 
     if (fun()->isHeavyweight()) {
         CallObject *callobj = CallObject::createForFunction(cx, this);
         if (!callobj)
             return false;
         pushOnScopeChain(*callobj);
         flags_ |= HAS_CALL_OBJ;
     }
 
+    if (script()->nesting()) {
+        types::NestingPrologue(cx, this);
+        flags_ |= HAS_NESTING;
+    }
+
     if (isConstructing()) {
         RootedObject callee(cx, &this->callee());
         JSObject *obj = js_CreateThisForFunction(cx, callee, newType);
         if (!obj)
             return false;
         functionThis() = ObjectValue(*obj);
     }
 
@@ -331,25 +299,28 @@ StackFrame::epilogue(JSContext *cx)
     }
 
     if (isGlobalFrame()) {
         JS_ASSERT(!scopeChain()->isScope());
         return;
     }
 
     JS_ASSERT(isNonEvalFunctionFrame());
-
-    if (fun()->isHeavyweight())
+    if (fun()->isHeavyweight()) {
         JS_ASSERT_IF(hasCallObj(), scopeChain()->asCall().callee().script() == script());
-    else
-        AssertDynamicScopeMatchesStaticScope(script(), scopeChain());
+    } else {
+        JS_ASSERT(!scopeChain()->isCall() || scopeChain()->asCall().isForEval() ||
+                  scopeChain()->asCall().callee().script() != script());
+    }
 
     if (cx->compartment->debugMode())
         cx->runtime->debugScopes->onPopCall(this, cx);
 
+    if (script()->nesting() && (flags_ & HAS_NESTING))
+        types::NestingEpilogue(this);
 
     if (isConstructing() && returnValue().isPrimitive())
         setReturnValue(ObjectValue(constructorThis()));
 }
 
 bool
 StackFrame::jitStrictEvalPrologue(JSContext *cx)
 {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -202,17 +202,17 @@ CallArgsListFromVp(unsigned argc, Value 
 enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
 
 /*****************************************************************************/
 
 /* Flags specified for a frame as it is constructed. */
 enum InitialFrameFlags {
     INITIAL_NONE           =          0,
     INITIAL_CONSTRUCT      =       0x40, /* == StackFrame::CONSTRUCTING, asserted below */
-    INITIAL_LOWERED        =   0x100000  /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
+    INITIAL_LOWERED        =   0x200000  /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
 };
 
 enum ExecuteType {
     EXECUTE_GLOBAL         =        0x1, /* == StackFrame::GLOBAL */
     EXECUTE_DIRECT_EVAL    =        0x8, /* == StackFrame::EVAL */
     EXECUTE_INDIRECT_EVAL  =        0x9, /* == StackFrame::GLOBAL | EVAL */
     EXECUTE_DEBUG          =       0x18  /* == StackFrame::EVAL | DEBUGGER */
 };
@@ -240,34 +240,35 @@ class StackFrame
 
         /* Function arguments */
         OVERFLOW_ARGS      =      0x200,  /* numActualArgs > numFormalArgs */
         UNDERFLOW_ARGS     =      0x400,  /* numActualArgs < numFormalArgs */
 
         /* Function prologue state */
         HAS_CALL_OBJ       =      0x800,  /* CallObject created for heavyweight fun */
         HAS_ARGS_OBJ       =     0x1000,  /* ArgumentsObject created for needsArgsObj script */
+        HAS_NESTING        =     0x2000,  /* NestingPrologue called for frame */
 
         /* Lazy frame initialization */
-        HAS_HOOK_DATA      =     0x2000,  /* frame has hookData_ set */
-        HAS_ANNOTATION     =     0x4000,  /* frame has annotation_ set */
-        HAS_RVAL           =     0x8000,  /* frame has rval_ set */
-        HAS_SCOPECHAIN     =    0x10000,  /* frame has scopeChain_ set */
-        HAS_PREVPC         =    0x20000,  /* frame has prevpc_ and prevInline_ set */
-        HAS_BLOCKCHAIN     =    0x40000,  /* frame has blockChain_ set */
+        HAS_HOOK_DATA      =     0x4000,  /* frame has hookData_ set */
+        HAS_ANNOTATION     =     0x8000,  /* frame has annotation_ set */
+        HAS_RVAL           =    0x10000,  /* frame has rval_ set */
+        HAS_SCOPECHAIN     =    0x20000,  /* frame has scopeChain_ set */
+        HAS_PREVPC         =    0x40000,  /* frame has prevpc_ and prevInline_ set */
+        HAS_BLOCKCHAIN     =    0x80000,  /* frame has blockChain_ set */
 
         /* Method JIT state */
-        DOWN_FRAMES_EXPANDED =  0x80000,  /* inlining in down frames has been expanded */
-        LOWERED_CALL_APPLY   = 0x100000,  /* Pushed by a lowered call/apply */
+        DOWN_FRAMES_EXPANDED = 0x100000,  /* inlining in down frames has been expanded */
+        LOWERED_CALL_APPLY   = 0x200000,  /* Pushed by a lowered call/apply */
 
         /* Debugger state */
-        PREV_UP_TO_DATE    =   0x200000,  /* see DebugScopes::updateLiveScopes */
+        PREV_UP_TO_DATE    =   0x400000,  /* see DebugScopes::updateLiveScopes */
 
         /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
-        HAS_PUSHED_SPS_FRAME = 0x400000  /* SPS was notified of enty */
+        HAS_PUSHED_SPS_FRAME = 0x800000  /* SPS was notified of enty */
     };
 
   private:
     mutable uint32_t    flags_;         /* bits described by Flags */
     union {                             /* describes what code is executing in a */
         JSScript        *script;        /*   global frame */
         JSFunction      *fun;           /*   function frame, pre GetScopeChain */
     } exec;
@@ -364,16 +365,17 @@ class StackFrame
      * there is one) should be given a new singleton type.
      */
 
     bool prologue(JSContext *cx, bool newType);
     void epilogue(JSContext *cx);
 
     /* Subsets of 'prologue' called from jit code. */
     inline bool jitHeavyweightFunctionPrologue(JSContext *cx);
+    inline void jitTypeNestingPrologue(JSContext *cx);
     bool jitStrictEvalPrologue(JSContext *cx);
 
     /* Initialize local variables of newly-pushed frame. */
     void initVarsToUndefined();
 
     /*
      * Stack frame type
      *
--- a/js/src/vm/Xdr.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -118,42 +118,37 @@ VersionCheck(XDRState<mode> *xdr)
 
 template<XDRMode mode>
 bool
 XDRState<mode>::codeFunction(JSObject **objp)
 {
     if (mode == XDR_DECODE)
         *objp = NULL;
 
-    if (!VersionCheck(this))
-        return false;
-
-    return XDRInterpretedFunction(this, NullPtr(), NullPtr(), objp);
+    return VersionCheck(this) && XDRInterpretedFunction(this, objp, NULL);
 }
 
 template<XDRMode mode>
 bool
 XDRState<mode>::codeScript(JSScript **scriptp)
 {
     JSScript *script;
     if (mode == XDR_DECODE) {
         script = NULL;
         *scriptp = NULL;
     } else {
         script = *scriptp;
     }
 
-    if (!VersionCheck(this))
-        return false;
-
-    if (!XDRScript(this, NullPtr(), NullPtr(), NullPtr(), &script))
+    if (!VersionCheck(this) || !XDRScript(this, &script, NULL))
         return false;
 
     if (mode == XDR_DECODE) {
         JS_ASSERT(!script->compileAndGo);
+        script->globalObject = GetCurrentGlobal(cx());
         js_CallNewScriptHook(cx(), script, NULL);
         Debugger::onNewScript(cx(), script, NULL);
         *scriptp = script;
     }
 
     return true;
 }
 
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -20,17 +20,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 120);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 119);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
 
     JSContext *cx() const {
         return context;