Bug 690446 - Emit *GNAME ops in non-eval strict-mode code. r=bhackett

--HG--
extra : rebase_source : 11bced315dd2d4fa125ac1e2cd7f4b599dd62c3c
This commit is contained in:
Jan de Mooij 2013-05-07 16:27:14 +02:00
parent 3a5e115094
commit db26d3fc93
8 changed files with 32 additions and 16 deletions

View File

@ -286,6 +286,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
CompileOptions options(cx);
options.setFileAndLine(filename, lineno)
.setCompileAndGo(true)
.setForEval(true)
.setNoScriptRval(false)
.setPrincipals(principals)
.setOriginPrincipals(originPrincipals);
@ -347,6 +348,7 @@ js::DirectEvalFromIon(JSContext *cx,
CompileOptions options(cx);
options.setFileAndLine(filename, lineno)
.setCompileAndGo(true)
.setForEval(true)
.setNoScriptRval(false)
.setPrincipals(principals)
.setOriginPrincipals(originPrincipals);

View File

@ -90,6 +90,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
* and non-zero static level requires callerFrame.
*/
JS_ASSERT_IF(evalCaller, options.compileAndGo);
JS_ASSERT_IF(evalCaller, options.forEval);
JS_ASSERT_IF(staticLevel != 0, evalCaller);
if (!CheckLength(cx, length))
@ -146,8 +147,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain,
JS_ASSERT_IF(globalScope, globalScope->isNative());
JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
BytecodeEmitter bce(/* parent = */ NULL, &parser, &globalsc, script, evalCaller, !!globalScope,
options.lineno, options.selfHostingMode);
BytecodeEmitter bce(/* parent = */ NULL, &parser, &globalsc, script, options.forEval, evalCaller,
!!globalScope, options.lineno, options.selfHostingMode);
if (!bce.init())
return NULL;
@ -330,6 +331,8 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
return false;
}
JS_ASSERT(!options.forEval);
Parser<FullParseHandler> parser(cx, options, chars, length, /* foldConstants = */ true);
if (!parser.init())
return false;
@ -420,7 +423,7 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO
* is cloned immediately onto the right scope chain.
*/
BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script,
/* evalCaller = */ NullPtr(),
/* insideEval = */ false, /* evalCaller = */ NullPtr(),
fun->environment() && fun->environment()->isGlobal(),
options.lineno);
if (!funbce.init())

View File

@ -90,8 +90,8 @@ struct frontend::StmtInfoBCE : public StmtInfoBase
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
Parser<FullParseHandler> *parser, SharedContext *sc,
HandleScript script, HandleScript evalCaller, bool hasGlobalScope,
uint32_t lineNum, bool selfHostingMode)
HandleScript script, bool insideEval, HandleScript evalCaller,
bool hasGlobalScope, uint32_t lineNum, bool selfHostingMode)
: sc(sc),
parent(parent),
script(sc->context, script),
@ -114,9 +114,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
hasSingletons(false),
emittingForInit(false),
emittingRunOnceLambda(false),
insideEval(insideEval),
hasGlobalScope(hasGlobalScope),
selfHostingMode(selfHostingMode)
{
JS_ASSERT_IF(evalCaller, insideEval);
}
bool
@ -1096,11 +1098,10 @@ EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
/*
* Try to convert a *NAME op to a *GNAME op, which optimizes access to
* undeclared globals. Return true if a conversion was made.
* globals. Return true if a conversion was made.
*
* This conversion is not made if we are in strict mode. In eval code nested
* within (strict mode) eval code, access to an undeclared "global" might
* merely be to a binding local to that outer eval:
* Don't convert to *GNAME ops within strict-mode eval, since access
* to a "global" might merely be to a binding local to that eval:
*
* "use strict";
* var x = "global";
@ -1136,7 +1137,7 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
bce->hasGlobalScope &&
!(bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->mightAliasLocals()) &&
!pn->isDeoptimized() &&
!bce->sc->strict)
!(bce->sc->strict && bce->insideEval))
{
// If you change anything here, you might also need to change
// js::ReportIfUndeclaredVarAssignment.
@ -4453,8 +4454,9 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
script->bindings = funbox->bindings;
uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
BytecodeEmitter bce2(bce, bce->parser, funbox, script, bce->evalCaller,
bce->hasGlobalScope, lineNum, bce->selfHostingMode);
BytecodeEmitter bce2(bce, bce->parser, funbox, script, bce->insideEval,
bce->evalCaller, bce->hasGlobalScope, lineNum,
bce->selfHostingMode);
if (!bce2.init())
return false;

View File

@ -124,6 +124,9 @@ struct BytecodeEmitter
bool emittingRunOnceLambda:1; /* true while emitting a lambda which is only
expected to run once. */
bool insideEval:1; /* True if compiling an eval-expression or a function
nested inside an eval. */
const bool hasGlobalScope:1; /* frontend::CompileScript's scope chain is the
global object */
@ -139,8 +142,8 @@ struct BytecodeEmitter
* destruction.
*/
BytecodeEmitter(BytecodeEmitter *parent, Parser<FullParseHandler> *parser, SharedContext *sc,
HandleScript script, HandleScript evalCaller, bool hasGlobalScope,
uint32_t lineNum, bool selfHostingMode = false);
HandleScript script, bool insideEval, HandleScript evalCaller,
bool hasGlobalScope, uint32_t lineNum, bool selfHostingMode = false);
bool init();
bool isAliasedName(ParseNode *pn);

View File

@ -5415,7 +5415,8 @@ CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
const Register objReg = ToRegister(ins->getOperand(0));
bool isSetName = JSOp(*ins->mir()->resumePoint()->pc()) == JSOP_SETNAME;
jsbytecode *pc = ins->mir()->resumePoint()->pc();
bool isSetName = JSOp(*pc) == JSOP_SETNAME || JSOp(*pc) == JSOP_SETGNAME;
pushArg(Imm32(isSetName));
pushArg(Imm32(ins->mir()->strict()));
@ -5451,7 +5452,8 @@ CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
RegisterSet liveRegs = ins->safepoint()->liveRegs();
Register objReg = ToRegister(ins->getOperand(0));
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
bool isSetName = JSOp(*ins->mir()->resumePoint()->pc()) == JSOP_SETNAME;
jsbytecode *pc = ins->mir()->resumePoint()->pc();
bool isSetName = JSOp(*pc) == JSOP_SETNAME || JSOp(*pc) == JSOP_SETGNAME;
SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value,
isSetName, ins->mir()->strict());

View File

@ -5258,6 +5258,7 @@ JS::CompileOptions::CompileOptions(JSContext *cx)
filename(NULL),
lineno(1),
compileAndGo(cx->hasOption(JSOPTION_COMPILE_N_GO)),
forEval(false),
noScriptRval(cx->hasOption(JSOPTION_NO_SCRIPT_RVAL)),
selfHostingMode(false),
userBit(false),

View File

@ -3844,6 +3844,7 @@ struct JS_PUBLIC_API(CompileOptions) {
const char *filename;
unsigned lineno;
bool compileAndGo;
bool forEval;
bool noScriptRval;
bool selfHostingMode;
bool userBit;
@ -3862,6 +3863,7 @@ struct JS_PUBLIC_API(CompileOptions) {
filename = f; lineno = l; return *this;
}
CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
CompileOptions &setForEval(bool eval) { forEval = eval; return *this; }
CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
CompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; }
CompileOptions &setUserBit(bool bit) { userBit = bit; return *this; }

View File

@ -3915,6 +3915,7 @@ js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, HandleValue thisv, AbstractFr
CompileOptions options(cx);
options.setPrincipals(env->compartment()->principals)
.setCompileAndGo(true)
.setForEval(true)
.setNoScriptRval(false)
.setFileAndLine(filename, lineno);
RootedScript callerScript(cx, frame ? frame.script() : NULL);