[token] Make sure we can simply range-check IsAnyIdentifier

This CL additionally uses IsInRange for token range checks. That only uses one
branch rather than two.

Change-Id: I52c6759ba195b55cb50c2ce9afbdc9b397495633
Reviewed-on: https://chromium-review.googlesource.com/1193875
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55494}
This commit is contained in:
Toon Verwaest 2018-08-29 15:26:51 +02:00 committed by Commit Bot
parent 1a8f24d84b
commit dd6290d189
6 changed files with 266 additions and 96 deletions

View File

@ -29,12 +29,6 @@ inline bool IsLineFeed(uc32 c) {
}
inline bool IsInRange(int value, int lower_limit, int higher_limit) {
DCHECK(lower_limit <= higher_limit);
return static_cast<unsigned int>(value - lower_limit) <=
static_cast<unsigned int>(higher_limit - lower_limit);
}
inline bool IsAsciiIdentifier(uc32 c) {
return IsAlphaNumeric(c) || c == '$' || c == '_';
}

View File

@ -769,14 +769,7 @@ class ParserBase {
return result;
}
bool is_any_identifier(Token::Value token) {
return token == Token::IDENTIFIER || token == Token::ENUM ||
token == Token::AWAIT || token == Token::ASYNC ||
token == Token::ESCAPED_STRICT_RESERVED_WORD ||
token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::LET ||
token == Token::STATIC || token == Token::YIELD;
}
bool peek_any_identifier() { return is_any_identifier(peek()); }
bool peek_any_identifier() { return Token::IsAnyIdentifier(peek()); }
bool CheckContextualKeyword(Token::Value token) {
if (PeekContextualKeyword(token)) {
@ -997,7 +990,7 @@ class ParserBase {
}
bool IsValidArrowFormalParametersStart(Token::Value token) {
return is_any_identifier(token) || token == Token::LPAREN;
return Token::IsAnyIdentifier(token) || token == Token::LPAREN;
}
void ValidateArrowFormalParameters(ExpressionT expr,

View File

@ -29,7 +29,6 @@ const uint8_t Token::string_length_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
const int8_t Token::precedence_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
#undef T
#define KT(a, b, c) 'T',
#define KK(a, b, c) 'K',
#define KC(a, b, c) 'C',

View File

@ -7,6 +7,7 @@
#include "src/base/logging.h"
#include "src/globals.h"
#include "src/utils.h"
namespace v8 {
namespace internal {
@ -32,6 +33,27 @@ namespace internal {
#define IGNORE_TOKEN(name, string, precedence)
/* Binary operators sorted by precedence */
#define BINARY_OP_TOKEN_LIST(T, E) \
E(T, BIT_OR, "|", 6) \
E(T, BIT_XOR, "^", 7) \
E(T, BIT_AND, "&", 8) \
E(T, SHL, "<<", 11) \
E(T, SAR, ">>", 11) \
E(T, SHR, ">>>", 11) \
E(T, ADD, "+", 12) \
E(T, SUB, "-", 12) \
E(T, MUL, "*", 13) \
E(T, DIV, "/", 13) \
E(T, MOD, "%", 13) \
E(T, EXP, "**", 14)
#define EXPAND_BINOP_ASSIGN_TOKEN(T, name, string, precedence) \
T(ASSIGN_##name, string "=", 2)
#define EXPAND_BINOP_TOKEN(T, name, string, precedence) \
T(name, string, precedence)
#define TOKEN_LIST(T, K, C) \
/* End of source indicator. */ \
T(EOS, "EOS", 0) \
@ -57,18 +79,7 @@ namespace internal {
/* contiguous and sorted in the same order! */ \
T(INIT, "=init", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \
T(ASSIGN_BIT_OR, "|=", 2) \
T(ASSIGN_BIT_XOR, "^=", 2) \
T(ASSIGN_BIT_AND, "&=", 2) \
T(ASSIGN_SHL, "<<=", 2) \
T(ASSIGN_SAR, ">>=", 2) \
T(ASSIGN_SHR, ">>>=", 2) \
T(ASSIGN_ADD, "+=", 2) \
T(ASSIGN_SUB, "-=", 2) \
T(ASSIGN_MUL, "*=", 2) \
T(ASSIGN_DIV, "/=", 2) \
T(ASSIGN_MOD, "%=", 2) \
T(ASSIGN_EXP, "**=", 2) \
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN) \
\
/* Binary operators sorted by precedence. */ \
/* IsBinaryOp() relies on this block of enum values */ \
@ -76,25 +87,14 @@ namespace internal {
T(COMMA, ",", 1) \
T(OR, "||", 4) \
T(AND, "&&", 5) \
T(BIT_OR, "|", 6) \
T(BIT_XOR, "^", 7) \
T(BIT_AND, "&", 8) \
T(SHL, "<<", 11) \
T(SAR, ">>", 11) \
T(SHR, ">>>", 11) \
T(ADD, "+", 12) \
T(SUB, "-", 12) \
T(MUL, "*", 13) \
T(DIV, "/", 13) \
T(MOD, "%", 13) \
T(EXP, "**", 14) \
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_TOKEN) \
\
/* Compare operators sorted by precedence. */ \
/* IsCompareOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \
T(EQ, "==", 9) \
T(NE, "!=", 9) \
T(EQ_STRICT, "===", 9) \
T(NE, "!=", 9) \
T(NE_STRICT, "!==", 9) \
T(LT, "<", 10) \
T(GT, ">", 10) \
@ -151,28 +151,27 @@ namespace internal {
\
/* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, nullptr, 0) \
T(PRIVATE_NAME, nullptr, 0) \
\
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
K(ASYNC, "async", 0) \
/* `await` is a reserved word in module code only */ \
K(AWAIT, "await", 0) \
K(CLASS, "class", 0) \
K(CONST, "const", 0) \
K(ENUM, "enum", 0) \
K(EXPORT, "export", 0) \
K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \
K(LET, "let", 0) \
K(STATIC, "static", 0) \
K(YIELD, "yield", 0) \
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
K(CLASS, "class", 0) \
K(CONST, "const", 0) \
K(EXPORT, "export", 0) \
K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \
K(SUPER, "super", 0) \
T(PRIVATE_NAME, nullptr, 0) \
\
/* Illegal token - not able to scan. */ \
T(ILLEGAL, "ILLEGAL", 0) \
T(ESCAPED_KEYWORD, nullptr, 0) \
T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
\
/* Scanner-internal use only. */ \
T(WHITESPACE, nullptr, 0) \
@ -243,70 +242,41 @@ class Token {
}
static bool IsAssignmentOp(Value tok) {
return INIT <= tok && tok <= ASSIGN_EXP;
return IsInRange(tok, INIT, ASSIGN_EXP);
}
static bool IsBinaryOp(Value op) { return COMMA <= op && op <= EXP; }
static bool IsBinaryOp(Value op) { return IsInRange(op, COMMA, EXP); }
static bool IsCompareOp(Value op) {
return EQ <= op && op <= IN;
}
static bool IsCompareOp(Value op) { return IsInRange(op, EQ, IN); }
static bool IsOrderedRelationalCompareOp(Value op) {
return op == LT || op == LTE || op == GT || op == GTE;
return IsInRange(op, LT, GTE);
}
static bool IsEqualityOp(Value op) {
return op == EQ || op == EQ_STRICT;
static bool IsEqualityOp(Value op) { return IsInRange(op, EQ, EQ_STRICT); }
static bool IsAnyIdentifier(Value tok) {
return IsInRange(tok, IDENTIFIER, ESCAPED_STRICT_RESERVED_WORD);
}
static Value BinaryOpForAssignment(Value op) {
DCHECK(IsAssignmentOp(op));
switch (op) {
case Token::ASSIGN_BIT_OR:
return Token::BIT_OR;
case Token::ASSIGN_BIT_XOR:
return Token::BIT_XOR;
case Token::ASSIGN_BIT_AND:
return Token::BIT_AND;
case Token::ASSIGN_SHL:
return Token::SHL;
case Token::ASSIGN_SAR:
return Token::SAR;
case Token::ASSIGN_SHR:
return Token::SHR;
case Token::ASSIGN_ADD:
return Token::ADD;
case Token::ASSIGN_SUB:
return Token::SUB;
case Token::ASSIGN_MUL:
return Token::MUL;
case Token::ASSIGN_DIV:
return Token::DIV;
case Token::ASSIGN_MOD:
return Token::MOD;
case Token::ASSIGN_EXP:
return Token::EXP;
default:
UNREACHABLE();
}
DCHECK(IsInRange(op, ASSIGN_BIT_OR, ASSIGN_EXP));
Value result = static_cast<Value>(op - ASSIGN_BIT_OR + BIT_OR);
DCHECK(IsBinaryOp(result));
return result;
}
static bool IsBitOp(Value op) {
return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
return IsInRange(op, BIT_OR, SHR) || op == BIT_NOT;
}
static bool IsUnaryOp(Value op) {
return (NOT <= op && op <= VOID) || op == ADD || op == SUB;
return IsInRange(op, NOT, VOID) || IsInRange(op, ADD, SUB);
}
static bool IsCountOp(Value op) {
return op == INC || op == DEC;
}
static bool IsCountOp(Value op) { return IsInRange(op, INC, DEC); }
static bool IsShiftOp(Value op) {
return (SHL <= op) && (op <= SHR);
}
static bool IsShiftOp(Value op) { return IsInRange(op, SHL, SHR); }
// Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or nullptr if the token doesn't

View File

@ -56,6 +56,14 @@ inline bool CStringEquals(const char* s1, const char* s2) {
return (s1 == s2) || (s1 != nullptr && s2 != nullptr && strcmp(s1, s2) == 0);
}
// Checks if value is in range [lower_limit, higher_limit] using a single
// branch.
inline bool IsInRange(int value, int lower_limit, int higher_limit) {
DCHECK_LE(lower_limit, higher_limit);
return static_cast<unsigned int>(value - lower_limit) <=
static_cast<unsigned int>(higher_limit - lower_limit);
}
// X must be a power of 2. Returns the number of trailing zeros.
template <typename T,
typename = typename std::enable_if<std::is_integral<T>::value>::type>

View File

@ -71,6 +71,212 @@ void MockUseCounterCallback(v8::Isolate* isolate,
} // namespace
bool TokenIsAnyIdentifier(Token::Value tok) {
switch (tok) {
case Token::IDENTIFIER:
case Token::ASYNC:
case Token::AWAIT:
case Token::ENUM:
case Token::LET:
case Token::STATIC:
case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD:
case Token::ESCAPED_STRICT_RESERVED_WORD:
return true;
default:
return false;
}
}
TEST(AnyIdentifierToken) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsAnyIdentifier(tok), Token::IsAnyIdentifier(tok));
}
}
bool TokenIsAssignmentOp(Token::Value tok) {
switch (tok) {
case Token::INIT:
case Token::ASSIGN:
#define T(name, string, precedence) case Token::name:
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN)
#undef T
return true;
default:
return false;
}
}
TEST(AssignmentOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsAssignmentOp(tok), Token::IsAssignmentOp(tok));
}
}
bool TokenIsBinaryOp(Token::Value tok) {
switch (tok) {
case Token::COMMA:
case Token::OR:
case Token::AND:
#define T(name, string, precedence) case Token::name:
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_TOKEN)
#undef T
return true;
default:
return false;
}
}
TEST(BinaryOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsBinaryOp(tok), Token::IsBinaryOp(tok));
}
}
bool TokenIsCompareOp(Token::Value tok) {
switch (tok) {
case Token::EQ:
case Token::EQ_STRICT:
case Token::NE:
case Token::NE_STRICT:
case Token::LT:
case Token::GT:
case Token::LTE:
case Token::GTE:
case Token::INSTANCEOF:
case Token::IN:
return true;
default:
return false;
}
}
TEST(CompareOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsCompareOp(tok), Token::IsCompareOp(tok));
}
}
bool TokenIsOrderedRelationalCompareOp(Token::Value tok) {
switch (tok) {
case Token::LT:
case Token::GT:
case Token::LTE:
case Token::GTE:
return true;
default:
return false;
}
}
TEST(IsOrderedRelationalCompareOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsOrderedRelationalCompareOp(tok),
Token::IsOrderedRelationalCompareOp(tok));
}
}
bool TokenIsEqualityOp(Token::Value tok) {
switch (tok) {
case Token::EQ:
case Token::EQ_STRICT:
return true;
default:
return false;
}
}
TEST(IsEqualityOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsEqualityOp(tok), Token::IsEqualityOp(tok));
}
}
bool TokenIsBitOp(Token::Value tok) {
switch (tok) {
case Token::BIT_OR:
case Token::BIT_XOR:
case Token::BIT_AND:
case Token::SHL:
case Token::SAR:
case Token::SHR:
case Token::BIT_NOT:
return true;
default:
return false;
}
}
TEST(IsBitOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsBitOp(tok), Token::IsBitOp(tok));
}
}
bool TokenIsUnaryOp(Token::Value tok) {
switch (tok) {
case Token::NOT:
case Token::BIT_NOT:
case Token::DELETE:
case Token::TYPEOF:
case Token::VOID:
case Token::ADD:
case Token::SUB:
return true;
default:
return false;
}
}
TEST(IsUnaryOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsUnaryOp(tok), Token::IsUnaryOp(tok));
}
}
bool TokenIsCountOp(Token::Value tok) {
switch (tok) {
case Token::INC:
case Token::DEC:
return true;
default:
return false;
}
}
TEST(IsCountOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsCountOp(tok), Token::IsCountOp(tok));
}
}
bool TokenIsShiftOp(Token::Value tok) {
switch (tok) {
case Token::SHL:
case Token::SAR:
case Token::SHR:
return true;
default:
return false;
}
}
TEST(IsShiftOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value tok = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsShiftOp(tok), Token::IsShiftOp(tok));
}
}
TEST(ScanKeywords) {
struct KeywordToken {
const char* keyword;