[Interpreter] Add implementations for load immediate bytecodes.

Adds implementations and tests for the following bytecodes:
  - LdaZero
  - LdaSmi8
  - LdaUndefined
  - LdaNull
  - LdaTheHole
  - LdaTrue
  - LdaFalse
  - LdaLdar
  - LdaStar

Also adds  Smi tagging / untagging and OperandType typed
BytecodeOperand operations to InterpreterAssembler.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30226}
This commit is contained in:
rmcilroy 2015-08-18 08:29:21 -07:00 committed by Commit bot
parent a2462683b7
commit f36cc258ff
6 changed files with 293 additions and 78 deletions

View File

@ -110,19 +110,21 @@ Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
}
Node* InterpreterAssembler::BytecodeOperand(int delta) {
DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
Node* InterpreterAssembler::BytecodeOperand(int operand_index) {
DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
return raw_assembler_->Load(
kMachUint8, BytecodeArrayTaggedPointer(),
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
raw_assembler_->IntPtrAdd(BytecodeOffset(),
Int32Constant(1 + operand_index)));
}
Node* InterpreterAssembler::BytecodeOperandSignExtended(int delta) {
DCHECK_LT(delta, interpreter::Bytecodes::NumberOfOperands(bytecode_));
Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) {
DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
Node* load = raw_assembler_->Load(
kMachInt8, BytecodeArrayTaggedPointer(),
raw_assembler_->IntPtrAdd(BytecodeOffset(), Int32Constant(1 + delta)));
raw_assembler_->IntPtrAdd(BytecodeOffset(),
Int32Constant(1 + operand_index)));
// Ensure that we sign extend to full pointer size
if (kPointerSize == 8) {
load = raw_assembler_->ChangeInt32ToInt64(load);
@ -131,6 +133,50 @@ Node* InterpreterAssembler::BytecodeOperandSignExtended(int delta) {
}
Node* InterpreterAssembler::BytecodeOperandImm8(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kImm8,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
return BytecodeOperandSignExtended(operand_index);
}
Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kReg,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
return BytecodeOperandSignExtended(operand_index);
}
Node* InterpreterAssembler::Int32Constant(int value) {
return raw_assembler_->Int32Constant(value);
}
Node* InterpreterAssembler::NumberConstant(double value) {
return raw_assembler_->NumberConstant(value);
}
Node* InterpreterAssembler::HeapConstant(Unique<HeapObject> object) {
return raw_assembler_->HeapConstant(object);
}
Node* InterpreterAssembler::SmiShiftBitsConstant() {
return Int32Constant(kSmiShiftSize + kSmiTagSize);
}
Node* InterpreterAssembler::SmiTag(Node* value) {
return raw_assembler_->WordShl(value, SmiShiftBitsConstant());
}
Node* InterpreterAssembler::SmiUntag(Node* value) {
return raw_assembler_->WordSar(value, SmiShiftBitsConstant());
}
void InterpreterAssembler::Return() {
Node* exit_trampoline_code_object =
HeapConstant(Unique<HeapObject>::CreateImmovable(
@ -213,19 +259,6 @@ Schedule* InterpreterAssembler::schedule() {
}
Node* InterpreterAssembler::Int32Constant(int value) {
return raw_assembler_->Int32Constant(value);
}
Node* InterpreterAssembler::NumberConstant(double value) {
return raw_assembler_->NumberConstant(value);
}
Node* InterpreterAssembler::HeapConstant(Unique<HeapObject> object) {
return raw_assembler_->HeapConstant(object);
}
} // namespace interpreter
} // namespace internal

View File

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_INTERPRETER_CODEGEN_H_
#define V8_COMPILER_INTERPRETER_CODEGEN_H_
#ifndef V8_COMPILER_INTERPRETER_ASSEMBLER_H_
#define V8_COMPILER_INTERPRETER_ASSEMBLER_H_
// Clients of this interface shouldn't depend on lots of compiler internals.
// Do not include anything from src/compiler here!
@ -36,6 +36,13 @@ class InterpreterAssembler {
Handle<Code> GenerateCode();
// Returns the Imm8 immediate for bytecode operand |operand_index| in the
// current bytecode.
Node* BytecodeOperandImm8(int operand_index);
// Returns the register index for bytecode operand |operand_index| in the
// current bytecode.
Node* BytecodeOperandReg(int operand_index);
// Accumulator.
Node* GetAccumulator();
void SetAccumulator(Node* value);
@ -49,15 +56,16 @@ class InterpreterAssembler {
Node* NumberConstant(double value);
Node* HeapConstant(Unique<HeapObject> object);
// Tag and untag Smi values.
Node* SmiTag(Node* value);
Node* SmiUntag(Node* value);
// Returns from the function.
void Return();
// Dispatch to the bytecode.
void Dispatch();
Node* BytecodeOperand(int index);
Node* BytecodeOperandSignExtended(int index);
protected:
// Close the graph.
void End();
@ -79,6 +87,10 @@ class InterpreterAssembler {
// Returns the offset of register |index| relative to RegisterFilePointer().
Node* RegisterFrameOffset(Node* index);
Node* SmiShiftBitsConstant();
Node* BytecodeOperand(int operand_index);
Node* BytecodeOperandSignExtended(int operand_index);
// Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not
// update BytecodeOffset() itself.
Node* Advance(int delta);
@ -103,4 +115,4 @@ class InterpreterAssembler {
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_INTERPRETER_CODEGEN_H_
#endif // V8_COMPILER_INTERPRETER_ASSEMBLER_H_

View File

@ -89,7 +89,8 @@ bool Interpreter::IsInterpreterTableInitialized(
//
// Load literal '0' into the accumulator.
void Interpreter::DoLdaZero(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* zero_value = __ NumberConstant(0.0);
__ SetAccumulator(zero_value);
__ Dispatch();
}
@ -98,7 +99,9 @@ void Interpreter::DoLdaZero(compiler::InterpreterAssembler* assembler) {
//
// Load an 8-bit integer literal into the accumulator as a Smi.
void Interpreter::DoLdaSmi8(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement 8-bit integer to SMI promotion.
Node* raw_int = __ BytecodeOperandImm8(0);
Node* smi_int = __ SmiTag(raw_int);
__ SetAccumulator(smi_int);
__ Dispatch();
}
@ -107,7 +110,9 @@ void Interpreter::DoLdaSmi8(compiler::InterpreterAssembler* assembler) {
//
// Load Undefined into the accumulator.
void Interpreter::DoLdaUndefined(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* undefined_value = __ HeapConstant(Unique<HeapObject>::CreateImmovable(
isolate_->factory()->undefined_value()));
__ SetAccumulator(undefined_value);
__ Dispatch();
}
@ -116,7 +121,9 @@ void Interpreter::DoLdaUndefined(compiler::InterpreterAssembler* assembler) {
//
// Load Null into the accumulator.
void Interpreter::DoLdaNull(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* null_value = __ HeapConstant(
Unique<HeapObject>::CreateImmovable(isolate_->factory()->null_value()));
__ SetAccumulator(null_value);
__ Dispatch();
}
@ -125,7 +132,9 @@ void Interpreter::DoLdaNull(compiler::InterpreterAssembler* assembler) {
//
// Load TheHole into the accumulator.
void Interpreter::DoLdaTheHole(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* the_hole_value = __ HeapConstant(Unique<HeapObject>::CreateImmovable(
isolate_->factory()->the_hole_value()));
__ SetAccumulator(the_hole_value);
__ Dispatch();
}
@ -134,7 +143,9 @@ void Interpreter::DoLdaTheHole(compiler::InterpreterAssembler* assembler) {
//
// Load True into the accumulator.
void Interpreter::DoLdaTrue(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* true_value = __ HeapConstant(
Unique<HeapObject>::CreateImmovable(isolate_->factory()->true_value()));
__ SetAccumulator(true_value);
__ Dispatch();
}
@ -143,7 +154,9 @@ void Interpreter::DoLdaTrue(compiler::InterpreterAssembler* assembler) {
//
// Load False into the accumulator.
void Interpreter::DoLdaFalse(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* false_value = __ HeapConstant(
Unique<HeapObject>::CreateImmovable(isolate_->factory()->false_value()));
__ SetAccumulator(false_value);
__ Dispatch();
}
@ -152,7 +165,8 @@ void Interpreter::DoLdaFalse(compiler::InterpreterAssembler* assembler) {
//
// Load accumulator with value from register <src>.
void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* value = __ LoadRegister(__ BytecodeOperandReg(0));
__ SetAccumulator(value);
__ Dispatch();
}
@ -161,7 +175,9 @@ void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) {
//
// Store accumulator to register <dst>.
void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
Node* reg_index = __ BytecodeOperandReg(0);
Node* accumulator = __ GetAccumulator();
__ StoreRegister(accumulator, reg_index);
__ Dispatch();
}

View File

@ -12,6 +12,7 @@
namespace v8 {
namespace internal {
namespace interpreter {
class InterpreterCallable {
public:
@ -60,10 +61,14 @@ class InterpreterTester {
DISALLOW_COPY_AND_ASSIGN(InterpreterTester);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
using namespace v8::internal;
using v8::internal::BytecodeArray;
using v8::internal::Handle;
using v8::internal::Object;
using v8::internal::Smi;
using namespace v8::internal::interpreter;
TEST(TestInterpreterReturn) {
@ -81,3 +86,123 @@ TEST(TestInterpreterReturn) {
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(undefined_value));
}
TEST(TestInterpreterLoadUndefined) {
InitializedHandleScope handles;
Handle<Object> undefined_value =
handles.main_isolate()->factory()->undefined_value();
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(0);
builder.LoadUndefined().Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
InterpreterCallable callable(tester.GetCallable());
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(undefined_value));
}
TEST(TestInterpreterLoadNull) {
InitializedHandleScope handles;
Handle<Object> null_value = handles.main_isolate()->factory()->null_value();
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(0);
builder.LoadNull().Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
InterpreterCallable callable(tester.GetCallable());
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(null_value));
}
TEST(TestInterpreterLoadTheHole) {
InitializedHandleScope handles;
Handle<Object> the_hole_value =
handles.main_isolate()->factory()->the_hole_value();
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(0);
builder.LoadTheHole().Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
InterpreterCallable callable(tester.GetCallable());
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(the_hole_value));
}
TEST(TestInterpreterLoadTrue) {
InitializedHandleScope handles;
Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(0);
builder.LoadTrue().Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
InterpreterCallable callable(tester.GetCallable());
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(true_value));
}
TEST(TestInterpreterLoadFalse) {
InitializedHandleScope handles;
Handle<Object> false_value = handles.main_isolate()->factory()->false_value();
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(0);
builder.LoadFalse().Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
InterpreterCallable callable(tester.GetCallable());
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(false_value));
}
TEST(TestInterpreterLoadLiteral) {
InitializedHandleScope handles;
for (int i = -128; i < 128; i++) {
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(0);
builder.LoadLiteral(Smi::FromInt(i)).Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
InterpreterCallable callable(tester.GetCallable());
Handle<Object> return_val = callable().ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
}
}
TEST(TestInterpreterLoadStoreRegisters) {
InitializedHandleScope handles;
Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
for (int i = 0; i <= Register::kMaxRegisterIndex; i++) {
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(i + 1);
Register reg(i);
builder.LoadTrue()
.StoreAccumulatorInRegister(reg)
.LoadFalse()
.LoadAccumulatorWithRegister(reg)
.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
InterpreterCallable callable(tester.GetCallable());
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(true_value));
}
}

View File

@ -23,10 +23,31 @@ const interpreter::Bytecode kBytecodes[] = {
};
Graph*
InterpreterAssemblerTest::InterpreterAssemblerForTest::GetCompletedGraph() {
End();
return graph();
Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher)
: IsInt32Add(lhs_matcher, rhs_matcher);
}
Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher)
: IsInt32Sub(lhs_matcher, rhs_matcher);
}
Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher)
: IsWord32Shl(lhs_matcher, rhs_matcher);
}
Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsWord64Sar(lhs_matcher, rhs_matcher)
: IsWord32Sar(lhs_matcher, rhs_matcher);
}
@ -48,24 +69,33 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore(
}
Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher)
: IsInt32Add(lhs_matcher, rhs_matcher);
Matcher<Node*>
InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand(
int operand) {
return IsLoad(
kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + operand)));
}
Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher)
: IsInt32Sub(lhs_matcher, rhs_matcher);
Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::
IsBytecodeOperandSignExtended(int operand) {
Matcher<Node*> load_matcher = IsLoad(
kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + operand)));
if (kPointerSize == 8) {
load_matcher = IsChangeInt32ToInt64(load_matcher);
}
return load_matcher;
}
Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher)
: IsWord32Shl(lhs_matcher, rhs_matcher);
Graph*
InterpreterAssemblerTest::InterpreterAssemblerForTest::GetCompletedGraph() {
End();
return graph();
}
@ -138,34 +168,19 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
InterpreterAssemblerForTest m(this, bytecode);
int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
for (int i = 0; i < number_of_operands; i++) {
Node* load_arg_node = m.BytecodeOperand(i);
EXPECT_THAT(
load_arg_node,
m.IsLoad(
kMachUint8,
IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(
IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + i))));
}
}
}
TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperandSignExtended) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
for (int i = 0; i < number_of_operands; i++) {
Node* load_arg_node = m.BytecodeOperandSignExtended(i);
Matcher<Node*> load_matcher = m.IsLoad(
kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + i)));
if (kPointerSize == 8) {
load_matcher = IsChangeInt32ToInt64(load_matcher);
switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
case interpreter::OperandType::kImm8:
EXPECT_THAT(m.BytecodeOperandImm8(i),
m.IsBytecodeOperandSignExtended(i));
break;
case interpreter::OperandType::kReg:
EXPECT_THAT(m.BytecodeOperandReg(i),
m.IsBytecodeOperandSignExtended(i));
break;
case interpreter::OperandType::kNone:
UNREACHABLE();
break;
}
EXPECT_THAT(load_arg_node, load_matcher);
}
}
}
@ -230,6 +245,18 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) {
}
}
TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
Node* value = m.Int32Constant(44);
EXPECT_THAT(m.SmiTag(value),
IsWordShl(value, IsInt32Constant(kSmiShiftSize + kSmiTagSize)));
EXPECT_THAT(m.SmiUntag(value),
IsWordSar(value, IsInt32Constant(kSmiShiftSize + kSmiTagSize)));
}
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -38,6 +38,8 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& index_matcher,
const Matcher<Node*>& value_matcher);
Matcher<Node*> IsBytecodeOperand(int operand);
Matcher<Node*> IsBytecodeOperandSignExtended(int operand);
using InterpreterAssembler::call_descriptor;
using InterpreterAssembler::graph;