Bug 788957 (part 2) - Split ContextFlags into AnyContextFlags and FunctionContextFlags. r=benjamin.

--HG--
extra : rebase_source : a850729d3ca94cc6a04c87bf26e6154a7e1ef18b
This commit is contained in:
Nicholas Nethercote 2012-09-10 20:40:11 -07:00
parent 198b733431
commit 90142084a7
6 changed files with 89 additions and 76 deletions

View File

@ -1178,7 +1178,7 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
}
if (bce->script->compileAndGo &&
bce->hasGlobalScope &&
!(bce->sc->inFunction() && bce->sc->funMightAliasLocals()) &&
!(bce->sc->inFunction() && bce->sc->funbox()->mightAliasLocals()) &&
!pn->isDeoptimized() &&
!bce->sc->inStrictMode())
{
@ -2613,7 +2613,8 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
* execution starts from script->code, so this has no semantic effect.
*/
if (bce->sc->funArgumentsHasLocalBinding()) {
FunctionBox *funbox = bce->sc->funbox();
if (funbox->argumentsHasLocalBinding()) {
JS_ASSERT(bce->next() == bce->base()); /* See JSScript::argumentsBytecode. */
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
@ -2634,7 +2635,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
bce->switchToMain();
}
if (bce->sc->funIsGenerator()) {
if (funbox->isGenerator()) {
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
return false;
@ -4846,9 +4847,9 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{
FunctionBox *funbox = pn->pn_funbox;
SharedContext sc(cx, /* scopeChain = */ NULL, funbox, funbox->strictModeState);
sc.cxFlags = funbox->cxFlags;
if (bce->sc->inFunction() && bce->sc->funMightAliasLocals())
sc.setFunMightAliasLocals(); // inherit funMightAliasLocals from parent
sc.anyCxFlags = funbox->anyCxFlags; // copy the non-func-specific flags
if (bce->sc->inFunction() && bce->sc->funbox()->mightAliasLocals())
funbox->setMightAliasLocals(); // inherit mightAliasLocals from parent
JS_ASSERT_IF(bce->sc->inStrictMode(), sc.inStrictMode());
// Inherit most things (principals, version, etc) from the parent.
@ -6087,7 +6088,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
ParseNode *rest = NULL;
bool restIsDefn = false;
if (fun->hasRest()) {
JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
JS_ASSERT(!bce->sc->funbox()->argumentsHasLocalBinding());
// Defaults with a rest parameter need special handling. The
// rest parameter needs to be undefined while defaults are being
// processed. To do this, we create the rest argument and let it
@ -6132,7 +6133,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false;
if (pn2->pn_next == pnlast && fun->hasRest() && !fun->hasDefaults()) {
// Fill rest parameter. We handled the case with defaults above.
JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
JS_ASSERT(!bce->sc->funbox()->argumentsHasLocalBinding());
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_REST) < 0)
return false;

View File

@ -316,7 +316,7 @@ ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*>
return false;
}
if (bindings->hasAnyAliasedBindings() || sc->funHasExtensibleScope())
if (bindings->hasAnyAliasedBindings() || sc->funbox()->hasExtensibleScope())
sc->funbox()->fun()->flags |= JSFUN_HEAVYWEIGHT;
return true;
@ -410,7 +410,8 @@ FunctionBox::FunctionBox(ObjectBox *traceListHead, JSFunction *fun, ParseContext
strictModeState(sms),
inWith(false), // initialized below
inGenexpLambda(false),
cxFlags() // the cxFlags are set in LeaveFunction
anyCxFlags(),
funCxFlags() // the funCxFlags are set in LeaveFunction
{
if (!outerpc) {
inWith = false;
@ -762,7 +763,7 @@ Parser::functionBody(FunctionBodyType type)
if (!pn->pn_kid) {
pn = NULL;
} else {
if (pc->sc->funIsGenerator()) {
if (pc->sc->funbox()->isGenerator()) {
ReportBadReturn(context, this, pn, &Parser::reportError,
JSMSG_BAD_GENERATOR_RETURN,
JSMSG_BAD_ANON_GENERATOR_RETURN);
@ -859,11 +860,12 @@ Parser::functionBody(FunctionBodyType type)
* arguments object. (Also see the flags' comments in ContextFlags.)
*/
if (argumentsHasLocalBinding) {
pc->sc->setFunArgumentsHasLocalBinding();
FunctionBox *funbox = pc->sc->funbox();
funbox->setArgumentsHasLocalBinding();
/* Dynamic scope access destroys all hope of optimization. */
if (pc->sc->bindingsAccessedDynamically())
pc->sc->setFunDefinitelyNeedsArgsObj();
funbox->setDefinitelyNeedsArgsObj();
/*
* Check whether any parameters have been assigned within this
@ -878,7 +880,7 @@ Parser::functionBody(FunctionBodyType type)
for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
Definition *dn = dr.front();
if (dn->kind() == Definition::ARG && dn->isAssigned()) {
pc->sc->setFunDefinitelyNeedsArgsObj();
funbox->setDefinitelyNeedsArgsObj();
goto exitLoop;
}
}
@ -1152,7 +1154,7 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL,
pc->blockidGen = funpc->blockidGen;
FunctionBox *funbox = fn->pn_funbox;
funbox->cxFlags = funpc->sc->cxFlags; // copy all the flags
funbox->anyCxFlags = funpc->sc->anyCxFlags; // copy the non-func flags
funbox->kids = funpc->functionList;
if (!pc->topStmt || pc->topStmt->type == STMT_BLOCK)
@ -1196,7 +1198,7 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL,
* by eval and function statements (which both flag the function as
* having an extensible scope) or any enclosing 'with'.
*/
if (funpc->sc->funHasExtensibleScope() || pc->parsingWith)
if (funpc->sc->funbox()->hasExtensibleScope() || pc->parsingWith)
DeoptimizeUsesWithin(dn, fn->pn_pos);
if (!outer_dn) {
@ -1598,8 +1600,9 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
JS_ASSERT(pc->sc->strictModeState != StrictMode::STRICT);
JS_ASSERT(pn->pn_cookie.isFree());
if (pc->sc->inFunction()) {
pc->sc->setFunMightAliasLocals();
pc->sc->setFunHasExtensibleScope();
FunctionBox *funbox = pc->sc->funbox();
funbox->setMightAliasLocals();
funbox->setHasExtensibleScope();
}
pn->setOp(JSOP_DEFFUN);
@ -1994,7 +1997,7 @@ Parser::statements(bool *hasFunctionStmt)
* General deoptimization was done in functionDef, here we just
* need to tell TOK_LC in Parser::statement to add braces.
*/
JS_ASSERT_IF(pc->sc->inFunction(), pc->sc->funHasExtensibleScope());
JS_ASSERT_IF(pc->sc->inFunction(), pc->sc->funbox()->hasExtensibleScope());
if (hasFunctionStmt)
*hasFunctionStmt = true;
}
@ -2194,8 +2197,8 @@ BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *p
if (stmt && stmt->type == STMT_WITH) {
pn->pn_dflags |= PND_DEOPTIMIZED;
if (pc->sc->inFunction())
pc->sc->setFunMightAliasLocals();
if (pc->sc->inFunction())
pc->sc->funbox()->setMightAliasLocals();
return true;
}
@ -2582,7 +2585,7 @@ Parser::returnOrYield(bool useAssignExpr)
* a |for| token, so we have to delay flagging the current function.
*/
if (pc->parenDepth == 0) {
pc->sc->setFunIsGenerator();
pc->sc->funbox()->setIsGenerator();
} else {
pc->yieldCount++;
pc->yieldNode = pn;
@ -2619,7 +2622,7 @@ Parser::returnOrYield(bool useAssignExpr)
pc->funHasReturnVoid = true;
}
if (pc->funHasReturnExpr && pc->sc->funIsGenerator()) {
if (pc->funHasReturnExpr && pc->sc->funbox()->isGenerator()) {
/* As in Python (see PEP-255), disallow return v; in generators. */
ReportBadReturn(context, this, pn, &Parser::reportError, JSMSG_BAD_GENERATOR_RETURN,
JSMSG_BAD_ANON_GENERATOR_RETURN);
@ -4859,9 +4862,9 @@ GenexpGuard::maybeNoteGenerator(ParseNode *pn)
parser->reportError(NULL, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
return false;
}
pc->sc->setFunIsGenerator();
pc->sc->funbox()->setIsGenerator();
if (pc->funHasReturnExpr) {
/* At the time we saw the yield, we might not have set funIsGenerator yet. */
/* At the time we saw the yield, we might not have set isGenerator yet. */
ReportBadReturn(pc->sc->context, parser, pn, &Parser::reportError,
JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN);
return false;
@ -5378,9 +5381,11 @@ Parser::generatorExpr(ParseNode *kid)
* simplicity we also do not detect if the flags were only set in the
* kid and could be removed from pc->sc.
*/
gensc.cxFlags = outerpc->sc->cxFlags;
gensc.setFunIsGenerator();
gensc.anyCxFlags = outerpc->sc->anyCxFlags;
if (outerpc->sc->inFunction())
funbox->funCxFlags = outerpc->sc->funbox()->funCxFlags;
funbox->setIsGenerator();
funbox->inGenexpLambda = true;
genfn->pn_funbox = funbox;
genfn->pn_blockid = genpc.bodyid;
@ -5704,7 +5709,7 @@ Parser::memberExpr(bool allowCallSyntax)
* variables to the call object.
*/
if (pc->sc->inFunction() && pc->sc->strictModeState != StrictMode::STRICT)
pc->sc->setFunHasExtensibleScope();
pc->sc->funbox()->setHasExtensibleScope();
}
} else if (lhs->isOp(JSOP_GETPROP)) {
/* Select JSOP_FUNAPPLY given foo.apply(...). */

View File

@ -20,7 +20,7 @@ SharedContext::SharedContext(JSContext *cx, JSObject *scopeChain, FunctionBox *f
: context(cx),
funbox_(funbox),
scopeChain_(cx, scopeChain),
cxFlags(),
anyCxFlags(),
strictModeState(sms)
{
JS_ASSERT((funbox && !scopeChain_) || !funbox);

View File

@ -22,11 +22,11 @@
namespace js {
namespace frontend {
class ContextFlags {
// These flags apply to both global and function contexts.
class AnyContextFlags {
// This class's data is all private and so only visible to these friends.
friend struct SharedContext;
friend struct FunctionBox;
// True if "use strict"; appears in the body instead of being inherited.
bool hasExplicitUseStrict:1;
@ -54,12 +54,24 @@ class ContextFlags {
//
bool bindingsAccessedDynamically:1;
public:
AnyContextFlags()
: hasExplicitUseStrict(false),
bindingsAccessedDynamically(false)
{ }
};
class FunctionContextFlags {
// This class's data is all private and so only visible to these friends.
friend struct FunctionBox;
// We parsed a yield statement in the function.
bool funIsGenerator:1;
bool isGenerator:1;
// The function or a function that encloses it may define new local names
// at runtime through means other than calling eval.
bool funMightAliasLocals:1;
bool mightAliasLocals:1;
// This function does something that can extend the set of bindings in its
// call objects --- it does a direct eval in non-strict code, or includes a
@ -68,7 +80,7 @@ class ContextFlags {
// This flag is *not* inherited by enclosed or enclosing functions; it
// applies only to the function in whose flags it appears.
//
bool funHasExtensibleScope:1;
bool hasExtensibleScope:1;
// Technically, every function has a binding named 'arguments'. Internally,
// this binding is only added when 'arguments' is mentioned by the function
@ -91,7 +103,7 @@ class ContextFlags {
// have no special semantics: the initial value is unconditionally the
// actual argument (or undefined if nactual < nformal).
//
bool funArgumentsHasLocalBinding:1;
bool argumentsHasLocalBinding:1;
// In many cases where 'arguments' has a local binding (as described above)
// we do not need to actually create an arguments object in the function
@ -102,17 +114,15 @@ class ContextFlags {
// be unsound in several cases. The frontend filters out such cases by
// setting this flag which eagerly sets script->needsArgsObj to true.
//
bool funDefinitelyNeedsArgsObj:1;
bool definitelyNeedsArgsObj:1;
public:
ContextFlags()
: hasExplicitUseStrict(false),
bindingsAccessedDynamically(false),
funIsGenerator(false),
funMightAliasLocals(false),
funHasExtensibleScope(false),
funArgumentsHasLocalBinding(false),
funDefinitelyNeedsArgsObj(false)
FunctionContextFlags()
: isGenerator(false),
mightAliasLocals(false),
hasExtensibleScope(false),
argumentsHasLocalBinding(false),
definitelyNeedsArgsObj(false)
{ }
};
@ -133,8 +143,7 @@ struct SharedContext {
(if inFunction() is false) */
public:
ContextFlags cxFlags;
AnyContextFlags anyCxFlags;
// strictModeState tracks the strictness of this context. Normally, it
// should be STRICT or NOTSTRICT. However, it can be UNKNOWN when parsing
@ -161,27 +170,11 @@ struct SharedContext {
inline SharedContext(JSContext *cx, JSObject *scopeChain, FunctionBox *funbox,
StrictMode sms);
// The |fun*| flags are only relevant if |inFunction()| is true.
#define INFUNC JS_ASSERT(inFunction())
bool hasExplicitUseStrict() const { return anyCxFlags.hasExplicitUseStrict; }
bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; }
bool hasExplicitUseStrict() const { return cxFlags.hasExplicitUseStrict; }
bool bindingsAccessedDynamically() const { return cxFlags.bindingsAccessedDynamically; }
bool funIsGenerator() const { INFUNC; return cxFlags.funIsGenerator; }
bool funMightAliasLocals() const { INFUNC; return cxFlags.funMightAliasLocals; }
bool funHasExtensibleScope() const { INFUNC; return cxFlags.funHasExtensibleScope; }
bool funArgumentsHasLocalBinding() const { INFUNC; return cxFlags.funArgumentsHasLocalBinding; }
bool funDefinitelyNeedsArgsObj() const { INFUNC; return cxFlags.funDefinitelyNeedsArgsObj; }
void setExplicitUseStrict() { cxFlags.hasExplicitUseStrict = true; }
void setBindingsAccessedDynamically() { cxFlags.bindingsAccessedDynamically = true; }
void setFunIsGenerator() { INFUNC; cxFlags.funIsGenerator = true; }
void setFunMightAliasLocals() { INFUNC; cxFlags.funMightAliasLocals = true; }
void setFunHasExtensibleScope() { INFUNC; cxFlags.funHasExtensibleScope = true; }
void setFunArgumentsHasLocalBinding() { INFUNC; cxFlags.funArgumentsHasLocalBinding = true; }
void setFunDefinitelyNeedsArgsObj() { JS_ASSERT(cxFlags.funArgumentsHasLocalBinding);
INFUNC; cxFlags.funDefinitelyNeedsArgsObj = true; }
#undef INFUNC
void setExplicitUseStrict() { anyCxFlags.hasExplicitUseStrict = true; }
void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; }
bool inFunction() const { return !!funbox_; }
@ -297,15 +290,27 @@ struct FunctionBox
or E4X filter-expression */
bool inGenexpLambda:1; /* lambda from generator expression */
ContextFlags cxFlags;
AnyContextFlags anyCxFlags;
FunctionContextFlags funCxFlags;
FunctionBox(ObjectBox *traceListHead, JSFunction *fun, ParseContext *pc, StrictMode sms);
bool funIsGenerator() const { return cxFlags.funIsGenerator; }
JSFunction *fun() const { return objbox.object->toFunction(); }
void recursivelySetStrictMode(StrictMode strictness);
bool isGenerator() const { return funCxFlags.isGenerator; }
bool mightAliasLocals() const { return funCxFlags.mightAliasLocals; }
bool hasExtensibleScope() const { return funCxFlags.hasExtensibleScope; }
bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
bool definitelyNeedsArgsObj() const { return funCxFlags.definitelyNeedsArgsObj; }
void setIsGenerator() { funCxFlags.isGenerator = true; }
void setMightAliasLocals() { funCxFlags.mightAliasLocals = true; }
void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; }
void setArgumentsHasLocalBinding() { funCxFlags.argumentsHasLocalBinding = true; }
void setDefinitelyNeedsArgsObj() { JS_ASSERT(funCxFlags.argumentsHasLocalBinding);
funCxFlags.definitelyNeedsArgsObj = true; }
};
// Push the C-stack-allocated struct at stmt onto the StmtInfoPC stack.

View File

@ -3104,7 +3104,7 @@ ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
bool isGenerator =
#if JS_HAS_GENERATORS
pn->pn_funbox->funIsGenerator();
pn->pn_funbox->isGenerator();
#else
false;
#endif

View File

@ -1670,7 +1670,7 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle<JSScript*> script, Bytecode
script->explicitUseStrict = bce->sc->hasExplicitUseStrict();
script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
script->funHasExtensibleScope =
bce->sc->inFunction() ? bce->sc->funHasExtensibleScope() : false;
bce->sc->inFunction() ? bce->sc->funbox()->hasExtensibleScope() : false;
script->hasSingletons = bce->hasSingletons;
#ifdef JS_METHODJIT
if (cx->compartment->debugMode())
@ -1678,21 +1678,23 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle<JSScript*> script, Bytecode
#endif
if (bce->sc->inFunction()) {
if (bce->sc->funArgumentsHasLocalBinding()) {
FunctionBox *funbox = bce->sc->funbox();
if (funbox->argumentsHasLocalBinding()) {
// This must precede the script->bindings.transfer() call below
script->setArgumentsHasVarBinding();
if (bce->sc->funDefinitelyNeedsArgsObj())
if (funbox->definitelyNeedsArgsObj())
script->setNeedsArgsObj(true);
} else {
JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj());
JS_ASSERT(!funbox->definitelyNeedsArgsObj());
}
}
RootedFunction fun(cx, NULL);
if (bce->sc->inFunction()) {
JS_ASSERT(!bce->script->noScriptRval);
script->isGenerator = bce->sc->funIsGenerator();
script->isGeneratorExp = bce->sc->funbox()->inGenexpLambda;
FunctionBox *funbox = bce->sc->funbox();
script->isGenerator = funbox->isGenerator();
script->isGeneratorExp = funbox->inGenexpLambda;
script->setFunction(bce->sc->funbox()->fun());
}