зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c45937a7da
Коммит
0ce3bb8e04
|
@ -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());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче