зеркало из https://github.com/mozilla/gecko-dev.git
Bug 514568 - Trace strict eval frame Call objects correctly, keep the eval script safe from GC, and properly put strict eval Call objects when the script completes. r=igor
This commit is contained in:
Родитель
f068c1f307
Коммит
0f38280e77
|
@ -1079,58 +1079,70 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
|
|
||||||
/* Get the arguments object to snapshot fp's actual argument values. */
|
/* Get the arguments object to snapshot fp's actual argument values. */
|
||||||
if (fp->hasArgsObj()) {
|
if (fp->hasArgsObj()) {
|
||||||
|
JS_ASSERT(!fp->isEvalFrame());
|
||||||
if (!fp->hasOverriddenArgs())
|
if (!fp->hasOverriddenArgs())
|
||||||
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
|
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
|
||||||
js_PutArgsObject(cx, fp);
|
js_PutArgsObject(cx, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSFunction *fun = fp->fun();
|
JSScript *script = fp->script();
|
||||||
JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
|
Bindings &bindings = script->bindings;
|
||||||
|
|
||||||
Bindings &bindings = fun->script()->bindings;
|
JSObject *callee = callobj.getCallObjCallee();
|
||||||
uintN n = bindings.countArgsAndVars();
|
if (callee) {
|
||||||
|
JSFunction *fun = fp->fun();
|
||||||
|
JS_ASSERT(fun == callee->getFunctionPrivate());
|
||||||
|
JS_ASSERT(script == fun->script());
|
||||||
|
|
||||||
if (n != 0) {
|
if (uintN n = bindings.countArgsAndVars()) {
|
||||||
JS_ASSERT(JSFunction::CLASS_RESERVED_SLOTS + n <= callobj.numSlots());
|
JS_ASSERT(JSObject::CALL_RESERVED_SLOTS + n <= callobj.numSlots());
|
||||||
|
|
||||||
uint32 nvars = bindings.countVars();
|
uint32 nvars = bindings.countVars();
|
||||||
uint32 nargs = bindings.countArgs();
|
uint32 nargs = bindings.countArgs();
|
||||||
JS_ASSERT(fun->nargs == nargs);
|
JS_ASSERT(fun->nargs == nargs);
|
||||||
JS_ASSERT(nvars + nargs == n);
|
JS_ASSERT(nvars + nargs == n);
|
||||||
|
|
||||||
JSScript *script = fun->script();
|
JSScript *script = fun->script();
|
||||||
if (script->usesEval
|
if (script->usesEval
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
|| script->debugMode
|
|| script->debugMode
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
|
CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* For each arg & var that is closed over, copy it from the stack
|
* For each arg & var that is closed over, copy it from the stack
|
||||||
* into the call object.
|
* into the call object.
|
||||||
*/
|
*/
|
||||||
uint32 nclosed = script->nClosedArgs;
|
uint32 nclosed = script->nClosedArgs;
|
||||||
for (uint32 i = 0; i < nclosed; i++) {
|
for (uint32 i = 0; i < nclosed; i++) {
|
||||||
uint32 e = script->getClosedArg(i);
|
uint32 e = script->getClosedArg(i);
|
||||||
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e));
|
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
nclosed = script->nClosedVars;
|
nclosed = script->nClosedVars;
|
||||||
for (uint32 i = 0; i < nclosed; i++) {
|
for (uint32 i = 0; i < nclosed; i++) {
|
||||||
uint32 e = script->getClosedVar(i);
|
uint32 e = script->getClosedVar(i);
|
||||||
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
|
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear private pointers to fp, which is about to go away (js_Invoke). */
|
/* Clear private pointers to fp, which is about to go away (js_Invoke). */
|
||||||
if (js_IsNamedLambda(fun)) {
|
if (js_IsNamedLambda(fun)) {
|
||||||
JSObject *env = callobj.getParent();
|
JSObject *env = callobj.getParent();
|
||||||
|
|
||||||
JS_ASSERT(env->getClass() == &js_DeclEnvClass);
|
JS_ASSERT(env->getClass() == &js_DeclEnvClass);
|
||||||
JS_ASSERT(env->getPrivate() == fp);
|
JS_ASSERT(env->getPrivate() == fp);
|
||||||
env->setPrivate(NULL);
|
env->setPrivate(NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JS_ASSERT(fp->isEvalFrame());
|
||||||
|
JS_ASSERT(script->strictModeCode);
|
||||||
|
JS_ASSERT(bindings.countArgs() == 0);
|
||||||
|
|
||||||
|
/* This could be optimized as above. But for now, keep it simple. */
|
||||||
|
CopyValuesToCallObject(callobj, 0, NULL, bindings.countVars(), fp->slots());
|
||||||
}
|
}
|
||||||
|
|
||||||
callobj.setPrivate(NULL);
|
callobj.setPrivate(NULL);
|
||||||
|
@ -1360,8 +1372,7 @@ static void
|
||||||
call_trace(JSTracer *trc, JSObject *obj)
|
call_trace(JSTracer *trc, JSObject *obj)
|
||||||
{
|
{
|
||||||
JS_ASSERT(obj->isCall());
|
JS_ASSERT(obj->isCall());
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
if (JSStackFrame *fp = obj->maybeCallObjStackFrame()) {
|
||||||
if (fp) {
|
|
||||||
/*
|
/*
|
||||||
* FIXME: Hide copies of stack values rooted by fp from the Cycle
|
* FIXME: Hide copies of stack values rooted by fp from the Cycle
|
||||||
* Collector, which currently lacks a non-stub Unlink implementation
|
* Collector, which currently lacks a non-stub Unlink implementation
|
||||||
|
@ -1370,7 +1381,7 @@ call_trace(JSTracer *trc, JSObject *obj)
|
||||||
* hiding hack.
|
* hiding hack.
|
||||||
*/
|
*/
|
||||||
uintN first = JSObject::CALL_RESERVED_SLOTS;
|
uintN first = JSObject::CALL_RESERVED_SLOTS;
|
||||||
uintN count = fp->fun()->script()->bindings.countArgsAndVars();
|
uintN count = fp->script()->bindings.countArgsAndVars();
|
||||||
|
|
||||||
JS_ASSERT(obj->numSlots() >= first + count);
|
JS_ASSERT(obj->numSlots() >= first + count);
|
||||||
SetValueRangeToUndefined(obj->getSlots() + first, count);
|
SetValueRangeToUndefined(obj->getSlots() + first, count);
|
||||||
|
|
|
@ -966,12 +966,12 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||||
initialVarObj = (cx->options & JSOPTION_VAROBJFIX) ? chain->getGlobal() : chain;
|
initialVarObj = (cx->options & JSOPTION_VAROBJFIX) ? chain->getGlobal() : chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 /* to be reenabled shortly when this works */
|
|
||||||
/*
|
/*
|
||||||
* Strict mode eval code receives its own, fresh lexical environment; thus
|
* Strict mode eval code receives its own, fresh lexical environment; thus
|
||||||
* strict mode eval can't mutate its calling frame's binding set.
|
* strict mode eval can't mutate its calling frame's binding set.
|
||||||
*/
|
*/
|
||||||
if (script->strictModeCode) {
|
if (script->strictModeCode) {
|
||||||
|
AutoScriptRooter root(cx, script);
|
||||||
initialVarObj = NewCallObject(cx, &script->bindings, *initialVarObj, NULL);
|
initialVarObj = NewCallObject(cx, &script->bindings, *initialVarObj, NULL);
|
||||||
if (!initialVarObj)
|
if (!initialVarObj)
|
||||||
return false;
|
return false;
|
||||||
|
@ -982,7 +982,6 @@ Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||||
frame.fp()->clearCallObj();
|
frame.fp()->clearCallObj();
|
||||||
frame.fp()->setScopeChainAndCallObj(*initialVarObj);
|
frame.fp()->setScopeChainAndCallObj(*initialVarObj);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
JS_ASSERT(!initialVarObj->getOps()->defineProperty);
|
JS_ASSERT(!initialVarObj->getOps()->defineProperty);
|
||||||
|
|
||||||
#if JS_HAS_SHARP_VARS
|
#if JS_HAS_SHARP_VARS
|
||||||
|
|
|
@ -722,13 +722,28 @@ ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
|
||||||
if (JS_UNLIKELY(hook != NULL) && (hookData = fp->maybeHookData()))
|
if (JS_UNLIKELY(hook != NULL) && (hookData = fp->maybeHookData()))
|
||||||
hook(cx, fp, JS_FALSE, &ok, hookData);
|
hook(cx, fp, JS_FALSE, &ok, hookData);
|
||||||
|
|
||||||
/*
|
if (fp->isEvalFrame()) {
|
||||||
* An eval frame's parent owns its activation objects. A yielding frame's
|
/*
|
||||||
* activation objects are transferred to the floating frame, stored in the
|
* The parent (ancestor for nested eval) of a non-strict eval frame
|
||||||
* generator.
|
* owns its activation objects. Strict mode eval frames own their own
|
||||||
*/
|
* Call objects but never have an arguments object (the first non-eval
|
||||||
if (fp->isFunctionFrame() && !fp->isEvalFrame() && !fp->isYielding())
|
* parent frame has it).
|
||||||
PutActivationObjects(cx, fp);
|
*/
|
||||||
|
if (fp->script()->strictModeCode) {
|
||||||
|
JS_ASSERT(!fp->isYielding());
|
||||||
|
JS_ASSERT(fp->hasCallObj());
|
||||||
|
JS_ASSERT(!fp->hasArgsObj());
|
||||||
|
js_PutCallObject(cx, fp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Otherwise only function frames have activation objects. A yielding
|
||||||
|
* frame's activation objects are transferred to the floating frame,
|
||||||
|
* stored in the generator, and thus need not be synced.
|
||||||
|
*/
|
||||||
|
if (fp->isFunctionFrame() && !fp->isYielding())
|
||||||
|
PutActivationObjects(cx, fp);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If inline-constructing, replace primitive rval with the new object
|
* If inline-constructing, replace primitive rval with the new object
|
||||||
|
|
|
@ -480,13 +480,6 @@ stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
|
||||||
stubs::PutCallObject(VMFrame &f)
|
|
||||||
{
|
|
||||||
JS_ASSERT(f.fp()->hasCallObj());
|
|
||||||
js_PutCallObject(f.cx, f.fp());
|
|
||||||
}
|
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::PutActivationObjects(VMFrame &f)
|
stubs::PutActivationObjects(VMFrame &f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -107,7 +107,6 @@ void UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr);
|
||||||
|
|
||||||
void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto);
|
void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto);
|
||||||
void JS_FASTCALL Throw(VMFrame &f);
|
void JS_FASTCALL Throw(VMFrame &f);
|
||||||
void JS_FASTCALL PutCallObject(VMFrame &f);
|
|
||||||
void JS_FASTCALL PutActivationObjects(VMFrame &f);
|
void JS_FASTCALL PutActivationObjects(VMFrame &f);
|
||||||
void JS_FASTCALL GetCallObject(VMFrame &f);
|
void JS_FASTCALL GetCallObject(VMFrame &f);
|
||||||
#if JS_MONOIC
|
#if JS_MONOIC
|
||||||
|
|
|
@ -16,22 +16,22 @@ url-prefix ../../jsreftest.html?test=ecma_5/eval/
|
||||||
# optimizations we might perform -- add new tests for such changes as needed.
|
# optimizations we might perform -- add new tests for such changes as needed.
|
||||||
#
|
#
|
||||||
|
|
||||||
# script exhaustive-fun-normalcaller-direct-normalcode.js
|
script exhaustive-fun-normalcaller-direct-normalcode.js
|
||||||
# script exhaustive-fun-normalcaller-direct-strictcode.js
|
script exhaustive-fun-normalcaller-direct-strictcode.js
|
||||||
# script exhaustive-fun-normalcaller-indirect-normalcode.js
|
script exhaustive-fun-normalcaller-indirect-normalcode.js
|
||||||
# script exhaustive-fun-normalcaller-indirect-strictcode.js
|
script exhaustive-fun-normalcaller-indirect-strictcode.js
|
||||||
# script exhaustive-fun-strictcaller-direct-normalcode.js
|
script exhaustive-fun-strictcaller-direct-normalcode.js
|
||||||
# script exhaustive-fun-strictcaller-direct-strictcode.js
|
script exhaustive-fun-strictcaller-direct-strictcode.js
|
||||||
# script exhaustive-fun-strictcaller-indirect-normalcode.js
|
script exhaustive-fun-strictcaller-indirect-normalcode.js
|
||||||
# script exhaustive-fun-strictcaller-indirect-strictcode.js
|
script exhaustive-fun-strictcaller-indirect-strictcode.js
|
||||||
# script exhaustive-global-normalcaller-direct-normalcode.js
|
script exhaustive-global-normalcaller-direct-normalcode.js
|
||||||
# script exhaustive-global-normalcaller-direct-strictcode.js
|
script exhaustive-global-normalcaller-direct-strictcode.js
|
||||||
# script exhaustive-global-normalcaller-indirect-normalcode.js
|
script exhaustive-global-normalcaller-indirect-normalcode.js
|
||||||
# script exhaustive-global-normalcaller-indirect-strictcode.js
|
script exhaustive-global-normalcaller-indirect-strictcode.js
|
||||||
# script exhaustive-global-strictcaller-direct-normalcode.js
|
script exhaustive-global-strictcaller-direct-normalcode.js
|
||||||
# script exhaustive-global-strictcaller-direct-strictcode.js
|
script exhaustive-global-strictcaller-direct-strictcode.js
|
||||||
# script exhaustive-global-strictcaller-indirect-normalcode.js
|
script exhaustive-global-strictcaller-indirect-normalcode.js
|
||||||
# script exhaustive-global-strictcaller-indirect-strictcode.js
|
script exhaustive-global-strictcaller-indirect-strictcode.js
|
||||||
|
|
||||||
# Not written yet! These require a new shell primitive to work there, though
|
# Not written yet! These require a new shell primitive to work there, though
|
||||||
# browser could probably use setTimeout for this. Moreover, we haven't
|
# browser could probably use setTimeout for this. Moreover, we haven't
|
||||||
|
|
|
@ -39,4 +39,4 @@ script unbrand-this.js
|
||||||
script this-for-function-expression-recursion.js
|
script this-for-function-expression-recursion.js
|
||||||
script assign-to-callee-name.js
|
script assign-to-callee-name.js
|
||||||
script directive-prologue-01.js
|
script directive-prologue-01.js
|
||||||
# script eval-variable-environment.js
|
script eval-variable-environment.js
|
||||||
|
|
Загрузка…
Ссылка в новой задаче