[Interpreter] Add implementations of arithmetic binary op bytecodes.

Adds implementations and tests for the following bytecodes:
  - Add
  - Sub
  - Mul
  - Div
  - Mod

Also adds the Mod bytecode and adds support to BytecodeGenerator and
BytecodeArrayBuilder to enable it's use.

The current bytecodes always call through to the JS builtins. This also adds
LoadObjectField and CallJSBuiltin operators to the InterpreterAssembler.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30352}
This commit is contained in:
rmcilroy 2015-08-25 04:31:09 -07:00 committed by Commit bot
parent cfdcc874a9
commit b5502099b7
14 changed files with 358 additions and 53 deletions

View File

@ -187,12 +187,54 @@ Node* InterpreterAssembler::SmiUntag(Node* value) {
}
Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) {
return raw_assembler_->Load(kMachAnyTagged, object,
IntPtrConstant(offset - kHeapObjectTag));
}
Node* InterpreterAssembler::LoadContextSlot(int slot_index) {
return raw_assembler_->Load(kMachAnyTagged, ContextTaggedPointer(),
IntPtrConstant(Context::SlotOffset(slot_index)));
}
Node* InterpreterAssembler::CallJSBuiltin(Builtins::JavaScript builtin,
Node* receiver, Node** js_args,
int js_arg_count) {
Node* global_object = LoadContextSlot(Context::GLOBAL_OBJECT_INDEX);
Node* builtins_object =
LoadObjectField(global_object, GlobalObject::kBuiltinsOffset);
Node* function = LoadObjectField(
builtins_object, JSBuiltinsObject::OffsetOfFunctionWithId(builtin));
Node* context = LoadObjectField(function, JSFunction::kContextOffset);
int index = 0;
Node** args = zone()->NewArray<Node*>(js_arg_count + 2);
args[index++] = receiver;
for (int i = 0; i < js_arg_count; i++) {
args[index++] = js_args[i];
}
args[index++] = context;
CallDescriptor* descriptor = Linkage::GetJSCallDescriptor(
zone(), false, js_arg_count + 1, CallDescriptor::kNoFlags);
return raw_assembler_->CallN(descriptor, function, args);
}
Node* InterpreterAssembler::CallJSBuiltin(Builtins::JavaScript builtin,
Node* receiver) {
return CallJSBuiltin(builtin, receiver, nullptr, 0);
}
Node* InterpreterAssembler::CallJSBuiltin(Builtins::JavaScript builtin,
Node* receiver, Node* arg1) {
return CallJSBuiltin(builtin, receiver, &arg1, 1);
}
void InterpreterAssembler::Return() {
Node* exit_trampoline_code_object =
HeapConstant(Unique<HeapObject>::CreateImmovable(
@ -204,10 +246,14 @@ void InterpreterAssembler::Return() {
STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
call_descriptor(), exit_trampoline_code_object, GetAccumulator(),
RegisterFileRawPointer(), BytecodeOffset(), BytecodeArrayTaggedPointer(),
DispatchTableRawPointer(), ContextTaggedPointer());
Node* args[] = { GetAccumulator(),
RegisterFileRawPointer(),
BytecodeOffset(),
BytecodeArrayTaggedPointer(),
DispatchTableRawPointer(),
ContextTaggedPointer() };
Node* tail_call = raw_assembler_->TailCallN(
call_descriptor(), exit_trampoline_code_object, args);
// This should always be the end node.
SetEndInput(tail_call);
}
@ -237,11 +283,14 @@ void InterpreterAssembler::Dispatch() {
STATIC_ASSERT(3 == Linkage::kInterpreterBytecodeArrayParameter);
STATIC_ASSERT(4 == Linkage::kInterpreterDispatchTableParameter);
STATIC_ASSERT(5 == Linkage::kInterpreterContextParameter);
Node* tail_call = raw_assembler_->TailCallInterpreterDispatch(
call_descriptor(), target_code_object, GetAccumulator(),
RegisterFileRawPointer(), new_bytecode_offset,
BytecodeArrayTaggedPointer(), DispatchTableRawPointer(),
ContextTaggedPointer());
Node* args[] = { GetAccumulator(),
RegisterFileRawPointer(),
new_bytecode_offset,
BytecodeArrayTaggedPointer(),
DispatchTableRawPointer(),
ContextTaggedPointer() };
Node* tail_call =
raw_assembler_->TailCallN(call_descriptor(), target_code_object, args);
// This should always be the end node.
SetEndInput(tail_call);
}
@ -278,6 +327,8 @@ Schedule* InterpreterAssembler::schedule() {
}
Zone* InterpreterAssembler::zone() { return raw_assembler_->zone(); }
} // namespace interpreter
} // namespace internal

