diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index ebe28c5ced1..804aa6efc9a 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -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; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9082a320a6b..58d72172391 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -316,7 +316,7 @@ ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle 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(...). */ diff --git a/js/src/frontend/SharedContext-inl.h b/js/src/frontend/SharedContext-inl.h index 5e62e7eec62..161fcb26590 100644 --- a/js/src/frontend/SharedContext-inl.h +++ b/js/src/frontend/SharedContext-inl.h @@ -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); diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index a437828d00c..248b40dac22 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -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. diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 7e661dd1c9b..b4fe1404d56 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -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 diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 03ee5fb7678..ab47d362974 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1670,7 +1670,7 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle 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 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()); }