diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index ff072ec44bdc..e14270a454c2 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1014,12 +1014,15 @@ Parser::parse() bool ParserBase::isValidStrictBinding(PropertyName* name) { - return name != context->names().eval && - name != context->names().arguments && - name != context->names().let && - name != context->names().static_ && - name != context->names().yield && - !IsStrictReservedWord(name); + TokenKind tt = ReservedWordTokenKind(name); + if (tt == TOK_NAME) { + return name != context->names().eval && + name != context->names().arguments; + } + return tt != TOK_LET && + tt != TOK_STATIC && + tt != TOK_YIELD && + !TokenKindIsStrictReservedWord(tt); } /* @@ -9086,75 +9089,80 @@ Parser::newName(PropertyName* name, TokenPos pos) template bool -Parser::checkLabelOrIdentifierReference(HandlePropertyName ident, +Parser::checkLabelOrIdentifierReference(PropertyName* ident, uint32_t offset, - YieldHandling yieldHandling) + YieldHandling yieldHandling, + TokenKind hint /* = TOK_LIMIT */) { - if (ident == context->names().yield) { - if (yieldHandling == YieldIsKeyword || - versionNumber() >= JSVERSION_1_7) - { - errorAt(offset, JSMSG_RESERVED_ID, "yield"); - return false; + TokenKind tt; + if (hint == TOK_LIMIT) { + tt = ReservedWordTokenKind(ident); + } else { + MOZ_ASSERT(hint == ReservedWordTokenKind(ident), "hint doesn't match actual token kind"); + tt = hint; + } + + if (tt == TOK_NAME) + return true; + if (TokenKindIsContextualKeyword(tt)) { + if (tt == TOK_YIELD) { + if (yieldHandling == YieldIsKeyword || versionNumber() >= JSVERSION_1_7) { + errorAt(offset, JSMSG_RESERVED_ID, "yield"); + return false; + } + if (pc->sc()->needStrictChecks()) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield")) + return false; + } + return true; + } + if (tt == TOK_AWAIT) { + if (awaitIsKeyword()) { + errorAt(offset, JSMSG_RESERVED_ID, "await"); + return false; + } + return true; } if (pc->sc()->needStrictChecks()) { - if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield")) - return false; - } - - return true; - } - - if (ident == context->names().await) { - if (awaitIsKeyword()) { - errorAt(offset, JSMSG_RESERVED_ID, "await"); - return false; + if (tt == TOK_LET) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let")) + return false; + return true; + } + if (tt == TOK_STATIC) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static")) + return false; + return true; + } } return true; } - - if (IsKeyword(ident) || IsReservedWordLiteral(ident)) { - errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(ident)); + if (TokenKindIsStrictReservedWord(tt)) { + if (pc->sc()->needStrictChecks()) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(tt))) + return false; + } + return true; + } + if (TokenKindIsKeyword(tt) || TokenKindIsReservedWordLiteral(tt)) { + errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(tt)); return false; } - - if (IsFutureReservedWord(ident)) { - errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident)); + if (TokenKindIsFutureReservedWord(tt)) { + errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(tt)); return false; } - - if (pc->sc()->needStrictChecks()) { - if (IsStrictReservedWord(ident)) { - if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident))) - return false; - return true; - } - - if (ident == context->names().let) { - if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let")) - return false; - return true; - } - - if (ident == context->names().static_) { - if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static")) - return false; - return true; - } - } - - return true; + MOZ_ASSERT_UNREACHABLE("Unexpected reserved word kind."); + return false; } template bool -Parser::checkBindingIdentifier(HandlePropertyName ident, +Parser::checkBindingIdentifier(PropertyName* ident, uint32_t offset, - YieldHandling yieldHandling) + YieldHandling yieldHandling, + TokenKind hint /* = TOK_LIMIT */) { - if (!checkLabelOrIdentifierReference(ident, offset, yieldHandling)) - return false; - if (pc->sc()->needStrictChecks()) { if (ident == context->names().arguments) { if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments")) @@ -9169,7 +9177,7 @@ Parser::checkBindingIdentifier(HandlePropertyName ident, } } - return true; + return checkLabelOrIdentifierReference(ident, offset, yieldHandling, hint); } template @@ -9183,8 +9191,13 @@ Parser::labelOrIdentifierReference(YieldHandling yieldHandling) // // Use PropertyName* instead of TokenKind to reflect the normalization. + // Unless the name contains escapes, we can reuse the current TokenKind + // to determine if the name is a restricted identifier. + TokenKind hint = !tokenStream.currentNameHasEscapes() + ? tokenStream.currentToken().type + : TOK_LIMIT; RootedPropertyName ident(context, tokenStream.currentName()); - if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling)) + if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling, hint)) return nullptr; return ident; } @@ -9193,8 +9206,11 @@ template PropertyName* Parser::bindingIdentifier(YieldHandling yieldHandling) { + TokenKind hint = !tokenStream.currentNameHasEscapes() + ? tokenStream.currentToken().type + : TOK_LIMIT; RootedPropertyName ident(context, tokenStream.currentName()); - if (!checkBindingIdentifier(ident, pos().begin, yieldHandling)) + if (!checkBindingIdentifier(ident, pos().begin, yieldHandling, hint)) return nullptr; return ident; } diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 0e90b9ab2515..b4a54ded8328 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1416,17 +1416,19 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, DefaultHandling defaultHandling); - bool checkLabelOrIdentifierReference(HandlePropertyName ident, + bool checkLabelOrIdentifierReference(PropertyName* ident, uint32_t offset, - YieldHandling yieldHandling); + YieldHandling yieldHandling, + TokenKind hint = TOK_LIMIT); - bool checkLocalExportName(HandlePropertyName ident, uint32_t offset) { + bool checkLocalExportName(PropertyName* ident, uint32_t offset) { return checkLabelOrIdentifierReference(ident, offset, YieldIsName); } - bool checkBindingIdentifier(HandlePropertyName ident, + bool checkBindingIdentifier(PropertyName* ident, uint32_t offset, - YieldHandling yieldHandling); + YieldHandling yieldHandling, + TokenKind hint = TOK_LIMIT); PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 23c6c996750e..13d5f506b2b8 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -194,41 +194,29 @@ frontend::IsKeyword(JSLinearString* str) return false; } -bool -frontend::IsFutureReservedWord(JSLinearString* str) +TokenKind +frontend::ReservedWordTokenKind(PropertyName* str) { if (const ReservedWordInfo* rw = FindReservedWord(str)) - return TokenKindIsFutureReservedWord(rw->tokentype); + return rw->tokentype; - return false; -} - -bool -frontend::IsStrictReservedWord(JSLinearString* str) -{ - if (const ReservedWordInfo* rw = FindReservedWord(str)) - return TokenKindIsStrictReservedWord(rw->tokentype); - - return false; -} - -bool -frontend::IsReservedWordLiteral(JSLinearString* str) -{ - if (const ReservedWordInfo* rw = FindReservedWord(str)) - return TokenKindIsReservedWordLiteral(rw->tokentype); - - return false; + return TOK_NAME; } const char* frontend::ReservedWordToCharZ(PropertyName* str) { - const ReservedWordInfo* rw = FindReservedWord(str); - if (rw == nullptr) - return nullptr; + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return ReservedWordToCharZ(rw->tokentype); - switch (rw->tokentype) { + return nullptr; +} + +const char* +frontend::ReservedWordToCharZ(TokenKind tt) +{ + MOZ_ASSERT(tt != TOK_NAME); + switch (tt) { #define EMIT_CASE(word, name, type) case type: return js_##word##_str; FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE) #undef EMIT_CASE diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index b797d6dcca53..a3d04eb33fe1 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -242,17 +242,14 @@ struct Token } }; +extern TokenKind +ReservedWordTokenKind(PropertyName* str); + extern const char* ReservedWordToCharZ(PropertyName* str); -extern MOZ_MUST_USE bool -IsFutureReservedWord(JSLinearString* str); - -extern MOZ_MUST_USE bool -IsReservedWordLiteral(JSLinearString* str); - -extern MOZ_MUST_USE bool -IsStrictReservedWord(JSLinearString* str); +extern const char* +ReservedWordToCharZ(TokenKind tt); // Ideally, tokenizing would be entirely independent of context. But the // strict mode flag, which is in SharedContext, affects tokenizing, and @@ -308,6 +305,16 @@ class TokenStreamBase return reservedWordToPropertyName(currentToken().type); } + bool currentNameHasEscapes() const { + if (isCurrentTokenType(TOK_NAME)) { + TokenPos pos = currentToken().pos; + return (pos.end - pos.begin) != currentToken().name()->length(); + } + + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(currentToken().type)); + return false; + } + PropertyName* nextName() const { if (nextToken().type != TOK_NAME) return nextToken().name();