[JAEGER] Merge from Tracemonkey. scopeChain and blockChain are still public so I can check one thing at a time--this merge is brutal.

This commit is contained in:
David Mandelin 2010-08-16 14:59:44 -07:00
commit 7463868bb1
14 changed files with 220 additions and 179 deletions

View File

@ -1823,7 +1823,7 @@ JS_GetGlobalForScopeChain(JSContext *cx)
VOUCH_DOES_NOT_REQUIRE_STACK(); VOUCH_DOES_NOT_REQUIRE_STACK();
if (cx->fp) if (cx->fp)
return cx->fp->scopeChain->getGlobal(); return cx->fp->getScopeChain()->getGlobal();
JSObject *scope = cx->globalObject; JSObject *scope = cx->globalObject;
if (!scope) { if (!scope) {

View File

@ -351,7 +351,7 @@ js_PopInterpFrame(JSContext* cx, TracerState* state)
return JS_FALSE; return JS_FALSE;
if (fp->imacpc) if (fp->imacpc)
return JS_FALSE; return JS_FALSE;
if (fp->blockChain) if (fp->hasBlockChain())
return JS_FALSE; return JS_FALSE;
fp->putActivationObjects(cx); fp->putActivationObjects(cx);

View File

@ -779,7 +779,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsid id, Value *vp)
fp->script = script; fp->script = script;
fp->fun = fun; fp->fun = fun;
fp->argv = vp + 2; fp->argv = vp + 2;
fp->scopeChain = closure->getParent(); fp->setScopeChain(closure->getParent());
fp->setArgsObj(NULL); fp->setArgsObj(NULL);
/* Initialize regs. */ /* Initialize regs. */
@ -1298,7 +1298,7 @@ JS_IsNativeFrame(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSObject *) JS_PUBLIC_API(JSObject *)
JS_GetFrameObject(JSContext *cx, JSStackFrame *fp) JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
{ {
return fp->scopeChain; return fp->maybeScopeChain();
} }
JS_PUBLIC_API(JSObject *) JS_PUBLIC_API(JSObject *)
@ -1664,7 +1664,7 @@ SetupFakeFrame(JSContext *cx, ExecuteFrameGuard &frame, JSFrameRegs &regs, JSObj
PodZero(fp); PodZero(fp);
fp->fun = fun; fp->fun = fun;
fp->argv = vp + 2; fp->argv = vp + 2;
fp->scopeChain = scopeobj->getGlobal(); fp->setScopeChain(scopeobj->getGlobal());
regs.pc = NULL; regs.pc = NULL;
regs.sp = fp->slots(); regs.sp = fp->slots();

View File

@ -215,7 +215,7 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
return fp->getArgsObj(); return fp->getArgsObj();
/* Compute the arguments object's parent slot from fp's scope chain. */ /* Compute the arguments object's parent slot from fp's scope chain. */
JSObject *global = fp->scopeChain->getGlobal(); JSObject *global = fp->getScopeChain()->getGlobal();
JSObject *argsobj = NewArguments(cx, global, fp->argc, &fp->argv[-2].toObject()); JSObject *argsobj = NewArguments(cx, global, fp->argc, &fp->argv[-2].toObject());
if (!argsobj) if (!argsobj)
return argsobj; return argsobj;
@ -770,7 +770,7 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
return NULL; return NULL;
/* Init immediately to avoid GC seeing a half-init'ed object. */ /* Init immediately to avoid GC seeing a half-init'ed object. */
envobj->init(&js_DeclEnvClass, NULL, fp->scopeChain, PrivateValue(fp)); envobj->init(&js_DeclEnvClass, NULL, fp->maybeScopeChain(), PrivateValue(fp));
envobj->map = cx->runtime->emptyDeclEnvScope->hold(); envobj->map = cx->runtime->emptyDeclEnvScope->hold();
return envobj; return envobj;
} }
@ -785,11 +785,11 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
#ifdef DEBUG #ifdef DEBUG
/* A call object should be a frame's outermost scope chain element. */ /* A call object should be a frame's outermost scope chain element. */
Class *classp = fp->scopeChain->getClass(); Class *classp = fp->getScopeChain()->getClass();
if (classp == &js_WithClass || classp == &js_BlockClass) if (classp == &js_WithClass || classp == &js_BlockClass)
JS_ASSERT(fp->scopeChain->getPrivate() != js_FloatingFrameIfGenerator(cx, fp)); JS_ASSERT(fp->getScopeChain()->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
else if (classp == &js_CallClass) else if (classp == &js_CallClass)
JS_ASSERT(fp->scopeChain->getPrivate() != fp); JS_ASSERT(fp->getScopeChain()->getPrivate() != fp);
#endif #endif
/* /*
@ -805,9 +805,9 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
return NULL; return NULL;
/* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */ /* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
fp->scopeChain = envobj; fp->setScopeChain(envobj);
JS_ASSERT(fp->argv); JS_ASSERT(fp->argv);
if (!js_DefineNativeProperty(cx, fp->scopeChain, ATOM_TO_JSID(lambdaName), if (!js_DefineNativeProperty(cx, fp->getScopeChain(), ATOM_TO_JSID(lambdaName),
fp->calleeValue(), fp->calleeValue(),
CalleeGetter, NULL, CalleeGetter, NULL,
JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_PERMANENT | JSPROP_READONLY,
@ -816,7 +816,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
} }
} }
JSObject *callobj = NewCallObject(cx, fp->fun, fp->scopeChain); JSObject *callobj = NewCallObject(cx, fp->fun, fp->getScopeChain());
if (!callobj) if (!callobj)
return NULL; return NULL;
@ -830,7 +830,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
* Push callobj on the top of the scope chain, and make it the * Push callobj on the top of the scope chain, and make it the
* variables object. * variables object.
*/ */
fp->scopeChain = callobj; fp->setScopeChain(callobj);
return callobj; return callobj;
} }

View File

@ -2278,8 +2278,8 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
/* Allow for primitive this parameter due to JSFUN_THISP_* flags. */ /* Allow for primitive this parameter due to JSFUN_THISP_* flags. */
MarkValue(trc, fp->thisv, "this"); MarkValue(trc, fp->thisv, "this");
MarkValue(trc, fp->rval, "rval"); MarkValue(trc, fp->rval, "rval");
if (fp->scopeChain) if (fp->hasScopeChain())
JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain"); JS_CALL_OBJECT_TRACER(trc, fp->getScopeChain(), "scope chain");
} }
void void

View File

