mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 11:57:32 +09:00
Issue #2142 - Reduce calls to FindReservedWord when checking for forbidden identifiers during parsing
Based-on: m-c 1351913/{1,2}
This commit is contained in:
parent
faed047e3f
commit
6abb54ff11
4 changed files with 116 additions and 96 deletions
|
|
@ -994,12 +994,15 @@ Parser<ParseHandler>::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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3725,6 +3728,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
|||
// The same goes when parsing |await| in arrow functions.
|
||||
YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
|
||||
AwaitHandling bodyAwaitHandling = GetAwaitHandling(pc->asyncKind());
|
||||
bool inheritedStrict = pc->sc()->strict();
|
||||
LexicalScopeNodeType body;
|
||||
{
|
||||
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, bodyAwaitHandling);
|
||||
|
|
@ -3733,9 +3737,15 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Revalidate the function name when we transitioned to strict mode.
|
||||
if ((kind == FunctionSyntaxKind::Statement ||
|
||||
kind == FunctionSyntaxKind::Expression) && fun->explicitName()) {
|
||||
RootedPropertyName propertyName(context, fun->explicitName()->asPropertyName());
|
||||
kind == FunctionSyntaxKind::Expression) && fun->explicitName()
|
||||
&& !inheritedStrict && pc->sc()->strict())
|
||||
{
|
||||
MOZ_ASSERT(pc->sc()->hasExplicitUseStrict(),
|
||||
"strict mode should only change when a 'use strict' directive is present");
|
||||
|
||||
PropertyName* propertyName = fun->explicitName()->asPropertyName();
|
||||
YieldHandling nameYieldHandling;
|
||||
if (kind == FunctionSyntaxKind::Expression) {
|
||||
// Named lambda has binding inside it.
|
||||
|
|
@ -9675,75 +9685,80 @@ Parser<ParseHandler>::memberCall(
|
|||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::checkLabelOrIdentifierReference(HandlePropertyName ident,
|
||||
Parser<ParseHandler>::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 <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::checkBindingIdentifier(HandlePropertyName ident,
|
||||
Parser<ParseHandler>::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"))
|
||||
|
|
@ -9758,7 +9773,7 @@ Parser<ParseHandler>::checkBindingIdentifier(HandlePropertyName ident,
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return checkLabelOrIdentifierReference(ident, offset, yieldHandling, hint);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
|
|
@ -9772,8 +9787,13 @@ Parser<ParseHandler>::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;
|
||||
}
|
||||
|
|
@ -9782,8 +9802,11 @@ template <typename ParseHandler>
|
|||
PropertyName*
|
||||
Parser<ParseHandler>::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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1479,17 +1479,19 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
|||
ClassNodeType 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -244,17 +244,14 @@ class CompileError : public JSErrorReport {
|
|||
void throwError(JSContext* cx);
|
||||
};
|
||||
|
||||
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
|
||||
|
|
@ -355,6 +352,16 @@ class MOZ_STACK_CLASS TokenStream
|
|||
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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue