bug 684529 - remove script object. r=jorendorff
authorIgor Bukanov <igor@mir2.org>
Thu, 22 Sep 2011 12:08:55 +0200
changeset 80504 d6f9285f623e48e540ea777dbd0d01be0deb8a0f
parent 80503 ce4005246dc96ec22d8210b027467695a2be46d4
child 80505 34bf415c96bbc55059400aef440edc92e52285a3
push idunknown
push userunknown
push dateunknown
reviewersjorendorff
bugs684529
milestone10.0a1
bug 684529 - remove script object. r=jorendorff
dom/base/nsJSEnvironment.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeGenerator.h
js/src/jsapi.cpp
js/src/jsapi.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/jsgcmark.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsxdrapi.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
js/src/vm/GlobalObject.h
js/xpconnect/src/nsXPConnect.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1638,17 +1638,17 @@ nsJSContext::ExecuteScript(void *aScript
   // operation callback or from ScriptEvaluated.
   jsval val;
   JSBool ok;
 
   JSScript *script = static_cast<JSScript *>(aScriptObject);
   nsCOMPtr<nsIPrincipal> principal;
 
   rv = sSecurityManager->GetObjectPrincipal(mContext,
-                                            JS_GetObjectFromScript(script),
+                                            JS_GetGlobalFromScript(script),
                                             getter_AddRefs(principal));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsJSContext::TerminationFuncHolder holder(this);
   JSAutoRequest ar(mContext);
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -67,17 +67,17 @@ BytecodeCompiler::compileScript(JSContex
                                 uintN staticLevel /* = 0 */)
 {
     TokenKind tt;
     ParseNode *pn;
     JSScript *script;
     bool inDirectivePrologue;
 
     JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_NEED_MUTABLE_SCRIPT |
-                            TCF_COMPILE_FOR_EVAL | TCF_NEED_SCRIPT_OBJECT)));
+                            TCF_COMPILE_FOR_EVAL | TCF_NEED_SCRIPT_GLOBAL)));
 
     /*
      * The scripted callerFrame can only be given for compile-and-go scripts
      * and non-zero static level requires callerFrame.
      */
     JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO);
     JS_ASSERT_IF(staticLevel != 0, callerFrame);
 
--- a/js/src/frontend/BytecodeGenerator.h
+++ b/js/src/frontend/BytecodeGenerator.h
@@ -270,17 +270,17 @@ struct StmtInfo {
  * This flag is *not* inherited by enclosed or enclosing functions; it
  * applies only to the function in whose flags it appears.
  */
 #define TCF_FUN_EXTENSIBLE_SCOPE 0x20000000
 
 /*
  * The caller is JS_Compile*Script*.
  */
-#define TCF_NEED_SCRIPT_OBJECT 0x40000000
+#define TCF_NEED_SCRIPT_GLOBAL 0x40000000
 
 /*
  * Flags to check for return; vs. return expr; in a function.
  */
 #define TCF_RETURN_FLAGS        (TCF_RETURN_EXPR | TCF_RETURN_VOID)
 
 /*
  * Sticky deoptimization flags to propagate from FunctionBody.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1273,40 +1273,43 @@ JS_EnterCrossCompartmentCall(JSContext *
         return NULL;
     if (!call->enter()) {
         Foreground::delete_(call);
         return NULL;
     }
     return reinterpret_cast<JSCrossCompartmentCall *>(call);
 }
 
+namespace js {
+
 // Declared in jscompartment.h
-JSClass js_dummy_class = {
+Class dummy_class = {
     "jdummy",
     JSCLASS_GLOBAL_FLAGS,
     JS_PropertyStub,  JS_PropertyStub,
     JS_PropertyStub,  JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub,
-    JS_ConvertStub,   NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    JS_ConvertStub
 };
 
+} /*namespace js */
+
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
 {
     CHECK_REQUEST(cx);
-
-    JSObject *scriptObject = target->u.object;
-    if (!scriptObject) {
+    JS_ASSERT(!target->isCachedEval);
+    GlobalObject *global = target->u.globalObject;
+    if (!global) {
         SwitchToCompartment sc(cx, target->compartment());
-        scriptObject = JS_NewGlobalObject(cx, &js_dummy_class);
-        if (!scriptObject)
+        global = GlobalObject::create(cx, &dummy_class);
+        if (!global)
             return NULL;
     }
-    return JS_EnterCrossCompartmentCall(cx, scriptObject);
+    return JS_EnterCrossCompartmentCall(cx, global);
 }
 
 JS_PUBLIC_API(JSCrossCompartmentCall *)
 JS_EnterCrossCompartmentCallStackFrame(JSContext *cx, JSStackFrame *target)
 {
     CHECK_REQUEST(cx);
 
     return JS_EnterCrossCompartmentCall(cx, Valueify(target)->scopeChain().getGlobal());
@@ -4577,17 +4580,17 @@ CompileUCScriptForPrincipalsCommon(JSCon
                                       const jschar *chars, size_t length,
                                       const char *filename, uintN lineno, JSVersion version)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     AutoLastFrameCheck lfc(cx);
 
-    uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT;
+    uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_GLOBAL;
     return BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, chars, length,
                                            filename, lineno, version);
 }
 
 extern JS_PUBLIC_API(JSScript *)
 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
                                        JSPrincipals *principals,
                                        const jschar *chars, size_t length,
@@ -4754,17 +4757,17 @@ CompileFileHelper(JSContext *cx, JSObjec
         // The |i < len| is necessary for files that lie about their length,
         // e.g. /dev/zero and /dev/random.  See bug 669434.
         while (i < len && (c = fast_getc(fp)) != EOF)
             buf[i++] = (jschar) (unsigned char) c;
     }
 
     JS_ASSERT(i <= len);
     len = i;
-    uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_OBJECT;
+    uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT | TCF_NEED_SCRIPT_GLOBAL;
     script = BytecodeCompiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len,
                                              filename, 1, cx->findVersion());
     cx->free_(buf);
     return script;
 }
 
 JS_PUBLIC_API(JSScript *)
 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
@@ -4815,21 +4818,22 @@ JS_CompileFileHandleForPrincipalsVersion
 JS_PUBLIC_API(JSScript *)
 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_GetObjectFromScript(JSScript *script)
-{
-    JS_ASSERT(script->u.object);
-
-    return script->u.object;
+JS_GetGlobalFromScript(JSScript *script)
+{
+    JS_ASSERT(!script->isCachedEval);
+    JS_ASSERT(script->u.globalObject);
+
+    return script->u.globalObject;
 }
 
 static JSFunction *
 CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
                                      JSPrincipals *principals, const char *name,
                                      uintN nargs, const char **argnames,
                                      const jschar *chars, size_t length,
                                      const char *filename, uintN lineno, JSVersion version)
@@ -5013,17 +5017,17 @@ bool
 EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
                                     JSPrincipals *principals,
                                     const jschar *chars, uintN length,
                                     const char *filename, uintN lineno,
                                     jsval *rval, JSVersion compileVersion)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
 
-    uint32 flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_OBJECT;
+    uint32 flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_GLOBAL;
     if (!rval)
         flags |= TCF_NO_SCRIPT_RVAL;
 
     CHECK_REQUEST(cx);
     AutoLastFrameCheck lfc(cx);
     JSScript *script = BytecodeCompiler::compileScript(cx, obj, NULL, principals, flags, chars,
                                                        length, filename, lineno, compileVersion);
     if (!script)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3812,17 +3812,17 @@ JS_CompileFileHandleForPrincipals(JSCont
 
 extern JS_PUBLIC_API(JSScript *)
 JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj,
                                          const char *filename, FILE *fh,
                                          JSPrincipals *principals,
                                          JSVersion version);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_GetObjectFromScript(JSScript *script);
