Bug 819509 - Reparse functions if we discover they are strict. r=njn
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user