Commit d85b5b75 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[parser] Reimplement duplicate __proto__ checking

Now that identifiers in the preparser also carry their string, we can simply
check that rather than relying on a weird "keyword". Dropping __proto__ as a
keyword allows us to delist '_' as keyword character.

Change-Id: I775df25f77a84de92a60790ca665f16d52abf4bf
Reviewed-on: https://chromium-review.googlesource.com/c/1329692
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57427}
parent de50808c
...@@ -321,7 +321,6 @@ class ParserBase { ...@@ -321,7 +321,6 @@ class ParserBase {
}; };
class ClassLiteralChecker; class ClassLiteralChecker;
class ObjectLiteralChecker;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// BlockState and FunctionState implement the parser's scope stack. // BlockState and FunctionState implement the parser's scope stack.
...@@ -1018,8 +1017,8 @@ class ParserBase { ...@@ -1018,8 +1017,8 @@ class ParserBase {
bool* is_private); bool* is_private);
ExpressionT ParseMemberInitializer(ClassInfo* class_info, int beg_pos, ExpressionT ParseMemberInitializer(ClassInfo* class_info, int beg_pos,
bool is_static); bool is_static);
ObjectLiteralPropertyT ParseObjectPropertyDefinition( ObjectLiteralPropertyT ParseObjectPropertyDefinition(bool* has_seen_proto,
ObjectLiteralChecker* checker, bool* is_computed_name, bool* is_computed_name,
bool* is_rest_property); bool* is_rest_property);
void ParseArguments(ExpressionListT* args, bool* has_spread, void ParseArguments(ExpressionListT* args, bool* has_spread,
bool maybe_arrow); bool maybe_arrow);
...@@ -1313,27 +1312,6 @@ class ParserBase { ...@@ -1313,27 +1312,6 @@ class ParserBase {
return factory()->NewReturnStatement(expr, pos, end_pos); return factory()->NewReturnStatement(expr, pos, end_pos);
} }
// Validation per ES6 object literals.
class ObjectLiteralChecker {
public:
explicit ObjectLiteralChecker(ParserBase* parser)
: parser_(parser), has_seen_proto_(false) {}
void CheckDuplicateProto(Token::Value property);
private:
bool IsProto() const {
return this->scanner()->CurrentMatchesContextualEscaped(
Token::PROTO_UNDERSCORED);
}
ParserBase* parser() const { return parser_; }
Scanner* scanner() const { return parser_->scanner(); }
ParserBase* parser_;
bool has_seen_proto_;
};
// Validation per ES6 class literals. // Validation per ES6 class literals.
class ClassLiteralChecker { class ClassLiteralChecker {
public: public:
...@@ -2354,7 +2332,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer( ...@@ -2354,7 +2332,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::ObjectLiteralPropertyT typename ParserBase<Impl>::ObjectLiteralPropertyT
ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, ParserBase<Impl>::ParseObjectPropertyDefinition(bool* has_seen_proto,
bool* is_computed_name, bool* is_computed_name,
bool* is_rest_property) { bool* is_rest_property) {
ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal; ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal;
...@@ -2389,8 +2367,14 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, ...@@ -2389,8 +2367,14 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
case ParsePropertyKind::kValue: { case ParsePropertyKind::kValue: {
DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
if (!*is_computed_name) { if (!*is_computed_name &&
checker->CheckDuplicateProto(name_token); (name_token == Token::IDENTIFIER || name_token == Token::STRING) &&
impl()->IdentifierEquals(name, ast_value_factory()->proto_string())) {
if (*has_seen_proto) {
classifier()->RecordExpressionError(scanner()->location(),
MessageTemplate::kDuplicateProto);
}
*has_seen_proto = true;
} }
Consume(Token::COLON); Consume(Token::COLON);
int beg_pos = peek_position(); int beg_pos = peek_position();
...@@ -2544,7 +2528,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral() { ...@@ -2544,7 +2528,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral() {
bool has_computed_names = false; bool has_computed_names = false;
bool has_rest_property = false; bool has_rest_property = false;
ObjectLiteralChecker checker(this); bool has_seen_proto = false;
Consume(Token::LBRACE); Consume(Token::LBRACE);
...@@ -2554,7 +2538,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral() { ...@@ -2554,7 +2538,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral() {
bool is_computed_name = false; bool is_computed_name = false;
bool is_rest_property = false; bool is_rest_property = false;
ObjectLiteralPropertyT property = ParseObjectPropertyDefinition( ObjectLiteralPropertyT property = ParseObjectPropertyDefinition(
&checker, &is_computed_name, &is_rest_property); &has_seen_proto, &is_computed_name, &is_rest_property);
if (impl()->IsNull(property)) return impl()->FailureExpression(); if (impl()->IsNull(property)) return impl()->FailureExpression();
if (is_computed_name) { if (is_computed_name) {
...@@ -5860,21 +5844,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ...@@ -5860,21 +5844,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
return final_loop; return final_loop;
} }
template <typename Impl>
void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto(
Token::Value property) {
if (property == Token::SMI || property == Token::NUMBER) return;
if (IsProto()) {
if (has_seen_proto_) {
this->parser()->classifier()->RecordExpressionError(
this->scanner()->location(), MessageTemplate::kDuplicateProto);
return;
}
has_seen_proto_ = true;
}
}
template <typename Impl> template <typename Impl>
void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName( void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
Token::Value property, ParsePropertyKind type, ParseFunctionFlags flags, Token::Value property, ParsePropertyKind type, ParseFunctionFlags flags,
......
...@@ -329,6 +329,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -329,6 +329,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
const char* name, DeclarationScope* scope, const char* name, DeclarationScope* scope,
ZonePtrList<ClassLiteral::Property>* fields); ZonePtrList<ClassLiteral::Property>* fields);
bool IdentifierEquals(const AstRawString* identifier,
const AstRawString* other) {
return identifier == other;
}
Statement* DeclareClass(const AstRawString* variable_name, Expression* value, Statement* DeclareClass(const AstRawString* variable_name, Expression* value,
ZonePtrList<const AstRawString>* names, ZonePtrList<const AstRawString>* names,
int class_token_pos, int end_pos); int class_token_pos, int end_pos);
......
...@@ -387,6 +387,12 @@ PreParserStatement PreParser::BuildParameterInitializationBlock( ...@@ -387,6 +387,12 @@ PreParserStatement PreParser::BuildParameterInitializationBlock(
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
bool PreParser::IdentifierEquals(const PreParserIdentifier& identifier,
const AstRawString* other) {
DCHECK_EQ(identifier.string_ == nullptr, has_error());
return identifier.string_ == other;
}
PreParserExpression PreParser::ExpressionFromIdentifier( PreParserExpression PreParser::ExpressionFromIdentifier(
const PreParserIdentifier& name, int start_position, InferName infer) { const PreParserIdentifier& name, int start_position, InferName infer) {
VariableProxy* proxy = nullptr; VariableProxy* proxy = nullptr;
......
...@@ -1146,6 +1146,9 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1146,6 +1146,9 @@ class PreParser : public ParserBase<PreParser> {
function_scope); function_scope);
} }
bool IdentifierEquals(const PreParserIdentifier& identifier,
const AstRawString* other);
// TODO(nikolaos): The preparser currently does not keep track of labels // TODO(nikolaos): The preparser currently does not keep track of labels
// and targets. // and targets.
V8_INLINE PreParserStatement V8_INLINE PreParserStatement
......
...@@ -234,8 +234,6 @@ static const Token::Value one_char_tokens[] = { ...@@ -234,8 +234,6 @@ static const Token::Value one_char_tokens[] = {
KEYWORD("with", Token::WITH) \ KEYWORD("with", Token::WITH) \
KEYWORD_GROUP('y') \ KEYWORD_GROUP('y') \
KEYWORD("yield", Token::YIELD) \ KEYWORD("yield", Token::YIELD) \
KEYWORD_GROUP('_') \
KEYWORD("__proto__", Token::PROTO_UNDERSCORED) \
KEYWORD_GROUP('#') \ KEYWORD_GROUP('#') \
KEYWORD("#constructor", Token::PRIVATE_CONSTRUCTOR) KEYWORD("#constructor", Token::PRIVATE_CONSTRUCTOR)
...@@ -299,12 +297,12 @@ enum class ScanFlags : uint8_t { ...@@ -299,12 +297,12 @@ enum class ScanFlags : uint8_t {
}; };
constexpr uint8_t GetScanFlags(char c) { constexpr uint8_t GetScanFlags(char c) {
return return
// Keywords are all lowercase and only contain letters and '_'. // Keywords are all lowercase and only contain letters.
// Note that non-identifier characters do not set this flag, so // Note that non-identifier characters do not set this flag, so
// that it plays well with kTerminatesLiteral // that it plays well with kTerminatesLiteral
// TODO(leszeks): We could probably get an even tighter measure // TODO(leszeks): We could probably get an even tighter measure
// here if not all letters are present in keywords. // here if not all letters are present in keywords.
(IsAsciiIdentifier(c) && !IsInRange(c, 'a', 'z') && c != '_' (IsAsciiIdentifier(c) && !IsInRange(c, 'a', 'z')
? static_cast<uint8_t>(ScanFlags::kCannotBeKeyword) ? static_cast<uint8_t>(ScanFlags::kCannotBeKeyword)
: 0) | : 0) |
// Anything that isn't an identifier character will terminate the // Anything that isn't an identifier character will terminate the
......
...@@ -204,7 +204,6 @@ namespace internal { ...@@ -204,7 +204,6 @@ namespace internal {
C(AS, "as", 0) \ C(AS, "as", 0) \
C(FROM, "from", 0) \ C(FROM, "from", 0) \
C(NAME, "name", 0) \ C(NAME, "name", 0) \
C(PROTO_UNDERSCORED, "__proto__", 0) \
C(CONSTRUCTOR, "constructor", 0) \ C(CONSTRUCTOR, "constructor", 0) \
C(PRIVATE_CONSTRUCTOR, "#constructor", 0) \ C(PRIVATE_CONSTRUCTOR, "#constructor", 0) \
C(PROTOTYPE, "prototype", 0) \ C(PROTOTYPE, "prototype", 0) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment