diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index a369c36a84c0..5b29310514f8 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -100,9 +100,9 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call return NULL; parser.sct = &sct; - SharedContext sc(cx, scopeChain, /* funbox = */ NULL, StrictModeFromContext(cx)); + GlobalSharedContext globalsc(cx, scopeChain, StrictModeFromContext(cx)); - ParseContext pc(&parser, &sc, staticLevel, /* bodyid = */ 0); + ParseContext pc(&parser, &globalsc, staticLevel, /* bodyid = */ 0); if (!pc.init()) return NULL; @@ -123,14 +123,14 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call JS_ASSERT_IF(globalScope, globalScope->isNative()); JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass())); - BytecodeEmitter bce(/* parent = */ NULL, &parser, &sc, script, callerFrame, !!globalScope, + BytecodeEmitter bce(/* parent = */ NULL, &parser, &globalsc, script, callerFrame, !!globalScope, options.lineno, options.selfHostingMode); if (!bce.init()) return NULL; /* If this is a direct call to eval, inherit the caller's strictness. */ if (callerFrame && callerFrame->script()->strictModeCode) - sc.strictModeState = StrictMode::STRICT; + globalsc.strictModeState = StrictMode::STRICT; if (options.compileAndGo) { if (source) { @@ -175,7 +175,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call if (!ok) return NULL; } - JS_ASSERT(sc.strictModeState != StrictMode::UNKNOWN); + JS_ASSERT(globalsc.strictModeState != StrictMode::UNKNOWN); for (;;) { TokenKind tt = tokenStream.peekToken(TSF_OPERAND); if (tt <= TOK_EOF) { @@ -277,12 +277,10 @@ frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions StrictMode sms = StrictModeFromContext(cx); FunctionBox *funbox = parser.newFunctionBox(fun, /* outerpc = */ NULL, sms); - - SharedContext funsc(cx, /* scopeChain = */ NULL, funbox, sms); fun->setArgCount(formals.length()); unsigned staticLevel = 0; - ParseContext funpc(&parser, &funsc, staticLevel, /* bodyid = */ 0); + ParseContext funpc(&parser, funbox, staticLevel, /* bodyid = */ 0); if (!funpc.init()) return false; @@ -332,7 +330,7 @@ frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions if (!funpc.generateFunctionBindings(cx, bindings)) return false; - BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, /* callerFrame = */ NULL, + BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script, /* callerFrame = */ NULL, /* hasGlobalScope = */ false, options.lineno); if (!funbce.init()) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 42fd5bcafeb7..a0bae3dd9f93 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -702,7 +702,7 @@ EnclosingStaticScope(BytecodeEmitter *bce) return NULL; } - return bce->sc->funbox()->fun(); + return bce->sc->asFunbox()->fun(); } // Push a block scope statement and link blockObj into bce->blockChain. @@ -918,9 +918,10 @@ EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce) */ for (unsigned i = pn->pn_cookie.level(); i; i--) { skippedScopes += ClonedBlockDepth(bceOfDef); - if (bceOfDef->sc->funbox()->fun()->isHeavyweight()) { + JSFunction *funOfDef = bceOfDef->sc->asFunbox()->fun(); + if (funOfDef->isHeavyweight()) { skippedScopes++; - if (bceOfDef->sc->funbox()->fun()->isNamedLambda()) + if (funOfDef->isNamedLambda()) skippedScopes++; } bceOfDef = bceOfDef->parent; @@ -1178,7 +1179,7 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op) } if (bce->script->compileAndGo && bce->hasGlobalScope && - !(bce->sc->isFunction && bce->sc->funbox()->mightAliasLocals()) && + !(bce->sc->isFunction && bce->sc->asFunbox()->mightAliasLocals()) && !pn->isDeoptimized() && !bce->sc->inStrictMode()) { @@ -1367,7 +1368,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } break; - case Definition::NAMED_LAMBDA: + case Definition::NAMED_LAMBDA: { JS_ASSERT(dn->isOp(JSOP_CALLEE)); JS_ASSERT(op != JSOP_CALLEE); @@ -1378,8 +1379,9 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (dn->pn_cookie.level() != bce->script->staticLevel) return true; - JS_ASSERT(bce->sc->funbox()->fun()->flags & JSFUN_LAMBDA); - JS_ASSERT(pn->pn_atom == bce->sc->funbox()->fun()->atom()); + RootedFunction fun(cx, bce->sc->asFunbox()->fun()); + JS_ASSERT(fun->flags & JSFUN_LAMBDA); + JS_ASSERT(pn->pn_atom == fun->atom()); /* * Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to @@ -1405,7 +1407,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) * heavyweight, ensuring that the function name is represented in * the scope chain so that assignment will throw a TypeError. */ - if (!bce->sc->funbox()->fun()->isHeavyweight()) { + if (!fun->isHeavyweight()) { op = JSOP_CALLEE; pn->pn_dflags |= PND_CONST; } @@ -1413,6 +1415,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) pn->setOp(op); pn->pn_dflags |= PND_BOUND; return true; + } case Definition::PLACEHOLDER: return true; @@ -1668,10 +1671,10 @@ BytecodeEmitter::needsImplicitThis() return true; if (sc->isFunction) { - if (sc->funbox()->inWith) + if (sc->asFunbox()->inWith) return true; } else { - JSObject *scope = sc->scopeChain(); + JSObject *scope = sc->asGlobal()->scopeChain(); while (scope) { if (scope->isWith()) return true; @@ -2613,7 +2616,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod * execution starts from script->code, so this has no semantic effect. */ - FunctionBox *funbox = bce->sc->funbox(); + FunctionBox *funbox = bce->sc->asFunbox(); if (funbox->argumentsHasLocalBinding()) { JS_ASSERT(bce->next() == bce->base()); /* See JSScript::argumentsBytecode. */ bce->switchToProlog(); @@ -2689,7 +2692,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode * } if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM && - (!bce->sc->isFunction || bce->sc->funbox()->fun()->isHeavyweight())) + (!bce->sc->isFunction || bce->sc->asFunbox()->fun()->isHeavyweight())) { bce->switchToProlog(); if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin)) @@ -4845,12 +4848,11 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } { + SharedContext *outersc = bce->sc; FunctionBox *funbox = pn->pn_funbox; - SharedContext sc(cx, /* scopeChain = */ NULL, funbox, funbox->strictModeState); - sc.anyCxFlags = funbox->anyCxFlags; // copy the non-func-specific flags - if (bce->sc->isFunction && bce->sc->funbox()->mightAliasLocals()) + if (outersc->isFunction && outersc->asFunbox()->mightAliasLocals()) funbox->setMightAliasLocals(); // inherit mightAliasLocals from parent - JS_ASSERT_IF(bce->sc->inStrictMode(), sc.inStrictMode()); + JS_ASSERT_IF(outersc->inStrictMode(), funbox->inStrictMode()); // Inherit most things (principals, version, etc) from the parent. Rooted parent(cx, bce->script); @@ -4870,8 +4872,8 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) script->bindings = funbox->bindings; - BytecodeEmitter bce2(bce, bce->parser, &sc, script, bce->callerFrame, bce->hasGlobalScope, - pn->pn_pos.begin.lineno, bce->selfHostingMode); + BytecodeEmitter bce2(bce, bce->parser, funbox, script, bce->callerFrame, + bce->hasGlobalScope, pn->pn_pos.begin.lineno, bce->selfHostingMode); if (!bce2.init()) return false; @@ -5959,8 +5961,8 @@ static bool EmitDefaults(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) { JS_ASSERT(pn->isKind(PNK_ARGSBODY)); - uint16_t ndefaults = bce->sc->funbox()->ndefaults; - JSFunction *fun = bce->sc->funbox()->fun(); + uint16_t ndefaults = bce->sc->asFunbox()->ndefaults; + JSFunction *fun = bce->sc->asFunbox()->fun(); unsigned nformal = fun->nargs - fun->hasRest(); EMIT_UINT16_IMM_OP(JSOP_ACTUALSFILLED, nformal - ndefaults); ptrdiff_t top = bce->offset(); @@ -6050,7 +6052,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) case PNK_ARGSBODY: { - RootedFunction fun(cx, bce->sc->funbox()->fun()); + RootedFunction fun(cx, bce->sc->asFunbox()->fun()); ParseNode *pnlast = pn->last(); // Carefully emit everything in the right order: @@ -6088,7 +6090,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) ParseNode *rest = NULL; bool restIsDefn = false; if (fun->hasRest()) { - JS_ASSERT(!bce->sc->funbox()->argumentsHasLocalBinding()); + JS_ASSERT(!bce->sc->asFunbox()->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 @@ -6133,7 +6135,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->funbox()->argumentsHasLocalBinding()); + JS_ASSERT(!bce->sc->asFunbox()->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 27717e90ef79..5135572887c0 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -316,8 +316,9 @@ ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle return false; } - if (bindings->hasAnyAliasedBindings() || sc->funbox()->hasExtensibleScope()) - sc->funbox()->fun()->flags |= JSFUN_HEAVYWEIGHT; + FunctionBox *funbox = sc->asFunbox(); + if (bindings->hasAnyAliasedBindings() || funbox->hasExtensibleScope()) + funbox->fun()->flags |= JSFUN_HEAVYWEIGHT; return true; } @@ -398,20 +399,19 @@ Parser::newObjectBox(JSObject *obj) return objbox; } -FunctionBox::FunctionBox(ObjectBox *traceListHead, JSFunction *fun, ParseContext *outerpc, - StrictMode sms) - : objbox(traceListHead, fun, this), +FunctionBox::FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fun, + ParseContext *outerpc, StrictMode sms) + : SharedContext(cx, /* isFunction = */ true, sms), + objbox(traceListHead, fun, this), siblings(outerpc ? outerpc->functionList : NULL), kids(NULL), bindings(), bufStart(0), bufEnd(0), ndefaults(0), - strictModeState(sms), inWith(false), // initialized below inGenexpLambda(false), - anyCxFlags(), - funCxFlags() // the funCxFlags are set in LeaveFunction + funCxFlags() { if (!outerpc) { inWith = false; @@ -436,7 +436,7 @@ FunctionBox::FunctionBox(ObjectBox *traceListHead, JSFunction *fun, ParseContext // ParseContext chain, and |parent| is NULL (again because of the // eval(), so we have to look at |outerpc|'s scopeChain. // - JSObject *scope = outerpc->sc->scopeChain(); + JSObject *scope = outerpc->sc->asGlobal()->scopeChain(); while (scope) { if (scope->isWith()) inWith = true; @@ -450,7 +450,7 @@ FunctionBox::FunctionBox(ObjectBox *traceListHead, JSFunction *fun, ParseContext // // In this case, the inner anonymous function needs to inherit the // setting of |inWith| from the outer one. - FunctionBox *parent = outerpc->sc->funbox(); + FunctionBox *parent = outerpc->sc->asFunbox(); if (parent && parent->inWith) inWith = true; } @@ -469,7 +469,7 @@ Parser::newFunctionBox(JSFunction *fun, ParseContext *outerpc, StrictMode sms) * function. */ FunctionBox *funbox = - context->tempLifoAlloc().new_(traceListHead, fun, outerpc, sms); + context->tempLifoAlloc().new_(context, traceListHead, fun, outerpc, sms); if (!funbox) { js_ReportOutOfMemory(context); return NULL; @@ -520,7 +520,7 @@ Parser::parse(JSObject *chain) * an object lock before it finishes generating bytecode into a script * protected from the GC by a root or a stack frame reference. */ - SharedContext globalsc(context, chain, /* funbox = */ NULL, StrictModeFromContext(context)); + GlobalSharedContext globalsc(context, chain, StrictModeFromContext(context)); ParseContext globalpc(this, &globalsc, /* staticLevel = */ 0, /* bodyid = */ 0); if (!globalpc.init()) return NULL; @@ -668,7 +668,7 @@ ReportBadReturn(JSContext *cx, Parser *parser, ParseNode *pn, Parser::Reporter r unsigned errnum, unsigned anonerrnum) { JSAutoByteString name; - JSAtom *atom = parser->pc->sc->funbox()->fun()->atom(); + JSAtom *atom = parser->pc->sc->asFunbox()->fun()->atom(); if (atom) { if (!js_AtomToPrintableString(cx, atom, &name)) return false; @@ -763,7 +763,7 @@ Parser::functionBody(FunctionBodyType type) if (!pn->pn_kid) { pn = NULL; } else { - if (pc->sc->funbox()->isGenerator()) { + if (pc->sc->asFunbox()->isGenerator()) { ReportBadReturn(context, this, pn, &Parser::reportError, JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN); @@ -833,7 +833,7 @@ Parser::functionBody(FunctionBodyType type) Definition *maybeArgDef = pc->decls().lookupFirst(arguments); bool argumentsHasBinding = !!maybeArgDef; bool argumentsHasLocalBinding = maybeArgDef && maybeArgDef->kind() != Definition::ARG; - bool hasRest = pc->sc->funbox()->fun()->hasRest(); + bool hasRest = pc->sc->asFunbox()->fun()->hasRest(); if (hasRest && argumentsHasLocalBinding) { reportError(NULL, JSMSG_ARGUMENTS_AND_REST); return NULL; @@ -860,7 +860,7 @@ Parser::functionBody(FunctionBodyType type) * arguments object. (Also see the flags' comments in ContextFlags.) */ if (argumentsHasLocalBinding) { - FunctionBox *funbox = pc->sc->funbox(); + FunctionBox *funbox = pc->sc->asFunbox(); funbox->setArgumentsHasLocalBinding(); /* Dynamic scope access destroys all hope of optimization. */ @@ -1080,15 +1080,15 @@ Parser::newFunction(ParseContext *pc, JSAtom *atom, FunctionSyntaxKind kind) /* * Find the global compilation context in order to pre-set the newborn - * function's parent slot to pc->sc->scopeChain. If the global context is a - * compile-and-go one, we leave the pre-set parent intact; otherwise we - * clear parent and proto. + * function's parent slot to pc->sc->asGlobal()->scopeChain. If the global + * context is a compile-and-go one, we leave the pre-set parent intact; + * otherwise we clear parent and proto. */ while (pc->parent) pc = pc->parent; RootedObject parent(context); - parent = pc->sc->isFunction ? NULL : pc->sc->scopeChain(); + parent = pc->sc->isFunction ? NULL : pc->sc->asGlobal()->scopeChain(); RootedFunction fun(context); uint32_t flags = JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0); @@ -1154,7 +1154,7 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL, pc->blockidGen = funpc->blockidGen; FunctionBox *funbox = fn->pn_funbox; - funbox->anyCxFlags = funpc->sc->anyCxFlags; // copy the non-func flags + JS_ASSERT(funbox == funpc->sc->asFunbox()); funbox->kids = funpc->functionList; if (!pc->topStmt || pc->topStmt->type == STMT_BLOCK) @@ -1187,7 +1187,7 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL, * produce an error (in strict mode). */ if (dn->isClosed() || dn->isAssigned()) - funpc->sc->funbox()->fun()->flags |= JSFUN_HEAVYWEIGHT; + funbox->fun()->flags |= JSFUN_HEAVYWEIGHT; continue; } @@ -1198,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->funbox()->hasExtensibleScope() || pc->parsingWith) + if (funbox->hasExtensibleScope() || pc->parsingWith) DeoptimizeUsesWithin(dn, fn->pn_pos); if (!outer_dn) { @@ -1364,7 +1364,7 @@ Parser::functionArguments(ParseNode **listp, ParseNode* funcpn, bool &hasRest) return false; } - FunctionBox *funbox = pc->sc->funbox(); + FunctionBox *funbox = pc->sc->asFunbox(); funbox->bufStart = tokenStream.offsetOfToken(tokenStream.currentToken()); hasRest = false; @@ -1600,7 +1600,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta JS_ASSERT(pc->sc->strictModeState != StrictMode::STRICT); JS_ASSERT(pn->pn_cookie.isFree()); if (pc->sc->isFunction) { - FunctionBox *funbox = pc->sc->funbox(); + FunctionBox *funbox = pc->sc->asFunbox(); funbox->setMightAliasLocals(); funbox->setHasExtensibleScope(); } @@ -1644,8 +1644,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta return NULL; /* Initialize early for possible flags mutation via destructuringExpr. */ - SharedContext funsc(context, /* scopeChain = */ NULL, funbox, sms); - ParseContext funpc(this, &funsc, outerpc->staticLevel + 1, outerpc->blockidGen); + ParseContext funpc(this, funbox, outerpc->staticLevel + 1, outerpc->blockidGen); if (!funpc.init()) return NULL; @@ -1711,7 +1710,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta * that the deoptimizing effects of dynamic name access apply equally to * parents: any local can be read at runtime. */ - if (funsc.bindingsAccessedDynamically()) + if (funbox->bindingsAccessedDynamically()) outerpc->sc->setBindingsAccessedDynamically(); #if JS_HAS_DESTRUCTURING @@ -1753,7 +1752,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta * If any nested function scope does a dynamic scope access, all enclosing * scopes may be accessed dynamically. */ - if (funsc.bindingsAccessedDynamically()) + if (funbox->bindingsAccessedDynamically()) outerpc->sc->setBindingsAccessedDynamically(); @@ -1822,7 +1821,6 @@ Parser::setStrictMode(bool strictMode) // Strict mode was inherited. JS_ASSERT(pc->sc->strictModeState == StrictMode::STRICT); if (pc->sc->isFunction) { - JS_ASSERT(pc->sc->funbox()->strictModeState == pc->sc->strictModeState); JS_ASSERT(pc->parent->sc->strictModeState == StrictMode::STRICT); } else { JS_ASSERT(StrictModeFromContext(context) == StrictMode::STRICT || pc->staticLevel); @@ -1853,7 +1851,7 @@ Parser::setStrictMode(bool strictMode) // We changed the strict mode state. Retroactively recursively set // strict mode status on all the function children we've seen so far // children (That is, functions in default expressions). - pc->sc->funbox()->strictModeState = pc->sc->strictModeState; + pc->sc->asFunbox()->strictModeState = pc->sc->strictModeState; for (FunctionBox *kid = pc->functionList; kid; kid = kid->siblings) kid->recursivelySetStrictMode(pc->sc->strictModeState); } @@ -1997,7 +1995,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->isFunction, pc->sc->funbox()->hasExtensibleScope()); + JS_ASSERT_IF(pc->sc->isFunction, pc->sc->asFunbox()->hasExtensibleScope()); if (hasFunctionStmt) *hasFunctionStmt = true; } @@ -2198,7 +2196,7 @@ BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *p if (stmt && stmt->type == STMT_WITH) { pn->pn_dflags |= PND_DEOPTIMIZED; if (pc->sc->isFunction) - pc->sc->funbox()->setMightAliasLocals(); + pc->sc->asFunbox()->setMightAliasLocals(); return true; } @@ -2585,7 +2583,7 @@ Parser::returnOrYield(bool useAssignExpr) * a |for| token, so we have to delay flagging the current function. */ if (pc->parenDepth == 0) { - pc->sc->funbox()->setIsGenerator(); + pc->sc->asFunbox()->setIsGenerator(); } else { pc->yieldCount++; pc->yieldNode = pn; @@ -2622,7 +2620,7 @@ Parser::returnOrYield(bool useAssignExpr) pc->funHasReturnVoid = true; } - if (pc->funHasReturnExpr && pc->sc->funbox()->isGenerator()) { + if (pc->funHasReturnExpr && pc->sc->asFunbox()->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); @@ -4862,7 +4860,7 @@ GenexpGuard::maybeNoteGenerator(ParseNode *pn) parser->reportError(NULL, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return false; } - pc->sc->funbox()->setIsGenerator(); + pc->sc->asFunbox()->setIsGenerator(); if (pc->funHasReturnExpr) { /* At the time we saw the yield, we might not have set isGenerator yet. */ ReportBadReturn(pc->sc->context, parser, pn, &Parser::reportError, @@ -4956,7 +4954,7 @@ CompExprTransplanter::transplant(ParseNode *pn) FunctionBox *funbox = pn->pn_funbox; if (++funcLevel == 1 && genexp) { - FunctionBox *parent = pc->sc->funbox(); + FunctionBox *parent = pc->sc->asFunbox(); FunctionBox **funboxp = &pc->parent->functionList; while (*funboxp != funbox) @@ -5366,12 +5364,11 @@ Parser::generatorExpr(ParseNode *kid) return NULL; /* Create box for fun->object early to protect against last-ditch GC. */ - FunctionBox *funbox = newFunctionBox(fun, outerpc, outerpc->sc->strictModeState); - if (!funbox) + FunctionBox *genFunbox = newFunctionBox(fun, outerpc, outerpc->sc->strictModeState); + if (!genFunbox) return NULL; - SharedContext gensc(context, /* scopeChain = */ NULL, funbox, outerpc->sc->strictModeState); - ParseContext genpc(this, &gensc, outerpc->staticLevel + 1, outerpc->blockidGen); + ParseContext genpc(this, genFunbox, outerpc->staticLevel + 1, outerpc->blockidGen); if (!genpc.init()) return NULL; @@ -5381,13 +5378,13 @@ 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.anyCxFlags = outerpc->sc->anyCxFlags; + genFunbox->anyCxFlags = outerpc->sc->anyCxFlags; if (outerpc->sc->isFunction) - funbox->funCxFlags = outerpc->sc->funbox()->funCxFlags; + genFunbox->funCxFlags = outerpc->sc->asFunbox()->funCxFlags; - funbox->setIsGenerator(); - funbox->inGenexpLambda = true; - genfn->pn_funbox = funbox; + genFunbox->setIsGenerator(); + genFunbox->inGenexpLambda = true; + genfn->pn_funbox = genFunbox; genfn->pn_blockid = genpc.bodyid; ParseNode *body = comprehensionTail(pn, outerpc->blockid(), true); @@ -5398,7 +5395,7 @@ Parser::generatorExpr(ParseNode *kid) genfn->pn_pos.begin = body->pn_pos.begin = kid->pn_pos.begin; genfn->pn_pos.end = body->pn_pos.end = tokenStream.currentToken().pos.end; - JSAtom *arguments = gensc.context->runtime->atomState.argumentsAtom; + JSAtom *arguments = context->runtime->atomState.argumentsAtom; if (AtomDefnPtr p = genpc.lexdeps->lookup(arguments)) { Definition *dn = p.value(); ParseNode *errorNode = dn->dn_uses ? dn->dn_uses : body; @@ -5709,7 +5706,7 @@ Parser::memberExpr(bool allowCallSyntax) * variables to the call object. */ if (pc->sc->isFunction && pc->sc->strictModeState != StrictMode::STRICT) - pc->sc->funbox()->setHasExtensibleScope(); + pc->sc->asFunbox()->setHasExtensibleScope(); } } else if (lhs->isOp(JSOP_GETPROP)) { /* Select JSOP_FUNAPPLY given foo.apply(...). */ @@ -6350,7 +6347,7 @@ Parser::parseXMLText(JSObject *chain, bool allowList) * lightweight function activation, or if its scope chain doesn't match * the one passed to us. */ - SharedContext xmlsc(context, chain, /* funbox = */ NULL, StrictMode::NOTSTRICT); + GlobalSharedContext xmlsc(context, chain, StrictMode::NOTSTRICT); ParseContext xmlpc(this, &xmlsc, /* staticLevel = */ 0, /* bodyid = */ 0); if (!xmlpc.init()) return NULL; diff --git a/js/src/frontend/SharedContext-inl.h b/js/src/frontend/SharedContext-inl.h index f2ffba8a6082..40d2bf3987e7 100644 --- a/js/src/frontend/SharedContext-inl.h +++ b/js/src/frontend/SharedContext-inl.h @@ -15,23 +15,18 @@ namespace js { namespace frontend { inline -SharedContext::SharedContext(JSContext *cx, JSObject *scopeChain, FunctionBox *funbox, - StrictMode sms) +SharedContext::SharedContext(JSContext *cx, bool isFun, StrictMode sms) : context(cx), - isFunction(!!funbox), - funbox_(funbox), - scopeChain_(cx, scopeChain), + isFunction(isFun), anyCxFlags(), strictModeState(sms) { - JS_ASSERT((funbox && !scopeChain_) || !funbox); } inline bool SharedContext::inStrictMode() { JS_ASSERT(strictModeState != StrictMode::UNKNOWN); - JS_ASSERT_IF(isFunction, funbox()->strictModeState == strictModeState); return strictModeState == StrictMode::STRICT; } @@ -41,6 +36,26 @@ SharedContext::needStrictChecks() return context->hasStrictOption() || strictModeState != StrictMode::NOTSTRICT; } +inline GlobalSharedContext * +SharedContext::asGlobal() +{ + JS_ASSERT(!isFunction); + return static_cast(this); +} + +inline FunctionBox * +SharedContext::asFunbox() +{ + JS_ASSERT(isFunction); + return static_cast(this); +} + +GlobalSharedContext::GlobalSharedContext(JSContext *cx, JSObject *scopeChain, StrictMode sms) + : SharedContext(cx, /* isFunction = */ false, sms), + scopeChain_(cx, scopeChain) +{ +} + } /* namespace frontend */ template diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 3c639104da88..e7a4b09a622e 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -23,8 +23,8 @@ namespace js { namespace frontend { // These flags apply to both global and function contexts. -class AnyContextFlags { - +class AnyContextFlags +{ // This class's data is all private and so only visible to these friends. friend struct SharedContext; @@ -61,8 +61,8 @@ class AnyContextFlags { { } }; -class FunctionContextFlags { - +class FunctionContextFlags +{ // This class's data is all private and so only visible to these friends. friend struct FunctionBox; @@ -126,25 +126,21 @@ class FunctionContextFlags { { } }; +class GlobalSharedContext; + /* * The struct SharedContext is part of the current parser context (see * ParseContext). It stores information that is reused between the parser and * the bytecode emitter. Note however, that this information is not shared * between the two; they simply reuse the same data structure. */ -struct SharedContext { +class SharedContext +{ + public: JSContext *const context; const bool isFunction; /* true for function code, false for global code */ - private: - FunctionBox *const funbox_; /* null or box for function we're compiling - (if isFunction is true) */ - - const RootedObject scopeChain_; /* scope chain object for the script - (if isFunction is false) */ - - public: AnyContextFlags anyCxFlags; // strictModeState tracks the strictness of this context. Normally, it @@ -169,8 +165,10 @@ struct SharedContext { // If it's function code, funbox must be non-NULL and scopeChain must be NULL. // If it's global code, funbox must be NULL. - inline SharedContext(JSContext *cx, JSObject *scopeChain, FunctionBox *funbox, - StrictMode sms); + inline SharedContext(JSContext *cx, bool isFun, StrictMode sms); + + inline GlobalSharedContext *asGlobal(); + inline FunctionBox *asFunbox(); bool hasExplicitUseStrict() const { return anyCxFlags.hasExplicitUseStrict; } bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; } @@ -178,14 +176,60 @@ struct SharedContext { void setExplicitUseStrict() { anyCxFlags.hasExplicitUseStrict = true; } void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; } - FunctionBox *funbox() const { JS_ASSERT(isFunction); return funbox_; } - JSObject *scopeChain() const { JS_ASSERT(!isFunction); return scopeChain_; } - // JSOPTION_STRICT warnings or strict mode errors. inline bool needStrictChecks(); inline bool inStrictMode(); }; +class GlobalSharedContext : public SharedContext +{ + private: + const RootedObject scopeChain_; /* scope chain object for the script */ + + public: + inline GlobalSharedContext(JSContext *cx, JSObject *scopeChain, StrictMode sms); + + JSObject *scopeChain() const { return scopeChain_; } +}; + +class FunctionBox : public SharedContext +{ + public: + ObjectBox objbox; + FunctionBox *siblings; + FunctionBox *kids; + Bindings bindings; /* bindings for this function */ + size_t bufStart; + size_t bufEnd; + uint16_t ndefaults; + bool inWith:1; /* some enclosing scope is a with-statement + or E4X filter-expression */ + bool inGenexpLambda:1; /* lambda from generator expression */ + + FunctionContextFlags funCxFlags; + + FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fun, ParseContext *pc, + StrictMode sms); + + 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; } +}; + + /* * NB: If you add a new type of statement that is a scope, add it between * STMT_WITH and STMT_CATCH, or you will break StmtInfoBase::linksScope. If you @@ -276,43 +320,6 @@ struct StmtInfoBase { } }; -struct FunctionBox -{ - ObjectBox objbox; - FunctionBox *siblings; - FunctionBox *kids; - Bindings bindings; /* bindings for this function */ - size_t bufStart; - size_t bufEnd; - uint16_t ndefaults; - StrictMode strictModeState; - bool inWith:1; /* some enclosing scope is a with-statement - or E4X filter-expression */ - bool inGenexpLambda:1; /* lambda from generator expression */ - - AnyContextFlags anyCxFlags; - FunctionContextFlags funCxFlags; - - FunctionBox(ObjectBox *traceListHead, JSFunction *fun, ParseContext *pc, StrictMode sms); - - 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. template void diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index bbf6ba06f07b..7287d08cdf8b 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1656,6 +1656,8 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle script, Bytecode } script->nslots = script->nfixed + bce->maxStackDepth; + FunctionBox *funbox = bce->sc->isFunction ? bce->sc->asFunbox() : NULL; + if (!FinishTakingSrcNotes(cx, bce, script->notes())) return false; if (bce->tryNoteList.length() != 0) @@ -1669,16 +1671,14 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle script, Bytecode script->strictModeCode = bce->sc->inStrictMode(); script->explicitUseStrict = bce->sc->hasExplicitUseStrict(); script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically(); - script->funHasExtensibleScope = - bce->sc->isFunction ? bce->sc->funbox()->hasExtensibleScope() : false; + script->funHasExtensibleScope = funbox ? funbox->hasExtensibleScope() : false; script->hasSingletons = bce->hasSingletons; #ifdef JS_METHODJIT if (cx->compartment->debugMode()) script->debugMode = true; #endif - if (bce->sc->isFunction) { - FunctionBox *funbox = bce->sc->funbox(); + if (funbox) { if (funbox->argumentsHasLocalBinding()) { // This must precede the script->bindings.transfer() call below script->setArgumentsHasVarBinding(); @@ -1690,12 +1690,11 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle script, Bytecode } RootedFunction fun(cx, NULL); - if (bce->sc->isFunction) { + if (funbox) { JS_ASSERT(!bce->script->noScriptRval); - FunctionBox *funbox = bce->sc->funbox(); script->isGenerator = funbox->isGenerator(); script->isGeneratorExp = funbox->inGenexpLambda; - script->setFunction(bce->sc->funbox()->fun()); + script->setFunction(funbox->fun()); } /*