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

--HG--
extra : rebase_source : ab04928f5922e6785f32dcd802b2474525981e99
This commit is contained in:
Benjamin Peterson 2012-12-12 01:35:05 -05:00
parent 8cbbec8014
commit 77dac08f38
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);

View File

@ -4850,12 +4850,8 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
SharedContext *outersc = bce->sc;
FunctionBox *funbox = pn->pn_funbox;
// If funbox's strictModeState is still unknown (as can happen for
// functions defined in defaults), inherit it from the parent.
if (funbox->strictModeState == StrictMode::UNKNOWN) {
JS_ASSERT(outersc->strictModeState != StrictMode::UNKNOWN);
funbox->strictModeState = outersc->strictModeState;
}
JS_ASSERT(outersc->strictModeState != StrictMode::UNKNOWN);
if (outersc->isFunction && outersc->asFunbox()->mightAliasLocals())
funbox->setMightAliasLocals(); // inherit mightAliasLocals from parent
JS_ASSERT_IF(outersc->inStrictMode(), funbox->inStrictMode());

View File

@ -775,6 +775,48 @@ struct ParseNode {
return !(isOp(JSOP_LAMBDA) || isOp(JSOP_DEFFUN));
}
/*
* True if this statement node could be a member of a Directive Prologue: an
* expression statement consisting of a single string literal.
*
* This considers only the node and its children, not its context. After
* parsing, check the node's pn_prologue flag to see if it is indeed part of
* a directive prologue.
*
* Note that a Directive Prologue can contain statements that cannot
* themselves be directives (string literals that include escape sequences
* or escaped newlines, say). This member function returns true for such
* nodes; we use it to determine the extent of the prologue.
* isEscapeFreeStringLiteral, below, checks whether the node itself could be
* a directive.
*/
bool isStringExprStatement() const {
if (getKind() == PNK_SEMI) {
JS_ASSERT(pn_arity == PN_UNARY);
ParseNode *kid = pn_kid;
return kid && kid->getKind() == PNK_STRING && !kid->pn_parens;
}
return false;
}
/*
* Return true if this node, known to be an unparenthesized string literal,
* could be the string of a directive in a Directive Prologue. Directive
* strings never contain escape sequences or line continuations.
*/
bool isEscapeFreeStringLiteral() const {
JS_ASSERT(isKind(PNK_STRING) && !pn_parens);
/*
* If the string's length in the source code is its length as a value,
* accounting for the quotes, then it must not contain any escape
* sequences or line continuations.
*/
JSString *str = pn_atom;
return (pn_pos.begin.lineno == pn_pos.end.lineno &&
pn_pos.begin.index + str->length() + 2 == pn_pos.end.index);
}
inline bool test(unsigned flag) const;
bool isLet() const { return test(PND_LET); }

View File

@ -50,7 +50,8 @@ ParseContext::ParseContext(Parser *prs, SharedContext *sc, unsigned staticLevel,
funHasReturnVoid(false),
parsingForInit(false),
parsingWith(prs->pc ? prs->pc->parsingWith : false), // inherit from parent context
inDeclDestructuring(false)
inDeclDestructuring(false),
funBecameStrict(false)
{
prs->pc = this;
}

View File

@ -706,6 +706,48 @@ CheckStrictBinding(JSContext *cx, Parser *parser, HandlePropertyName name, Parse
return true;
}
ParseNode *
Parser::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals, HandleScript script,
ParseNode *fn, FunctionBox **funbox, bool strict, bool *becameStrict)
{
if (becameStrict)
*becameStrict = false;
*funbox = newFunctionBox(fun, /* outerpc = */ NULL, strict ? StrictMode::STRICT : StrictMode::NOTSTRICT);
if (!funbox)
return NULL;
ParseContext funpc(this, *funbox, 0, /* staticLevel = */ 0);
if (!funpc.init())
return NULL;
for (unsigned i = 0; i < formals.length(); i++) {
if (!DefineArg(this, fn, formals[i]))
return NULL;
}
ParseNode *pn = functionBody(StatementListBody);
if (!pn) {
if (becameStrict && pc->funBecameStrict)
*becameStrict = true;
return NULL;
}
if (!tokenStream.matchToken(TOK_EOF)) {
reportError(NULL, JSMSG_SYNTAX_ERROR);
return NULL;
}
if (!FoldConstants(context, pn, this))
return NULL;
InternalHandle<Bindings*> bindings(script, &script->bindings);
if (!funpc.generateFunctionBindings(context, bindings))
return NULL;
return pn;
}
ParseNode *
Parser::functionBody(FunctionBodyType type)
{
@ -719,10 +761,6 @@ Parser::functionBody(FunctionBodyType type)
JS_ASSERT(type == ExpressionBody);
JS_ASSERT(JS_HAS_EXPR_CLOSURES);
// There are no directives to parse, so indicate we're done finding
// strict mode directives.
if (!setStrictMode(false))
return NULL;
pn = UnaryNode::create(PNK_RETURN, this);
if (pn) {
pn->pn_kid = assignExpr();
@ -1475,7 +1513,8 @@ Parser::functionArguments(ParseNode **listp, ParseNode* funcpn, bool &hasRest)
}
ParseNode *
Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSyntaxKind kind)
Parser::functionDef(HandlePropertyName funName, const TokenStream::Position &start,
FunctionType type, FunctionSyntaxKind kind)
{
JS_ASSERT_IF(kind == Statement, funName);
@ -1484,6 +1523,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
if (!pn)
return NULL;
pn->pn_body = NULL;
pn->pn_funbox = NULL;
pn->pn_cookie.makeFree();
pn->pn_dflags = 0;
@ -1589,31 +1629,55 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
pn->setOp(JSOP_LAMBDA);
}
ParseContext *outerpc = pc;
RootedFunction fun(context, newFunction(outerpc, funName, kind));
RootedFunction fun(context, newFunction(pc, funName, kind));
if (!fun)
return NULL;
// Inherit strictness if neeeded.
StrictMode sms = (outerpc->sc->strictModeState == StrictMode::STRICT) ?
StrictMode::STRICT : StrictMode::UNKNOWN;
// If the outer scope is strict, immediately parse the function in strict
// mode. Otherwise, we parse it normally. If we see a "use strict"
// directive, we backup and reparse it as strict.
pn->pn_body = NULL;
bool initiallyStrict = pc->sc->strictModeState == StrictMode::STRICT;
bool becameStrict;
if (!functionArgsAndBody(pn, fun, funName, type, kind, initiallyStrict, &becameStrict)) {
if (initiallyStrict || !becameStrict || tokenStream.hadError())
return NULL;
// Reparse the function in strict mode.
tokenStream.seek(start);
if (funName && tokenStream.getToken() == TOK_ERROR)
return NULL;
pn->pn_body = NULL;
if (!functionArgsAndBody(pn, fun, funName, type, kind, true))
return NULL;
}
return pn;
}
bool
Parser::functionArgsAndBody(ParseNode *pn, HandleFunction fun, HandlePropertyName funName, FunctionType type,
FunctionSyntaxKind kind, bool strict, bool *becameStrict)
{
if (becameStrict)
*becameStrict = false;
ParseContext *outerpc = pc;
// Create box for fun->object early to protect against last-ditch GC.
FunctionBox *funbox = newFunctionBox(fun, outerpc, sms);
FunctionBox *funbox = newFunctionBox(fun, pc, strict ? StrictMode::STRICT : StrictMode::NOTSTRICT);
if (!funbox)
return NULL;
return false;
/* Initialize early for possible flags mutation via destructuringExpr. */
ParseContext funpc(this, funbox, outerpc->staticLevel + 1, outerpc->blockidGen);
if (!funpc.init())
return NULL;
return false;
/* Now parse formal argument list and compute fun->nargs. */
ParseNode *prelude = NULL;
bool hasRest;
if (!functionArguments(&prelude, pn, hasRest))
return NULL;
return false;
fun->setArgCount(funpc.numArgs());
if (funbox->ndefaults)
@ -1623,44 +1687,54 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
if (type == Getter && fun->nargs > 0) {
reportError(NULL, JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
return NULL;
return false;
}
if (type == Setter && fun->nargs != 1) {
reportError(NULL, JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return NULL;
return false;
}
FunctionBodyType bodyType = StatementListBody;
#if JS_HAS_EXPR_CLOSURES
if (tokenStream.getToken(TSF_OPERAND) != TOK_LC) {
tokenStream.ungetToken();
fun->setIsExprClosure();
bodyType = ExpressionBody;
fun->setIsExprClosure();
}
#else
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
if (!tokenStream.matchToken(TOK_LC)) {
reportError(NULL, JSMSG_CURLY_BEFORE_BODY);
return false;
}
#endif
ParseNode *body = functionBody(bodyType);
if (!body)
return NULL;
if (!body) {
// Notify the caller if this function was discovered to be strict.
if (becameStrict && pc->funBecameStrict)
*becameStrict = true;
return false;
}
if (funName && !CheckStrictBinding(context, this, funName, pn))
return NULL;
return false;
#if JS_HAS_EXPR_CLOSURES
if (bodyType == StatementListBody) {
#endif
MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
if (!tokenStream.matchToken(TOK_RC)) {
reportError(NULL, JSMSG_CURLY_AFTER_BODY);
return false;
}
funbox->bufEnd = tokenStream.offsetOfToken(tokenStream.currentToken()) + 1;
#if JS_HAS_EXPR_CLOSURES
} else {
// We shouldn't call endOffset if the tokenizer got an error.
if (tokenStream.hadError())
return NULL;
return false;
funbox->bufEnd = tokenStream.endOffset(tokenStream.currentToken());
if (kind == Statement && !MatchOrInsertSemicolon(context, &tokenStream))
return NULL;
return false;
}
#endif
pn->pn_pos.end = tokenStream.currentToken().pos.end;
@ -1687,7 +1761,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
block = ListNode::create(PNK_SEQ, this);
if (!block)
return NULL;
return false;
block->pn_pos = body->pn_pos;
block->initList(body);
@ -1696,7 +1770,7 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
ParseNode *item = UnaryNode::create(PNK_SEMI, this);
if (!item)
return NULL;
return false;
item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
item->pn_kid = prelude;
@ -1723,9 +1797,9 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
pn->pn_blockid = outerpc->blockid();
if (!LeaveFunction(pn, this, funName, kind))
return NULL;
return false;
return pn;
return true;
}
ParseNode *
@ -1741,12 +1815,15 @@ Parser::functionStmt()
return NULL;
}
TokenStream::Position start;
tokenStream.positionAfterLastFunctionKeyword(start);
/* We forbid function statements in strict mode code. */
if (!pc->atBodyLevel() && pc->sc->needStrictChecks() &&
!reportStrictModeError(NULL, JSMSG_STRICT_FUNCTION_STATEMENT))
return NULL;
return functionDef(name, Normal, Statement);
return functionDef(name, start, Normal, Statement);
}
ParseNode *
@ -1754,78 +1831,13 @@ Parser::functionExpr()
{
RootedPropertyName name(context);
JS_ASSERT(tokenStream.currentToken().type == TOK_FUNCTION);
TokenStream::Position start;
tokenStream.positionAfterLastFunctionKeyword(start);
if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME)
name = tokenStream.currentToken().name();
else
tokenStream.ungetToken();
return functionDef(name, Normal, Expression);
}
/*
* Indicate that the current scope can't switch to strict mode with a body-level
* "use strict" directive anymore. Return false on error.
*/
bool
Parser::setStrictMode(bool strictMode)
{
if (pc->sc->strictModeState != StrictMode::UNKNOWN) {
// Strict mode was inherited.
JS_ASSERT(pc->sc->strictModeState == StrictMode::STRICT);
if (pc->sc->isFunction) {
JS_ASSERT_IF(pc->parent, pc->parent->sc->strictModeState == StrictMode::STRICT);
} else {
JS_ASSERT_IF(pc->staticLevel == 0,
StrictModeFromContext(context) == StrictMode::STRICT);
}
return true;
}
if (strictMode) {
if (pc->queuedStrictModeError) {
// There was a strict mode error in this scope before we knew it was
// strict. Throw it.
JS_ASSERT(!(pc->queuedStrictModeError->report.flags & JSREPORT_WARNING));
pc->queuedStrictModeError->throwError();
return false;
}
pc->sc->strictModeState = StrictMode::STRICT;
} else {
if (!pc->parent || pc->parent->sc->strictModeState == StrictMode::NOTSTRICT) {
// This scope lacks a strict directive, and its parent (if it has
// one) definitely isn't strict, so it definitely won't be strict.
pc->sc->strictModeState = StrictMode::NOTSTRICT;
if (pc->queuedStrictModeError && context->hasStrictOption() &&
pc->queuedStrictModeError->report.errorNumber != JSMSG_STRICT_CODE_WITH) {
// Convert queued strict mode error to a warning.
pc->queuedStrictModeError->report.flags |= JSREPORT_WARNING;
pc->queuedStrictModeError->throwError();
}
} else {
// This scope (which has a parent and so must be a function) lacks
// a strict directive, but it's not yet clear if its parent is
// strict. (This can only happen for functions in default
// arguments.) Leave it in the UNKNOWN state for now.
JS_ASSERT(pc->sc->isFunction);
}
}
return true;
}
/*
* Return true if this token, known to be an unparenthesized string literal,
* could be the string of a directive in a Directive Prologue. Directive
* strings never contain escape sequences or line continuations.
*/
static bool
IsEscapeFreeStringLiteral(const Token &tok)
{
/*
* If the string's length in the source code is its length as a value,
* accounting for the quotes, then it must not contain any escape
* sequences or line continuations.
*/
return (tok.pos.begin.lineno == tok.pos.end.lineno &&
tok.pos.begin.index + tok.atom()->length() + 2 == tok.pos.end.index);
return functionDef(name, start, Normal, Expression);
}
/*
@ -1848,52 +1860,49 @@ IsEscapeFreeStringLiteral(const Token &tok)
* to the "use strict" statement, which is indeed a directive.
*/
bool
Parser::processDirectives(ParseNode *stmts)
Parser::maybeParseDirective(ParseNode *pn, bool *cont)
{
bool gotStrictMode = false;
for (TokenKind tt = tokenStream.getToken(TSF_OPERAND); tt == TOK_STRING; tt = tokenStream.getToken(TSF_OPERAND)) {
ParseNode *stringNode = atomNode(PNK_STRING, JSOP_STRING);
if (!stringNode)
return false;
const Token directive = tokenStream.currentToken();
bool isDirective = IsEscapeFreeStringLiteral(directive);
JSAtom *atom = directive.atom();
TokenKind next = tokenStream.peekTokenSameLine();
*cont = pn->isStringExprStatement();
if (!*cont)
return true;
// We need to check whether the directive ends explicitly or implicitly
// due to ASI. In the latter case, the expression must not continue on
// the next line.
if (next != TOK_EOF && next != TOK_SEMI && next != TOK_RC &&
(next != TOK_EOL || TokenContinuesStringExpression(tokenStream.peekToken())))
{
freeTree(stringNode);
if (next == TOK_ERROR)
return false;
break;
}
tokenStream.matchToken(TOK_SEMI);
if (isDirective) {
// It's a directive. Is it one we know?
if (atom == context->names().useStrict && !gotStrictMode) {
pc->sc->setExplicitUseStrict();
if (!setStrictMode(true))
ParseNode *string = pn->pn_kid;
if (string->isEscapeFreeStringLiteral()) {
// Mark this statement as being a possibly legitimate part of a
// directive prologue, so the bytecode emitter won't warn about it being
// useless code. (We mustn't just omit the statement entirely yet, as it
// could be producing the value of an eval or JSScript execution.)
//
// Note that even if the string isn't one we recognize as a directive,
// the emitter still shouldn't flag it as useless, as it could become a
// directive in the future. We don't want to interfere with people
// taking advantage of directive-prologue-enabled features that appear
// in other browsers first.
pn->pn_prologue = true;
JSAtom *directive = string->pn_atom;
if (directive == context->runtime->atomState.useStrict) {
// We're going to be in strict mode. Note that this scope explicitly
// had "use strict";
pc->sc->setExplicitUseStrict();
if (pc->sc->strictModeState == StrictMode::NOTSTRICT) {
if (pc->sc->isFunction) {
// Request that this function be reparsed as strict.
pc->funBecameStrict = true;
return false;
gotStrictMode = true;
} else {
// We don't reparse global scopes, so we keep track of the
// one possible strict violation that could occur in the
// directive prologue -- octal escapes -- and complain now.
if (tokenStream.sawOctalEscape()) {
reportError(NULL, JSMSG_DEPRECATED_OCTAL);
return false;
}
pc->sc->strictModeState = StrictMode::STRICT;
}
}
}
ParseNode *stmt = UnaryNode::create(PNK_SEMI, this);
if (!stmt) {
freeTree(stringNode);
return false;
}
stmt->pn_pos = stringNode->pn_pos;
stmt->pn_kid = stringNode;
stmt->pn_prologue = isDirective;
stmts->append(stmt);
}
tokenStream.ungetToken();
if (!gotStrictMode && !setStrictMode(false))
return false;
return true;
}
@ -1917,8 +1926,7 @@ Parser::statements(bool *hasFunctionStmt)
ParseNode *saveBlock = pc->blockNode;
pc->blockNode = pn;
if (pc->atBodyLevel() && !processDirectives(pn))
return NULL;
bool canHaveDirectives = pc->atBodyLevel();
for (;;) {
TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
if (tt <= TOK_EOF || tt == TOK_RC) {
@ -1936,6 +1944,11 @@ Parser::statements(bool *hasFunctionStmt)
return NULL;
}
if (canHaveDirectives) {
if (!maybeParseDirective(next, &canHaveDirectives))
return NULL;
}
if (next->isKind(PNK_FUNCTION)) {
/*
* PNX_FUNCDEFS notifies the emitter that the block contains body-
@ -6711,7 +6724,10 @@ Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
/* NB: Getter function in { get x(){} } is unnamed. */
Rooted<PropertyName*> funName(context, NULL);
pn2 = functionDef(funName, op == JSOP_GETTER ? Getter : Setter, Expression);
TokenStream::Position start;
tokenStream.tell(&start);
pn2 = functionDef(funName, start, op == JSOP_GETTER ? Getter : Setter,
Expression);
if (!pn2)
return NULL;
TokenPos pos = {begin, pn2->pn_pos.end};

View File

@ -199,6 +199,10 @@ struct ParseContext /* tree context for semantic checks */
// they need to be treated differently.
bool inDeclDestructuring:1;
// True if we are in a function, saw a "use strict" directive, and weren't
// strict before.
bool funBecameStrict:1;
inline ParseContext(Parser *prs, SharedContext *sc, unsigned staticLevel, uint32_t bodyid);
inline ~ParseContext();
@ -350,7 +354,12 @@ struct Parser : private AutoGCRooter
/* Public entry points for parsing. */
ParseNode *statement();
bool processDirectives(ParseNode *stringsAtStart);
bool maybeParseDirective(ParseNode *pn, bool *cont);
// Parse a function, given only its body. Used for the Function constructor.
ParseNode *standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals, HandleScript script,
ParseNode *fn, FunctionBox **funbox, bool strict,
bool *becameStrict = NULL);
/*
* Parse a function body. Pass StatementListBody if the body is a list of
@ -424,7 +433,11 @@ struct Parser : private AutoGCRooter
enum FunctionType { Getter, Setter, Normal };
bool functionArguments(ParseNode **list, ParseNode *funcpn, bool &hasRest);
ParseNode *functionDef(HandlePropertyName name, FunctionType type, FunctionSyntaxKind kind);
ParseNode *functionDef(HandlePropertyName name, const TokenStream::Position &start,
FunctionType type, FunctionSyntaxKind kind);
bool functionArgsAndBody(ParseNode *pn, HandleFunction fun, HandlePropertyName funName,
FunctionType type, FunctionSyntaxKind kind, bool strict,
bool *becameStrict = NULL);
ParseNode *unaryOpExpr(ParseNodeKind kind, JSOp op);
@ -473,7 +486,6 @@ struct Parser : private AutoGCRooter
ParseNode *propertyQualifiedIdentifier();
#endif /* JS_HAS_XML_SUPPORT */
bool setStrictMode(bool strictMode);
bool setAssignmentLhsOps(ParseNode *pn, JSOp op);
bool matchInOrOf(bool *isForOfp);
};

View File

@ -33,7 +33,7 @@ SharedContext::inStrictMode()
inline bool
SharedContext::needStrictChecks()
{
return context->hasStrictOption() || strictModeState != StrictMode::NOTSTRICT;
return context->hasStrictOption() || strictModeState == StrictMode::STRICT;
}
inline GlobalSharedContext *

View File

@ -475,7 +475,7 @@ MOZ_END_ENUM_CLASS(StrictMode)
inline StrictMode
StrictModeFromContext(JSContext *cx)
{
return cx->hasRunOption(JSOPTION_STRICT_MODE) ? StrictMode::STRICT : StrictMode::UNKNOWN;
return cx->hasRunOption(JSOPTION_STRICT_MODE) ? StrictMode::STRICT : StrictMode::NOTSTRICT;
}
// Ideally, tokenizing would be entirely independent of context. But the