View File

@ -9,6 +9,7 @@
// Do not include anything from src/compiler here!
#include "src/allocation.h"
#include "src/base/smart-pointers.h"
#include "src/builtins.h"
#include "src/frames.h"
#include "src/interpreter/bytecodes.h"
#include "src/unique.h"
@ -61,9 +62,16 @@ class InterpreterAssembler {
Node* SmiTag(Node* value);
Node* SmiUntag(Node* value);
// Load a field from an object on the heap.
Node* LoadObjectField(Node* object, int offset);
// Load |slot_index| from the current context.
Node* LoadContextSlot(int slot_index);
// Call JS builtin.
Node* CallJSBuiltin(Builtins::JavaScript builtin, Node* receiver);
Node* CallJSBuiltin(Builtins::JavaScript builtin, Node* receiver, Node* arg1);
// Returns from the function.
void Return();
@ -97,6 +105,9 @@ class InterpreterAssembler {
Node* BytecodeOperand(int operand_index);
Node* BytecodeOperandSignExtended(int operand_index);
Node* CallJSBuiltin(Builtins::JavaScript builtin, Node* receiver,
Node** js_args, int js_arg_count);
// Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not
// update BytecodeOffset() itself.
Node* Advance(int delta);
@ -107,6 +118,7 @@ class InterpreterAssembler {
// Private helpers which delegate to RawMachineAssembler.
Isolate* isolate();
Schedule* schedule();
Zone* zone();
interpreter::Bytecode bytecode_;
base::SmartPointer<RawMachineAssembler> raw_assembler_;

View File

@ -104,7 +104,8 @@ Node* RawMachineAssembler::CallN(CallDescriptor* desc, Node* function,
Node** args) {
int param_count =
static_cast<int>(desc->GetMachineSignature()->parameter_count());
Node** buffer = zone()->NewArray<Node*>(param_count + 3);
int input_count = param_count + 3;
Node** buffer = zone()->NewArray<Node*>(input_count);
int index = 0;
buffer[index++] = function;
for (int i = 0; i < param_count; i++) {
@ -112,12 +113,54 @@ Node* RawMachineAssembler::CallN(CallDescriptor* desc, Node* function,
}
buffer[index++] = graph()->start();
buffer[index++] = graph()->start();
Node* call = graph()->NewNode(common()->Call(desc), param_count + 3, buffer);
Node* call = graph()->NewNode(common()->Call(desc), input_count, buffer);
schedule()->AddNode(CurrentBlock(), call);
return call;
}
Node* RawMachineAssembler::CallNWithFrameState(CallDescriptor* desc,
Node* function, Node** args,
Node* frame_state) {
DCHECK(desc->NeedsFrameState());
int param_count =
static_cast<int>(desc->GetMachineSignature()->parameter_count());
int input_count = param_count + 4;
Node** buffer = zone()->NewArray<Node*>(input_count);
int index = 0;
buffer[index++] = function;
for (int i = 0; i < param_count; i++) {
buffer[index++] = args[i];
}
buffer[index++] = frame_state;
buffer[index++] = graph()->start();
buffer[index++] = graph()->start();
Node* call = graph()->NewNode(common()->Call(desc), input_count, buffer);
schedule()->AddNode(CurrentBlock(), call);
return call;
}
Node* RawMachineAssembler::TailCallN(CallDescriptor* desc, Node* function,
Node** args) {
int param_count =
static_cast<int>(desc->GetMachineSignature()->parameter_count());
int input_count = param_count + 3;
Node** buffer = zone()->NewArray<Node*>(input_count);
int index = 0;
buffer[index++] = function;
for (int i = 0; i < param_count; i++) {
buffer[index++] = args[i];
}
buffer[index++] = graph()->start();
buffer[index++] = graph()->start();
Node* tail_call =
graph()->NewNode(common()->TailCall(desc), input_count, buffer);
schedule()->AddTailCall(CurrentBlock(), tail_call);
return tail_call;
}
Node* RawMachineAssembler::CallFunctionStub0(Node* function, Node* receiver,
Node* context, Node* frame_state,
CallFunctionFlags flags) {
@ -134,18 +177,6 @@ Node* RawMachineAssembler::CallFunctionStub0(Node* function, Node* receiver,
}
Node* RawMachineAssembler::CallJS0(Node* function, Node* receiver,
Node* context, Node* frame_state) {
CallDescriptor* descriptor = Linkage::GetJSCallDescriptor(
zone(), false, 1, CallDescriptor::kNeedsFrameState);
Node* call =
graph()->NewNode(common()->Call(descriptor), function, receiver, context,
frame_state, graph()->start(), graph()->start());
schedule()->AddNode(CurrentBlock(), call);
return call;
}
Node* RawMachineAssembler::CallRuntime1(Runtime::FunctionId function,
Node* arg0, Node* context,
Node* frame_state) {
@ -249,17 +280,6 @@ Node* RawMachineAssembler::CallCFunction8(
}
Node* RawMachineAssembler::TailCallInterpreterDispatch(
const CallDescriptor* call_descriptor, Node* target, Node* arg1, Node* arg2,
Node* arg3, Node* arg4, Node* arg5, Node* arg6) {
Node* tail_call = graph()->NewNode(common()->TailCall(call_descriptor),
target, arg1, arg2, arg3, arg4, arg5, arg6,
graph()->start(), graph()->start());
schedule()->AddTailCall(CurrentBlock(), tail_call);
return tail_call;
}
void RawMachineAssembler::Bind(Label* label) {
DCHECK(current_block_ == nullptr);
DCHECK(!label->bound_);

View File

@ -481,13 +481,14 @@ class RawMachineAssembler {
// Call a given call descriptor and the given arguments.
Node* CallN(CallDescriptor* desc, Node* function, Node** args);
// Call a given call descriptor and the given arguments and frame-state.
Node* CallNWithFrameState(CallDescriptor* desc, Node* function, Node** args,
Node* frame_state);
// Tail call the given call descriptor and the given arguments.
Node* TailCallN(CallDescriptor* call_descriptor, Node* function, Node** args);
// Call through CallFunctionStub with lazy deopt and frame-state.
Node* CallFunctionStub0(Node* function, Node* receiver, Node* context,
Node* frame_state, CallFunctionFlags flags);
// Call to a JS function with zero arguments.
Node* CallJS0(Node* function, Node* receiver, Node* context,
Node* frame_state);
// Call to a runtime function with zero arguments.
Node* CallRuntime1(Runtime::FunctionId function, Node* arg0, Node* context,
Node* frame_state);
@ -508,10 +509,6 @@ class RawMachineAssembler {
MachineType arg7_type, Node* function, Node* arg0,
Node* arg1, Node* arg2, Node* arg3, Node* arg4,
Node* arg5, Node* arg6, Node* arg7);
Node* TailCallInterpreterDispatch(const CallDescriptor* call_descriptor,
Node* target, Node* arg1, Node* arg2,
Node* arg3, Node* arg4, Node* arg5,
Node* arg6);
// ===========================================================================
// The following utility methods deal with control flow, hence might switch

View File

@ -193,6 +193,8 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
return Bytecode::kMul;
case Token::Value::DIV:
return Bytecode::kDiv;
case Token::Value::MOD:
return Bytecode::kMod;
default:
UNIMPLEMENTED();
return static_cast<Bytecode>(-1);

View File

@ -42,6 +42,7 @@ namespace interpreter {
V(Sub, OperandType::kReg) \
V(Mul, OperandType::kReg) \
V(Div, OperandType::kReg) \
V(Mod, OperandType::kReg) \
\
/* Control Flow */ \
V(Return, OperandType::kNone)

View File

@ -165,7 +165,8 @@ void Interpreter::DoLdaFalse(compiler::InterpreterAssembler* assembler) {
//
// Load accumulator with value from register <src>.
void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) {
Node* value = __ LoadRegister(__ BytecodeOperandReg(0));
Node* reg_index = __ BytecodeOperandReg(0);
Node* value = __ LoadRegister(reg_index);
__ SetAccumulator(value);
__ Dispatch();
}
@ -182,12 +183,24 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
}
void Interpreter::DoBinaryOp(Builtins::JavaScript binop_builtin,
compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized
// operations, instead of calling builtins directly.
Node* reg_index = __ BytecodeOperandReg(0);
Node* lhs = __ LoadRegister(reg_index);
Node* rhs = __ GetAccumulator();
Node* result = __ CallJSBuiltin(binop_builtin, lhs, rhs);
__ SetAccumulator(result);
__ Dispatch();
}
// Add <src>
//
// Add register <src> to accumulator.
void Interpreter::DoAdd(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
__ Dispatch();
DoBinaryOp(Builtins::ADD, assembler);
}
@ -195,8 +208,7 @@ void Interpreter::DoAdd(compiler::InterpreterAssembler* assembler) {
//
// Subtract register <src> from accumulator.
void Interpreter::DoSub(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
__ Dispatch();
DoBinaryOp(Builtins::SUB, assembler);
}
@ -204,8 +216,7 @@ void Interpreter::DoSub(compiler::InterpreterAssembler* assembler) {
//
// Multiply accumulator by register <src>.
void Interpreter::DoMul(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement add register to accumulator.
__ Dispatch();
DoBinaryOp(Builtins::MUL, assembler);
}
@ -213,8 +224,15 @@ void Interpreter::DoMul(compiler::InterpreterAssembler* assembler) {
//
// Divide register <src> by accumulator.
void Interpreter::DoDiv(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy) Implement.
__ Dispatch();
DoBinaryOp(Builtins::DIV, assembler);
}
// Mod <src>
//
// Modulo register <src> by accumulator.
void Interpreter::DoMod(compiler::InterpreterAssembler* assembler) {
DoBinaryOp(Builtins::MOD, assembler);
}

View File

@ -9,6 +9,7 @@
// Do not include anything from src/interpreter other than
// src/interpreter/bytecodes.h here!
#include "src/base/macros.h"
#include "src/builtins.h"
#include "src/interpreter/bytecodes.h"
namespace v8 {
@ -46,6 +47,10 @@ class Interpreter {
BYTECODE_LIST(DECLARE_BYTECODE_HANDLER_GENERATOR)
#undef DECLARE_BYTECODE_HANDLER_GENERATOR
// Generates code to perform the binary operations via |binop_builtin|.
void DoBinaryOp(Builtins::JavaScript binop_builtin,
compiler::InterpreterAssembler* assembler);
bool IsInterpreterTableInitialized(Handle<FixedArray> handler_table);
Isolate* isolate_;

View File

@ -69,6 +69,7 @@ using v8::internal::BytecodeArray;
using v8::internal::Handle;
using v8::internal::Object;
using v8::internal::Smi;
using v8::internal::Token;
using namespace v8::internal::interpreter;
TEST(TestInterpreterReturn) {
@ -206,3 +207,104 @@ TEST(TestInterpreterLoadStoreRegisters) {
CHECK(return_val.is_identical_to(true_value));
}
}
TEST(TestInterpreterAdd) {
InitializedHandleScope handles;
// TODO(rmcilroy): Do add tests for heap numbers and strings once we support
// them.
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(1);
Register reg(0);
builder.LoadLiteral(Smi::FromInt(1))
.StoreAccumulatorInRegister(reg)
.LoadLiteral(Smi::FromInt(2))
.BinaryOperation(Token::Value::ADD, 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_EQ(Smi::cast(*return_val), Smi::FromInt(3));
}
TEST(TestInterpreterSub) {
InitializedHandleScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(1);
Register reg(0);
builder.LoadLiteral(Smi::FromInt(5))
.StoreAccumulatorInRegister(reg)
.LoadLiteral(Smi::FromInt(31))
.BinaryOperation(Token::Value::SUB, 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_EQ(Smi::cast(*return_val), Smi::FromInt(-26));
}
TEST(TestInterpreterMul) {
InitializedHandleScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(1);
Register reg(0);
builder.LoadLiteral(Smi::FromInt(111))
.StoreAccumulatorInRegister(reg)
.LoadLiteral(Smi::FromInt(6))
.BinaryOperation(Token::Value::MUL, 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_EQ(Smi::cast(*return_val), Smi::FromInt(666));
}
TEST(TestInterpreterDiv) {
InitializedHandleScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(1);
Register reg(0);
builder.LoadLiteral(Smi::FromInt(-20))
.StoreAccumulatorInRegister(reg)
.LoadLiteral(Smi::FromInt(5))
.BinaryOperation(Token::Value::DIV, 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_EQ(Smi::cast(*return_val), Smi::FromInt(-4));
}
TEST(TestInterpreterMod) {
InitializedHandleScope handles;
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
BytecodeArrayBuilder builder(handles.main_isolate());
builder.set_locals_count(1);
Register reg(0);
builder.LoadLiteral(Smi::FromInt(121))
.StoreAccumulatorInRegister(reg)
.LoadLiteral(Smi::FromInt(100))
.BinaryOperation(Token::Value::MOD, 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_EQ(Smi::cast(*return_val), Smi::FromInt(21));
}

View File

@ -366,6 +366,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
ZoneVector<MachineType> int32_type(1, kMachInt32, zone());
ZoneVector<MachineType> empty_types(zone());
CallDescriptor* descriptor = Linkage::GetJSCallDescriptor(
zone(), false, 1, CallDescriptor::kNeedsFrameState);
Node* parameters =
m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1));
Node* locals = m.NewNode(m.common()->TypedStateValues(&empty_types));
@ -377,7 +380,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
m.GetFrameStateFunctionInfo(1, 0)),
parameters, locals, stack, context_dummy, function_node,
m.UndefinedConstant());
Node* call = m.CallJS0(function_node, receiver, context, state_node);
Node* args[] = {receiver, context};
Node* call =
m.CallNWithFrameState(descriptor, function_node, args, state_node);
m.Return(call);
Stream s = m.Build(kAllExceptNopInstructions);

View File

@ -277,6 +277,52 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
}
}
TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
Node* object = m.IntPtrConstant(0xdeadbeef);
int offset = 16;
Node* load_field = m.LoadObjectField(object, offset);
EXPECT_THAT(load_field,
m.IsLoad(kMachAnyTagged, object,
IsIntPtrConstant(offset - kHeapObjectTag)));
}
}
TARGET_TEST_F(InterpreterAssemblerTest, CallJSBuiltin) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
Node* receiver = m.IntPtrConstant(1234);
Node* call_js_builtin_0 = m.CallJSBuiltin(Builtins::SUB, receiver);
Matcher<Node*> load_globals_matcher = m.IsLoad(
kMachAnyTagged, IsParameter(Linkage::kInterpreterContextParameter),
IsIntPtrConstant(Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
Matcher<Node*> load_builtins_matcher = m.IsLoad(
kMachAnyTagged, load_globals_matcher,
IsIntPtrConstant(GlobalObject::kBuiltinsOffset - kHeapObjectTag));
Matcher<Node*> function_matcher =
m.IsLoad(kMachAnyTagged, load_builtins_matcher,
IsIntPtrConstant(
JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::SUB) -
kHeapObjectTag));
Matcher<Node*> context_matcher =
m.IsLoad(kMachAnyTagged, function_matcher,
IsIntPtrConstant(JSFunction::kContextOffset - kHeapObjectTag));
EXPECT_THAT(call_js_builtin_0,
IsCall(_, function_matcher, receiver, context_matcher,
m.graph()->start(), m.graph()->start()));
Node* arg1 = m.Int32Constant(0xabcd);
Node* call_js_builtin_1 = m.CallJSBuiltin(Builtins::SUB, receiver, arg1);
EXPECT_THAT(call_js_builtin_1,
IsCall(_, function_matcher, receiver, arg1, context_matcher,
m.graph()->start(), m.graph()->start()));
}
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -1627,6 +1627,38 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
}
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
std::vector<Matcher<Node*>> value_matchers;
value_matchers.push_back(value0_matcher);
value_matchers.push_back(value1_matcher);
value_matchers.push_back(value2_matcher);
return MakeMatcher(new IsCallMatcher(descriptor_matcher, value_matchers,
effect_matcher, control_matcher));
}
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& value3_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
std::vector<Matcher<Node*>> value_matchers;
value_matchers.push_back(value0_matcher);
value_matchers.push_back(value1_matcher);
value_matchers.push_back(value2_matcher);
value_matchers.push_back(value3_matcher);
return MakeMatcher(new IsCallMatcher(descriptor_matcher, value_matchers,
effect_matcher, control_matcher));
}
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,

View File

@ -105,6 +105,19 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& value3_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,

View File

@ -41,7 +41,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.BinaryOperation(Token::Value::ADD, reg)
.BinaryOperation(Token::Value::SUB, reg)
.BinaryOperation(Token::Value::MUL, reg)
.BinaryOperation(Token::Value::DIV, reg);
.BinaryOperation(Token::Value::DIV, reg)
.BinaryOperation(Token::Value::MOD, reg);
// Emit control flow. Return must be the last instruction.
builder.Return();