@ -105,7 +105,7 @@ jsbytecode *const JSStackFrame::sInvalidPC = (jsbytecode *)0xbeef;
JSObject * JSObject *
js_GetScopeChain(JSContext *cx, JSStackFrame *fp) js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
{ {
JSObject *sharedBlock = fp->blockChain; JSObject *sharedBlock = fp->maybeBlockChain();
if (!sharedBlock) { if (!sharedBlock) {
/* /*
@ -115,8 +115,8 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
JS_ASSERT(!fp->fun || JS_ASSERT(!fp->fun ||
!(fp->fun->flags & JSFUN_HEAVYWEIGHT) || !(fp->fun->flags & JSFUN_HEAVYWEIGHT) ||
fp->hasCallObj()); fp->hasCallObj());
JS_ASSERT(fp->scopeChain); JS_ASSERT(fp->hasScopeChain());
return fp->scopeChain; return fp->getScopeChain();
} }
/* We don't handle cloning blocks on trace. */ /* We don't handle cloning blocks on trace. */
@ -131,8 +131,8 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
*/ */
JSObject *limitBlock, *limitClone; JSObject *limitBlock, *limitClone;
if (fp->fun && !fp->hasCallObj()) { if (fp->fun && !fp->hasCallObj()) {
JS_ASSERT_IF(fp->scopeChain->getClass() == &js_BlockClass, JS_ASSERT_IF(fp->getScopeChain()->getClass() == &js_BlockClass,
fp->scopeChain->getPrivate() != js_FloatingFrameIfGenerator(cx, fp)); fp->getScopeChain()->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
if (!js_GetCallObject(cx, fp)) if (!js_GetCallObject(cx, fp))
return NULL; return NULL;
@ -145,7 +145,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
* prototype should appear on blockChain; we'll clone blockChain up * prototype should appear on blockChain; we'll clone blockChain up
* to, but not including, that prototype. * to, but not including, that prototype.
*/ */
limitClone = fp->scopeChain; limitClone = fp->getScopeChain();
while (limitClone->getClass() == &js_WithClass) while (limitClone->getClass() == &js_WithClass)
limitClone = limitClone->getParent(); limitClone = limitClone->getParent();
JS_ASSERT(limitClone); JS_ASSERT(limitClone);
@ -172,7 +172,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
/* If the innermost block has already been cloned, we are done. */ /* If the innermost block has already been cloned, we are done. */
if (limitBlock == sharedBlock) if (limitBlock == sharedBlock)
return fp->scopeChain; return fp->getScopeChain();
} }
/* /*
@ -208,7 +208,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
newChild->setParent(clone); newChild->setParent(clone);
newChild = clone; newChild = clone;
} }
newChild->setParent(fp->scopeChain); newChild->setParent(fp->getScopeChain());
/* /*
@ -221,7 +221,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
sharedBlock); sharedBlock);
/* Place our newly cloned blocks at the head of the scope chain. */ /* Place our newly cloned blocks at the head of the scope chain. */
fp->scopeChain = innermostNewChild; fp->setScopeChain(innermostNewChild);
return innermostNewChild; return innermostNewChild;
} }
@ -544,8 +544,8 @@ InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native,
fp->argv = args.argv(); fp->argv = args.argv();
fp->rval = (flags & JSINVOKE_CONSTRUCT) ? fp->thisv : UndefinedValue(); fp->rval = (flags & JSINVOKE_CONSTRUCT) ? fp->thisv : UndefinedValue();
fp->annotation = NULL; fp->annotation = NULL;
fp->scopeChain = NULL; fp->setScopeChain(NULL);
fp->blockChain = NULL; fp->setBlockChain(NULL);
fp->imacpc = NULL; fp->imacpc = NULL;
fp->flags = flags; fp->flags = flags;
@ -567,14 +567,14 @@ InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native,
if (native) { if (native) {
/* Slow natives and call ops expect the caller's scopeChain as their scopeChain. */ /* Slow natives and call ops expect the caller's scopeChain as their scopeChain. */
if (JSStackFrame *down = fp->down) if (JSStackFrame *down = fp->down)
fp->scopeChain = down->scopeChain; fp->setScopeChain(down->maybeScopeChain());
/* Ensure that we have a scope chain. */ /* Ensure that we have a scope chain. */
if (!fp->scopeChain) if (!fp->hasScopeChain())
fp->scopeChain = parent; fp->setScopeChain(parent);
} else { } else {
/* Use parent scope so js_GetCallObject can find the right "Call". */ /* Use parent scope so js_GetCallObject can find the right "Call". */
fp->scopeChain = parent; fp->setScopeChain(parent);
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
return false; return false;
} }
@ -885,7 +885,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
fp->argc = down->argc; fp->argc = down->argc;
fp->argv = down->argv; fp->argv = down->argv;
fp->annotation = down->annotation; fp->annotation = down->annotation;
fp->scopeChain = chain; fp->setScopeChain(chain);
/* /*
* We want to call |down->varobj()|, but this requires knowing the * We want to call |down->varobj()|, but this requires knowing the
@ -911,7 +911,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
OBJ_TO_INNER_OBJECT(cx, innerizedChain); OBJ_TO_INNER_OBJECT(cx, innerizedChain);
if (!innerizedChain) if (!innerizedChain)
return false; return false;
fp->scopeChain = innerizedChain; fp->setScopeChain(innerizedChain);
initialVarObj = (cx->options & JSOPTION_VAROBJFIX) initialVarObj = (cx->options & JSOPTION_VAROBJFIX)
? chain->getGlobal() ? chain->getGlobal()
@ -922,7 +922,7 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
fp->script = script; fp->script = script;
fp->imacpc = NULL; fp->imacpc = NULL;
fp->rval.setUndefined(); fp->rval.setUndefined();
fp->blockChain = NULL; fp->setBlockChain(NULL);
/* Initialize regs. */ /* Initialize regs. */
regs.pc = script->code; regs.pc = script->code;
@ -1308,7 +1308,7 @@ js_EnterWith(JSContext *cx, jsint stackIndex)
if (!withobj) if (!withobj)
return JS_FALSE; return JS_FALSE;
fp->scopeChain = withobj; fp->setScopeChain(withobj);
return JS_TRUE; return JS_TRUE;
} }
@ -1317,11 +1317,11 @@ js_LeaveWith(JSContext *cx)
{ {
JSObject *withobj; JSObject *withobj;
withobj = cx->fp->scopeChain; withobj = cx->fp->getScopeChain();
JS_ASSERT(withobj->getClass() == &js_WithClass); JS_ASSERT(withobj->getClass() == &js_WithClass);
JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp)); JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp));
JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0); JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
cx->fp->scopeChain = withobj->getParent(); cx->fp->setScopeChain(withobj->getParent());
withobj->setPrivate(NULL); withobj->setPrivate(NULL);
} }
@ -1353,15 +1353,15 @@ js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind)
JS_ASSERT(cx->fp->base() + stackDepth <= cx->regs->sp); JS_ASSERT(cx->fp->base() + stackDepth <= cx->regs->sp);
JSStackFrame *fp = cx->fp; JSStackFrame *fp = cx->fp;
for (obj = fp->blockChain; obj; obj = obj->getParent()) { for (obj = fp->maybeBlockChain(); obj; obj = obj->getParent()) {
JS_ASSERT(obj->getClass() == &js_BlockClass); JS_ASSERT(obj->getClass() == &js_BlockClass);
if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth) if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth)
break; break;
} }
fp->blockChain = obj; fp->setBlockChain(obj);
for (;;) { for (;;) {
obj = fp->scopeChain; obj = fp->getScopeChain();
clasp = js_IsActiveWithOrBlock(cx, obj, stackDepth); clasp = js_IsActiveWithOrBlock(cx, obj, stackDepth);
if (!clasp) if (!clasp)
break; break;
@ -2643,11 +2643,11 @@ BEGIN_CASE(JSOP_POPN)
regs.sp -= GET_UINT16(regs.pc); regs.sp -= GET_UINT16(regs.pc);
#ifdef DEBUG #ifdef DEBUG
JS_ASSERT(fp->base() <= regs.sp); JS_ASSERT(fp->base() <= regs.sp);
JSObject *obj = fp->blockChain; JSObject *obj = fp->maybeBlockChain();
JS_ASSERT_IF(obj, JS_ASSERT_IF(obj,
OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj) OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
<= (size_t) (regs.sp - fp->base())); <= (size_t) (regs.sp - fp->base()));
for (obj = fp->scopeChain; obj; obj = obj->getParent()) { for (obj = fp->maybeScopeChain(); obj; obj = obj->getParent()) {
Class *clasp = obj->getClass(); Class *clasp = obj->getClass();
if (clasp != &js_BlockClass && clasp != &js_WithClass) if (clasp != &js_BlockClass && clasp != &js_WithClass)
continue; continue;
@ -2682,11 +2682,11 @@ BEGIN_CASE(JSOP_ENTERWITH)
* We set sp[-1] to the current "with" object to help asserting the * We set sp[-1] to the current "with" object to help asserting the
* enter/leave balance in [leavewith]. * enter/leave balance in [leavewith].
*/ */
regs.sp[-1].setObject(*fp->scopeChain); regs.sp[-1].setObject(*fp->getScopeChain());
END_CASE(JSOP_ENTERWITH) END_CASE(JSOP_ENTERWITH)
BEGIN_CASE(JSOP_LEAVEWITH) BEGIN_CASE(JSOP_LEAVEWITH)
JS_ASSERT(&regs.sp[-1].toObject() == fp->scopeChain); JS_ASSERT(&regs.sp[-1].toObject() == fp->getScopeChain());
regs.sp--; regs.sp--;
js_LeaveWith(cx); js_LeaveWith(cx);
END_CASE(JSOP_LEAVEWITH) END_CASE(JSOP_LEAVEWITH)
@ -2742,8 +2742,8 @@ BEGIN_CASE(JSOP_STOP)
if (entryFrame != fp) if (entryFrame != fp)
inline_return: inline_return:
{ {
JS_ASSERT(!fp->blockChain); JS_ASSERT(!fp->hasBlockChain());
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
void *hookData = fp->hookData; void *hookData = fp->hookData;
if (JS_UNLIKELY(hookData != NULL)) { if (JS_UNLIKELY(hookData != NULL)) {
if (JSInterpreterHook hook = cx->debugHooks->callHook) { if (JSInterpreterHook hook = cx->debugHooks->callHook) {
@ -3276,7 +3276,7 @@ BEGIN_CASE(JSOP_BINDNAME)
* the rhs. We desire such resolve hook equivalence between the two * the rhs. We desire such resolve hook equivalence between the two
* forms. * forms.
*/ */
obj = fp->scopeChain; obj = fp->getScopeChain();
if (!obj->getParent()) if (!obj->getParent())
break; break;
@ -3290,7 +3290,7 @@ BEGIN_CASE(JSOP_BINDNAME)
} }
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
obj = js_FindIdentifierBase(cx, fp->scopeChain, id); obj = js_FindIdentifierBase(cx, fp->getScopeChain(), id);
if (!obj) if (!obj)
goto error; goto error;
} while (0); } while (0);
@ -3849,7 +3849,7 @@ BEGIN_CASE(JSOP_DECGNAME)
BEGIN_CASE(JSOP_GNAMEINC) BEGIN_CASE(JSOP_GNAMEINC)
BEGIN_CASE(JSOP_GNAMEDEC) BEGIN_CASE(JSOP_GNAMEDEC)
{ {
obj = fp->scopeChain; obj = fp->getScopeChain();
if (js_CodeSpec[op].format & JOF_GNAME) if (js_CodeSpec[op].format & JOF_GNAME)
obj = obj->getGlobal(); obj = obj->getGlobal();
@ -4728,9 +4728,9 @@ BEGIN_CASE(JSOP_APPLY)
newfp->argv = vp + 2; newfp->argv = vp + 2;
newfp->rval.setUndefined(); newfp->rval.setUndefined();
newfp->annotation = NULL; newfp->annotation = NULL;
newfp->scopeChain = obj->getParent(); newfp->setScopeChain(obj->getParent());
newfp->flags = flags; newfp->flags = flags;
newfp->blockChain = NULL; newfp->setBlockChain(NULL);
JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags)); JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
JS_ASSERT_IF(!vp[1].isPrimitive(), IsSaneThisObject(vp[1].toObject())); JS_ASSERT_IF(!vp[1].isPrimitive(), IsSaneThisObject(vp[1].toObject()));
newfp->thisv = vp[1]; newfp->thisv = vp[1];
@ -4879,7 +4879,7 @@ BEGIN_CASE(JSOP_CALLGNAME)
BEGIN_CASE(JSOP_NAME) BEGIN_CASE(JSOP_NAME)
BEGIN_CASE(JSOP_CALLNAME) BEGIN_CASE(JSOP_CALLNAME)
{ {
JSObject *obj = fp->scopeChain; JSObject *obj = fp->getScopeChain();
if (op == JSOP_GETGNAME || op == JSOP_CALLGNAME) if (op == JSOP_GETGNAME || op == JSOP_CALLGNAME)
obj = obj->getGlobal(); obj = obj->getGlobal();
@ -5036,7 +5036,7 @@ BEGIN_CASE(JSOP_REGEXP)
*/ */
jsatomid index = GET_FULL_INDEX(0); jsatomid index = GET_FULL_INDEX(0);
JSObject *proto; JSObject *proto;
if (!js_GetClassPrototype(cx, fp->scopeChain, JSProto_RegExp, &proto)) if (!js_GetClassPrototype(cx, fp->getScopeChain(), JSProto_RegExp, &proto))
goto error; goto error;
JS_ASSERT(proto); JS_ASSERT(proto);
JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto); JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto);
@ -5521,7 +5521,7 @@ BEGIN_CASE(JSOP_DEFFUN)
* FIXME: bug 476950, although debugger users may also demand some kind * FIXME: bug 476950, although debugger users may also demand some kind
* of scope link for debugger-assisted eval-in-frame. * of scope link for debugger-assisted eval-in-frame.
*/ */
obj2 = fp->scopeChain; obj2 = fp->getScopeChain();
} else { } else {
JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
@ -5529,8 +5529,8 @@ BEGIN_CASE(JSOP_DEFFUN)
* Inline js_GetScopeChain a bit to optimize for the case of a * Inline js_GetScopeChain a bit to optimize for the case of a
* top-level function. * top-level function.
*/ */
if (!fp->blockChain) { if (!fp->hasBlockChain()) {
obj2 = fp->scopeChain; obj2 = fp->getScopeChain();
} else { } else {
obj2 = js_GetScopeChain(cx, fp); obj2 = js_GetScopeChain(cx, fp);
if (!obj2) if (!obj2)
@ -5559,7 +5559,7 @@ BEGIN_CASE(JSOP_DEFFUN)
* fp->scopeChain code below the parent->defineProperty call. * fp->scopeChain code below the parent->defineProperty call.
*/ */
MUST_FLOW_THROUGH("restore_scope"); MUST_FLOW_THROUGH("restore_scope");
fp->scopeChain = obj; fp->setScopeChain(obj);
Value rval = ObjectValue(*obj); Value rval = ObjectValue(*obj);
@ -5629,7 +5629,7 @@ BEGIN_CASE(JSOP_DEFFUN)
restore_scope: restore_scope:
/* Restore fp->scopeChain now that obj is defined in fp->callobj. */ /* Restore fp->scopeChain now that obj is defined in fp->callobj. */
fp->scopeChain = obj2; fp->setScopeChain(obj2);
if (!ok) if (!ok)
goto error; goto error;
} }
@ -5684,7 +5684,7 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
JSObject *obj = FUN_OBJECT(fun); JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun)) { if (FUN_NULL_CLOSURE(fun)) {
obj = CloneFunctionObject(cx, fun, fp->scopeChain); obj = CloneFunctionObject(cx, fun, fp->getScopeChain());
if (!obj) if (!obj)
goto error; goto error;
} else { } else {
@ -5751,7 +5751,7 @@ BEGIN_CASE(JSOP_LAMBDA)
do { do {
JSObject *parent; JSObject *parent;
if (FUN_NULL_CLOSURE(fun)) { if (FUN_NULL_CLOSURE(fun)) {
parent = fp->scopeChain; parent = fp->getScopeChain();
if (obj->getParent() == parent) { if (obj->getParent() == parent) {
jsbytecode *pc2 = regs.pc + JSOP_LAMBDA_LENGTH; jsbytecode *pc2 = regs.pc + JSOP_LAMBDA_LENGTH;
@ -6753,7 +6753,7 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
regs.sp = vp; regs.sp = vp;
#ifdef DEBUG #ifdef DEBUG
JS_ASSERT(fp->blockChain == obj->getParent()); JS_ASSERT(fp->maybeBlockChain() == obj->getParent());
/* /*
* The young end of fp->scopeChain may omit blocks if we haven't closed * The young end of fp->scopeChain may omit blocks if we haven't closed
@ -6762,7 +6762,7 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
* anything else we should have popped off fp->scopeChain when we left its * anything else we should have popped off fp->scopeChain when we left its
* static scope. * static scope.
*/ */
JSObject *obj2 = fp->scopeChain; JSObject *obj2 = fp->getScopeChain();
Class *clasp; Class *clasp;
while ((clasp = obj2->getClass()) == &js_WithClass) while ((clasp = obj2->getClass()) == &js_WithClass)
obj2 = obj2->getParent(); obj2 = obj2->getParent();
@ -6776,7 +6776,7 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
} }
#endif #endif
fp->blockChain = obj; fp->setBlockChain(obj);
} }
END_CASE(JSOP_ENTERBLOCK) END_CASE(JSOP_ENTERBLOCK)
@ -6784,8 +6784,8 @@ BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
BEGIN_CASE(JSOP_LEAVEBLOCK) BEGIN_CASE(JSOP_LEAVEBLOCK)
{ {
#ifdef DEBUG #ifdef DEBUG
JS_ASSERT(fp->blockChain->getClass() == &js_BlockClass); JS_ASSERT(fp->getBlockChain()->getClass() == &js_BlockClass);
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain); uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->getBlockChain());
JS_ASSERT(blockDepth <= StackDepth(script)); JS_ASSERT(blockDepth <= StackDepth(script));
#endif #endif
@ -6794,15 +6794,15 @@ BEGIN_CASE(JSOP_LEAVEBLOCK)
* cloned onto fp->scopeChain, clear its private data, move its locals from * cloned onto fp->scopeChain, clear its private data, move its locals from
* the stack into the clone, and pop it off the chain. * the stack into the clone, and pop it off the chain.
*/ */
JSObject *obj = fp->scopeChain; JSObject *obj = fp->getScopeChain();
if (obj->getProto() == fp->blockChain) { if (obj->getProto() == fp->getBlockChain()) {
JS_ASSERT(obj->getClass() == &js_BlockClass); JS_ASSERT(obj->getClass() == &js_BlockClass);
if (!js_PutBlockObject(cx, JS_TRUE)) if (!js_PutBlockObject(cx, JS_TRUE))
goto error; goto error;
} }
/* Pop the block chain, too. */ /* Pop the block chain, too. */
fp->blockChain = fp->blockChain->getParent(); fp->setBlockChain(fp->getBlockChain()->getParent());
/* Move the result of the expression to the new topmost stack slot. */ /* Move the result of the expression to the new topmost stack slot. */
Value *vp = NULL; /* silence GCC warnings */ Value *vp = NULL; /* silence GCC warnings */
@ -7133,8 +7133,8 @@ END_CASE(JSOP_ARRAYPUSH)
AbortRecording(cx, "recording out of Interpret"); AbortRecording(cx, "recording out of Interpret");
#endif #endif
JS_ASSERT_IF(!fp->isGenerator(), !fp->blockChain); JS_ASSERT_IF(!fp->isGenerator(), !fp->hasBlockChain());
JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
/* Undo the remaining effects committed on entry to Interpret. */ /* Undo the remaining effects committed on entry to Interpret. */
if (cx->version == currentVersion && currentVersion != originalVersion) if (cx->version == currentVersion && currentVersion != originalVersion)

View File

@ -122,44 +122,10 @@ struct JSStackFrame
void *ncode; /* jit return pc */ void *ncode; /* jit return pc */
/* public:
* We can't determine in advance which local variables can live on
* the stack and be freed when their dynamic scope ends, and which
* will be closed over and need to live in the heap. So we place
* variables on the stack initially, note when they are closed
* over, and copy those that are out to the heap when we leave
* their dynamic scope.
*
* The bytecode compiler produces a tree of block objects
* accompanying each JSScript representing those lexical blocks in
* the script that have let-bound variables associated with them.
* These block objects are never modified, and never become part
* of any function's scope chain. Their parent slots point to the
* innermost block that encloses them, or are NULL in the
* outermost blocks within a function or in eval or global code.
*
* When we are in the static scope of such a block, blockChain
* points to its compiler-allocated block object; otherwise, it is
* NULL.
*
* scopeChain is the current scope chain, including 'call' and
* 'block' objects for those function calls and lexical blocks
* whose static scope we are currently executing in, and 'with'
* objects for with statements; the chain is typically terminated
* by a global object. However, as an optimization, the young end
* of the chain omits block objects we have not yet cloned. To
* create a closure, we clone the missing blocks from blockChain
* (which is always current), place them at the head of
* scopeChain, and use that for the closure's scope chain. If we
* never close over a lexical block, we never place a mutable
* clone of it on scopeChain.
*
* This lazy cloning is implemented in js_GetScopeChain, which is
* also used in some other cases --- entering 'with' blocks, for
* example.
*/
JSObject *scopeChain; JSObject *scopeChain;
JSObject *blockChain; JSObject *blockChain;
public:
uint32 flags; /* frame flags -- see below */ uint32 flags; /* frame flags -- see below */
@ -232,6 +198,89 @@ struct JSStackFrame
return offsetof(JSStackFrame, argsobj); return offsetof(JSStackFrame, argsobj);
} }
/*
* We can't determine in advance which local variables can live on
* the stack and be freed when their dynamic scope ends, and which
* will be closed over and need to live in the heap. So we place
* variables on the stack initially, note when they are closed
* over, and copy those that are out to the heap when we leave
* their dynamic scope.
*
* The bytecode compiler produces a tree of block objects
* accompanying each JSScript representing those lexical blocks in
* the script that have let-bound variables associated with them.
* These block objects are never modified, and never become part
* of any function's scope chain. Their parent slots point to the
* innermost block that encloses them, or are NULL in the
* outermost blocks within a function or in eval or global code.
*
* When we are in the static scope of such a block, blockChain
* points to its compiler-allocated block object; otherwise, it is
* NULL.
*
* scopeChain is the current scope chain, including 'call' and
* 'block' objects for those function calls and lexical blocks
* whose static scope we are currently executing in, and 'with'
* objects for with statements; the chain is typically terminated
* by a global object. However, as an optimization, the young end
* of the chain omits block objects we have not yet cloned. To
* create a closure, we clone the missing blocks from blockChain
* (which is always current), place them at the head of
* scopeChain, and use that for the closure's scope chain. If we
* never close over a lexical block, we never place a mutable
* clone of it on scopeChain.
*
* This lazy cloning is implemented in js_GetScopeChain, which is
* also used in some other cases --- entering 'with' blocks, for
* example.
*/
/* Scope chain accessors */
bool hasScopeChain() const {
return scopeChain != NULL;
}
JSObject* getScopeChain() const {
JS_ASSERT(hasScopeChain());
return scopeChain;
}
JSObject* maybeScopeChain() const {
return scopeChain;
}
void setScopeChain(JSObject *obj) {
scopeChain = obj;
}
JSObject** addressScopeChain() {
return &scopeChain;
}
static size_t offsetScopeChain() {
return offsetof(JSStackFrame, scopeChain);
}
/* Block chain accessors */
bool hasBlockChain() const {
return blockChain != NULL;
}
JSObject* getBlockChain() const {
JS_ASSERT(hasBlockChain());
return blockChain;
}
JSObject* maybeBlockChain() const {
return blockChain;
}
void setBlockChain(JSObject *obj) {
blockChain = obj;
}
/* Other accessors */ /* Other accessors */
void putActivationObjects(JSContext *cx) { void putActivationObjects(JSContext *cx) {

View File

@ -1190,9 +1190,9 @@ js_NewGenerator(JSContext *cx)
newfp->argv = vp + 2; newfp->argv = vp + 2;
newfp->rval = fp->rval; newfp->rval = fp->rval;
newfp->annotation = NULL; newfp->annotation = NULL;
newfp->scopeChain = fp->scopeChain; newfp->setScopeChain(fp->maybeScopeChain());
JS_ASSERT(!fp->blockChain); JS_ASSERT(!fp->hasBlockChain());
newfp->blockChain = NULL; newfp->setBlockChain(NULL);
newfp->flags = fp->flags | JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR; newfp->flags = fp->flags | JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR;
/* Copy in arguments and slots. */ /* Copy in arguments and slots. */
@ -1320,7 +1320,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
JSObject *enumerators = cx->enumerators; JSObject *enumerators = cx->enumerators;
cx->enumerators = gen->enumerators; cx->enumerators = gen->enumerators;
ok = RunScript(cx, fp->script, fp->fun, fp->scopeChain); ok = RunScript(cx, fp->script, fp->fun, fp->getScopeChain());
/* Restore the original enumerators stack. */ /* Restore the original enumerators stack. */
gen->enumerators = cx->enumerators; gen->enumerators = cx->enumerators;

View File

@ -2954,7 +2954,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2); JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
JSStackFrame *const fp = cx->fp; JSStackFrame *const fp = cx->fp;
JSObject *obj = fp->scopeChain; JSObject *obj = fp->getScopeChain();
JS_ASSERT(obj->getClass() == &js_BlockClass); JS_ASSERT(obj->getClass() == &js_BlockClass);
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp)); JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp));
JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj)); JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj));
@ -2988,7 +2988,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
/* We must clear the private slot even with errors. */ /* We must clear the private slot even with errors. */
obj->setPrivate(NULL); obj->setPrivate(NULL);
fp->scopeChain = obj->getParent(); fp->setScopeChain(obj->getParent());
return normalUnwind; return normalUnwind;
} }
@ -3737,7 +3737,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
*/ */
VOUCH_DOES_NOT_REQUIRE_STACK(); VOUCH_DOES_NOT_REQUIRE_STACK();
if (!start && (fp = cx->fp) != NULL) if (!start && (fp = cx->fp) != NULL)
start = fp->scopeChain; start = fp->maybeScopeChain();
if (start) { if (start) {
/* Find the topmost object in the scope chain. */ /* Find the topmost object in the scope chain. */
@ -4456,7 +4456,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
JSProperty *prop; JSProperty *prop;
JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx)); JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
scopeChain = js_GetTopStackFrame(cx)->scopeChain; scopeChain = js_GetTopStackFrame(cx)->getScopeChain();
/* Scan entries on the scope chain that we can cache across. */ /* Scan entries on the scope chain that we can cache across. */
entry = JS_NO_PROP_CACHE_FILL; entry = JS_NO_PROP_CACHE_FILL;
@ -5562,7 +5562,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
if (protoKey != JSProto_Null) { if (protoKey != JSProto_Null) {
if (!scope) { if (!scope) {
if (cx->fp) if (cx->fp)
scope = cx->fp->scopeChain; scope = cx->fp->maybeScopeChain();
if (!scope) { if (!scope) {
scope = cx->globalObject; scope = cx->globalObject;
if (!scope) { if (!scope) {
@ -6425,10 +6425,10 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
fprintf(stderr, " overridden_args"); fprintf(stderr, " overridden_args");
fputc('\n', stderr); fputc('\n', stderr);
if (fp->scopeChain) if (fp->hasScopeChain())
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->scopeChain); fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->getScopeChain());
if (fp->blockChain) if (fp->hasBlockChain())
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->blockChain); fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->getBlockChain());
fputc('\n', stderr); fputc('\n', stderr);
} }

View File

@ -611,7 +611,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp)
if (!global) if (!global)
return NULL; return NULL;
} else { } else {
global = cx->fp->scopeChain->getGlobal(); global = cx->fp->getScopeChain()->getGlobal();
} }
JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL); JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL);

View File

@ -186,7 +186,7 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame)
exit->numStackSlotsBelowCurrentFrame = cx->fp->down->argv ? exit->numStackSlotsBelowCurrentFrame = cx->fp->down->argv ?
nativeStackOffset(&cx->fp->argv[-2]) / sizeof(double) : 0; nativeStackOffset(&cx->fp->argv[-2]) / sizeof(double) : 0;
exit->exitType = UNSTABLE_LOOP_EXIT; exit->exitType = UNSTABLE_LOOP_EXIT;
exit->block = cx->fp->down->blockChain; exit->block = cx->fp->down->maybeBlockChain();
exit->pc = downFrame->pc + JSOP_CALL_LENGTH; exit->pc = downFrame->pc + JSOP_CALL_LENGTH;
exit->imacpc = NULL; exit->imacpc = NULL;
exit->sp_adj = ((downPostSlots + 1) * sizeof(double)) - tree->nativeStackBase; exit->sp_adj = ((downPostSlots + 1) * sizeof(double)) - tree->nativeStackBase;
@ -596,7 +596,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
/* argsobj */ /* argsobj */
slurpFrameObjPtrSlot(fp_ins, JSStackFrame::offsetArgsObj(), fp->addressArgsObj(), &info); slurpFrameObjPtrSlot(fp_ins, JSStackFrame::offsetArgsObj(), fp->addressArgsObj(), &info);
/* scopeChain */ /* scopeChain */
slurpFrameObjPtrSlot(fp_ins, offsetof(JSStackFrame, scopeChain), &fp->scopeChain, &info); slurpFrameObjPtrSlot(fp_ins, JSStackFrame::offsetScopeChain(), fp->addressScopeChain(), &info);
/* vars */ /* vars */
LIns* slots_ins = addName(lir->ins2(LIR_addp, fp_ins, INS_CONSTWORD(sizeof(JSStackFrame))), LIns* slots_ins = addName(lir->ins2(LIR_addp, fp_ins, INS_CONSTWORD(sizeof(JSStackFrame))),
"slots"); "slots");

View File

@ -1204,7 +1204,7 @@ GlobalSlotHash(JSContext* cx, unsigned slot)
fp = fp->down; fp = fp->down;
HashAccum(h, uintptr_t(fp->script), ORACLE_MASK); HashAccum(h, uintptr_t(fp->script), ORACLE_MASK);
HashAccum(h, uintptr_t(fp->scopeChain->getGlobal()->shape()), ORACLE_MASK); HashAccum(h, uintptr_t(fp->getScopeChain()->getGlobal()->shape()), ORACLE_MASK);
HashAccum(h, uintptr_t(slot), ORACLE_MASK); HashAccum(h, uintptr_t(slot), ORACLE_MASK);
return int(h); return int(h);
} }
@ -1825,7 +1825,7 @@ VisitFrameSlots(Visitor &visitor, JSContext *cx, unsigned depth,
// requires type |Value|. But the bits are the same, so we can import // requires type |Value|. But the bits are the same, so we can import
// it with a cast and the (identity function) unboxing will be OK. // it with a cast and the (identity function) unboxing will be OK.
visitor.setStackSlotKind("scopeChain"); visitor.setStackSlotKind("scopeChain");
if (!visitor.visitFrameObjPtr(&fp->scopeChain, fp)) if (!visitor.visitFrameObjPtr(fp->addressScopeChain(), fp))
return false; return false;
visitor.setStackSlotKind("var"); visitor.setStackSlotKind("var");
if (!visitor.visitStackSlots(fp->slots(), fp->script->nfixed, fp)) if (!visitor.visitStackSlots(fp->slots(), fp->script->nfixed, fp))
@ -1877,7 +1877,7 @@ template <typename Visitor>
static JS_REQUIRES_STACK JS_ALWAYS_INLINE void static JS_REQUIRES_STACK JS_ALWAYS_INLINE void
VisitGlobalSlots(Visitor &visitor, JSContext *cx, SlotList &gslots) VisitGlobalSlots(Visitor &visitor, JSContext *cx, SlotList &gslots)
{ {
VisitGlobalSlots(visitor, cx, cx->fp->scopeChain->getGlobal(), VisitGlobalSlots(visitor, cx, cx->fp->getScopeChain()->getGlobal(),
gslots.length(), gslots.data()); gslots.length(), gslots.data());
} }
@ -1896,7 +1896,7 @@ static JS_REQUIRES_STACK JS_ALWAYS_INLINE void
VisitSlots(Visitor& visitor, JSContext* cx, unsigned callDepth, VisitSlots(Visitor& visitor, JSContext* cx, unsigned callDepth,
unsigned ngslots, uint16* gslots) unsigned ngslots, uint16* gslots)
{ {
VisitSlots(visitor, cx, cx->fp->scopeChain->getGlobal(), VisitSlots(visitor, cx, cx->fp->getScopeChain()->getGlobal(),
callDepth, ngslots, gslots); callDepth, ngslots, gslots);
} }
@ -1914,7 +1914,7 @@ static JS_REQUIRES_STACK JS_ALWAYS_INLINE void
VisitSlots(Visitor &visitor, JSContext *cx, unsigned callDepth, VisitSlots(Visitor &visitor, JSContext *cx, unsigned callDepth,
const SlotList& slots) const SlotList& slots)
{ {
VisitSlots(visitor, cx, cx->fp->scopeChain->getGlobal(), VisitSlots(visitor, cx, cx->fp->getScopeChain()->getGlobal(),
callDepth, slots.length(), slots.data()); callDepth, slots.length(), slots.data());
} }
@ -2228,7 +2228,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag
globalObj(tree->globalObj), globalObj(tree->globalObj),
outer(outer), outer(outer),
outerArgc(outerArgc), outerArgc(outerArgc),
lexicalBlock(cx->fp->blockChain), lexicalBlock(cx->fp->maybeBlockChain()),
anchor(anchor), anchor(anchor),
lir(NULL), lir(NULL),
cx_ins(NULL), cx_ins(NULL),
@ -2259,7 +2259,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag
generatedSpecializedNative(), generatedSpecializedNative(),
tempTypeMap(cx) tempTypeMap(cx)
{ {
JS_ASSERT(globalObj == cx->fp->scopeChain->getGlobal()); JS_ASSERT(globalObj == cx->fp->getScopeChain()->getGlobal());
JS_ASSERT(globalObj->scope()->hasOwnShape()); JS_ASSERT(globalObj->scope()->hasOwnShape());
JS_ASSERT(cx->regs->pc == (jsbytecode*)fragment->ip); JS_ASSERT(cx->regs->pc == (jsbytecode*)fragment->ip);
@ -3465,15 +3465,15 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const JSValueType* mp,
// Iff these fields are NULL, then |fp| was synthesized on trace exit, so // Iff these fields are NULL, then |fp| was synthesized on trace exit, so
// we need to update the frame fields. // we need to update the frame fields.
if (!fp->hasCallObj()) if (!fp->hasCallObj())
fp->setCallObj(fp->scopeChain); fp->setCallObj(fp->getScopeChain());
// Iff scope chain's private is NULL, then |fp->scopeChain| was created // Iff scope chain's private is NULL, then |fp->scopeChain| was created
// on trace for a call, so we set the private field now. (Call objects // on trace for a call, so we set the private field now. (Call objects
// that correspond to returned frames also have a NULL private, but such // that correspond to returned frames also have a NULL private, but such
// a call object would not occur as the |scopeChain| member of a frame, // a call object would not occur as the |scopeChain| member of a frame,
// so we cannot be in that case here.) // so we cannot be in that case here.)
if (!fp->scopeChain->getPrivate()) if (!fp->getScopeChain()->getPrivate())
fp->scopeChain->setPrivate(fp); fp->getScopeChain()->setPrivate(fp);
} }
fp->thisv = fp->argv[-1]; fp->thisv = fp->argv[-1];
} }
@ -3865,7 +3865,7 @@ TraceRecorder::isValidFrameObjPtr(JSObject **p)
{ {
JSStackFrame *fp = cx->fp; JSStackFrame *fp = cx->fp;
for (; fp; fp = fp->down) { for (; fp; fp = fp->down) {
if (&fp->scopeChain == p || fp->addressArgsObj() == p) if (fp->addressScopeChain() == p || fp->addressArgsObj() == p)
return true; return true;
} }
return false; return false;
@ -4275,9 +4275,9 @@ TraceRecorder::snapshot(ExitType exitType)
nativeStackOffset(&cx->fp->argv[-2]) / sizeof(double) : nativeStackOffset(&cx->fp->argv[-2]) / sizeof(double) :
0; 0;
exit->exitType = exitType; exit->exitType = exitType;
exit->block = fp->blockChain; exit->block = fp->maybeBlockChain();
if (fp->blockChain) if (fp->hasBlockChain())
tree->gcthings.addUnique(ObjectValue(*fp->blockChain)); tree->gcthings.addUnique(ObjectValue(*fp->getBlockChain()));
exit->pc = pc; exit->pc = pc;
exit->imacpc = fp->imacpc; exit->imacpc = fp->imacpc;
exit->sp_adj = (stackSlots * sizeof(double)) - tree->nativeStackBase; exit->sp_adj = (stackSlots * sizeof(double)) - tree->nativeStackBase;
@ -5673,14 +5673,7 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee)
cx->regs->sp = sp; cx->regs->sp = sp;
cx->regs->pc = fi.pc; cx->regs->pc = fi.pc;
fp->imacpc = fi.imacpc; fp->imacpc = fi.imacpc;
fp->blockChain = fi.block; fp->setBlockChain(fi.block);
fp->blockChain = fi.block;
#ifdef DEBUG
if (fi.block != fp->blockChain) {
for (JSObject* obj = fi.block; obj != fp->blockChain; obj = obj->getParent())
JS_ASSERT(obj);
}
#endif
/* /*
* Get pointer to new frame/slots, without changing global state. * Get pointer to new frame/slots, without changing global state.
@ -5718,9 +5711,9 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee)
#endif #endif
newfp->rval = UndefinedValue(); newfp->rval = UndefinedValue();
newfp->annotation = NULL; newfp->annotation = NULL;
newfp->scopeChain = NULL; // will be updated in FlushNativeStackFrame newfp->setScopeChain(NULL); // will be updated in FlushNativeStackFrame
newfp->flags = fi.is_constructing() ? JSFRAME_CONSTRUCTING : 0; newfp->flags = fi.is_constructing() ? JSFRAME_CONSTRUCTING : 0;
newfp->blockChain = NULL; newfp->setBlockChain(NULL);
newfp->thisv.setNull(); // will be updated in FlushNativeStackFrame newfp->thisv.setNull(); // will be updated in FlushNativeStackFrame
newfp->imacpc = NULL; newfp->imacpc = NULL;
@ -5790,9 +5783,8 @@ SynthesizeSlowNativeFrame(TracerState& state, JSContext *cx, VMSideExit *exit)
fp->fun = GET_FUNCTION_PRIVATE(cx, fp->callee()); fp->fun = GET_FUNCTION_PRIVATE(cx, fp->callee());
fp->rval = UndefinedValue(); fp->rval = UndefinedValue();
fp->annotation = NULL; fp->annotation = NULL;
JS_ASSERT(cx->fp->scopeChain); fp->setScopeChain(cx->fp->maybeScopeChain());
fp->scopeChain = cx->fp->scopeChain; fp->setBlockChain(NULL);
fp->blockChain = NULL;
fp->flags = exit->constructing() ? JSFRAME_CONSTRUCTING : 0; fp->flags = exit->constructing() ? JSFRAME_CONSTRUCTING : 0;
state.bailedSlowNativeRegs = *cx->regs; state.bailedSlowNativeRegs = *cx->regs;
@ -6136,7 +6128,7 @@ JS_REQUIRES_STACK MonitorResult
TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount) TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
{ {
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
if (cx->fp->scopeChain->getGlobal()->scope()->title.ownercx != cx) { if (cx->fp->getScopeChain()->getGlobal()->scope()->title.ownercx != cx) {
AbortRecording(cx, "Global object not owned by this context"); AbortRecording(cx, "Global object not owned by this context");
return MONITOR_NOT_RECORDING; /* we stay away from shared global objects */ return MONITOR_NOT_RECORDING; /* we stay away from shared global objects */
} }
@ -6159,7 +6151,7 @@ TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCall
* Make sure the shape of the global object still matches (this might flush * Make sure the shape of the global object still matches (this might flush
* the JIT cache). * the JIT cache).
*/ */
JSObject* globalObj = cx->fp->scopeChain->getGlobal(); JSObject* globalObj = cx->fp->getScopeChain()->getGlobal();
uint32 globalShape = -1; uint32 globalShape = -1;
SlotList* globalSlots = NULL; SlotList* globalSlots = NULL;
if (!CheckGlobalObjectShape(cx, tm, globalObj, &globalShape, &globalSlots)) { if (!CheckGlobalObjectShape(cx, tm, globalObj, &globalShape, &globalSlots)) {
@ -6665,7 +6657,7 @@ ExecuteTrace(JSContext* cx, Fragment* f, TracerState& state)
static JS_REQUIRES_STACK JS_ALWAYS_INLINE bool static JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
ScopeChainCheck(JSContext* cx, TreeFragment* f) ScopeChainCheck(JSContext* cx, TreeFragment* f)
{ {
JS_ASSERT(f->globalObj == cx->fp->scopeChain->getGlobal()); JS_ASSERT(f->globalObj == cx->fp->getScopeChain()->getGlobal());
/* /*
* The JIT records and expects to execute with two scope-chain * The JIT records and expects to execute with two scope-chain
@ -6683,7 +6675,7 @@ ScopeChainCheck(JSContext* cx, TreeFragment* f)
* class types; once a global is found, it's checked for #1. Failing * class types; once a global is found, it's checked for #1. Failing
* either check causes an early return from execution. * either check causes an early return from execution.
*/ */
JSObject* child = cx->fp->scopeChain; JSObject* child = cx->fp->getScopeChain();
while (JSObject* parent = child->getParent()) { while (JSObject* parent = child->getParent()) {
if (!js_IsCacheableNonGlobalScope(child)) { if (!js_IsCacheableNonGlobalScope(child)) {
debug_only_print0(LC_TMTracer,"Blacklist: non-cacheable object on scope chain.\n"); debug_only_print0(LC_TMTracer,"Blacklist: non-cacheable object on scope chain.\n");
@ -7021,7 +7013,7 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr)
*/ */
JSStackFrame* const fp = cx->fp; JSStackFrame* const fp = cx->fp;
fp->blockChain = innermost->block; fp->setBlockChain(innermost->block);
/* /*
* If we are not exiting from an inlined frame, the state->sp is spbase. * If we are not exiting from an inlined frame, the state->sp is spbase.
@ -7184,7 +7176,7 @@ MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, RecordReason reason)
* Make sure the shape of the global object still matches (this might flush * Make sure the shape of the global object still matches (this might flush
* the JIT cache). * the JIT cache).
*/ */
JSObject* globalObj = cx->fp->scopeChain->getGlobal(); JSObject* globalObj = cx->fp->getScopeChain()->getGlobal();
uint32 globalShape = -1; uint32 globalShape = -1;
SlotList* globalSlots = NULL; SlotList* globalSlots = NULL;
@ -8103,7 +8095,7 @@ JS_REQUIRES_STACK LIns*
TraceRecorder::scopeChain() TraceRecorder::scopeChain()
{ {
return cx->fp->callee() return cx->fp->callee()
? getFrameObjPtr(&cx->fp->scopeChain) ? getFrameObjPtr(cx->fp->addressScopeChain())
: entryScopeChain(); : entryScopeChain();
} }
@ -8117,7 +8109,7 @@ TraceRecorder::entryScopeChain() const
{ {
return lir->insLoad(LIR_ldp, return lir->insLoad(LIR_ldp,
lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACCSET_OTHER), lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACCSET_OTHER),
offsetof(JSStackFrame, scopeChain), ACCSET_OTHER); JSStackFrame::offsetScopeChain(), ACCSET_OTHER);
} }
/* /*
@ -8159,7 +8151,7 @@ JS_DEFINE_CALLINFO_4(extern, UINT32, GetClosureArg, CONTEXT, OBJECT, CVIPTR, DOU
JS_REQUIRES_STACK AbortableRecordingStatus JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::scopeChainProp(JSObject* chainHead, Value*& vp, LIns*& ins, NameResult& nr) TraceRecorder::scopeChainProp(JSObject* chainHead, Value*& vp, LIns*& ins, NameResult& nr)
{ {
JS_ASSERT(chainHead == cx->fp->scopeChain); JS_ASSERT(chainHead == cx->fp->getScopeChain());
JS_ASSERT(chainHead != globalObj); JS_ASSERT(chainHead != globalObj);
TraceMonitor &localtm = *traceMonitor; TraceMonitor &localtm = *traceMonitor;
@ -10258,7 +10250,7 @@ TraceRecorder::clearFrameSlotsFromTracker(Tracker& which, JSStackFrame* fp, unsi
while (vp < vpstop) while (vp < vpstop)
which.set(vp++, (LIns*)0); which.set(vp++, (LIns*)0);
which.set(fp->addressArgsObj(), (LIns*)0); which.set(fp->addressArgsObj(), (LIns*)0);
which.set(&fp->scopeChain, (LIns*)0); which.set(fp->addressScopeChain(), (LIns*)0);
} }
vp = &fp->slots()[0]; vp = &fp->slots()[0];
vpstop = &fp->slots()[nslots]; vpstop = &fp->slots()[nslots];
@ -10337,7 +10329,7 @@ TraceRecorder::putActivationObjects()
slots_ins = INS_CONSTPTR(0); slots_ins = INS_CONSTPTR(0);
} }
LIns* scopeChain_ins = getFrameObjPtr(&cx->fp->scopeChain); LIns* scopeChain_ins = getFrameObjPtr(cx->fp->addressScopeChain());
LIns* args[] = { slots_ins, INS_CONST(nslots), args_ins, LIns* args[] = { slots_ins, INS_CONST(nslots), args_ins,
INS_CONST(cx->fp->fun->nargs), scopeChain_ins, cx_ins }; INS_CONST(cx->fp->fun->nargs), scopeChain_ins, cx_ins };
lir->insCall(&js_PutCallObjectOnTrace_ci, args); lir->insCall(&js_PutCallObjectOnTrace_ci, args);
@ -10361,7 +10353,7 @@ IsTraceableRecursion(JSContext *cx)
return false; return false;
if ((fp->flags & JSFRAME_CONSTRUCTING) || (down->flags & JSFRAME_CONSTRUCTING)) if ((fp->flags & JSFRAME_CONSTRUCTING) || (down->flags & JSFRAME_CONSTRUCTING))
return false; return false;
if (fp->blockChain || down->blockChain) if (fp->hasBlockChain() || down->hasBlockChain())
return false; return false;
if (*fp->script->code != JSOP_TRACE) if (*fp->script->code != JSOP_TRACE)
return false; return false;
@ -10409,7 +10401,7 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount)
nativeFrameTracker.set(fp->addressArgsObj(), NULL); nativeFrameTracker.set(fp->addressArgsObj(), NULL);
setFrameObjPtr(fp->addressArgsObj(), INS_NULL()); setFrameObjPtr(fp->addressArgsObj(), INS_NULL());
nativeFrameTracker.set(&fp->scopeChain, NULL); nativeFrameTracker.set(fp->addressScopeChain(), NULL);
vp = fp->slots(); vp = fp->slots();
vpstop = vp + fp->script->nfixed; vpstop = vp + fp->script->nfixed;
@ -10429,7 +10421,7 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount)
if (cx->fp->fun && JSFUN_HEAVYWEIGHT_TEST(cx->fp->fun->flags)) { if (cx->fp->fun && JSFUN_HEAVYWEIGHT_TEST(cx->fp->fun->flags)) {
// We need to make sure every part of the frame is known to the tracker // We need to make sure every part of the frame is known to the tracker
// before taking a snapshot. // before taking a snapshot.
setFrameObjPtr(&fp->scopeChain, INS_NULL()); setFrameObjPtr(fp->addressScopeChain(), INS_NULL());
if (js_IsNamedLambda(cx->fp->fun)) if (js_IsNamedLambda(cx->fp->fun))
RETURN_STOP_A("can't call named lambda heavyweight on trace"); RETURN_STOP_A("can't call named lambda heavyweight on trace");
@ -10440,9 +10432,9 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount)
LIns* call_ins = lir->insCall(&js_CreateCallObjectOnTrace_ci, args); LIns* call_ins = lir->insCall(&js_CreateCallObjectOnTrace_ci, args);
guard(false, lir->insEqP_0(call_ins), snapshot(OOM_EXIT)); guard(false, lir->insEqP_0(call_ins), snapshot(OOM_EXIT));
setFrameObjPtr(&fp->scopeChain, call_ins); setFrameObjPtr(fp->addressScopeChain(), call_ins);
} else { } else {
setFrameObjPtr(&fp->scopeChain, scopeChain_ins); setFrameObjPtr(fp->addressScopeChain(), scopeChain_ins);
} }
#if 0 #if 0
@ -10501,7 +10493,7 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount)
* Make sure the shape of the global object still matches (this might * Make sure the shape of the global object still matches (this might
* flush the JIT cache). * flush the JIT cache).
*/ */
JSObject* globalObj = cx->fp->scopeChain->getGlobal(); JSObject* globalObj = cx->fp->getScopeChain()->getGlobal();
uint32 globalShape = -1; uint32 globalShape = -1;
SlotList* globalSlots = NULL; SlotList* globalSlots = NULL;
if (!CheckGlobalObjectShape(cx, traceMonitor, globalObj, &globalShape, &globalSlots)) if (!CheckGlobalObjectShape(cx, traceMonitor, globalObj, &globalShape, &globalSlots))
@ -13107,7 +13099,7 @@ TraceRecorder::record_JSOP_SETELEM()
JS_REQUIRES_STACK AbortableRecordingStatus JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_CALLNAME() TraceRecorder::record_JSOP_CALLNAME()
{ {
JSObject* obj = cx->fp->scopeChain; JSObject* obj = cx->fp->getScopeChain();
if (obj != globalObj) { if (obj != globalObj) {
Value* vp; Value* vp;
LIns* ins; LIns* ins;
@ -13403,9 +13395,9 @@ TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc,
JS_ASSERT(argc < FrameInfo::CONSTRUCTING_FLAG); JS_ASSERT(argc < FrameInfo::CONSTRUCTING_FLAG);
tree->gcthings.addUnique(fval); tree->gcthings.addUnique(fval);
fi->block = fp->blockChain; fi->block = fp->maybeBlockChain();
if (fp->blockChain) if (fp->hasBlockChain())
tree->gcthings.addUnique(ObjectValue(*fp->blockChain)); tree->gcthings.addUnique(ObjectValue(*fp->getBlockChain()));
fi->pc = cx->regs->pc; fi->pc = cx->regs->pc;
fi->imacpc = fp->imacpc; fi->imacpc = fp->imacpc;
fi->spdist = cx->regs->sp - fp->slots(); fi->spdist = cx->regs->sp - fp->slots();
@ -13649,7 +13641,7 @@ TraceRecorder::record_NativeCallComplete()
JS_REQUIRES_STACK AbortableRecordingStatus JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::name(Value*& vp, LIns*& ins, NameResult& nr) TraceRecorder::name(Value*& vp, LIns*& ins, NameResult& nr)
{ {
JSObject* obj = cx->fp->scopeChain; JSObject* obj = cx->fp->getScopeChain();
JSOp op = JSOp(*cx->regs->pc); JSOp op = JSOp(*cx->regs->pc);
if (js_CodeSpec[op].format & JOF_GNAME) if (js_CodeSpec[op].format & JOF_GNAME)
obj = obj->getGlobal(); obj = obj->getGlobal();
@ -14769,7 +14761,7 @@ TraceRecorder::record_JSOP_BINDNAME()
JSObject *obj; JSObject *obj;
if (!fp->fun) { if (!fp->fun) {
obj = fp->scopeChain; obj = fp->getScopeChain();
#ifdef DEBUG #ifdef DEBUG
JSStackFrame *fp2 = fp; JSStackFrame *fp2 = fp;
@ -14830,7 +14822,7 @@ TraceRecorder::record_JSOP_BINDNAME()
JSAtom *atom = atoms[GET_INDEX(cx->regs->pc)]; JSAtom *atom = atoms[GET_INDEX(cx->regs->pc)];
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
JSContext *localCx = cx; JSContext *localCx = cx;
JSObject *obj2 = js_FindIdentifierBase(cx, fp->scopeChain, id); JSObject *obj2 = js_FindIdentifierBase(cx, fp->getScopeChain(), id);
if (!obj2) if (!obj2)
RETURN_ERROR_A("error in js_FindIdentifierBase"); RETURN_ERROR_A("error in js_FindIdentifierBase");
if (!TRACE_RECORDER(localCx)) if (!TRACE_RECORDER(localCx))
@ -15803,7 +15795,7 @@ JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_LEAVEBLOCK() TraceRecorder::record_JSOP_LEAVEBLOCK()
{ {
/* We mustn't exit the lexical block we began recording in. */ /* We mustn't exit the lexical block we began recording in. */
if (cx->fp->blockChain == lexicalBlock) if (cx->fp->getBlockChain() == lexicalBlock)
return ARECORD_STOP; return ARECORD_STOP;
return ARECORD_CONTINUE; return ARECORD_CONTINUE;
} }

View File

@ -387,7 +387,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
* we parent all wrappers to the global object in their home compartment. * we parent all wrappers to the global object in their home compartment.
* This loses us some transparency, and is generally very cheesy. * This loses us some transparency, and is generally very cheesy.
*/ */
JSObject *global = cx->fp ? cx->fp->scopeChain->getGlobal() : cx->globalObject; JSObject *global = cx->fp ? cx->fp->getScopeChain()->getGlobal() : cx->globalObject;
wrapper->setParent(global); wrapper->setParent(global);
return true; return true;
} }
@ -515,7 +515,7 @@ SetupFakeFrame(JSContext *cx, ExecuteFrameGuard &frame, JSFrameRegs &regs, JSObj
JSStackFrame *fp = frame.getFrame(); JSStackFrame *fp = frame.getFrame();
PodZero(fp); // fp->fun and fp->script are both NULL PodZero(fp); // fp->fun and fp->script are both NULL
fp->argv = vp + 2; fp->argv = vp + 2;
fp->scopeChain = obj->getGlobal(); fp->setScopeChain(obj->getGlobal());
fp->flags = JSFRAME_DUMMY; fp->flags = JSFRAME_DUMMY;
regs.pc = NULL; regs.pc = NULL;

View File

@ -1735,7 +1735,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
{ {
Parser parser(cx); Parser parser(cx);
if (parser.init(chars, length, NULL, filename, lineno)) { if (parser.init(chars, length, NULL, filename, lineno)) {
JSObject *scopeChain = js_GetTopStackFrame(cx)->scopeChain; JSObject *scopeChain = js_GetTopStackFrame(cx)->getScopeChain();
JSParseNode *pn = parser.parseXMLText(scopeChain, false); JSParseNode *pn = parser.parseXMLText(scopeChain, false);
uintN flags; uintN flags;
if (pn && GetXMLSettingFlags(cx, &flags)) { if (pn && GetXMLSettingFlags(cx, &flags)) {
@ -7227,7 +7227,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp)
fp = js_GetTopStackFrame(cx); fp = js_GetTopStackFrame(cx);
obj = NULL; obj = NULL;
for (tmp = fp->scopeChain; tmp; tmp = tmp->getParent()) { for (tmp = fp->getScopeChain(); tmp; tmp = tmp->getParent()) {
Class *clasp = tmp->getClass(); Class *clasp = tmp->getClass();
if (clasp == &js_BlockClass || clasp == &js_WithClass) if (clasp == &js_BlockClass || clasp == &js_WithClass)
continue; continue;
@ -7440,7 +7440,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
if (!IsFunctionQName(cx, qn, &funid)) if (!IsFunctionQName(cx, qn, &funid))
return JS_FALSE; return JS_FALSE;
obj = js_GetTopStackFrame(cx)->scopeChain; obj = js_GetTopStackFrame(cx)->getScopeChain();
do { do {
/* Skip any With object that can wrap XML. */ /* Skip any With object that can wrap XML. */
target = obj; target = obj;