+JS_GetGlobalFromScript(JSScript *script);
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
                    uintN nargs, const char **argnames,
                    const char *bytes, size_t length,
                    const char *filename, uintN lineno);
 
 extern JS_PUBLIC_API(JSFunction *)
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -203,18 +203,18 @@ class CompartmentChecker
                     check(ida->vector[i]);
             }
         }
     }
 
     void check(JSScript *script) {
         if (script) {
             check(script->compartment());
-            if (script->u.object)
-                check(script->u.object);
+            if (!script->isCachedEval && script->u.globalObject)
+                check(script->u.globalObject);
         }
     }
 
     void check(StackFrame *fp) {
         check(&fp->scopeChain());
     }
 };
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -273,17 +273,17 @@ JSCompartment::wrap(JSContext *cx, Value
     }
 
     /* If we already have a wrapper for this value, use it. */
     if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) {
         *vp = p->value;
         if (vp->isObject()) {
             JSObject *obj = &vp->toObject();
             JS_ASSERT(obj->isCrossCompartmentWrapper());
-            if (global->getJSClass() != &js_dummy_class && obj->getParent() != global) {
+            if (global->getClass() != &dummy_class && obj->getParent() != global) {
                 do {
                     obj->setParent(global);
                     obj = obj->getProto();
                 } while (obj && obj->isCrossCompartmentWrapper());
             }
         }
         return true;
     }
@@ -856,39 +856,36 @@ JSCompartment::removeDebuggee(JSContext 
 BreakpointSite *
 JSCompartment::getBreakpointSite(jsbytecode *pc)
 {
     BreakpointSiteMap::Ptr p = breakpointSites.lookup(pc);
     return p ? p->value : NULL;
 }
 
 BreakpointSite *
-JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc, JSObject *scriptObject)
+JSCompartment::getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc,
+                                         GlobalObject *scriptGlobal)
 {
     JS_ASSERT(script->code <= pc);
     JS_ASSERT(pc < script->code + script->length);
-    JS_ASSERT_IF(scriptObject, scriptObject->isScript() || scriptObject->isFunction());
-    JS_ASSERT_IF(scriptObject && scriptObject->isFunction(),
-                 scriptObject->getFunctionPrivate()->script() == script);
-    JS_ASSERT_IF(scriptObject && scriptObject->isScript(), scriptObject->getScript() == script);
 
     BreakpointSiteMap::AddPtr p = breakpointSites.lookupForAdd(pc);
     if (!p) {
         BreakpointSite *site = cx->runtime->new_<BreakpointSite>(script, pc);
         if (!site || !breakpointSites.add(p, pc, site)) {
             js_ReportOutOfMemory(cx);
             return NULL;
         }
     }
 
     BreakpointSite *site = p->value;
-    if (site->scriptObject)
-        JS_ASSERT_IF(scriptObject, site->scriptObject == scriptObject);
+    if (site->scriptGlobal)
+        JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
     else
-        site->scriptObject = scriptObject;
+        site->scriptGlobal = scriptGlobal;
 
     return site;
 }
 
 void
 JSCompartment::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script,
                                   JSObject *handler)
 {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -288,20 +288,21 @@ struct TraceMonitor {
     JS_FRIEND_API(size_t) getVMAllocatorsMainSize(JSUsableSizeFun usf) const;
     JS_FRIEND_API(size_t) getVMAllocatorsReserveSize(JSUsableSizeFun usf) const;
     JS_FRIEND_API(size_t) getTraceMonitorSize(JSUsableSizeFun usf) const;
 };
 
 namespace mjit {
 class JaegerCompartment;
 }
-}
 
 /* Defined in jsapi.cpp */
-extern JSClass js_dummy_class;
+extern Class dummy_class;
+
+} /* namespace js */
 
 #ifndef JS_EVAL_CACHE_SHIFT
 # define JS_EVAL_CACHE_SHIFT        6
 #endif
 
 /* Number of buckets in the hash of eval scripts. */
 #define JS_EVAL_CACHE_SIZE          JS_BIT(JS_EVAL_CACHE_SHIFT)
 
@@ -610,17 +611,17 @@ struct JS_FRIEND_API(JSCompartment) {
     js::GlobalObjectSet &getDebuggees() { return debuggees; }
     bool addDebuggee(JSContext *cx, js::GlobalObject *global);
     void removeDebuggee(JSContext *cx, js::GlobalObject *global,
                         js::GlobalObjectSet::Enum *debuggeesEnum = NULL);
     bool setDebugModeFromC(JSContext *cx, bool b);
 
     js::BreakpointSite *getBreakpointSite(jsbytecode *pc);
     js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, JSScript *script, jsbytecode *pc,
-                                                  JSObject *scriptObject);
+                                                  js::GlobalObject *scriptGlobal);
     void clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSScript *script, JSObject *handler);
     void clearTraps(JSContext *cx, JSScript *script);
     bool markTrapClosuresIteratively(JSTracer *trc);
 
   private:
     void sweepBreakpoints(JSContext *cx);
 
   public:
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1044,19 +1044,16 @@ JS_PUBLIC_API(size_t)
 JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
 {
     size_t nbytes, pbytes;
     jssrcnote *sn, *notes;
     JSObjectArray *objarray;
     JSPrincipals *principals;
 
     nbytes = sizeof *script;
-    if (script->u.object)
-        nbytes += JS_GetObjectTotalSize(cx, script->u.object);
-
     nbytes += script->length * sizeof script->code[0];
     nbytes += script->natoms * sizeof script->atoms[0];
     for (size_t i = 0; i < script->natoms; i++)
         nbytes += GetAtomTotalSize(cx, script->atoms[i]);
 
     if (script->filename)
         nbytes += strlen(script->filename) + 1;
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1553,67 +1553,62 @@ js_XDRFunctionObject(JSXDRState *xdr, JS
     JSContext *cx;
     JSFunction *fun;
     uint32 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 flagsword;           /* word for argument count and fun->flags */
 
     cx = xdr->cx;
+    JSScript *script;
     if (xdr->mode == JSXDR_ENCODE) {
         fun = (*objp)->getFunctionPrivate();
         if (!fun->isInterpreted()) {
             JSAutoByteString funNameBytes;
             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
                                      name);
             }
             return false;
         }
         firstword = (fun->u.i.skipmin << 2) | !!fun->atom;
         flagsword = (fun->nargs << 16) | fun->flags;
+        script = fun->script();
     } else {
         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
         if (!fun)
             return false;
         fun->clearParent();
         fun->clearType();
+        script = NULL;
     }
 
     AutoObjectRooter tvr(cx, fun);
 
     if (!JS_XDRUint32(xdr, &firstword))
         return false;
     if ((firstword & 1U) && !js_XDRAtom(xdr, &fun->atom))
         return false;
     if (!JS_XDRUint32(xdr, &flagsword))
         return false;
 
+    if (!js_XDRScript(xdr, &script))
+        return false;
+
     if (xdr->mode == JSXDR_DECODE) {
         fun->nargs = flagsword >> 16;
         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         fun->flags = uint16(flagsword);
         fun->u.i.skipmin = uint16(firstword >> 2);
-    }
-
-    /*
-     * Don't directly store into fun->u.i.script because we want this to happen
-     * at the same time as we set the script's owner.
-     */
-    JSScript *script = fun->script();
-    if (!js_XDRScript(xdr, &script))
-        return false;
-
-    if (xdr->mode == JSXDR_DECODE) {
-        *objp = fun;
         fun->setScript(script);
-        if (!fun->script()->typeSetFunction(cx, fun))
+        if (!script->typeSetFunction(cx, fun))
             return false;
         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
+        *objp = fun;
     }
 
     return true;
 }
 
 #else  /* !JS_HAS_XDR */
 
 #define js_XDRFunctionObject NULL
@@ -1669,20 +1664,18 @@ fun_trace(JSTracer *trc, JSObject *obj)
                            obj->getFlatClosureUpvars(), "upvars");
         }
         return;
     }
 
     if (fun->atom)
         MarkString(trc, fun->atom, "atom");
 
-    if (fun->isInterpreted() && fun->script()) {
-        CheckScriptOwner(fun->script(), obj);
+    if (fun->isInterpreted() && fun->script())
         MarkScript(trc, fun->script(), "script");
-    }
 }
 
 static void
 fun_finalize(JSContext *cx, JSObject *obj)
 {
     obj->finalizeUpvarsIfFlatClosure();
 }
 
@@ -2416,29 +2409,28 @@ js_CloneFunctionObject(JSContext *cx, JS
         cfun->u = fun->getFunctionPrivate()->u;
         cfun->atom = fun->atom;
         clone->setPrivate(cfun);
         if (cfun->isInterpreted()) {
             JSScript *script = fun->script();
             JS_ASSERT(script);
             JS_ASSERT(script->compartment() == fun->compartment());
             JS_ASSERT(script->compartment() != cx->compartment);
-            JS_OPT_ASSERT(script->ownerObject == fun);
 
             cfun->u.i.script_ = NULL;
             JSScript *cscript = js_CloneScript(cx, script);
             if (!cscript)
                 return NULL;
-
+            cscript->u.globalObject = cfun->getGlobal();
             cfun->setScript(cscript);
-            if (!cfun->script()->typeSetFunction(cx, cfun))
+            if (!cscript->typeSetFunction(cx, cfun))
                 return NULL;
 
             js_CallNewScriptHook(cx, cfun->script(), cfun);
-            Debugger::onNewScript(cx, cfun->script(), cfun, NULL);
+            Debugger::onNewScript(cx, cfun->script(), NULL);
         }
     }
     return clone;
 }
 
 #ifdef JS_TRACER
 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CloneFunctionObject, CONTEXT, FUNCTION, OBJECT, OBJECT, 0,
                      nanojit::ACCSET_STORE_ANY)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -198,20 +198,19 @@ struct JSFunction : public JSObject_Slot
     JSScript *script() const {
         JS_ASSERT(isInterpreted());
         return u.i.script_;
     }
 
     void setScript(JSScript *script) {
         JS_ASSERT(isInterpreted());
         u.i.script_ = script;
-        script->setOwnerObject(this);
     }
 
-    JSScript * maybeScript() const {
+    JSScript *maybeScript() const {
         return isInterpreted() ? script() : NULL;
     }
 
     JSNative native() const {
         JS_ASSERT(isNative());
         return u.n.native;
     }
 
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -827,18 +827,18 @@ MarkChildren(JSTracer *trc, JSScript *sc
         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
     }
 
     if (JSScript::isValidOffset(script->constOffset)) {
         JSConstArray *constarray = script->consts();
         MarkValueRange(trc, constarray->length, constarray->vector, "consts");
     }
 
-    if (!script->isCachedEval && script->u.object)
-        MarkObject(trc, *script->u.object, "object");
+    if (!script->isCachedEval && script->u.globalObject)
+        MarkObject(trc, *script->u.globalObject, "object");
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 
     script->bindings.trace(trc);
 
     if (script->types)
         script->types->trace(trc);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1121,17 +1121,16 @@ class EvalScriptGuard
             script_->isCachedEval = false;
             script_->isActiveEval = true;
         }
     }
 
     void setNewScript(JSScript *script) {
         /* NewScriptFromCG has already called js_CallNewScriptHook. */
         JS_ASSERT(!script_ && script);
-        script->setOwnerObject(JS_CACHED_SCRIPT);
         script_ = script;
         script_->isActiveEval = true;
     }
 
     bool foundScript() {
         return !!script_;
     }
 
