Bug 753657 (part 3): Remove the remaining parts of TreeContextFlags. r=luke.

--HG--
extra : rebase_source : 7d62aac9f3049a5bb6e8821d2055e59348cf9d85
This commit is contained in:
Nicholas Nethercote 2012-05-15 00:03:39 -07:00
parent 0da09800c8
commit dc9e955005
12 changed files with 198 additions and 151 deletions

View File

@ -157,8 +157,9 @@ frontend::CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
/* If this is a direct call to eval, inherit the caller's strictness. */
if (callerFrame &&
callerFrame->isScriptFrame() &&
callerFrame->script()->strictModeCode) {
bce.sc->flags |= TCF_STRICT_MODE_CODE;
callerFrame->script()->strictModeCode)
{
bce.sc->setInStrictMode();
tokenStream.setStrictMode();
}

View File

@ -1000,7 +1000,7 @@ BytecodeEmitter::noteClosedVar(ParseNode *pn)
for (size_t i = 0; i < closedVars.length(); ++i)
JS_ASSERT(closedVars[i] != pn->pn_cookie.slot());
#endif
sc->flags |= TCF_FUN_HEAVYWEIGHT;
sc->setFunIsHeavyweight();
return closedVars.append(pn->pn_cookie.slot());
}
@ -1015,7 +1015,7 @@ BytecodeEmitter::noteClosedArg(ParseNode *pn)
for (size_t i = 0; i < closedArgs.length(); ++i)
JS_ASSERT(closedArgs[i] != pn->pn_cookie.slot());
#endif
sc->flags |= TCF_FUN_HEAVYWEIGHT;
sc->setFunIsHeavyweight();
return closedArgs.append(pn->pn_cookie.slot());
}
@ -1090,7 +1090,7 @@ EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
* clones must get unique shapes; see the comments for
* js::Bindings::extensibleParents.
*/
if ((bce->sc->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
if (bce->sc->funHasExtensibleScope() ||
bce->sc->bindings.extensibleParents()) {
Shape *newShape = Shape::setExtensibleParents(cx, blockObj->lastProperty());
if (!newShape)
@ -1127,9 +1127,9 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
{
if (bce->parser->compileAndGo &&
bce->globalScope->globalObj &&
!bce->sc->mightAliasLocals() &&
!bce->sc->funMightAliasLocals() &&
!pn->isDeoptimized() &&
!(bce->sc->flags & TCF_STRICT_MODE_CODE)) {
!bce->sc->inStrictMode()) {
switch (*op) {
case JSOP_NAME: *op = JSOP_GETGNAME; break;
case JSOP_SETNAME: *op = JSOP_SETGNAME; break;
@ -1356,7 +1356,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* the scope chain so that assignment will throw a TypeError.
*/
JS_ASSERT(op != JSOP_DELNAME);
if (!(bce->sc->flags & TCF_FUN_HEAVYWEIGHT)) {
if (!bce->sc->funIsHeavyweight()) {
op = JSOP_CALLEE;
pn->pn_dflags |= PND_CONST;
}
@ -2618,7 +2618,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
* execution starts from script->code, so this has no semantic effect.
*/
if (bce->sc->argumentsHasLocalBinding()) {
if (bce->sc->funArgumentsHasLocalBinding()) {
JS_ASSERT(bce->next() == bce->base()); /* See JSScript::argumentsBytecode. */
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
@ -2637,7 +2637,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
bce->switchToMain();
}
if (bce->sc->flags & TCF_FUN_IS_GENERATOR) {
if (bce->sc->funIsGenerator()) {
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
return false;
@ -2663,7 +2663,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *
}
if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
(!bce->sc->inFunction || (bce->sc->flags & TCF_FUN_HEAVYWEIGHT)))
(!bce->sc->inFunction || bce->sc->funIsHeavyweight()))
{
bce->switchToProlog();
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
@ -4827,7 +4827,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return EmitFunctionDefNop(cx, bce, pn->pn_index);
}
JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
JS_ASSERT_IF(pn->pn_funbox->funIsHeavyweight(),
fun->kind() == JSFUN_INTERPRETED);
{
@ -4837,10 +4837,14 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!bce2.init())
return false;
bce2.sc->flags = pn->pn_funbox->tcflags | (bce->sc->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
bce2.sc->bindings.transfer(cx, &pn->pn_funbox->bindings);
FunctionBox *funbox = pn->pn_funbox;
bce2.sc->cxFlags = funbox->cxFlags;
if (bce->sc->funMightAliasLocals())
bce2.sc->setFunMightAliasLocals(); // inherit funMightAliasLocals from parent
bce2.sc->bindings.transfer(cx, &funbox->bindings);
bce2.sc->setFunction(fun);
bce2.sc->funbox = pn->pn_funbox;
bce2.sc->funbox = funbox;
bce2.parent = bce;
bce2.globalScope = bce->globalScope;
@ -4863,7 +4867,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
/* Emit a bytecode pointing to the closure object in its immediate. */
if (pn->getOp() != JSOP_NOP) {
if ((pn->pn_funbox->inGenexpLambda) && NewSrcNote(cx, bce, SRC_GENEXP) < 0)
if (pn->pn_funbox->inGenexpLambda && NewSrcNote(cx, bce, SRC_GENEXP) < 0)
return false;
return EmitFunctionOp(cx, pn->getOp(), index, bce);

View File

@ -39,6 +39,7 @@
* ***** END LICENSE BLOCK ***** */
#include "frontend/ParseNode.h"
#include "frontend/Parser.h"
#include "jsscriptinlines.h"
@ -112,18 +113,12 @@ bool
FunctionBox::inAnyDynamicScope() const
{
for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) {
if (funbox->inWith || (funbox->tcflags & TCF_FUN_EXTENSIBLE_SCOPE))
if (funbox->inWith || funbox->funHasExtensibleScope())
return true;
}
return false;
}
bool
FunctionBox::scopeIsExtensible() const
{
return tcflags & TCF_FUN_EXTENSIBLE_SCOPE;
}
/* Add |node| to |parser|'s free node list. */
void
ParseNodeAllocator::freeNode(ParseNode *pn)

View File

@ -47,6 +47,7 @@
#include "frontend/ParseMaps.h"
#include "frontend/TokenStream.h"
#include "frontend/TreeContext.h"
namespace js {
@ -1534,18 +1535,25 @@ struct ObjectBox {
struct FunctionBox : public ObjectBox
{
ParseNode *node;
FunctionBox *siblings;
FunctionBox *kids;
FunctionBox *parent;
Bindings bindings; /* bindings for this function */
uint32_t queued:1,
inLoop:1, /* in a loop in parent function */
level:JSFB_LEVEL_BITS;
uint32_t tcflags;
bool inWith:1; /* some enclosing scope is a with-statement
or E4X filter-expression */
bool inGenexpLambda:1; /* lambda from generator expression */
ParseNode *node;
FunctionBox *siblings;
FunctionBox *kids;
FunctionBox *parent;
Bindings bindings; /* bindings for this function */
uint32_t level:JSFB_LEVEL_BITS;
bool queued:1;
bool inLoop:1; /* in a loop in parent function */
bool inWith:1; /* some enclosing scope is a with-statement
or E4X filter-expression */
bool inGenexpLambda:1; /* lambda from generator expression */
ContextFlags cxFlags;
bool funIsHeavyweight() const { return cxFlags.funIsHeavyweight; }
bool funIsGenerator() const { return cxFlags.funIsGenerator; }
bool funHasExtensibleScope() const { return cxFlags.funHasExtensibleScope; }
void setFunIsHeavyweight() { cxFlags.funIsHeavyweight = true; }
JSFunction *function() const { return (JSFunction *) object; }
@ -1554,12 +1562,6 @@ struct FunctionBox : public ObjectBox
* filter-expression, or a function that uses direct eval.
*/
bool inAnyDynamicScope() const;
/*
* Must this function's descendants be marked as having an extensible
* ancestor?
*/
bool scopeIsExtensible() const;
};
struct FunctionBoxQueue {

View File

@ -236,7 +236,6 @@ Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
}
}
funbox->level = tc->sc->staticLevel;
funbox->tcflags = 0; // this is set in LeaveFunction
funbox->inWith = !!tc->innermostWith;
if (!tc->sc->inFunction) {
JSObject *scope = tc->sc->scopeChain();
@ -247,6 +246,9 @@ Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
}
}
funbox->inGenexpLambda = false;
new (&funbox->cxFlags) ContextFlags(context); // the cxFlags are set in LeaveFunction
return funbox;
}
@ -619,7 +621,7 @@ Parser::functionBody(FunctionBodyType type)
if (!pn->pn_kid) {
pn = NULL;
} else {
if (tc->sc->flags & TCF_FUN_IS_GENERATOR) {
if (tc->sc->funIsGenerator()) {
ReportBadReturn(context, this, pn, JSREPORT_ERROR,
JSMSG_BAD_GENERATOR_RETURN,
JSMSG_BAD_ANON_GENERATOR_RETURN);
@ -665,16 +667,16 @@ Parser::functionBody(FunctionBodyType type)
for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
PropertyName *name = r.front()->asPropertyName();
if (name == arguments)
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setBindingsAccessedDynamically();
else if (Definition *dn = tc->decls.lookupFirst(name))
dn->pn_dflags |= PND_CLOSED;
}
}
/*
* As explained by the TCF_ARGUMENTS_HAS_LOCAL_BINDING comment, turn uses
* of 'arguments' into bindings. Use of 'arguments' should never escape a
* nested function as an upvar.
* As explained by the ContextFlags::funArgumentsHasLocalBinding comment,
* turn uses of 'arguments' into bindings. Use of 'arguments' should never
* escape a nested function as an upvar.
*/
for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) {
JSAtom *atom = r.front().key();
@ -712,11 +714,11 @@ Parser::functionBody(FunctionBodyType type)
*/
BindingKind bindKind = tc->sc->bindings.lookup(context, arguments, NULL);
if (bindKind == VARIABLE || bindKind == CONSTANT) {
tc->sc->noteArgumentsHasLocalBinding();
tc->sc->setFunArgumentsHasLocalBinding();
/* Dynamic scope access destroys all hope of optimization. */
if (tc->sc->bindingsAccessedDynamically())
tc->sc->noteDefinitelyNeedsArgsObj();
tc->sc->setFunDefinitelyNeedsArgsObj();
/*
* Check whether any parameters have been assigned within this
@ -729,7 +731,7 @@ Parser::functionBody(FunctionBodyType type)
AtomDeclsIter iter(&tc->decls);
while (Definition *dn = iter.next()) {
if (dn->kind() == Definition::ARG && dn->isAssigned()) {
tc->sc->noteDefinitelyNeedsArgsObj();
tc->sc->setFunDefinitelyNeedsArgsObj();
break;
}
}
@ -1083,25 +1085,23 @@ EnterFunction(ParseNode *fn, Parser *parser, JSAtom *funAtom = NULL,
FunctionSyntaxKind kind = Expression)
{
TreeContext *funtc = parser->tc;
TreeContext *tc = funtc->parent;
JSFunction *fun = parser->newFunction(tc, funAtom, kind);
TreeContext *outertc = funtc->parent;
JSFunction *fun = parser->newFunction(outertc, funAtom, kind);
if (!fun)
return NULL;
/* Create box for fun->object early to protect against last-ditch GC. */
FunctionBox *funbox = parser->newFunctionBox(fun, fn, tc);
FunctionBox *funbox = parser->newFunctionBox(fun, fn, outertc);
if (!funbox)
return NULL;
/* Initialize non-default members of funtc. */
JS_ASSERT(!funtc->sc->flags);
funtc->sc->flags = tc->sc->flags & TCF_STRICT_MODE_CODE; // inherit strict mode from parent
funtc->sc->blockidGen = tc->sc->blockidGen;
/* 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, tc->sc->staticLevel + 1))
if (!SetStaticLevel(funtc->sc, outertc->sc->staticLevel + 1))
return NULL;
return funbox;
@ -1139,8 +1139,7 @@ LeaveFunction(ParseNode *fn, Parser *parser, PropertyName *funName = NULL,
tc->sc->blockidGen = funtc->sc->blockidGen;
FunctionBox *funbox = fn->pn_funbox;
JS_ASSERT(!funbox->tcflags); // we don't set any of these flags until now
funbox->tcflags = funtc->sc->flags;
funbox->cxFlags = funtc->sc->cxFlags; // copy all the flags
fn->pn_dflags |= PND_INITIALIZED;
if (!tc->sc->topStmt || tc->sc->topStmt->type == STMT_BLOCK)
@ -1542,6 +1541,9 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
if (!funbox)
return NULL;
if (outertc->sc->inStrictMode())
funsc.setInStrictMode(); // inherit strict mode from parent
RootedVarFunction fun(context, funbox->function());
/* Now parse formal argument list and compute fun->nargs. */
@ -1619,7 +1621,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
* parents: any local can be read at runtime.
*/
if (funsc.bindingsAccessedDynamically())
outertc->sc->noteBindingsAccessedDynamically();
outertc->sc->setBindingsAccessedDynamically();
#if JS_HAS_DESTRUCTURING
/*
@ -1662,9 +1664,9 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
* visible eval call, or assignment to 'arguments'), flag the function as
* heavyweight (requiring a call object per invocation).
*/
if (funsc.flags & TCF_FUN_HEAVYWEIGHT) {
if (funsc.funIsHeavyweight()) {
fun->flags |= JSFUN_HEAVYWEIGHT;
outertc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
outertc->sc->setFunIsHeavyweight();
}
JSOp op = JSOP_NOP;
@ -1680,12 +1682,12 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
*/
JS_ASSERT(!outertc->sc->inStrictMode());
op = JSOP_DEFFUN;
outertc->sc->noteMightAliasLocals();
outertc->sc->noteHasExtensibleScope();
outertc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
outertc->sc->setFunMightAliasLocals();
outertc->sc->setFunHasExtensibleScope();
outertc->sc->setFunIsHeavyweight();
/*
* Instead of noteBindingsAccessedDynamically, which would be
* Instead of setting bindingsAccessedDynamically, which would be
* overly conservative, remember the names of all function
* statements and mark any bindings with the same as aliased at the
* end of functionBody.
@ -1821,7 +1823,7 @@ Parser::recognizeDirectivePrologue(ParseNode *pn, bool *isDirectivePrologueMembe
return false;
}
tc->sc->flags |= TCF_STRICT_MODE_CODE;
tc->sc->setInStrictMode();
tokenStream.setStrictMode();
}
}
@ -1887,7 +1889,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(tc->sc->hasExtensibleScope());
JS_ASSERT(tc->sc->funHasExtensibleScope());
if (hasFunctionStmt)
*hasFunctionStmt = true;
}
@ -2124,7 +2126,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
if (stmt && stmt->type == STMT_WITH) {
data->fresh = false;
pn->pn_dflags |= PND_DEOPTIMIZED;
tc->sc->noteMightAliasLocals();
tc->sc->setFunMightAliasLocals();
return true;
}
@ -2308,7 +2310,7 @@ NoteLValue(JSContext *cx, ParseNode *pn, SharedContext *sc, unsigned dflag = PND
* happens by making such functions heavyweight.
*/
if (sc->inFunction && pn->pn_atom == sc->fun()->atom)
sc->flags |= TCF_FUN_HEAVYWEIGHT;
sc->setFunIsHeavyweight();
}
static bool
@ -2660,7 +2662,7 @@ Parser::returnOrYield(bool useAssignExpr)
* a |for| token, so we have to delay flagging the current function.
*/
if (tc->parenDepth == 0) {
tc->sc->flags |= TCF_FUN_IS_GENERATOR;
tc->sc->setFunIsGenerator();
} else {
tc->yieldCount++;
tc->yieldNode = pn;
@ -2697,7 +2699,7 @@ Parser::returnOrYield(bool useAssignExpr)
tc->hasReturnVoid = true;
}
if (tc->hasReturnExpr && (tc->sc->flags & TCF_FUN_IS_GENERATOR)) {
if (tc->hasReturnExpr && tc->sc->funIsGenerator()) {
/* As in Python (see PEP-255), disallow return v; in generators. */
ReportBadReturn(context, this, pn, JSREPORT_ERROR,
JSMSG_BAD_GENERATOR_RETURN,
@ -3607,7 +3609,7 @@ Parser::withStatement()
* doesn't even merit a warning under JSOPTION_STRICT. See
* https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
*/
if (tc->sc->flags & TCF_STRICT_MODE_CODE) {
if (tc->sc->inStrictMode()) {
reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_STRICT_CODE_WITH);
return NULL;
}
@ -3635,8 +3637,8 @@ Parser::withStatement()
pn->pn_pos.end = pn2->pn_pos.end;
pn->pn_right = pn2;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->innermostWith = oldWith;
/*
@ -4121,7 +4123,7 @@ Parser::statement()
pn = new_<DebuggerStatement>(tokenStream.currentToken().pos);
if (!pn)
return NULL;
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setFunIsHeavyweight();
break;
#if JS_HAS_XML_SUPPORT
@ -4146,7 +4148,7 @@ Parser::statement()
JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
/* Is this an E4X dagger I see before me? */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setFunIsHeavyweight();
ParseNode *pn2 = expr();
if (!pn2)
return NULL;
@ -4959,14 +4961,14 @@ GenexpGuard::maybeNoteGenerator(ParseNode *pn)
{
TreeContext *tc = parser->tc;
if (tc->yieldCount > 0) {
tc->sc->flags |= TCF_FUN_IS_GENERATOR;
tc->sc->setFunIsGenerator();
if (!tc->sc->inFunction) {
parser->reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD,
js_yield_str);
return false;
}
if (tc->hasReturnExpr) {
/* At the time we saw the yield, we might not have set TCF_FUN_IS_GENERATOR yet. */
/* At the time we saw the yield, we might not have set funIsGenerator yet. */
ReportBadReturn(tc->sc->context, parser, pn, JSREPORT_ERROR,
JSMSG_BAD_GENERATOR_RETURN,
JSMSG_BAD_ANON_GENERATOR_RETURN);
@ -5462,12 +5464,14 @@ Parser::generatorExpr(ParseNode *kid)
return NULL;
/*
* We assume conservatively that any deoptimization flags in tc->sc->flags
* We assume conservatively that any deoptimization flags in tc->sc
* come from the kid. So we propagate these flags into genfn. For code
* simplicity we also do not detect if the flags were only set in the
* kid and could be removed from tc->sc->flags.
* kid and could be removed from tc->sc.
*/
gensc.flags |= TCF_FUN_IS_GENERATOR | outertc->sc->flags;
gensc.cxFlags = outertc->sc->cxFlags;
gensc.setFunIsGenerator();
funbox->inGenexpLambda = true;
genfn->pn_funbox = funbox;
genfn->pn_blockid = gensc.bodyid;
@ -5638,8 +5642,8 @@ Parser::memberExpr(JSBool allowCallSyntax)
TokenPtr begin = lhs->pn_pos.begin;
if (tt == TOK_LP) {
/* Filters are effectively 'with', so deoptimize names. */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
StmtInfo stmtInfo(context);
ParseNode *oldWith = tc->innermostWith;
@ -5758,14 +5762,14 @@ Parser::memberExpr(JSBool allowCallSyntax)
if (lhs->pn_atom == context->runtime->atomState.evalAtom) {
/* Select JSOP_EVAL and flag tc as heavyweight. */
nextMember->setOp(JSOP_EVAL);
tc->sc->noteBindingsAccessedDynamically();
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->setBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
/*
* In non-strict mode code, direct calls to eval can add
* variables to the call object.
*/
if (!tc->sc->inStrictMode())
tc->sc->noteHasExtensibleScope();
tc->sc->setFunHasExtensibleScope();
}
} else if (lhs->isOp(JSOP_GETPROP)) {
/* Select JSOP_FUNAPPLY given foo.apply(...). */
@ -5914,8 +5918,8 @@ Parser::qualifiedSuffix(ParseNode *pn)
if (!pn2)
return NULL;
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
/* Left operand of :: must be evaluated if it is an identifier. */
if (pn->isOp(JSOP_QNAMEPART))
@ -5961,8 +5965,8 @@ Parser::qualifiedIdentifier()
return NULL;
if (tokenStream.matchToken(TOK_DBLCOLON)) {
/* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
pn = qualifiedSuffix(pn);
}
return pn;
@ -6466,8 +6470,8 @@ Parser::propertyQualifiedIdentifier()
JS_ASSERT(tokenStream.peekToken() == TOK_DBLCOLON);
/* Deoptimize QualifiedIdentifier properties to avoid tricky analysis. */
tc->sc->flags |= TCF_FUN_HEAVYWEIGHT;
tc->sc->noteBindingsAccessedDynamically();
tc->sc->setFunIsHeavyweight();
tc->sc->setBindingsAccessedDynamically();
PropertyName *name = tokenStream.currentToken().name();
ParseNode *node = NameNode::create(PNK_NAME, name, this, this->tc->sc);

View File

@ -52,7 +52,7 @@ using namespace js;
using namespace js::frontend;
static void
FlagHeavyweights(Definition *dn, FunctionBox *funbox, uint32_t *tcflags, bool topInFunction)
FlagHeavyweights(Definition *dn, FunctionBox *funbox, bool *isHeavyweight, bool topInFunction)
{
unsigned dnLevel = dn->frameLevel();
@ -64,17 +64,17 @@ FlagHeavyweights(Definition *dn, FunctionBox *funbox, uint32_t *tcflags, bool to
* funbox whose body contains the dn definition.
*/
if (funbox->level + 1U == dnLevel || (dnLevel == 0 && dn->isLet())) {
funbox->tcflags |= TCF_FUN_HEAVYWEIGHT;
funbox->setFunIsHeavyweight();
break;
}
}
if (!funbox && topInFunction)
*tcflags |= TCF_FUN_HEAVYWEIGHT;
*isHeavyweight = true;
}
static void
SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, bool isDirectEval)
SetFunctionKinds(FunctionBox *funbox, bool *isHeavyweight, bool topInFunction, bool isDirectEval)
{
for (; funbox; funbox = funbox->siblings) {
ParseNode *fn = funbox->node;
@ -86,13 +86,13 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, boo
continue;
if (funbox->kids)
SetFunctionKinds(funbox->kids, tcflags, topInFunction, isDirectEval);
SetFunctionKinds(funbox->kids, isHeavyweight, topInFunction, isDirectEval);
JSFunction *fun = funbox->function();
JS_ASSERT(fun->kind() == JSFUN_INTERPRETED);
if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) {
if (funbox->funIsHeavyweight()) {
/* nothing to do */
} else if (isDirectEval || funbox->inAnyDynamicScope()) {
/*
@ -134,7 +134,7 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, boo
* ensure that its containing function has been flagged as
* heavyweight.
*
* The emitter must see TCF_FUN_HEAVYWEIGHT accurately before
* The emitter must see funIsHeavyweight() accurately before
* generating any code for a tree of nested functions.
*/
AtomDefnMapPtr upvars = pn->pn_names;
@ -144,7 +144,7 @@ SetFunctionKinds(FunctionBox *funbox, uint32_t *tcflags, bool topInFunction, boo
Definition *defn = r.front().value();
Definition *lexdep = defn->resolve();
if (!lexdep->isFreeVar())
FlagHeavyweights(lexdep, funbox, tcflags, topInFunction);
FlagHeavyweights(lexdep, funbox, isHeavyweight, topInFunction);
}
}
}
@ -179,7 +179,9 @@ MarkExtensibleScopeDescendants(JSContext *context, FunctionBox *funbox, bool has
if (funbox->kids) {
if (!MarkExtensibleScopeDescendants(context, funbox->kids,
hasExtensibleParent || funbox->scopeIsExtensible())) {
hasExtensibleParent ||
funbox->funHasExtensibleScope()))
{
return false;
}
}
@ -197,6 +199,9 @@ frontend::AnalyzeFunctions(Parser *parser)
if (!MarkExtensibleScopeDescendants(sc->context, sc->functionList, false))
return false;
bool isDirectEval = !!parser->callerFrame;
SetFunctionKinds(sc->functionList, &sc->flags, sc->inFunction, isDirectEval);
bool isHeavyweight = false;
SetFunctionKinds(sc->functionList, &isHeavyweight, sc->inFunction, isDirectEval);
if (isHeavyweight)
sc->setFunIsHeavyweight();
return true;
}

View File

@ -563,7 +563,7 @@ js::ReportStrictModeError(JSContext *cx, TokenStream *ts, SharedContext *sc, Par
/* In strict mode code, this is an error, not merely a warning. */
unsigned flags;
if ((ts && ts->isStrictMode()) || (sc && (sc->flags & TCF_STRICT_MODE_CODE))) {
if ((ts && ts->isStrictMode()) || (sc && sc->inStrictMode())) {
flags = JSREPORT_ERROR;
} else {
if (!cx->hasStrictOption())

View File

@ -51,7 +51,6 @@ namespace js {
inline
SharedContext::SharedContext(JSContext *cx, bool inFunction)
: context(cx),
flags(0),
bodyid(0),
blockidGen(0),
topStmt(NULL),
@ -65,7 +64,8 @@ SharedContext::SharedContext(JSContext *cx, bool inFunction)
bindings(cx),
bindingsRoot(cx, &bindings),
inFunction(inFunction),
inForInit(false)
inForInit(false),
cxFlags(cx)
{
}
@ -119,8 +119,6 @@ TreeContext::TreeContext(Parser *prs, SharedContext *sc)
inline bool
TreeContext::init(JSContext *cx)
{
if (cx->hasRunOption(JSOPTION_STRICT_MODE))
sc->flags |= TCF_STRICT_MODE_CODE;
return decls.init() && lexdeps.ensureMap(sc->context);
}

View File

@ -56,20 +56,20 @@ typedef struct BindData BindData;
namespace js {
JS_ENUM_HEADER(TreeContextFlags, uint32_t)
{
// function needs Call object per call
TCF_FUN_HEAVYWEIGHT = 0x1,
struct StmtInfo;
// parsed yield statement in function
TCF_FUN_IS_GENERATOR = 0x2,
class ContextFlags {
// This class's data is all private and so only visible to these friends.
friend class SharedContext;
friend class FunctionBox;
// This function/global/eval code body contained a Use Strict Directive.
// Treat certain strict warnings as errors, and forbid the use of 'with'.
// See also TSF_STRICT_MODE_CODE, JSScript::strictModeCode, and
// JSREPORT_STRICT_ERROR.
//
TCF_STRICT_MODE_CODE = 0x4,
bool inStrictMode:1;
// The (static) bindings of this script need to support dynamic name
// read/write access. Here, 'dynamic' means dynamic dictionary lookup on
@ -91,11 +91,22 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// taken not to turn off the whole 'arguments' optimization). To answer the
// more general "is this argument aliased" question, script->needsArgsObj
// should be tested (see JSScript::argIsAlised).
TCF_BINDINGS_ACCESSED_DYNAMICALLY = 0x8,
//
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;
// We parsed a yield statement in the function.
bool funIsGenerator:1;
// The function or a function that encloses it may define new local names
// at runtime through means other than calling eval.
TCF_FUN_MIGHT_ALIAS_LOCALS = 0x10,
bool funMightAliasLocals:1;
// This function does something that can extend the set of bindings in its
// call objects --- it does a direct eval in non-strict code, or includes a
@ -104,7 +115,7 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// This flag is *not* inherited by enclosed or enclosing functions; it
// applies only to the function in whose flags it appears.
//
TCF_FUN_EXTENSIBLE_SCOPE = 0x20,
bool funHasExtensibleScope:1;
// Technically, every function has a binding named 'arguments'. Internally,
// this binding is only added when 'arguments' is mentioned by the function
@ -127,7 +138,7 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// have no special semantics: the initial value is unconditionally the
// actual argument (or undefined if nactual < nformal).
//
TCF_ARGUMENTS_HAS_LOCAL_BINDING = 0x40,
bool funArgumentsHasLocalBinding:1;
// In many cases where 'arguments' has a local binding (as described above)
// we do not need to actually create an arguments object in the function
@ -138,16 +149,24 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_t)
// be unsound in several cases. The frontend filters out such cases by
// setting this flag which eagerly sets script->needsArgsObj to true.
//
TCF_DEFINITELY_NEEDS_ARGS_OBJ = 0x80
bool funDefinitelyNeedsArgsObj:1;
} JS_ENUM_FOOTER(TreeContextFlags);
struct StmtInfo;
public:
ContextFlags(JSContext *cx)
: inStrictMode(cx->hasRunOption(JSOPTION_STRICT_MODE)),
bindingsAccessedDynamically(false),
funIsHeavyweight(false),
funIsGenerator(false),
funMightAliasLocals(false),
funHasExtensibleScope(false),
funArgumentsHasLocalBinding(false),
funDefinitelyNeedsArgsObj(false)
{ }
};
struct SharedContext {
JSContext *context;
uint32_t flags; /* statement state flags, see above */
uint32_t bodyid; /* block number of program/function body */
uint32_t blockidGen; /* preincremented block number generator */
@ -179,21 +198,28 @@ struct SharedContext {
bool inForInit:1; /* parsing/emitting init expr of for; exclude 'in' */
ContextFlags cxFlags;
inline SharedContext(JSContext *cx, bool inFunction);
bool inStrictMode() const { return flags & TCF_STRICT_MODE_CODE; }
bool bindingsAccessedDynamically() const { return flags & TCF_BINDINGS_ACCESSED_DYNAMICALLY; }
bool mightAliasLocals() const { return flags & TCF_FUN_MIGHT_ALIAS_LOCALS; }
bool hasExtensibleScope() const { return flags & TCF_FUN_EXTENSIBLE_SCOPE; }
bool argumentsHasLocalBinding() const { return flags & TCF_ARGUMENTS_HAS_LOCAL_BINDING; }
bool definitelyNeedsArgsObj() const { return flags & TCF_DEFINITELY_NEEDS_ARGS_OBJ; }
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; }
void noteMightAliasLocals() { flags |= TCF_FUN_MIGHT_ALIAS_LOCALS; }
void noteBindingsAccessedDynamically() { flags |= TCF_BINDINGS_ACCESSED_DYNAMICALLY; }
void noteHasExtensibleScope() { flags |= TCF_FUN_EXTENSIBLE_SCOPE; }
void noteArgumentsHasLocalBinding() { flags |= TCF_ARGUMENTS_HAS_LOCAL_BINDING; }
void noteDefinitelyNeedsArgsObj() { JS_ASSERT(argumentsHasLocalBinding());
flags |= TCF_DEFINITELY_NEEDS_ARGS_OBJ; }
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; }
void setFunDefinitelyNeedsArgsObj() { JS_ASSERT(cxFlags.funArgumentsHasLocalBinding);
cxFlags.funDefinitelyNeedsArgsObj = true; }
unsigned argumentsLocalSlot() const;

View File

@ -2950,7 +2950,7 @@ ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
bool isGenerator =
#if JS_HAS_GENERATORS
pn->pn_funbox->tcflags & TCF_FUN_IS_GENERATOR;
pn->pn_funbox->funIsGenerator();
#else
false;
#endif

View File

@ -1329,24 +1329,28 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
bce->regexpList.finish(script->regexps());
if (bce->constList.length() != 0)
bce->constList.finish(script->consts());
if (bce->sc->flags & TCF_STRICT_MODE_CODE)
script->strictModeCode = true;
script->strictModeCode = bce->sc->inStrictMode();
if (bce->parser->compileAndGo) {
script->compileAndGo = true;
const StackFrame *fp = bce->parser->callerFrame;
if (fp && fp->isFunctionFrame())
script->savedCallerFun = true;
}
if (bce->sc->bindingsAccessedDynamically())
script->bindingsAccessedDynamically = true;
script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
script->hasSingletons = bce->hasSingletons;
if (bce->sc->flags & TCF_FUN_IS_GENERATOR)
script->isGenerator = true;
if (bce->sc->argumentsHasLocalBinding()) {
script->setArgumentsHasLocalBinding(bce->sc->argumentsLocalSlot());
if (bce->sc->definitelyNeedsArgsObj())
script->setNeedsArgsObj(true);
if (bce->sc->inFunction) {
if (bce->sc->funArgumentsHasLocalBinding()) {
// This must precede the script->bindings.transfer() call below.
script->setArgumentsHasLocalBinding(bce->sc->argumentsLocalSlot());
if (bce->sc->funDefinitelyNeedsArgsObj())
script->setNeedsArgsObj(true);
} else {
JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj());
}
} else {
JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj());
}
if (nClosedArgs)
@ -1360,6 +1364,9 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
if (bce->sc->inFunction) {
JS_ASSERT(!bce->noScriptRval);
JS_ASSERT(!bce->needScriptGlobal);
script->isGenerator = bce->sc->funIsGenerator();
/*
* We initialize fun->script() to be the script constructed above
* so that the debugger has a valid fun->script().
@ -1367,7 +1374,7 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
fun = bce->sc->fun();
JS_ASSERT(fun->isInterpreted());
JS_ASSERT(!fun->script());
if (bce->sc->flags & TCF_FUN_HEAVYWEIGHT)
if (bce->sc->funIsHeavyweight())
fun->flags |= JSFUN_HEAVYWEIGHT;
/*
@ -1383,7 +1390,12 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
fun->setScript(script);
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.

View File

@ -529,7 +529,7 @@ struct JSScript : public js::gc::Cell
bool savedCallerFun:1; /* can call getCallerFunction() */
bool strictModeCode:1; /* code is in strict mode */
bool compileAndGo:1; /* see Parser::compileAndGo */
bool bindingsAccessedDynamically:1; /* see TCF_BINDINGS_ACCESSED_DYNAMICALLY */
bool bindingsAccessedDynamically:1; /* see ContextFlags' field of the same name */
bool warnedAboutTwoArgumentEval:1; /* have warned about use of
obsolete eval(s, o) in
this script */
@ -589,7 +589,7 @@ struct JSScript : public js::gc::Cell
void setVersion(JSVersion v) { version = v; }
/* See TCF_ARGUMENTS_HAS_LOCAL_BINDING comment. */
/* See ContextFlags::funArgumentsHasLocalBinding comment. */
bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; }
jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
unsigned argumentsLocalSlot() const { JS_ASSERT(argsHasLocalBinding_); return argsSlot_; }