Commit 00308056 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add support for for count operations.

Adds support for count operations to the interpreter. Deals with count
operations on locals, globals, context allocated variables and named and
keyed properties.

Adds the following bytecodes:
  ToNumber
  Inc
  Dec

BUG=v8:4280
LOG=N
TBR=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/1416623003

Cr-Commit-Position: refs/heads/master@{#31484}
parent 5676415b
......@@ -476,6 +476,18 @@ void BytecodeGraphBuilder::VisitShiftRightLogical(
}
void BytecodeGraphBuilder::VisitInc(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitDec(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitLogicalNot(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
......@@ -560,6 +572,12 @@ void BytecodeGraphBuilder::VisitToName(
}
void BytecodeGraphBuilder::VisitToNumber(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitJump(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
......
......@@ -172,6 +172,17 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
Strength strength) {
if (is_strong(strength)) {
UNIMPLEMENTED();
}
Output(BytecodeForCountOperation(op));
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
Output(Bytecode::kLogicalNot);
return *this;
......@@ -465,6 +476,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() {
// TODO(rmcilroy): consider omitting if the preceeding bytecode always returns
// a number.
Output(Bytecode::kToNumber);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
if (label->is_forward_target()) {
// An earlier jump instruction refers to this label. Update it's location.
......@@ -826,6 +845,20 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
}
// static
Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) {
switch (op) {
case Token::Value::ADD:
return Bytecode::kInc;
case Token::Value::SUB:
return Bytecode::kDec;
default:
UNREACHABLE();
return static_cast<Bytecode>(-1);
}
}
// static
Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
switch (op) {
......
......@@ -146,6 +146,9 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
Strength strength);
// Count Operators (value stored in accumulator).
BytecodeArrayBuilder& CountOperation(Token::Value op, Strength strength);
// Unary Operators.
BytecodeArrayBuilder& LogicalNot();
BytecodeArrayBuilder& TypeOf();
......@@ -157,6 +160,7 @@ class BytecodeArrayBuilder {
// Casts.
BytecodeArrayBuilder& CastAccumulatorToBoolean();
BytecodeArrayBuilder& CastAccumulatorToName();
BytecodeArrayBuilder& CastAccumulatorToNumber();
// Flow Control.
BytecodeArrayBuilder& Bind(BytecodeLabel* label);
......@@ -186,6 +190,7 @@ class BytecodeArrayBuilder {
Isolate* isolate() const { return isolate_; }
static Bytecode BytecodeForBinaryOperation(Token::Value op);
static Bytecode BytecodeForCountOperation(Token::Value op);
static Bytecode BytecodeForCompareOperation(Token::Value op);
static Bytecode BytecodeForLoadIC(LanguageMode language_mode);
static Bytecode BytecodeForKeyedLoadIC(LanguageMode language_mode);
......
......@@ -960,6 +960,21 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
}
void BytecodeGenerator::VisitVariableLoadForAccumulatorValue(
Variable* variable, FeedbackVectorSlot slot) {
AccumulatorResultScope accumulator_result(this);
VisitVariableLoad(variable, slot);
}
Register BytecodeGenerator::VisitVariableLoadForRegisterValue(
Variable* variable, FeedbackVectorSlot slot) {
RegisterResultScope register_scope(this);
VisitVariableLoad(variable, slot);
return register_scope.ResultRegister();
}
void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
FeedbackVectorSlot slot) {
switch (variable->location()) {
......@@ -1174,10 +1189,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
// Load callee as a global variable.
VariableProxy* proxy = callee_expr->AsVariableProxy();
// Result scope for VisitVariableLoad to avoid using our temporaries
// and double setting the result in our result_scope() and.
AccumulatorResultScope accumulator_execution_result(this);
VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
VisitVariableLoadForAccumulatorValue(proxy->var(),
proxy->VariableFeedbackSlot());
builder()->StoreAccumulatorInRegister(callee);
break;
}
......@@ -1295,7 +1308,93 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
// Left-hand side can only be a property, a global or a variable slot.
Property* property = expr->expression()->AsProperty();
LhsKind assign_type = Property::GetAssignType(property);
// TODO(rmcilroy): Set is_postfix to false if visiting for effect.
bool is_postfix = expr->is_postfix();
// Evaluate LHS expression and get old value.
Register obj, key, old_value;
size_t name_index = kMaxUInt32;
switch (assign_type) {
case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
VisitVariableLoadForAccumulatorValue(proxy->var(),
proxy->VariableFeedbackSlot());
break;
}
case NAMED_PROPERTY: {
FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
obj = VisitForRegisterValue(property->obj());
name_index = builder()->GetConstantPoolEntry(
property->key()->AsLiteral()->AsPropertyName());
builder()->LoadNamedProperty(obj, name_index, feedback_index(slot),
language_mode());
break;
}
case KEYED_PROPERTY: {
FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
obj = VisitForRegisterValue(property->obj());
// Use visit for accumulator here since we need the key in the accumulator
// for the LoadKeyedProperty.
key = execution_result()->NewRegister();
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
obj, feedback_index(slot), language_mode());
break;
}
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNIMPLEMENTED();
}
// Convert old value into a number.
if (!is_strong(language_mode())) {
builder()->CastAccumulatorToNumber();
}
// Save result for postfix expressions.
if (is_postfix) {
old_value = execution_result()->NewRegister();
builder()->StoreAccumulatorInRegister(old_value);
}
// Perform +1/-1 operation.
builder()->CountOperation(expr->binary_op(), language_mode_strength());
// Store the value.
FeedbackVectorSlot feedback_slot = expr->CountSlot();
switch (assign_type) {
case VARIABLE: {
Variable* variable = expr->expression()->AsVariableProxy()->var();
VisitVariableAssignment(variable, feedback_slot);
break;
}
case NAMED_PROPERTY: {
builder()->StoreNamedProperty(
obj, name_index, feedback_index(feedback_slot), language_mode());
break;
}
case KEYED_PROPERTY: {
builder()->StoreKeyedProperty(obj, key, feedback_index(feedback_slot),
language_mode());
break;
}
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNIMPLEMENTED();
}
// Restore old value for postfix expressions.
if (is_postfix) {
execution_result()->SetResultInRegister(old_value);
} else {
execution_result()->SetResultInAccumulator();
}
}
......
......@@ -41,17 +41,28 @@ class BytecodeGenerator : public AstVisitor {
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
Register VisitArguments(ZoneList<Expression*>* arguments);
// Dispatched from VisitBinaryOperation.
void VisitArithmeticExpression(BinaryOperation* binop);
void VisitCommaExpression(BinaryOperation* binop);
void VisitLogicalOrExpression(BinaryOperation* binop);
void VisitLogicalAndExpression(BinaryOperation* binop);
// Dispatched from VisitUnaryOperation.
void VisitVoid(UnaryOperation* expr);
void VisitTypeOf(UnaryOperation* expr);
void VisitNot(UnaryOperation* expr);
// Helper visitors which perform common operations.
Register VisitArguments(ZoneList<Expression*>* arguments);
void VisitPropertyLoad(Register obj, Property* expr);
void VisitPropertyLoadForAccumulator(Register obj, Property* expr);
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
void VisitVariableLoadForAccumulatorValue(Variable* variable,
FeedbackVectorSlot slot);
MUST_USE_RESULT Register VisitVariableLoadForRegisterValue(
Variable* variable, FeedbackVectorSlot slot);
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
void VisitNewLocalFunctionContext();
......@@ -64,10 +75,6 @@ class BytecodeGenerator : public AstVisitor {
ObjectLiteralProperty* property,
Register value_out);
// Dispatched from VisitUnaryOperation.
void VisitVoid(UnaryOperation* expr);
void VisitTypeOf(UnaryOperation* expr);
void VisitNot(UnaryOperation* expr);
// Visitors for obtaining expression result in the accumulator, in a
// register, or just getting the effect.
......
......@@ -87,6 +87,8 @@ namespace interpreter {
V(ShiftRightLogical, OperandType::kReg8) \
\
/* Unary Operators */ \
V(Inc, OperandType::kNone) \
V(Dec, OperandType::kNone) \
V(LogicalNot, OperandType::kNone) \
V(TypeOf, OperandType::kNone) \
\
......@@ -113,6 +115,7 @@ namespace interpreter {
/* Cast operators */ \
V(ToBoolean, OperandType::kNone) \
V(ToName, OperandType::kNone) \
V(ToNumber, OperandType::kNone) \
\
/* Literals */ \
V(CreateRegExpLiteral, OperandType::kIdx8, OperandType::kReg8) \
......
......@@ -591,6 +591,32 @@ void Interpreter::DoShiftRightLogical(
}
void Interpreter::DoCountOp(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) {
Node* value = __ GetAccumulator();
Node* one = __ NumberConstant(1);
Node* result = __ CallRuntime(function_id, value, one);
__ SetAccumulator(result);
__ Dispatch();
}
// Inc
//
// Increments value in the accumulator by one.
void Interpreter::DoInc(compiler::InterpreterAssembler* assembler) {
DoCountOp(Runtime::kAdd, assembler);
}
// Dec
//
// Decrements value in the accumulator by one.
void Interpreter::DoDec(compiler::InterpreterAssembler* assembler) {
DoCountOp(Runtime::kSubtract, assembler);
}
// LogicalNot
//
// Perform logical-not on the accumulator, first casting the
......@@ -776,6 +802,17 @@ void Interpreter::DoToName(compiler::InterpreterAssembler* assembler) {
}
// ToNumber
//
// Cast the object referenced by the accumulator to a number.
void Interpreter::DoToNumber(compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* result = __ CallRuntime(Runtime::kToNumber, accumulator);
__ SetAccumulator(result);
__ Dispatch();
}
// Jump <imm8>
//
// Jump by number of bytes represented by the immediate operand |imm8|.
......
......@@ -54,6 +54,10 @@ class Interpreter {
void DoBinaryOp(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler);
// Generates code to perform the count operations via |function_id|.
void DoCountOp(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler);
// Generates code to perform the comparison operation associated with
// |compare_op|.
void DoCompareOp(Token::Value compare_op,
......
This diff is collapsed.
......@@ -94,9 +94,14 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.BinaryOperation(Token::Value::SAR, reg, Strength::WEAK)
.BinaryOperation(Token::Value::SHR, reg, Strength::WEAK);
// Emit count operatior invocations
builder.CountOperation(Token::Value::ADD, Strength::WEAK)
.CountOperation(Token::Value::SUB, Strength::WEAK);
// Emit unary operator invocations.
builder.LogicalNot().TypeOf();
// Emit new.
builder.New(reg, reg, 0);
......@@ -113,7 +118,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CompareOperation(Token::Value::IN, reg, Strength::WEAK);
// Emit cast operator invocations.
builder.LoadNull()
builder.CastAccumulatorToNumber()
.CastAccumulatorToBoolean()
.CastAccumulatorToName();
......
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