[ast] Create CompoundAssignment subclass of Assignment

This saves one pointer in Assignment for non-compound
assignment expressions.

Change-Id: I7ec32c1d378917c81ab55c42733b6af450ce65db
Reviewed-on: https://chromium-review.googlesource.com/612673
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47380}
This commit is contained in:
Adam Klein 2017-08-16 09:50:09 -07:00 committed by Commit Bot
parent 8f1bc55817
commit 8024d38a64
10 changed files with 96 additions and 53 deletions

View File

@ -265,6 +265,10 @@ void AstExpressionRewriter::VisitAssignment(Assignment* node) {
AST_REWRITE_PROPERTY(Expression, node, value); AST_REWRITE_PROPERTY(Expression, node, value);
} }
void AstExpressionRewriter::VisitCompoundAssignment(CompoundAssignment* node) {
VisitAssignment(node);
}
void AstExpressionRewriter::VisitYield(Yield* node) { void AstExpressionRewriter::VisitYield(Yield* node) {
REWRITE_THIS(node); REWRITE_THIS(node);
AST_REWRITE_PROPERTY(Expression, node, expression); AST_REWRITE_PROPERTY(Expression, node, expression);

View File

@ -313,12 +313,15 @@ void AstNumberingVisitor::VisitProperty(Property* node) {
void AstNumberingVisitor::VisitAssignment(Assignment* node) { void AstNumberingVisitor::VisitAssignment(Assignment* node) {
if (node->is_compound()) VisitBinaryOperation(node->binary_operation());
VisitReference(node->target()); VisitReference(node->target());
Visit(node->value()); Visit(node->value());
ReserveFeedbackSlots(node); ReserveFeedbackSlots(node);
} }
void AstNumberingVisitor::VisitCompoundAssignment(CompoundAssignment* node) {
VisitBinaryOperation(node->binary_operation());
VisitAssignment(node);
}
void AstNumberingVisitor::VisitBinaryOperation(BinaryOperation* node) { void AstNumberingVisitor::VisitBinaryOperation(BinaryOperation* node) {
Visit(node->left()); Visit(node->left());

View File

@ -359,6 +359,12 @@ void AstTraversalVisitor<Subclass>::VisitAssignment(Assignment* expr) {
RECURSE_EXPRESSION(Visit(expr->value())); RECURSE_EXPRESSION(Visit(expr->value()));
} }
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitCompoundAssignment(
CompoundAssignment* expr) {
VisitAssignment(expr);
}
template <class Subclass> template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitYield(Yield* expr) { void AstTraversalVisitor<Subclass>::VisitYield(Yield* expr) {
PROCESS_EXPRESSION(expr); PROCESS_EXPRESSION(expr);

View File

@ -251,12 +251,9 @@ void ForInStatement::AssignFeedbackSlots(FeedbackVectorSpec* spec,
for_in_feedback_slot_ = spec->AddGeneralSlot(); for_in_feedback_slot_ = spec->AddGeneralSlot();
} }
Assignment::Assignment(Token::Value op, Expression* target, Expression* value, Assignment::Assignment(NodeType node_type, Token::Value op, Expression* target,
int pos) Expression* value, int pos)
: Expression(pos, kAssignment), : Expression(pos, node_type), target_(target), value_(value) {
target_(target),
value_(value),
binary_operation_(NULL) {
bit_field_ |= IsUninitializedField::encode(false) | bit_field_ |= IsUninitializedField::encode(false) |
KeyTypeField::encode(ELEMENT) | KeyTypeField::encode(ELEMENT) |
StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op); StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op);
@ -278,24 +275,6 @@ void CountOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
} }
Token::Value Assignment::binary_op() const {
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;
default: UNREACHABLE();
}
return Token::ILLEGAL;
}
bool FunctionLiteral::ShouldEagerCompile() const { bool FunctionLiteral::ShouldEagerCompile() const {
return scope()->ShouldEagerCompile(); return scope()->ShouldEagerCompile();
} }

View File

@ -72,6 +72,7 @@ namespace internal {
#define PROPERTY_NODE_LIST(V) \ #define PROPERTY_NODE_LIST(V) \
V(Assignment) \ V(Assignment) \
V(CompoundAssignment) \
V(CountOperation) \ V(CountOperation) \
V(Property) V(Property)
@ -2099,13 +2100,8 @@ class Conditional final : public Expression {
Expression* else_expression_; Expression* else_expression_;
}; };
class Assignment : public Expression {
class Assignment final : public Expression {
public: public:
Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
Token::Value binary_op() const;
Token::Value op() const { return TokenField::decode(bit_field_); } Token::Value op() const { return TokenField::decode(bit_field_); }
Expression* target() const { return target_; } Expression* target() const { return target_; }
Expression* value() const { return value_; } Expression* value() const { return value_; }
@ -2113,11 +2109,6 @@ class Assignment final : public Expression {
void set_target(Expression* e) { target_ = e; } void set_target(Expression* e) { target_ = e; }
void set_value(Expression* e) { value_ = e; } void set_value(Expression* e) { value_ = e; }
BinaryOperation* binary_operation() const { return binary_operation_; }
// This check relies on the definition order of token in token.h.
bool is_compound() const { return op() > Token::ASSIGN; }
// Type feedback information. // Type feedback information.
bool IsUninitialized() const { bool IsUninitialized() const {
return IsUninitializedField::decode(bit_field_); return IsUninitializedField::decode(bit_field_);
@ -2157,11 +2148,13 @@ class Assignment final : public Expression {
FeedbackSlotCache* cache); FeedbackSlotCache* cache);
FeedbackSlot AssignmentSlot() const { return slot_; } FeedbackSlot AssignmentSlot() const { return slot_; }
protected:
Assignment(NodeType type, Token::Value op, Expression* target,
Expression* value, int pos);
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
Assignment(Token::Value op, Expression* target, Expression* value, int pos);
class IsUninitializedField class IsUninitializedField
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class KeyTypeField class KeyTypeField
@ -2175,10 +2168,23 @@ class Assignment final : public Expression {
FeedbackSlot slot_; FeedbackSlot slot_;
Expression* target_; Expression* target_;
Expression* value_; Expression* value_;
BinaryOperation* binary_operation_;
SmallMapList receiver_types_; SmallMapList receiver_types_;
}; };
class CompoundAssignment final : public Assignment {
public:
BinaryOperation* binary_operation() const { return binary_operation_; }
private:
friend class AstNodeFactory;
CompoundAssignment(Token::Value op, Expression* target, Expression* value,
int pos, BinaryOperation* binary_operation)
: Assignment(kCompoundAssignment, op, target, value, pos),
binary_operation_(binary_operation) {}
BinaryOperation* binary_operation_;
};
// The RewritableExpression class is a wrapper for AST nodes that wait // The RewritableExpression class is a wrapper for AST nodes that wait
// for some potential rewriting. However, even if such nodes are indeed // for some potential rewriting. However, even if such nodes are indeed
@ -3360,12 +3366,15 @@ class AstNodeFactory final BASE_EMBEDDED {
target->AsVariableProxy()->set_is_assigned(); target->AsVariableProxy()->set_is_assigned();
} }
Assignment* assign = new (zone_) Assignment(op, target, value, pos); if (op == Token::ASSIGN || op == Token::INIT) {
if (assign->is_compound()) { return new (zone_)
assign->binary_operation_ = Assignment(AstNode::kAssignment, op, target, value, pos);
NewBinaryOperation(assign->binary_op(), target, value, pos + 1); } else {
return new (zone_) CompoundAssignment(
op, target, value, pos,
NewBinaryOperation(Token::BinaryOpForAssignment(op), target, value,
pos + 1));
} }
return assign;
} }
Suspend* NewYield(Expression* expression, int pos, Suspend* NewYield(Expression* expression, int pos,

View File

@ -269,6 +269,10 @@ void CallPrinter::VisitAssignment(Assignment* node) {
Find(node->value()); Find(node->value());
} }
void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
VisitAssignment(node);
}
void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); }
void CallPrinter::VisitYieldStar(YieldStar* node) { Find(node->expression()); } void CallPrinter::VisitYieldStar(YieldStar* node) { Find(node->expression()); }
@ -1141,6 +1145,10 @@ void AstPrinter::VisitAssignment(Assignment* node) {
Visit(node->value()); Visit(node->value());
} }
void AstPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
VisitAssignment(node);
}
void AstPrinter::VisitYield(Yield* node) { void AstPrinter::VisitYield(Yield* node) {
EmbeddedVector<char, 128> buf; EmbeddedVector<char, 128> buf;
SNPrintF(buf, "YIELD id %d", node->suspend_id()); SNPrintF(buf, "YIELD id %d", node->suspend_id());

View File

@ -2488,7 +2488,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
// Evaluate the value and potentially handle compound assignments by loading // Evaluate the value and potentially handle compound assignments by loading
// the left-hand side value and performing a binary operation. // the left-hand side value and performing a binary operation.
if (expr->is_compound()) { if (expr->IsCompoundAssignment()) {
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
VariableProxy* proxy = expr->target()->AsVariableProxy(); VariableProxy* proxy = expr->target()->AsVariableProxy();
@ -2519,17 +2519,17 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
break; break;
} }
} }
FeedbackSlot slot = expr->binary_operation()->BinaryOperationFeedbackSlot(); BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation();
FeedbackSlot slot = binop->BinaryOperationFeedbackSlot();
if (expr->value()->IsSmiLiteral()) { if (expr->value()->IsSmiLiteral()) {
builder()->BinaryOperationSmiLiteral( builder()->BinaryOperationSmiLiteral(
expr->binary_op(), expr->value()->AsLiteral()->AsSmiLiteral(), binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(),
feedback_index(slot)); feedback_index(slot));
} else { } else {
Register old_value = register_allocator()->NewRegister(); Register old_value = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(old_value); builder()->StoreAccumulatorInRegister(old_value);
VisitForAccumulatorValue(expr->value()); VisitForAccumulatorValue(expr->value());
builder()->BinaryOperation(expr->binary_op(), old_value, builder()->BinaryOperation(binop->op(), old_value, feedback_index(slot));
feedback_index(slot));
} }
} else { } else {
VisitForAccumulatorValue(expr->value()); VisitForAccumulatorValue(expr->value());
@ -2571,6 +2571,10 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
} }
} }
void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
VisitAssignment(expr);
}
// Suspends the generator to resume at |suspend_id|, with output stored in the // Suspends the generator to resume at |suspend_id|, with output stored in the
// accumulator. When the generator is resumed, the sent value is loaded in the // accumulator. When the generator is resumed, the sent value is loaded in the
// accumulator. // accumulator.

