Bug 819509 - Reparse functions if we discover they are strict. r=njn

This commit is contained in:
Benjamin Peterson
2012-12-12 01:35:05 -05:00
parent 9a9cbb18a0
commit 144f39bafa
8 changed files with 249 additions and 197 deletions

View File

@@ -168,17 +168,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
#endif
TokenStream &tokenStream = parser.tokenStream;
{
ParseNode *stringsAtStart = ListNode::create(PNK_STATEMENTLIST, &parser);
if (!stringsAtStart)
return NULL;
stringsAtStart->makeEmpty();
bool ok = parser.processDirectives(stringsAtStart) && EmitTree(cx, &bce, stringsAtStart);
parser.freeTree(stringsAtStart);
if (!ok)
return NULL;
}
JS_ASSERT(globalsc.strictModeState != StrictMode::UNKNOWN);
bool canHaveDirectives = true;
for (;;) {
TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
if (tt <= TOK_EOF) {
@@ -192,6 +182,11 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
if (!pn)
return NULL;
if (canHaveDirectives) {
if (!parser.maybeParseDirective(pn, &canHaveDirectives))
return NULL;
}
if (!FoldConstants(cx, pn, &parser))
return NULL;
if (!NameFunctions(cx, pn))
@@ -279,15 +274,8 @@ frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions
JS_ASSERT(fun);
StrictMode sms = StrictModeFromContext(cx);
FunctionBox *funbox = parser.newFunctionBox(fun, /* outerpc = */ NULL, sms);
fun->setArgCount(formals.length());
unsigned staticLevel = 0;
ParseContext funpc(&parser, funbox, staticLevel, /* bodyid = */ 0);
if (!funpc.init())
return false;
/* FIXME: make Function format the source for a function definition. */
ParseNode *fn = FunctionNode::create(PNK_NAME, &parser);
if (!fn)
@@ -303,36 +291,33 @@ frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun, CompileOptions
argsbody->makeEmpty();
fn->pn_body = argsbody;
for (unsigned i = 0; i < formals.length(); i++) {
if (!DefineArg(&parser, fn, formals[i]))
return false;
}
/*
* After we're done parsing, we must fold constants, analyze any nested
* functions, and generate code for this function, including a stop opcode
* at the end.
*/
ParseNode *pn = parser.functionBody(Parser::StatementListBody);
if (!pn)
return false;
if (!parser.tokenStream.matchToken(TOK_EOF)) {
parser.reportError(NULL, JSMSG_SYNTAX_ERROR);
return false;
}
if (!FoldConstants(cx, pn, &parser))
return false;
Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), false, options,
staticLevel, ss, 0, length));
/* staticLevel = */ 0, ss,
/* sourceStart = */ 0, length));
if (!script)
return false;
InternalHandle<Bindings*> bindings(script, &script->bindings);
if (!funpc.generateFunctionBindings(cx, bindings))
return false;
// If the context is strict, immediately parse the body in strict
// mode. Otherwise, we parse it normally. If we see a "use strict"
// directive, we backup and reparse it as strict.
TokenStream::Position start;
parser.tokenStream.tell(&start);
bool initiallyStrict = StrictModeFromContext(cx) == StrictMode::STRICT;
bool becameStrict;
FunctionBox *funbox;
ParseNode *pn = parser.standaloneFunctionBody(fun, formals, script, fn, &funbox,
initiallyStrict, &becameStrict);
if (!pn) {
if (initiallyStrict || !becameStrict || parser.tokenStream.hadError())
return false;
// Reparse in strict mode.
parser.tokenStream.seek(start);
pn = parser.standaloneFunctionBody(fun, formals, script, fn, &funbox,
/* strict = */ true);
if (!pn)
return false;
}
BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script, /* callerFrame = */ NULL,
/* hasGlobalScope = */ false, options.lineno);