@@ -6746,34 +6745,30 @@ JSBool
 js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
                      JSObject **protop, Class *clasp)
 {
     VOUCH_DOES_NOT_REQUIRE_STACK();
     JS_ASSERT(JSProto_Null <= protoKey);
     JS_ASSERT(protoKey < JSProto_LIMIT);
 
     if (protoKey != JSProto_Null) {
-        if (!scopeobj) {
-            if (cx->hasfp())
-                scopeobj = &cx->fp()->scopeChain();
-            if (!scopeobj) {
-                scopeobj = cx->globalObject;
-                if (!scopeobj) {
-                    *protop = NULL;
-                    return true;
-                }
+        GlobalObject *global;
+        if (scopeobj) {
+            global = scopeobj->getGlobal();
+        } else {
+            global = GetCurrentGlobal(cx);
+            if (!global) {
+                *protop = NULL;
+                return true;
             }
         }
-        scopeobj = scopeobj->getGlobal();
-        if (scopeobj->isGlobal()) {
-            const Value &v = scopeobj->getReservedSlot(JSProto_LIMIT + protoKey);
-            if (v.isObject()) {
-                *protop = &v.toObject();
-                return true;
-            }
+        const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey);
+        if (v.isObject()) {
+            *protop = &v.toObject();
+            return true;
         }
     }
 
     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
 }
 
 JSObject *
 PrimitiveToObject(JSContext *cx, const Value &v)
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1180,22 +1180,16 @@ struct JSObject : js::gc::Cell {
     /*
      * Iterator-specific getters and setters.
      */
 
     inline js::NativeIterator *getNativeIterator() const;
     inline void setNativeIterator(js::NativeIterator *);
 
     /*
-     * Script-related getters.
-     */
-
-    inline JSScript *getScript() const;
-
-    /*
      * XML-related getters and setters.
      */
 
     /*
      * Slots for XML-related classes are as follows:
      * - NamespaceClass.base reserves the *_NAME_* and *_NAMESPACE_* slots.
      * - QNameClass.base, AttributeNameClass, AnyNameClass reserve
      *   the *_NAME_* and *_QNAME_* slots.
@@ -1460,17 +1454,16 @@ struct JSObject : js::gc::Cell {
     inline bool isObject() const { return clasp == &js::ObjectClass; }
     inline bool isWith() const { return clasp == &js::WithClass; }
     inline bool isBlock() const { return clasp == &js::BlockClass; }
     inline bool isStaticBlock() const { return isBlock() && !getProto(); }
     inline bool isClonedBlock() const { return isBlock() && !!getProto(); }
     inline bool isCall() const { return clasp == &js::CallClass; }
     inline bool isDeclEnv() const { return clasp == &js::DeclEnvClass; }
     inline bool isRegExp() const { return clasp == &js::RegExpClass; }
-    inline bool isScript() const { return clasp == &js::ScriptClass; }
     inline bool isGenerator() const { return clasp == &js::GeneratorClass; }
     inline bool isIterator() const { return clasp == &js::IteratorClass; }
     inline bool isStopIteration() const { return clasp == &js::StopIterationClass; }
     inline bool isError() const { return clasp == &js::ErrorClass; }
     inline bool isXML() const { return clasp == &js::XMLClass; }
     inline bool isNamespace() const { return clasp == &js::NamespaceClass; }
     inline bool isWeakMap() const { return clasp == &js::WeakMapClass; }
     inline bool isProxy() const;
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1467,16 +1467,23 @@ NewNativeClassInstance(JSContext *cx, Cl
 
 static inline JSObject *
 NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
 {
     gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
     return NewNativeClassInstance(cx, clasp, proto, parent, kind);
 }
 
+inline GlobalObject *
+GetCurrentGlobal(JSContext *cx)
+{
+    JSObject *scopeChain = (cx->hasfp()) ? &cx->fp()->scopeChain() : cx->globalObject;
+    return scopeChain ? scopeChain->getGlobal() : NULL;
+}
+
 bool
 FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
                    Class *clasp);
 
 /*
  * Helper used to create Boolean, Date, RegExp, etc. instances of built-in
  * classes with class prototypes of the same Class. See, e.g., jsdate.cpp,
  * jsregexp.cpp, and js_PrimitiveToObject in jsobj.cpp. Use this to get the
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -301,24 +301,16 @@ CheckScript(JSScript *script, JSScript *
 {
     if (script->cookie1[0] != JS_SCRIPT_COOKIE || script->cookie2[0] != JS_SCRIPT_COOKIE) {
         crash::StackBuffer<sizeof(JSScript), 0x87> buf1(script);
         crash::StackBuffer<sizeof(JSScript), 0x88> buf2(prev);
         JS_OPT_ASSERT(false);
     }
 }
 
-void
-CheckScriptOwner(JSScript *script, JSObject *owner)
-{
-    JS_OPT_ASSERT(script->ownerObject == owner);
-    if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT)
-        JS_OPT_ASSERT(script->compartment() == owner->compartment());
-}
-
 #endif /* JS_CRASH_DIAGNOSTICS */
 
 } /* namespace js */
 
 #if JS_HAS_XDR
 
 enum ScriptBits {
     NoScriptRval,
@@ -751,47 +743,16 @@ void
 JSPCCounters::destroy(JSContext *cx)
 {
     if (counts) {
         cx->free_(counts);
         counts = NULL;
     }
 }
 
-static void
-script_trace(JSTracer *trc, JSObject *obj)
-{
-    JSScript *script = (JSScript *) obj->getPrivate();
-    if (script) {
-        CheckScriptOwner(script, obj);
-        MarkScript(trc, script, "script");
-    }
-}
-
-JS_FRIEND_DATA(Class) js::ScriptClass = {
-    "Script",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    JS_PropertyStub,         /* addProperty */
-    JS_PropertyStub,         /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    NULL,                    /* finalize */
-    NULL,                    /* reserved0   */
-    NULL,                    /* checkAccess */
-    NULL,                    /* call        */
-    NULL,                    /* construct   */
-    NULL,                    /* xdrObject   */
-    NULL,                    /* hasInstance */
-    script_trace
-};
-
 /*
  * Shared script filename management.
  */
 
 static const char *
 SaveScriptFilename(JSContext *cx, const char *filename)
 {
     JSCompartment *comp = cx->compartment;
@@ -960,17 +921,16 @@ JSScript::NewScript(JSContext *cx, uint3
     if (!script) {
         Foreground::free_(data);
         return NULL;
     }
 
     PodZero(script);
 #ifdef JS_CRASH_DIAGNOSTICS
     script->cookie1[0] = script->cookie2[0] = JS_SCRIPT_COOKIE;
-    script->ownerObject = JS_NEW_SCRIPT;
 #endif
 #if JS_SCRIPT_INLINE_DATA_LIMIT
     if (!data)
         data = script->inlineData;
 #endif
     script->data  = data;
     script->length = length;
     script->version = version;
@@ -1236,33 +1196,36 @@ JSScript::NewScriptFromCG(JSContext *cx,
         bool singleton =
             cx->typeInferenceEnabled() && cg->parent && cg->parent->compiling() &&
             cg->parent->asCodeGenerator()->checkSingletonContext();
 
         if (!script->typeSetFunction(cx, fun, singleton))
             return NULL;
 
         fun->setScript(script);
+        script->u.globalObject = fun->getParent() ? fun->getParent()->getGlobal() : NULL;
     } else {
         /*
          * Initialize script->object, if necessary, so that the debugger has a
          * valid holder object.
          */
-        if ((cg->flags & TCF_NEED_SCRIPT_OBJECT) && !js_NewScriptObject(cx, script))
-            return NULL;
+        if (cg->flags & TCF_NEED_SCRIPT_GLOBAL)
+            script->u.globalObject = GetCurrentGlobal(cx);
     }
 
     /* Tell the debugger about this compiled script. */
     js_CallNewScriptHook(cx, script, fun);
     if (!cg->parent) {
-        JSObject *owner = fun ? fun : script->u.object;
         GlobalObject *compileAndGoGlobal = NULL;
-        if (script->compileAndGo)
-            compileAndGoGlobal = (owner ? owner : cg->scopeChain())->getGlobal();
-        Debugger::onNewScript(cx, script, owner, compileAndGoGlobal);
+        if (script->compileAndGo) {
+            compileAndGoGlobal = script->u.globalObject;
+            if (!compileAndGoGlobal)
+                compileAndGoGlobal = cg->scopeChain()->getGlobal();
+        }
+        Debugger::onNewScript(cx, script, compileAndGoGlobal);
     }
 
     return script;
 }
 
 size_t
 JSScript::dataSize()
 {
@@ -1283,25 +1246,16 @@ JSScript::dataSize(JSUsableSizeFun usf)
     if (data == inlineData)
         return 0;
 #endif
 
     size_t usable = usf(data);
     return usable ? usable : dataSize();
 }
 
-void
-JSScript::setOwnerObject(JSObject *owner)
-{
-#ifdef JS_CRASH_DIAGNOSTICS
-    CheckScriptOwner(this, JS_NEW_SCRIPT);
-    ownerObject = owner;
-#endif
-}
-
 /*
  * Nb: srcnotes are variable-length.  This function computes the number of
  * srcnote *slots*, which may be greater than the number of srcnotes.
  */
 uint32
 JSScript::numNotes()
 {
     jssrcnote *sn;
@@ -1366,37 +1320,16 @@ JSScript::finalize(JSContext *cx)
     if (data != inlineData)
 #endif
     {
         JS_POISON(data, 0xdb, dataSize());
         cx->free_(data);
     }
 }
 
-JSObject *
-js_NewScriptObject(JSContext *cx, JSScript *script)
-{
-    JS_ASSERT(!script->u.object);
-
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &ScriptClass, NULL, NULL);
-    if (!obj)
-        return NULL;
-    obj->setPrivate(script);
-    script->u.object = obj;
-    script->setOwnerObject(obj);
-
-    /*
-     * Clear the object's type/proto, to avoid entraining stuff. Once we no longer use the parent
-     * for security checks, then we can clear the parent, too.
-     */
-    obj->clearType();
-
-    return obj;
-}
-
 namespace js {
 
 static const uint32 GSN_CACHE_THRESHOLD = 100;
 static const uint32 GSN_CACHE_MAP_INIT_SIZE = 20;
 
 void
 GSNCache::purge()
 {
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -421,19 +421,16 @@ class JSPCCounters {
         JS_ASSERT(offset < numBytecodes);
         JS_ASSERT(counts);
         return get(runmode)[offset];
     }
 };
 
 static const uint32 JS_SCRIPT_COOKIE = 0xc00cee;
 
-static JSObject * const JS_NEW_SCRIPT = (JSObject *)0x12345678;
-static JSObject * const JS_CACHED_SCRIPT = (JSObject *)0x12341234;
-
 struct JSScript : public js::gc::Cell {
     /*
      * Two successively less primitive ways to make a new JSScript.  The first
      * does *not* call a non-null cx->runtime->newScriptHook -- only the second,
      * NewScriptFromCG, calls this optional debugger hook.
      *
      * The NewScript function can't know whether the script it creates belongs
      * to a function, or is top-level or eval code, but the debugger wants access
@@ -556,45 +553,42 @@ struct JSScript : public js::gc::Cell {
   public:
     js::Bindings    bindings;   /* names of top-level variables in this script
                                    (and arguments if this is a function script) */
     JSPrincipals    *principals;/* principals for this script */
     jschar          *sourceMap; /* source map file or null */
 
     union {
         /*
-         * A script object of class ScriptClass, to ensure the script is GC'd.
+         * A global object for the script.
          * - All scripts returned by JSAPI functions (JS_CompileScript,
-         *   JS_CompileFile, etc.) have these objects.
-         * - Function scripts never have script objects; such scripts are owned
-         *   by their function objects.
+         *   JS_CompileFile, 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 these objects; such scripts are
-         *   explicitly destroyed by the code that created them.
+         *   similar functions never have the globalObject field set; for such
+         *   scripts the global should be extracted from the JS frame that
+         *   execute scripts.
          */
-        JSObject    *object;
+        js::GlobalObject    *globalObject;
 
         /* Hash table chaining for JSCompartment::evalCache. */
-        JSScript    *evalHashLink;
+        JSScript            *evalHashLink;
     } u;
 
     uint32          *closedSlots; /* vector of closed slots; args first, then vars. */
 
     /* array of execution counters for every JSOp in the script, by runmode */
     JSPCCounters    pcCounters;
 
 #ifdef JS_CRASH_DIAGNOSTICS
-    JSObject        *ownerObject;
-
     /* All diagnostic fields must be multiples of Cell::CellSize. */
-    uint32          cookie2[sizeof(JSObject *) == 4 ? 1 : 2];
+    uint32          cookie2[Cell::CellSize / sizeof(uint32)];
 #endif
 
-    void setOwnerObject(JSObject *owner);
-
 #ifdef DEBUG
     /*
      * Unique identifier within the compartment for this script, used for
      * printing analysis information.
      */
     uint32 id_;
     uint32 idpad;
     unsigned id();
@@ -633,16 +627,21 @@ struct JSScript : public js::gc::Cell {
     inline bool hasClearedGlobal() const;
 
     inline JSFunction *function() const;
     inline js::GlobalObject *global() const;
     inline js::types::TypeScriptNesting *nesting() const;
 
     inline void clearNesting();
 
+    /* Return creation time global or null. */
+    js::GlobalObject *getGlobalObjectOrNull() const {
+        return isCachedEval ? NULL : u.globalObject;
+    }
+
   private:
     bool makeTypes(JSContext *cx, JSFunction *fun);
     bool makeAnalysis(JSContext *cx);
   public:
 
 #ifdef JS_METHODJIT
     // Fast-cached pointers to make calls faster. These are also used to
     // quickly test whether there is JIT code; a NULL value means no
@@ -680,17 +679,17 @@ struct JSScript : public js::gc::Cell {
             return JITScript_None;
         if (addr == JS_UNJITTABLE_SCRIPT)
             return JITScript_Invalid;
         return JITScript_Valid;
     }
 
     /* Size of the JITScript and all sections.  (This method is implemented in MethodJIT.h.) */
     JS_FRIEND_API(size_t) jitDataSize(JSUsableSizeFun usf);
-    
+
 #endif
 
     jsbytecode *main() {
         return code + mainOffset;
     }
 
     /*
      * The first dataSize() is the in-use size of all the data sections, the
@@ -798,17 +797,17 @@ struct JSScript : public js::gc::Cell {
   public:
     /*
      * Set or clear the single-step flag. If the flag is set or the count
      * (adjusted by changeStepModeCount) is non-zero, then the script is in
      * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
      * count-style interface.)
      */
     bool setStepModeFlag(JSContext *cx, bool step);
-    
+
     /*
      * Increment or decrement the single-step count. If the count is non-zero or
      * the flag (set by setStepModeFlag) is set, then the script is in
      * single-step mode. (JSD uses an on/off-style interface; Debugger uses a
      * count-style interface.)
      */
     bool changeStepModeCount(JSContext *cx, int delta);
 
@@ -843,19 +842,16 @@ StackDepth(JSScript *script)
             JS_ASSERT((size_t)(index) < js_common_atom_count);                \
             (atom) = cx->runtime->atomState.commonAtomsStart()[index];        \
         } else {                                                              \
             (atom) = script_->getAtom(index);                                 \
         }                                                                     \
     JS_END_MACRO
 
 
-extern JSObject *
-js_InitScriptClass(JSContext *cx, JSObject *obj);
-
 extern void
 js_MarkScriptFilename(const char *filename);
 
 extern void
 js_SweepScriptFilenames(JSCompartment *comp);
 
 /*
  * New-script-hook calling is factored from js_NewScriptFromCG so that it
@@ -869,40 +865,29 @@ js_CallNewScriptHook(JSContext *cx, JSSc
 extern void
 js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
 
 namespace js {
 
 #ifdef JS_CRASH_DIAGNOSTICS
 
 void
-CheckScriptOwner(JSScript *script, JSObject *owner);
-
-void
 CheckScript(JSScript *script, JSScript *prev);
 
 #else
 
 inline void
-CheckScriptOwner(JSScript *script, JSObject *owner)
-{
-}
-
-inline void
 CheckScript(JSScript *script, JSScript *prev)
 {
 }
 
 #endif /* !JS_CRASH_DIAGNOSTICS */
 
 } /* namespace js */
 
-extern JSObject *
-js_NewScriptObject(JSContext *cx, JSScript *script);
-
 /*
  * To perturb as little code as possible, we introduce a js_GetSrcNote lookup
  * cache without adding an explicit cx parameter.  Thus js_GetSrcNote becomes
  * a macro that uses cx from its calls' lexical environments.
  */
 #define js_GetSrcNote(script,pc) js_GetSrcNoteCached(cx, script, pc)
 
 extern jssrcnote *
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -210,16 +210,9 @@ JSScript::clearNesting()
 {
     js::types::TypeScriptNesting *nesting = this->nesting();
     if (nesting) {
         js::Foreground::delete_(nesting);
         types->nesting = NULL;
     }
 }
 
-inline JSScript *
-JSObject::getScript() const
-{
-    JS_ASSERT(isScript());
-    return static_cast<JSScript *>(getPrivate());
-}
-
 #endif /* jsscriptinlines_h___ */
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -718,20 +718,19 @@ JS_XDRScript(JSXDRState *xdr, JSScript *
     if (!JS_XDRCStringOrNull(xdr, (char **) &state.filename))
         return false;
 
     if (!js_XDRScript(xdr, &script))
         return false;
 
     if (xdr->mode == JSXDR_DECODE) {
         JS_ASSERT(!script->compileAndGo);
-        if (!js_NewScriptObject(xdr->cx, script))
-            return false;
+        script->u.globalObject = GetCurrentGlobal(xdr->cx);
         js_CallNewScriptHook(xdr->cx, script, NULL);
-        Debugger::onNewScript(xdr->cx, script, script->u.object, NULL);
+        Debugger::onNewScript(xdr->cx, script, NULL);
         *scriptp = script;
     }
 
     return true;
 }
 
 #define CLASS_REGISTRY_MIN      8
 #define CLASS_INDEX_TO_ID(i)    ((i)+1)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1557,19 +1557,17 @@ ValueToScript(JSContext *cx, jsval v, JS
 {
     JSScript *script = NULL;
     JSFunction *fun = NULL;
 
     if (!JSVAL_IS_PRIMITIVE(v)) {
         JSObject *obj = JSVAL_TO_OBJECT(v);
         JSClass *clasp = JS_GET_CLASS(cx, obj);
 
-        if (clasp == Jsvalify(&ScriptClass)) {
-            script = (JSScript *) JS_GetPrivate(cx, obj);
-        } else if (clasp == Jsvalify(&GeneratorClass)) {
+        if (clasp == Jsvalify(&GeneratorClass)) {
             JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
             fun = gen->floatingFrame()->fun();
             script = fun->script();
         }
     }
 
     if (!script) {
         fun = JS_ValueToFunction(cx, v);
@@ -1619,18 +1617,17 @@ GetTrapArgs(JSContext *cx, uintN argc, j
     JSScript *script;
 
     *scriptp = JS_GetFrameScript(cx, JS_GetScriptedCaller(cx, NULL));
     *ip = 0;
     if (argc != 0) {
         v = argv[0];
         intarg = 0;
         if (!JSVAL_IS_PRIMITIVE(v) &&
-            (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass) ||
-             JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&ScriptClass))) {
+            JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass)) {
             script = ValueToScript(cx, v);
             if (!script)
                 return JS_FALSE;
             *scriptp = script;
             intarg++;
         }
         if (argc > intarg) {
             if (!JS_ValueToInt32(cx, argv[intarg], ip))
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -83,17 +83,16 @@ enum {
     JSSLOT_DEBUGOBJECT_OWNER,
     JSSLOT_DEBUGOBJECT_COUNT
 };
 
 extern Class DebuggerScript_class;
 
 enum {
     JSSLOT_DEBUGSCRIPT_OWNER,
-    JSSLOT_DEBUGSCRIPT_HOLDER,  /* PrivateValue, cross-compartment pointer */
     JSSLOT_DEBUGSCRIPT_COUNT
 };
 
 
 /*** Utils ***************************************************************************************/
 
 bool
 ReportMoreArgsNeeded(JSContext *cx, const char *name, uintN required)
@@ -120,53 +119,53 @@ ReportObjectRequired(JSContext *cx)
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
     return false;
 }
 
 
 /*** Breakpoints *********************************************************************************/
 
 BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc)
-  : script(script), pc(pc), realOpcode(JSOp(*pc)), scriptObject(NULL), enabledCount(0),
+  : script(script), pc(pc), realOpcode(JSOp(*pc)), scriptGlobal(NULL), enabledCount(0),
     trapHandler(NULL), trapClosure(UndefinedValue())
 {
     JS_ASSERT(realOpcode != JSOP_TRAP);
     JS_INIT_CLIST(&breakpoints);
 }
 
 /*
  * Precondition: script is live, meaning either it is a non-held script that is
  * on the stack or a held script that hasn't been GC'd.
  */
-static JSObject *
-ScriptScope(JSContext *cx, JSScript *script, JSObject *holder)
+static GlobalObject *
+ScriptGlobal(JSContext *cx, JSScript *script, GlobalObject *scriptGlobal)
 {
-    if (holder)
-        return holder;
+    if (scriptGlobal)
+        return scriptGlobal;
 
     /*
      * The referent is a non-held script. There is no direct reference from
      * script to the scope, so find it on the stack.
      */
     for (AllFramesIter i(cx->stack.space()); ; ++i) {
         JS_ASSERT(!i.done());
         if (i.fp()->maybeScript() == script)
-            return &i.fp()->scopeChain();
+            return i.fp()->scopeChain().getGlobal();
     }
-    JS_NOT_REACHED("ScriptScope: live non-held script not on stack");
+    JS_NOT_REACHED("ScriptGlobal: live non-held script not on stack");
 }
 
 bool
 BreakpointSite::recompile(JSContext *cx, bool forTrap)
 {
 #ifdef JS_METHODJIT
     if (script->hasJITCode()) {
         Maybe<AutoCompartment> ac;
         if (!forTrap) {
-            ac.construct(cx, ScriptScope(cx, script, scriptObject));
+            ac.construct(cx, ScriptGlobal(cx, script, scriptGlobal));
             if (!ac.ref().enter())
                 return false;
         }
         js::mjit::Recompiler recompiler(cx, script);
         recompiler.recompile();
     }
 #endif
     return true;
@@ -728,27 +727,27 @@ Debugger::fireEnterFrame(JSContext *cx)
         return;
     }
     Value rv;
     if (!Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, argv, &rv))
         handleUncaughtException(ac, NULL, true);
 }
 
 void
-Debugger::fireNewScript(JSContext *cx, JSScript *script, JSObject *obj)
+Debugger::fireNewScript(JSContext *cx, JSScript *script)
 {
     JSObject *hook = getHook(OnNewScript);
     JS_ASSERT(hook);
     JS_ASSERT(hook->isCallable());
 
     AutoCompartment ac(cx, object);
     if (!ac.enter())
         return;
 
-    JSObject *dsobj = wrapScript(cx, script, obj);
+    JSObject *dsobj = wrapScript(cx, script);
     if (!dsobj) {
         handleUncaughtException(ac, NULL, false);
         return;
     }
 
     Value argv[1];
     argv[0].setObject(*dsobj);
     Value rv;
@@ -811,18 +810,17 @@ AddNewScriptRecipients(GlobalObject::Deb
         {
             return false;
         }
     }
     return true;
 }
 
 void
-Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj,
-                              GlobalObject *compileAndGoGlobal)
+Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal)
 {
     JS_ASSERT(script->compileAndGo == !!compileAndGoGlobal);
 
     /*
      * Build the list of recipients. For compile-and-go scripts, this is the
      * same as the generic Debugger::dispatchHook code, but non-compile-and-go
      * scripts are not tied to particular globals. We deliver them to every
      * debugger observing any global in the script's compartment.
@@ -844,17 +842,17 @@ Debugger::slowPathOnNewScript(JSContext 
     /*
      * Deliver the event to each debugger, checking again as in
      * Debugger::dispatchHook.
      */
     for (Value *p = triggered.begin(); p != triggered.end(); p++) {
         Debugger *dbg = Debugger::fromJSObject(&p->toObject());
         if ((!compileAndGoGlobal || dbg->debuggees.has(compileAndGoGlobal)) &&
             dbg->enabled && dbg->getHook(OnNewScript)) {
-            dbg->fireNewScript(cx, script, obj);
+            dbg->fireNewScript(cx, script);
         }
     }
 }
 
 JSTrapStatus
 Debugger::onTrap(JSContext *cx, Value *vp)
 {
     StackFrame *fp = cx->fp();
@@ -1777,38 +1775,25 @@ JSFunctionSpec Debugger::methods[] = {
 
 
 /*** Debugger.Script *****************************************************************************/
 
 static inline JSScript *
 GetScriptReferent(JSObject *obj)
 {
     JS_ASSERT(obj->getClass() == &DebuggerScript_class);
-    return (JSScript *) obj->getPrivate();
-}
-
-static inline JSObject *
-GetScriptHolder(JSObject *obj)
-{
-    JS_ASSERT(obj->getClass() == &DebuggerScript_class);
-    Value v = obj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER);
-    return (JSObject *) v.toPrivate();
+    return static_cast<JSScript *>(obj->getPrivate());
 }
 
 static void
 DebuggerScript_trace(JSTracer *trc, JSObject *obj)
 {
     if (!trc->context->runtime->gcCurrentCompartment) {
         if (JSScript *script = GetScriptReferent(obj))
             MarkScript(trc, script, "Debugger.Script referent");
-        Value v = obj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER);
-        if (!v.isUndefined()) {
-            if (JSObject *obj = (JSObject *) v.toPrivate())
-                MarkObject(trc, *obj, "Debugger.Script referent holder");
-        }
     }
 }
 
 Class DebuggerScript_class = {
     "Script", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT),
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
     NULL,                 /* reserved0   */
@@ -1816,83 +1801,73 @@ Class DebuggerScript_class = {
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     NULL,                 /* hasInstance */
     DebuggerScript_trace
 };
 
 JSObject *
-Debugger::newDebuggerScript(JSContext *cx, JSScript *script, JSObject *holder)
+Debugger::newDebuggerScript(JSContext *cx, JSScript *script)
 {
     assertSameCompartment(cx, object);
 
     JSObject *proto = &object->getReservedSlot(JSSLOT_DEBUG_SCRIPT_PROTO).toObject();
     JS_ASSERT(proto);
     JSObject *scriptobj = NewNonFunction<WithProto::Given>(cx, &DebuggerScript_class, proto, NULL);
     if (!scriptobj || !scriptobj->ensureClassReservedSlots(cx))
         return NULL;
     scriptobj->setPrivate(script);
     scriptobj->setReservedSlot(JSSLOT_DEBUGSCRIPT_OWNER, ObjectValue(*object));
-    scriptobj->setReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER, PrivateValue(holder));
 
     return scriptobj;
 }
 
 JSObject *