View File

@ -2458,7 +2458,7 @@ void Parser::AddArrowFunctionFormalParameters(
Expression* initializer = nullptr; Expression* initializer = nullptr;
if (expr->IsAssignment()) { if (expr->IsAssignment()) {
Assignment* assignment = expr->AsAssignment(); Assignment* assignment = expr->AsAssignment();
DCHECK(!assignment->is_compound()); DCHECK(!assignment->IsCompoundAssignment());
initializer = assignment->value(); initializer = assignment->value();
expr = assignment->target(); expr = assignment->target();
} }

View File

@ -782,6 +782,7 @@ NOT_A_PATTERN(CallRuntime)
NOT_A_PATTERN(CaseClause) NOT_A_PATTERN(CaseClause)
NOT_A_PATTERN(ClassLiteral) NOT_A_PATTERN(ClassLiteral)
NOT_A_PATTERN(CompareOperation) NOT_A_PATTERN(CompareOperation)
NOT_A_PATTERN(CompoundAssignment)
NOT_A_PATTERN(Conditional) NOT_A_PATTERN(Conditional)
NOT_A_PATTERN(ContinueStatement) NOT_A_PATTERN(ContinueStatement)
NOT_A_PATTERN(CountOperation) NOT_A_PATTERN(CountOperation)

View File

@ -53,9 +53,8 @@ namespace internal {
T(ARROW, "=>", 0) \ T(ARROW, "=>", 0) \
\ \
/* Assignment operators. */ \ /* Assignment operators. */ \
/* IsAssignmentOp() and Assignment::is_compound() relies on */ \ /* IsAssignmentOp() relies on this block of enum values being */ \
/* this block of enum values being contiguous and sorted in the */ \ /* contiguous and sorted in the same order! */ \
/* same order! */ \
T(INIT, "=init", 2) /* AST-use only. */ \ T(INIT, "=init", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \ T(ASSIGN, "=", 2) \
T(ASSIGN_BIT_OR, "|=", 2) \ T(ASSIGN_BIT_OR, "|=", 2) \
@ -318,6 +317,36 @@ class Token {
} }
} }
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;
default:
UNREACHABLE();
}
}
static bool IsBitOp(Value op) { static bool IsBitOp(Value op) {
return (BIT_OR <= op && op <= SHR) || op == BIT_NOT; return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
} }