[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);
}
void AstExpressionRewriter::VisitCompoundAssignment(CompoundAssignment* node) {
VisitAssignment(node);
}
void AstExpressionRewriter::VisitYield(Yield* node) {
REWRITE_THIS(node);
AST_REWRITE_PROPERTY(Expression, node, expression);

View File

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

View File

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

View File

@ -251,12 +251,9 @@ void ForInStatement::AssignFeedbackSlots(FeedbackVectorSpec* spec,
for_in_feedback_slot_ = spec->AddGeneralSlot();
}
Assignment::Assignment(Token::Value op, Expression* target, Expression* value,
int pos)
: Expression(pos, kAssignment),
target_(target),
value_(value),
binary_operation_(NULL) {
Assignment::Assignment(NodeType node_type, Token::Value op, Expression* target,
Expression* value, int pos)
: Expression(pos, node_type), target_(target), value_(value) {
bit_field_ |= IsUninitializedField::encode(false) |
KeyTypeField::encode(ELEMENT) |
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 {
return scope()->ShouldEagerCompile();
}

View File

@ -72,6 +72,7 @@ namespace internal {
#define PROPERTY_NODE_LIST(V) \
V(Assignment) \
V(CompoundAssignment) \
V(CountOperation) \
V(Property)
@ -2099,13 +2100,8 @@ class Conditional final : public Expression {
Expression* else_expression_;
};
class Assignment final : public Expression {
class Assignment : public Expression {
public:
Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
Token::Value binary_op() const;
Token::Value op() const { return TokenField::decode(bit_field_); }
Expression* target() const { return target_; }
Expression* value() const { return value_; }
@ -2113,11 +2109,6 @@ class Assignment final : public Expression {
void set_target(Expression* e) { target_ = 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.
bool IsUninitialized() const {
return IsUninitializedField::decode(bit_field_);
@ -2157,11 +2148,13 @@ class Assignment final : public Expression {
FeedbackSlotCache* cache);
FeedbackSlot AssignmentSlot() const { return slot_; }
protected:
Assignment(NodeType type, Token::Value op, Expression* target,
Expression* value, int pos);
private:
friend class AstNodeFactory;
Assignment(Token::Value op, Expression* target, Expression* value, int pos);
class IsUninitializedField
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class KeyTypeField
@ -2175,10 +2168,23 @@ class Assignment final : public Expression {
FeedbackSlot slot_;
Expression* target_;
Expression* value_;
BinaryOperation* binary_operation_;
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
// 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();
}
Assignment* assign = new (zone_) Assignment(op, target, value, pos);
if (assign->is_compound()) {
assign->binary_operation_ =
NewBinaryOperation(assign->binary_op(), target, value, pos + 1);
if (op == Token::ASSIGN || op == Token::INIT) {
return new (zone_)
Assignment(AstNode::kAssignment, op, target, value, pos);
} 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,

View File

@ -269,6 +269,10 @@ void CallPrinter::VisitAssignment(Assignment* node) {
Find(node->value());
}
void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
VisitAssignment(node);
}
void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); }
void CallPrinter::VisitYieldStar(YieldStar* node) { Find(node->expression()); }
@ -1141,6 +1145,10 @@ void AstPrinter::VisitAssignment(Assignment* node) {
Visit(node->value());
}
void AstPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
VisitAssignment(node);
}
void AstPrinter::VisitYield(Yield* node) {
EmbeddedVector<char, 128> buf;
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
// the left-hand side value and performing a binary operation.
if (expr->is_compound()) {
if (expr->IsCompoundAssignment()) {
switch (assign_type) {
case VARIABLE: {
VariableProxy* proxy = expr->target()->AsVariableProxy();
@ -2519,17 +2519,17 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
break;
}
}
FeedbackSlot slot = expr->binary_operation()->BinaryOperationFeedbackSlot();
BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation();
FeedbackSlot slot = binop->BinaryOperationFeedbackSlot();
if (expr->value()->IsSmiLiteral()) {
builder()->BinaryOperationSmiLiteral(
expr->binary_op(), expr->value()->AsLiteral()->AsSmiLiteral(),
binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(),
feedback_index(slot));
} else {
Register old_value = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(old_value);
VisitForAccumulatorValue(expr->value());
builder()->BinaryOperation(expr->binary_op(), old_value,
feedback_index(slot));
builder()->BinaryOperation(binop->op(), old_value, feedback_index(slot));
}
} else {
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
// accumulator. When the generator is resumed, the sent value is loaded in the
// accumulator.

View File

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

View File

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

View File

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