-Debugger::wrapScript(JSContext *cx, JSScript *script, JSObject *obj)
+Debugger::wrapScript(JSContext *cx, JSScript *script)
 {
     assertSameCompartment(cx, object);
     JS_ASSERT(cx->compartment != script->compartment());
-    JS_ASSERT_IF(obj, script->compartment() == obj->compartment());
-
     CellWeakMap::AddPtr p = scripts.lookupForAdd(script);
     if (!p) {
-        JSObject *scriptobj = newDebuggerScript(cx, script, obj);
+        JSObject *scriptobj = newDebuggerScript(cx, script);
 
         /* The allocation may have caused a GC, which can remove table entries. */
         if (!scriptobj || !scripts.relookupOrAdd(p, script, scriptobj))
             return NULL;
     }
 
     JS_ASSERT(GetScriptReferent(p->value) == script);
     return p->value;
 }
 
-JSObject *
-Debugger::wrapFunctionScript(JSContext *cx, JSFunction *fun)
-{
-    return wrapScript(cx, fun->script(), fun);
-}
-
 static JSObject *
 DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const char *fnname)
 {
     if (!v.isObject()) {
         ReportObjectRequired(cx);
         return NULL;
     }
     JSObject *thisobj = &v.toObject();
     if (thisobj->getClass() != &DebuggerScript_class) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                              clsname, fnname, thisobj->getClass()->name);
         return NULL;
     }
 
     /*
      * Check for Debugger.Script.prototype, which is of class DebuggerScript_class
-     * but whose holding object is undefined.
+     * but whose script is null.
      */
-    if (thisobj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER).isUndefined()) {
+    if (!GetScriptReferent(thisobj)) {
         JS_ASSERT(!GetScriptReferent(thisobj));
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                              clsname, fnname, "prototype object");
         return NULL;
     }
-    JS_ASSERT(GetScriptReferent(thisobj));
 
     return thisobj;
 }
 
 static JSObject *
 DebuggerScript_checkThis(JSContext *cx, const CallArgs &args, const char *fnname)
 {
     return DebuggerScript_check(cx, args.thisv(), "Debugger.Script", fnname);
@@ -1949,17 +1924,18 @@ DebuggerScript_getChildScripts(JSContext
          * script->savedCallerFun indicates that this is a direct eval script
          * and the calling function is stored as script->objects()->vector[0].
          * It is not really a child script of this script, so skip it.
          */
         JSObjectArray *objects = script->objects();
         for (uint32 i = script->savedCallerFun ? 1 : 0; i < objects->length; i++) {
             JSObject *obj = objects->vector[i];
             if (obj->isFunction()) {
-                JSObject *s = dbg->wrapFunctionScript(cx, (JSFunction *) obj);
+                JSFunction *fun = static_cast<JSFunction *>(obj);
+                JSObject *s = dbg->wrapScript(cx, fun->script());
                 if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s)))
                     return false;
             }
         }
     }
     args.rval().setObject(*result);
     return true;
 }
