Bug 788957 (part 4) - Add GlobalSharedContext, a sub-class of SharedContext, and also make FunctionBox a sub-class of SharedContext. r=benjamin.

--HG--
extra : rebase_source : 625a93dc48acbbdb9185378534e52b700688011d
This commit is contained in:
Nicholas Nethercote 2012-09-10 20:43:14 -07:00
Родитель c45937a7da
Коммит 0ce3bb8e04
6 изменённых файлов: 168 добавлений и 150 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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<JSScript*> 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;

Просмотреть файл

@ -316,8 +316,9 @@ ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*>
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_<FunctionBox>(traceListHead, fun, outerpc, sms);
context->tempLifoAlloc().new_<FunctionBox>(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;

Просмотреть файл

@ -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<GlobalSharedContext*>(this);
}
inline FunctionBox *
SharedContext::asFunbox()
{
JS_ASSERT(isFunction);
return static_cast<FunctionBox*>(this);
}
GlobalSharedContext::GlobalSharedContext(JSContext *cx, JSObject *scopeChain, StrictMode sms)
: SharedContext(cx, /* isFunction = */ false, sms),
scopeChain_(cx, scopeChain)
{
}
} /* namespace frontend */
template <class ContextT>

Просмотреть файл

@ -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 <class ContextT>
void

Просмотреть файл

@ -1656,6 +1656,8 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle<JSScript*> 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<JSScript*> 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<JSScript*> 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());
}
/*