From 4cde2c6b53d523f8abaafd844e167b3bbf171874 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 28 May 2012 21:50:52 -0700 Subject: [PATCH] Bug 759246 (part 3) - Initialize more SharedContext stuff via the constructor. r=jorendorff. --HG-- extra : rebase_source : 8ffdf29429f0606181bf04c00d57d13bbb650b8d --- js/src/frontend/BytecodeCompiler.cpp | 7 +- js/src/frontend/BytecodeEmitter.cpp | 41 +++++----- js/src/frontend/BytecodeEmitter.h | 2 +- js/src/frontend/Parser.cpp | 111 +++++++++++++-------------- js/src/frontend/SemanticAnalysis.cpp | 2 +- js/src/frontend/TreeContext-inl.h | 11 +-- js/src/frontend/TreeContext.cpp | 3 +- js/src/frontend/TreeContext.h | 85 ++++++++++---------- js/src/jsscript.cpp | 13 +--- 9 files changed, 130 insertions(+), 145 deletions(-) diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 6aeea36c685..10a6f97eec6 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -99,7 +99,7 @@ frontend::CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF if (!parser.init()) return NULL; - SharedContext sc(cx, /* inFunction = */ false); + SharedContext sc(cx, scopeChain, /* fun = */ NULL, /* funbox = */ NULL); TreeContext tc(&parser, &sc); if (!tc.init()) @@ -118,7 +118,6 @@ frontend::CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF JS_ASSERT_IF(globalObj, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalObj->getClass())); GlobalScope globalScope(cx, globalObj); - sc.setScopeChain(scopeChain); bce.globalScope = &globalScope; if (!SetStaticLevel(&sc, staticLevel)) return NULL; @@ -264,7 +263,8 @@ frontend::CompileFunctionBody(JSContext *cx, JSFunction *fun, if (!parser.init()) return false; - SharedContext funsc(cx, /* inFunction = */ true); + JS_ASSERT(fun); + SharedContext funsc(cx, /* scopeChain = */ NULL, fun, /* funbox = */ NULL); TreeContext funtc(&parser, &funsc); if (!funtc.init()) @@ -275,7 +275,6 @@ frontend::CompileFunctionBody(JSContext *cx, JSFunction *fun, if (!funbce.init()) return false; - funsc.setFunction(fun); funsc.bindings.transfer(cx, bindings); fun->setArgCount(funsc.bindings.numArgs()); if (!GenerateBlockId(&funsc, funsc.bodyid)) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 202872c289c..29c38c15378 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -660,7 +660,7 @@ LookupCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, Val */ constp->setMagic(JS_NO_CONSTANT); do { - if (bce->sc->inFunction || bce->parser->compileAndGo) { + if (bce->sc->inFunction() || bce->parser->compileAndGo) { /* XXX this will need revising if 'const' becomes block-scoped. */ StmtInfo *stmt = LexicalLookup(bce->sc, atom, NULL); if (stmt) @@ -679,7 +679,7 @@ LookupCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, Val * with object or catch variable; nor can prop's value be changed, * nor can prop be deleted. */ - if (bce->sc->inFunction) { + if (bce->sc->inFunction()) { if (bce->sc->bindings.hasBinding(cx, atom)) break; } else { @@ -997,7 +997,7 @@ static int AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot) { JS_ASSERT((unsigned) slot < bce->maxStackDepth); - if (bce->sc->inFunction) { + if (bce->sc->inFunction()) { slot += bce->sc->bindings.numVars(); if ((unsigned) slot >= SLOTNO_LIMIT) { ReportCompileErrorNumber(cx, bce->tokenStream(), NULL, JSREPORT_ERROR, @@ -1564,7 +1564,13 @@ BytecodeEmitter::needsImplicitThis() { if (!parser->compileAndGo) return true; - if (!sc->inFunction) { + + if (sc->inFunction()) { + for (const FunctionBox *funbox = this->sc->funbox(); funbox; funbox = funbox->parent) { + if (funbox->inWith) + return true; + } + } else { JSObject *scope = sc->scopeChain(); while (scope) { if (scope->isWith()) @@ -1572,10 +1578,7 @@ BytecodeEmitter::needsImplicitThis() scope = scope->enclosingScope(); } } - for (const FunctionBox *funbox = this->sc->funbox; funbox; funbox = funbox->parent) { - if (funbox->inWith) - return true; - } + for (StmtInfo *stmt = sc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_WITH) return true; @@ -2630,7 +2633,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode * } if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM && - (!bce->sc->inFunction || bce->sc->funIsHeavyweight())) + (!bce->sc->inFunction() || bce->sc->funIsHeavyweight())) { bce->switchToProlog(); if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno)) @@ -2640,7 +2643,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode * bce->switchToMain(); } - if (bce->sc->inFunction && + if (bce->sc->inFunction() && JOF_OPTYPE(pn->getOp()) == JOF_LOCAL && !pn->isLet() && bce->shouldNoteClosedName(pn)) @@ -4402,7 +4405,7 @@ EmitLexicalScope(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) (stmtInfo.down ? stmtInfo.down->type == STMT_BLOCK && (!stmtInfo.down->down || stmtInfo.down->down->type != STMT_FOR_IN_LOOP) - : !bce->sc->inFunction)) + : !bce->sc->inFunction())) { /* There must be no source note already output for the next op. */ JS_ASSERT(bce->noteCount() == 0 || @@ -4792,7 +4795,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) * comments in EmitStatementList. */ JS_ASSERT(pn->isOp(JSOP_NOP)); - JS_ASSERT(bce->sc->inFunction); + JS_ASSERT(bce->sc->inFunction()); return EmitFunctionDefNop(cx, bce, pn->pn_index); } @@ -4800,20 +4803,18 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) fun->kind() == JSFUN_INTERPRETED); { - SharedContext sc(cx, /* inFunction = */ true); + FunctionBox *funbox = pn->pn_funbox; + SharedContext sc(cx, /* scopeChain = */ NULL, fun, funbox); BytecodeEmitter bce2(bce->parser, &sc, pn->pn_pos.begin.lineno, /* noScriptRval = */ false, /* needsScriptGlobal = */ false); if (!bce2.init()) return false; - FunctionBox *funbox = pn->pn_funbox; sc.cxFlags = funbox->cxFlags; if (bce->sc->funMightAliasLocals()) sc.setFunMightAliasLocals(); // inherit funMightAliasLocals from parent sc.bindings.transfer(cx, &funbox->bindings); - sc.setFunction(fun); - sc.funbox = funbox; bce2.parent = bce; bce2.globalScope = bce->globalScope; @@ -4851,7 +4852,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) * invocation of the emitter and calls to EmitTree for function * definitions can be scheduled before generating the rest of code. */ - if (!bce->sc->inFunction) { + if (!bce->sc->inFunction()) { JS_ASSERT(!bce->sc->topStmt); JS_ASSERT(pn->pn_cookie.isFree()); if (pn->pn_cookie.isFree()) { @@ -5137,7 +5138,7 @@ EmitStatement(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) */ bool wantval = false; JSBool useful = JS_FALSE; - if (bce->sc->inFunction) { + if (bce->sc->inFunction()) { JS_ASSERT(!bce->noScriptRval); } else { useful = wantval = !bce->noScriptRval; @@ -5825,7 +5826,7 @@ static bool EmitDefaults(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) { JS_ASSERT(pn->isKind(PNK_ARGSBODY)); - uint16_t ndefaults = bce->sc->funbox->ndefaults; + uint16_t ndefaults = bce->sc->funbox()->ndefaults; JSFunction *fun = bce->sc->fun(); unsigned nformal = fun->nargs - fun->hasRest(); EMIT_UINT16_IMM_OP(JSOP_ACTUALSFILLED, nformal - ndefaults); @@ -6074,7 +6075,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) #if JS_HAS_GENERATORS case PNK_YIELD: - JS_ASSERT(bce->sc->inFunction); + JS_ASSERT(bce->sc->inFunction()); if (pn->pn_kid) { if (!EmitTree(cx, bce, pn->pn_kid)) return JS_FALSE; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index bf1e920ee61..de12b7d83b6 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -163,7 +163,7 @@ struct BytecodeEmitter } bool checkSingletonContext() { - if (!parser->compileAndGo || sc->inFunction) + if (!parser->compileAndGo || sc->inFunction()) return false; for (StmtInfo *stmt = sc->topStmt; stmt; stmt = stmt->down) { if (STMT_IS_LOOP(stmt)) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1332c5d5059..f52a15ed5dc 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -175,7 +175,7 @@ FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, node(fn), siblings(tc->functionList), kids(NULL), - parent(tc->sc->funbox), + parent(tc->sc->inFunction() ? tc->sc->funbox() : NULL), bindings(tc->sc->context), level(tc->sc->staticLevel), ndefaults(0), @@ -192,7 +192,7 @@ FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseNode *fn, break; } } - if (!tc->sc->inFunction) { + if (!tc->sc->inFunction()) { JSObject *scope = tc->sc->scopeChain(); while (scope) { if (scope->isWith()) @@ -267,11 +267,10 @@ 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, /* inFunction = */ false); + SharedContext globalsc(context, chain, /* fun = */ NULL, /* funbox = */ NULL); TreeContext globaltc(this, &globalsc); if (!globaltc.init()) return NULL; - globalsc.setScopeChain(chain); if (!GenerateBlockId(&globalsc, globalsc.bodyid)) return NULL; @@ -432,7 +431,7 @@ ReportBadReturn(JSContext *cx, Parser *parser, ParseNode *pn, unsigned flags, un static JSBool CheckFinalReturn(JSContext *cx, Parser *parser, ParseNode *pn) { - JS_ASSERT(parser->tc->sc->inFunction); + JS_ASSERT(parser->tc->sc->inFunction()); return HasFinalReturn(pn) == ENDS_IN_RETURN || ReportBadReturn(cx, parser, pn, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE); @@ -505,7 +504,7 @@ static bool CheckStrictParameters(JSContext *cx, Parser *parser) { SharedContext *sc = parser->tc->sc; - JS_ASSERT(sc->inFunction); + JS_ASSERT(sc->inFunction()); if (!sc->needStrictChecks() || sc->bindings.numArgs() == 0) return true; @@ -574,7 +573,7 @@ BindLocalVariable(JSContext *cx, SharedContext *sc, ParseNode *pn, BindingKind k ParseNode * Parser::functionBody(FunctionBodyType type) { - JS_ASSERT(tc->sc->inFunction); + JS_ASSERT(tc->sc->inFunction()); StmtInfo stmtInfo(context); PushStatement(tc->sc, &stmtInfo, STMT_BLOCK, -1); @@ -734,7 +733,7 @@ Parser::functionBody(FunctionBodyType type) bool Parser::checkForArgumentsAndRest() { - JS_ASSERT(!tc->sc->inFunction); + JS_ASSERT(!tc->sc->inFunction()); if (callerFrame && callerFrame->isFunctionFrame() && callerFrame->fun()->hasRest()) { PropertyName *arguments = context->runtime->atomState.argumentsAtom; for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) { @@ -992,7 +991,7 @@ static JSBool BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser) { TreeContext *tc = parser->tc; - JS_ASSERT(tc->sc->inFunction); + JS_ASSERT(tc->sc->inFunction()); /* * NB: Check tc->decls rather than tc->sc->bindings, because destructuring @@ -1048,7 +1047,7 @@ Parser::newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind) tc = tc->parent; RootedObject parent(context); - parent = tc->sc->inFunction ? NULL : tc->sc->scopeChain(); + parent = tc->sc->inFunction() ? NULL : tc->sc->scopeChain(); RootedFunction fun(context); fun = js_NewFunction(context, NULL, NULL, 0, @@ -1080,31 +1079,17 @@ MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts) return JS_TRUE; } -static FunctionBox * -EnterFunction(ParseNode *fn, Parser *parser, JSAtom *funAtom = NULL, - FunctionSyntaxKind kind = Expression) +static bool +EnterFunction(SharedContext *outersc, SharedContext *funsc) { - TreeContext *funtc = parser->tc; - TreeContext *outertc = funtc->parent; - JSFunction *fun = parser->newFunction(outertc, funAtom, kind); - if (!fun) - return NULL; + /* Initialize non-default members of funsc. */ + funsc->blockidGen = outersc->blockidGen; + if (!GenerateBlockId(funsc, funsc->bodyid)) + return false; + if (!SetStaticLevel(funsc, outersc->staticLevel + 1)) + return false; - /* Create box for fun->object early to protect against last-ditch GC. */ - FunctionBox *funbox = parser->newFunctionBox(fun, fn, outertc); - if (!funbox) - return NULL; - - /* Initialize non-default members of funtc->sc. */ - funtc->sc->blockidGen = outertc->sc->blockidGen; - if (!GenerateBlockId(funtc->sc, funtc->sc->bodyid)) - return NULL; - funtc->sc->setFunction(fun); - funtc->sc->funbox = funbox; - if (!SetStaticLevel(funtc->sc, outertc->sc->staticLevel + 1)) - return NULL; - - return funbox; + return true; } static bool @@ -1293,7 +1278,7 @@ Parser::functionArguments(ParseNode **listp, bool &hasRest) return false; argsbody->setOp(JSOP_NOP); argsbody->makeEmpty(); - tc->sc->funbox->node->pn_body = argsbody; + tc->sc->funbox()->node->pn_body = argsbody; if (!tokenStream.matchToken(TOK_RP)) { bool hasDefaults = false; @@ -1418,7 +1403,7 @@ Parser::functionArguments(ParseNode **listp, bool &hasRest) uint16_t slot; if (!tc->sc->bindings.addArgument(context, name, &slot)) return false; - if (!DefineArg(tc->sc->funbox->node, name, slot, this)) + if (!DefineArg(tc->sc->funbox()->node, name, slot, this)) return false; if (tokenStream.matchToken(TOK_ASSIGN)) { @@ -1430,10 +1415,10 @@ Parser::functionArguments(ParseNode **listp, bool &hasRest) ParseNode *def_expr = assignExprWithoutYield(JSMSG_YIELD_IN_DEFAULT); if (!def_expr) return false; - ParseNode *arg = tc->sc->funbox->node->pn_body->last(); + ParseNode *arg = tc->sc->funbox()->node->pn_body->last(); arg->pn_dflags |= PND_DEFAULT; arg->pn_expr = def_expr; - tc->sc->funbox->ndefaults++; + tc->sc->funbox()->ndefaults++; } else if (!hasRest && hasDefaults) { reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT); return false; @@ -1552,7 +1537,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta * when BytecodeEmitter.cpp's BindNameToSlot can optimize a JSOP_NAME * into a JSOP_GETLOCAL bytecode). */ - if (bodyLevel && tc->sc->inFunction) { + if (bodyLevel && tc->sc->inFunction()) { /* * Define a local in the outer function so that BindNameToSlot * can properly optimize accesses. Note that we need a local @@ -1581,21 +1566,27 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta TreeContext *outertc = tc; + RootedFunction fun(context, newFunction(outertc, funName, kind)); + if (!fun) + return NULL; + + /* Create box for fun->object early to protect against last-ditch GC. */ + FunctionBox *funbox = newFunctionBox(fun, pn, outertc); + if (!funbox) + return NULL; + /* Initialize early for possible flags mutation via destructuringExpr. */ - SharedContext funsc(context, /* inFunction = */ true); + SharedContext funsc(context, /* scopeChain = */ NULL, fun, funbox); TreeContext funtc(this, &funsc); if (!funtc.init()) return NULL; - FunctionBox *funbox = EnterFunction(pn, this, funName, kind); - if (!funbox) + if (!EnterFunction(outertc->sc, &funsc)) return NULL; if (outertc->sc->inStrictMode()) funsc.setInStrictMode(); // inherit strict mode from parent - RootedFunction fun(context, funbox->function()); - /* Now parse formal argument list and compute fun->nargs. */ ParseNode *prelude = NULL; bool hasRest; @@ -1764,7 +1755,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta pn->pn_body->append(body); pn->pn_body->pn_pos = body->pn_pos; - JS_ASSERT_IF(!outertc->sc->inFunction && bodyLevel && kind == Statement, + JS_ASSERT_IF(!outertc->sc->inFunction() && bodyLevel && kind == Statement, pn->pn_cookie.isFree()); pn->pn_blockid = outertc->sc->blockid(); @@ -2123,7 +2114,7 @@ OuterLet(SharedContext *sc, StmtInfo *stmt, JSAtom *atom) static bool BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, SharedContext *sc) { - JS_ASSERT(sc->inFunction); + JS_ASSERT(sc->inFunction()); ParseNode *pn = data->pn; JSAtom *name = pn->pn_atom; @@ -2146,7 +2137,7 @@ BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, SharedCont } if (kind == ARGUMENT) { - JS_ASSERT(sc->inFunction); + JS_ASSERT(sc->inFunction()); JS_ASSERT(!mdl.empty() && mdl.front()->kind() == Definition::ARG); } else { JS_ASSERT(kind == VARIABLE || kind == CONSTANT); @@ -2299,7 +2290,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser) if (data->op == JSOP_DEFCONST) pn->pn_dflags |= PND_CONST; - if (tc->sc->inFunction) + if (tc->sc->inFunction()) return BindFunctionLocal(cx, data, mdl, tc->sc); return true; @@ -2355,7 +2346,7 @@ NoteLValue(JSContext *cx, ParseNode *pn, SharedContext *sc, unsigned dflag = PND * mode, we must have a binding for it in the scope chain; we ensure this * happens by making such functions heavyweight. */ - if (sc->inFunction && pn->pn_atom == sc->fun()->atom) + if (sc->inFunction() && pn->pn_atom == sc->fun()->atom) sc->setFunIsHeavyweight(); } @@ -2691,7 +2682,7 @@ ParseNode * Parser::returnOrYield(bool useAssignExpr) { TokenKind tt = tokenStream.currentToken().type; - if (!tc->sc->inFunction) { + if (!tc->sc->inFunction()) { reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD, (tt == TOK_RETURN) ? js_return_str : js_yield_str); return NULL; @@ -5007,7 +4998,7 @@ GenexpGuard::maybeNoteGenerator(ParseNode *pn) TreeContext *tc = parser->tc; if (tc->yieldCount > 0) { tc->sc->setFunIsGenerator(); - if (!tc->sc->inFunction) { + if (!tc->sc->inFunction()) { parser->reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str); return false; @@ -5112,7 +5103,7 @@ CompExprTransplanter::transplant(ParseNode *pn) funbox->level = tc->sc->staticLevel + funcLevel; if (++funcLevel == 1 && genexp) { - FunctionBox *parent = tc->sc->funbox; + FunctionBox *parent = tc->sc->funbox(); FunctionBox **funboxp = &tc->parent->functionList; while (*funboxp != funbox) @@ -5499,13 +5490,22 @@ Parser::generatorExpr(ParseNode *kid) { TreeContext *outertc = tc; - SharedContext gensc(context, /* inFunction = */ true); + + RootedFunction fun(context, newFunction(outertc, /* atom = */ NULL, Expression)); + if (!fun) + return NULL; + + /* Create box for fun->object early to protect against last-ditch GC. */ + FunctionBox *funbox = newFunctionBox(fun, genfn, outertc); + if (!funbox) + return NULL; + + SharedContext gensc(context, /* scopeChain = */ NULL, fun, funbox); TreeContext gentc(this, &gensc); if (!gentc.init()) return NULL; - FunctionBox *funbox = EnterFunction(genfn, this); - if (!funbox) + if (!EnterFunction(outertc->sc, &gensc)) return NULL; /* @@ -6477,12 +6477,11 @@ 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, /* inFunction = */ false); + SharedContext xmlsc(context, chain, /* fun = */ NULL, /* funbox = */ NULL); TreeContext xmltc(this, &xmlsc); if (!xmltc.init()) return NULL; JS_ASSERT(!xmlsc.inStrictMode()); - xmlsc.setScopeChain(chain); /* Set XML-only mode to turn off special treatment of {expr} in XML. */ tokenStream.setXMLOnlyMode(); diff --git a/js/src/frontend/SemanticAnalysis.cpp b/js/src/frontend/SemanticAnalysis.cpp index 8d31b29b60b..bf699f6c0ab 100644 --- a/js/src/frontend/SemanticAnalysis.cpp +++ b/js/src/frontend/SemanticAnalysis.cpp @@ -168,7 +168,7 @@ frontend::AnalyzeFunctions(Parser *parser) return false; bool isDirectEval = !!parser->callerFrame; bool isHeavyweight = false; - SetFunctionKinds(tc->functionList, &isHeavyweight, sc->inFunction, isDirectEval); + SetFunctionKinds(tc->functionList, &isHeavyweight, sc->inFunction(), isDirectEval); if (isHeavyweight) sc->setFunIsHeavyweight(); return true; diff --git a/js/src/frontend/TreeContext-inl.h b/js/src/frontend/TreeContext-inl.h index 8b8524bfe90..1d14e740910 100644 --- a/js/src/frontend/TreeContext-inl.h +++ b/js/src/frontend/TreeContext-inl.h @@ -16,23 +16,24 @@ namespace js { inline -SharedContext::SharedContext(JSContext *cx, bool inFunction) +SharedContext::SharedContext(JSContext *cx, JSObject *scopeChain, JSFunction *fun, + FunctionBox *funbox) : context(cx), bodyid(0), blockidGen(0), topStmt(NULL), topScopeStmt(NULL), blockChain(cx), - fun_(cx), - scopeChain_(cx), + fun_(cx, fun), + funbox_(funbox), + scopeChain_(cx, scopeChain), staticLevel(0), - funbox(NULL), bindings(cx), bindingsRoot(cx, &bindings), - inFunction(inFunction), inForInit(false), cxFlags(cx) { + JS_ASSERT((fun && !scopeChain_) || (!fun && !funbox)); } inline unsigned diff --git a/js/src/frontend/TreeContext.cpp b/js/src/frontend/TreeContext.cpp index 8606879df6d..b5348266143 100644 --- a/js/src/frontend/TreeContext.cpp +++ b/js/src/frontend/TreeContext.cpp @@ -43,8 +43,7 @@ bool frontend::GenerateBlockId(SharedContext *sc, uint32_t &blockid) { if (sc->blockidGen == JS_BIT(20)) { - JS_ReportErrorNumber(sc->context, js_GetErrorMessage, NULL, - JSMSG_NEED_DIET, "program"); + JS_ReportErrorNumber(sc->context, js_GetErrorMessage, NULL, JSMSG_NEED_DIET, "program"); return false; } blockid = sc->blockidGen++; diff --git a/js/src/frontend/TreeContext.h b/js/src/frontend/TreeContext.h index 94ac8ee267c..f476978d208 100644 --- a/js/src/frontend/TreeContext.h +++ b/js/src/frontend/TreeContext.h @@ -61,10 +61,6 @@ class ContextFlags { // bool bindingsAccessedDynamically:1; - // The |fun*| flags are only relevant if |inFunction| is true. Due to - // sloppiness, however, some are set in cases where |inFunction| is - // false. - // The function needs Call object per call. bool funIsHeavyweight:1; @@ -145,66 +141,63 @@ struct SharedContext { chain when in head of let block/expr) */ private: - RootedFunction fun_; /* function to store argument and variable - names when inFunction is set */ - RootedObject scopeChain_; /* scope chain object for the script */ + const RootedFunction fun_; /* function to store argument and variable + names when it's a function's context */ + FunctionBox *const funbox_; /* null or box for function we're compiling + if inFunction() is true and not in + js::frontend::CompileFunctionBody */ + + const RootedObject scopeChain_; /* scope chain object for the script */ public: unsigned staticLevel; /* static compilation unit nesting level */ - FunctionBox *funbox; /* null or box for function we're compiling - if inFunction is set and not in - js::frontend::CompileFunctionBody */ - Bindings bindings; /* bindings in this code, including arguments if we're compiling a function */ Bindings::AutoRooter bindingsRoot; /* root for stack allocated bindings. */ - const bool inFunction:1; /* parsing/emitting inside function body */ - bool inForInit:1; /* parsing/emitting init expr of for; exclude 'in' */ ContextFlags cxFlags; - inline SharedContext(JSContext *cx, bool inFunction); + // If it's function code, fun must be non-NULL and scopeChain must be NULL. + // If it's global code, fun and funbox must be NULL. + inline SharedContext(JSContext *cx, JSObject *scopeChain, JSFunction *fun, FunctionBox *funbox); - bool inStrictMode() const { return cxFlags.inStrictMode; } - bool bindingsAccessedDynamically() const { return cxFlags.bindingsAccessedDynamically; } - bool funIsHeavyweight() const { return cxFlags.funIsHeavyweight; } - bool funIsGenerator() const { return cxFlags.funIsGenerator; } - bool funMightAliasLocals() const { return cxFlags.funMightAliasLocals; } - bool funHasExtensibleScope() const { return cxFlags.funHasExtensibleScope; } - bool funArgumentsHasLocalBinding() const { return cxFlags.funArgumentsHasLocalBinding; } - bool funDefinitelyNeedsArgsObj() const { return cxFlags.funDefinitelyNeedsArgsObj; } + // In theory, |fun*| flags are only relevant if |inFunction()| is true. + // However, we get and set in some cases where |inFunction()| is false, + // which is why |INFUNC| doesn't appear in all of the fun* and setFun* + // functions below. +#define INFUNC JS_ASSERT(inFunction()) - void setInStrictMode() { cxFlags.inStrictMode = true; } - void setBindingsAccessedDynamically() { cxFlags.bindingsAccessedDynamically = true; } - void setFunIsHeavyweight() { cxFlags.funIsHeavyweight = true; } - void setFunIsGenerator() { cxFlags.funIsGenerator = true; } - void setFunMightAliasLocals() { cxFlags.funMightAliasLocals = true; } - void setFunHasExtensibleScope() { cxFlags.funHasExtensibleScope = true; } - void setFunArgumentsHasLocalBinding() { cxFlags.funArgumentsHasLocalBinding = true; } + bool inStrictMode() const { return cxFlags.inStrictMode; } + bool bindingsAccessedDynamically() const { return cxFlags.bindingsAccessedDynamically; } + bool funIsHeavyweight() const { INFUNC; return cxFlags.funIsHeavyweight; } + bool funIsGenerator() const { INFUNC; return cxFlags.funIsGenerator; } + bool funMightAliasLocals() const { return cxFlags.funMightAliasLocals; } + bool funHasExtensibleScope() const { return cxFlags.funHasExtensibleScope; } + bool funArgumentsHasLocalBinding() const { INFUNC; return cxFlags.funArgumentsHasLocalBinding; } + bool funDefinitelyNeedsArgsObj() const { INFUNC; return cxFlags.funDefinitelyNeedsArgsObj; } + + void setInStrictMode() { cxFlags.inStrictMode = true; } + void setBindingsAccessedDynamically() { cxFlags.bindingsAccessedDynamically = true; } + void setFunIsHeavyweight() { cxFlags.funIsHeavyweight = true; } + void setFunIsGenerator() { INFUNC; cxFlags.funIsGenerator = true; } + void setFunMightAliasLocals() { cxFlags.funMightAliasLocals = true; } + void setFunHasExtensibleScope() { cxFlags.funHasExtensibleScope = true; } + void setFunArgumentsHasLocalBinding() { INFUNC; cxFlags.funArgumentsHasLocalBinding = true; } void setFunDefinitelyNeedsArgsObj() { JS_ASSERT(cxFlags.funArgumentsHasLocalBinding); - cxFlags.funDefinitelyNeedsArgsObj = true; } + INFUNC; cxFlags.funDefinitelyNeedsArgsObj = true; } + +#undef INFUNC unsigned argumentsLocalSlot() const; - JSFunction *fun() const { - JS_ASSERT(inFunction); - return fun_; - } - void setFunction(JSFunction *fun) { - JS_ASSERT(inFunction); - fun_ = fun; - } - JSObject *scopeChain() const { - JS_ASSERT(!inFunction); - return scopeChain_; - } - void setScopeChain(JSObject *scopeChain) { - JS_ASSERT(!inFunction); - scopeChain_ = scopeChain; - } + bool inFunction() const { return !!fun_; } + + JSFunction *fun() const { JS_ASSERT(inFunction()); return fun_; } + FunctionBox *funbox() const { JS_ASSERT(inFunction()); return funbox_; } + JSObject *scopeChain() const { JS_ASSERT(!inFunction()); return scopeChain_; } unsigned blockid(); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 8bbc322454a..7dc546466ec 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1246,7 +1246,7 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) script->mainOffset = prologLength; PodCopy(script->code, bce->prologBase(), prologLength); PodCopy(script->main(), bce->base(), mainLength); - nfixed = bce->sc->inFunction ? bce->sc->bindings.numVars() : 0; + nfixed = bce->sc->inFunction() ? bce->sc->bindings.numVars() : 0; JS_ASSERT(nfixed < SLOTNO_LIMIT); script->nfixed = uint16_t(nfixed); InitAtomMap(cx, bce->atomIndices.getMap(), script->atoms); @@ -1309,7 +1309,7 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) script->debugMode = true; #endif - if (bce->sc->inFunction) { + if (bce->sc->inFunction()) { if (bce->sc->funArgumentsHasLocalBinding()) { // This must precede the script->bindings.transfer() call below. script->setArgumentsHasLocalBinding(bce->sc->argumentsLocalSlot()); @@ -1318,9 +1318,6 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) } else { JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj()); } - } else { - JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding()); - JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj()); } if (nClosedArgs) @@ -1331,7 +1328,7 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) script->bindings.transfer(cx, &bce->sc->bindings); fun = NULL; - if (bce->sc->inFunction) { + if (bce->sc->inFunction()) { JS_ASSERT(!bce->noScriptRval); JS_ASSERT(!bce->needScriptGlobal); @@ -1362,10 +1359,6 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce) script->globalObject = fun->getParent() ? &fun->getParent()->global() : NULL; } else { - // It'd be nice to JS_ASSERT(!bce->sc->funIsHeavyweight()) here, but - // Parser.cpp is sloppy and sometimes applies it to non-functions. - JS_ASSERT(!bce->sc->funIsGenerator()); - /* * Initialize script->object, if necessary, so that the debugger has a * valid holder object.