@@ -2252,33 +2228,33 @@ DebuggerScript_getLineOffsets(JSContext 
 
 static JSBool
 DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.Script.setBreakpoint", 2);
     THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "setBreakpoint", args, obj, script);
     Debugger *dbg = Debugger::fromChildJSObject(obj);
 
-    JSObject *holder = GetScriptHolder(obj);
-    if (!dbg->observesScope(ScriptScope(cx, script, holder))) {
+    GlobalObject *scriptGlobal = script->getGlobalObjectOrNull();
+    if (!dbg->observesGlobal(ScriptGlobal(cx, script, scriptGlobal))) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_DEBUGGING);
         return false;
     }
 
     size_t offset;
     if (!ScriptOffset(cx, script, args[0], &offset))
         return false;
 
     JSObject *handler = NonNullObject(cx, args[1]);
     if (!handler)
         return false;
 
     JSCompartment *comp = script->compartment();
     jsbytecode *pc = script->code + offset;
-    BreakpointSite *site = comp->getOrCreateBreakpointSite(cx, script, pc, holder);
+    BreakpointSite *site = comp->getOrCreateBreakpointSite(cx, script, pc, scriptGlobal);
     if (!site)
         return false;
     if (site->inc(cx)) {
         if (cx->runtime->new_<Breakpoint>(dbg, site, handler)) {
             args.rval().setUndefined();
             return true;
         }
         site->dec(cx);
@@ -2623,28 +2599,27 @@ DebuggerFrame_getScript(JSContext *cx, u
 {
     THIS_FRAME(cx, argc, vp, "get script", args, thisobj, fp);
     Debugger *debug = Debugger::fromChildJSObject(thisobj);
 
     JSObject *scriptObject = NULL;
     if (fp->isFunctionFrame() && !fp->isEvalFrame()) {
         JSFunction *callee = fp->callee().getFunctionPrivate();
         if (callee->isInterpreted()) {
-            scriptObject = debug->wrapFunctionScript(cx, callee);
+            scriptObject = debug->wrapScript(cx, callee->script());
             if (!scriptObject)
                 return false;
         }
     } else if (fp->isScriptFrame()) {
         /*
          * We got eval, JS_Evaluate*, or JS_ExecuteScript non-function script
          * frames.
          */
         JSScript *script = fp->script();
-        scriptObject = debug->wrapScript(cx, script,
-                                         script->isCachedEval ? NULL : script->u.object);
+        scriptObject = debug->wrapScript(cx, script);
         if (!scriptObject)
             return false;
     }
     args.rval().setObjectOrNull(scriptObject);
     return true;
 }
 
 static JSBool
@@ -2739,17 +2714,17 @@ EvaluateInScope(JSContext *cx, JSObject 
     /*
      * NB: This function breaks the assumption that the compiler can see all
      * calls and properly compute a static level. In order to get around this,
      * we use a static level that will cause us not to attempt to optimize
      * variable references made by this frame.
      */
     JSScript *script = BytecodeCompiler::compileScript(cx, scobj, fp,
                                                        fp->scopeChain().principals(cx),
-                                                       TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_OBJECT,
+                                                       TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_GLOBAL,
                                                        chars, length, filename, lineno,
                                                        cx->findVersion(), NULL,
                                                        UpvarCookie::UPVAR_LEVEL_LIMIT);
 
     if (!script)
         return false;
 
     return ExecuteKernel(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, rval);
@@ -3051,17 +3026,17 @@ DebuggerObject_getScript(JSContext *cx, 
 
     if (!obj->isFunction())
         return true;
 
     JSFunction *fun = obj->getFunctionPrivate();
     if (!fun->isInterpreted())
         return true;
 
-    JSObject *scriptObject = dbg->wrapFunctionScript(cx, fun);
+    JSObject *scriptObject = dbg->wrapScript(cx, fun->script());
     if (!scriptObject)
         return false;
 
     args.rval().setObject(*scriptObject);
     return true;
 }
 
 static JSBool
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -196,37 +196,35 @@ class Debugger {
     static JSPropertySpec properties[];
     static JSFunctionSpec methods[];
 
     JSObject *getHook(Hook hook) const;
     bool hasAnyLiveHooks(JSContext *cx) const;
 
     static void slowPathOnEnterFrame(JSContext *cx);
     static void slowPathOnLeaveFrame(JSContext *cx);
-    static void slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj,
+    static void slowPathOnNewScript(JSContext *cx, JSScript *script,
                                     GlobalObject *compileAndGoGlobal);
     static JSTrapStatus dispatchHook(JSContext *cx, js::Value *vp, Hook which);
 
     JSTrapStatus fireDebuggerStatement(JSContext *cx, Value *vp);
     JSTrapStatus fireExceptionUnwind(JSContext *cx, Value *vp);
     void fireEnterFrame(JSContext *cx);
 
     /*
-     * Allocate and initialize a Debugger.Script instance whose referent is |script| and
-     * whose holder is |obj|. If |obj| is NULL, this creates a Debugger.Script whose holder
-     * is null, for non-held scripts.
+     * Allocate and initialize a Debugger.Script instance whose referent is
+     * |script|.
      */
-    JSObject *newDebuggerScript(JSContext *cx, JSScript *script, JSObject *obj);
+    JSObject *newDebuggerScript(JSContext *cx, JSScript *script);
 
     /*
      * Receive a "new script" event from the engine. A new script was compiled
-     * or deserialized. For eval scripts obj must be null, otherwise it must be
-     * a script object.
+     * or deserialized.
      */
-    void fireNewScript(JSContext *cx, JSScript *script, JSObject *obj);
+    void fireNewScript(JSContext *cx, JSScript *script);
 
     static inline Debugger *fromLinks(JSCList *links);
     inline Breakpoint *firstBreakpoint() const;
 
   public:
     Debugger(JSContext *cx, JSObject *dbg);
     ~Debugger();
 
@@ -257,26 +255,26 @@ class Debugger {
     static void sweepAll(JSContext *cx);
     static void detachAllDebuggersFromGlobal(JSContext *cx, GlobalObject *global,
                                              GlobalObjectSet::Enum *compartmentEnum);
 
     static inline void onEnterFrame(JSContext *cx);
     static inline void onLeaveFrame(JSContext *cx);
     static inline JSTrapStatus onDebuggerStatement(JSContext *cx, js::Value *vp);
     static inline JSTrapStatus onExceptionUnwind(JSContext *cx, js::Value *vp);
-    static inline void onNewScript(JSContext *cx, JSScript *script, JSObject *obj,
+    static inline void onNewScript(JSContext *cx, JSScript *script,
                                    GlobalObject *compileAndGoGlobal);
     static JSTrapStatus onTrap(JSContext *cx, Value *vp);
     static JSTrapStatus onSingleStep(JSContext *cx, Value *vp);
 
     /************************************* Functions for use by Debugger.cpp. */
 
     inline bool observesEnterFrame() const;
     inline bool observesNewScript() const;
-    inline bool observesScope(JSObject *obj) const;
+    inline bool observesGlobal(GlobalObject *global) const;
     inline bool observesFrame(StackFrame *fp) const;
 
     /*
      * Like cx->compartment->wrap(cx, vp), but for the debugger compartment.
      *
      * Preconditions: *vp is a value from a debuggee compartment; cx is in the
      * debugger's compartment.
      *
@@ -327,30 +325,21 @@ class Debugger {
      *
      * On success, a completion value is in vp and ac.context does not have a
      * pending exception. (This ordinarily returns true even if the ok argument
      * is false.)
      */
     bool newCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
 
     /*
-     * Return the Debugger.Script object for |fun|'s script, or create a new
-     * one if needed.  The context |cx| must be in the debugger compartment;
-     * |fun| must be a cross-compartment wrapper referring to the JSFunction in
-     * a debuggee compartment.
+     * Return the Debugger.Script object for |script|, or create a new one if
+     * needed. The context |cx| must be in the debugger compartment; |script|
+     * must be a script in a debuggee compartment.
      */
-    JSObject *wrapFunctionScript(JSContext *cx, JSFunction *fun);
-
-    /*
-     * Return the Debugger.Script object for |script|, or create a new one if
-     * needed. The context |cx| must be in the debugger compartment; |script| must
-     * be a script in a debuggee compartment. |obj| is either the script holder or
-     * null for non-held scripts.
-     */
-    JSObject *wrapScript(JSContext *cx, JSScript *script, JSObject *obj);
+    JSObject *wrapScript(JSContext *cx, JSScript *script);
 
   private:
     /* Prohibit copying. */
     Debugger(const Debugger &);
     Debugger & operator=(const Debugger &);
 };
 
 class BreakpointSite {
@@ -364,31 +353,31 @@ class BreakpointSite {
     const JSOp realOpcode;
 
   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.
      */
-    JSObject *scriptObject;
+    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 */
     Value trapClosure;
 
     bool recompile(JSContext *cx, bool forTrap);
 
   public:
     BreakpointSite(JSScript *script, jsbytecode *pc);
     Breakpoint *firstBreakpoint() const;
     bool hasBreakpoint(Breakpoint *bp);
     bool hasTrap() const { return !!trapHandler; }
-    JSObject *getScriptObject() const { return scriptObject; }
+    GlobalObject *getScriptGlobal() const { return scriptGlobal; }
 
     bool inc(JSContext *cx);
     void dec(JSContext *cx);
     bool setTrap(JSContext *cx, JSTrapHandler handler, const Value &closure);
     void clearTrap(JSContext *cx, BreakpointSiteMap::Enum *e = NULL,
                    JSTrapHandler *handlerp = NULL, Value *closurep = NULL);
     void destroyIfEmpty(JSRuntime *rt, BreakpointSiteMap::Enum *e);
 };
@@ -470,25 +459,25 @@ Debugger::observesEnterFrame() const
 
 bool
 Debugger::observesNewScript() const
 {
     return enabled && getHook(OnNewScript);
 }
 
 bool
-Debugger::observesScope(JSObject *obj) const
+Debugger::observesGlobal(GlobalObject *global) const
 {
-    return debuggees.has(obj->getGlobal());
+    return debuggees.has(global);
 }
 
 bool
 Debugger::observesFrame(StackFrame *fp) const
 {
-    return observesScope(&fp->scopeChain());
+    return observesGlobal(fp->scopeChain().getGlobal());
 }
 
 void
 Debugger::onEnterFrame(JSContext *cx)
 {
     if (!cx->compartment->getDebuggees().empty())
         slowPathOnEnterFrame(cx);
 }
@@ -512,23 +501,22 @@ JSTrapStatus
 Debugger::onExceptionUnwind(JSContext *cx, js::Value *vp)
 {
     return cx->compartment->getDebuggees().empty()
            ? JSTRAP_CONTINUE
            : dispatchHook(cx, vp, OnExceptionUnwind);
 }
 
 void
-Debugger::onNewScript(JSContext *cx, JSScript *script, JSObject *obj,
-                      GlobalObject *compileAndGoGlobal)
+Debugger::onNewScript(JSContext *cx, JSScript *script, GlobalObject *compileAndGoGlobal)
 {
     JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
     JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal);
     if (!script->compartment()->getDebuggees().empty())
-        slowPathOnNewScript(cx, script, obj, compileAndGoGlobal);
+        slowPathOnNewScript(cx, script, compileAndGoGlobal);
 }
 
 extern JSBool
 EvaluateInScope(JSContext *cx, JSObject *scobj, StackFrame *fp, const jschar *chars,
                 uintN length, const char *filename, uintN lineno, Value *rval);
 
 }
 
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -368,12 +368,12 @@ DefinePropertiesAndBrand(JSContext *cx, 
 typedef HashSet<GlobalObject *, DefaultHasher<GlobalObject *>, SystemAllocPolicy> GlobalObjectSet;
 
 } // namespace js
 
 js::GlobalObject *
 JSObject::asGlobal()
 {
     JS_ASSERT(isGlobal());
-    return reinterpret_cast<js::GlobalObject *>(this);
+    return static_cast<js::GlobalObject *>(this);
 }
 
 #endif /* GlobalObject_h___ */
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -774,25 +774,16 @@ nsXPConnect::Traverse(void *p, nsCycleCo
             if (IS_PROTO_CLASS(clazz)) {
                 XPCWrappedNativeProto* p =
                     (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
                 si = p->GetScriptableInfo();
             }
             if (si) {
                 JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
                             clazz->name, si->GetJSClass()->name);
-            } else if (clazz == &js::ScriptClass) {
-                JSScript* script = (JSScript*) xpc_GetJSPrivate(obj);
-                if (script->filename) {
-                    JS_snprintf(name, sizeof(name),
-                                "JS Object (Script - %s)",
-                                script->filename);
-                } else {
-                    JS_snprintf(name, sizeof(name), "JS Object (Script)");
-                }
             } else if (clazz == &js::FunctionClass) {
                 JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj);
                 JSString* str = JS_GetFunctionId(fun);
                 if (str) {
                     NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
                     JS_snprintf(name, sizeof(name),
                                 "JS Object (Function - %s)", fname.get());
                 } else {