diff --git a/src/compiler/interpreter-assembler.cc b/src/compiler/interpreter-assembler.cc index f981a4f675..e3401fb9fb 100644 --- a/src/compiler/interpreter-assembler.cc +++ b/src/compiler/interpreter-assembler.cc @@ -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(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::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 diff --git a/src/compiler/interpreter-assembler.h b/src/compiler/interpreter-assembler.h index b15311bbed..2dcb08f931 100644 --- a/src/compiler/interpreter-assembler.h +++ b/src/compiler/interpreter-assembler.h @@ -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 raw_assembler_; diff --git a/src/compiler/raw-machine-assembler.cc b/src/compiler/raw-machine-assembler.cc index 81faa7d840..83dbbf15d9 100644 --- a/src/compiler/raw-machine-assembler.cc +++ b/src/compiler/raw-machine-assembler.cc @@ -104,7 +104,8 @@ Node* RawMachineAssembler::CallN(CallDescriptor* desc, Node* function, Node** args) { int param_count = static_cast(desc->GetMachineSignature()->parameter_count()); - Node** buffer = zone()->NewArray(param_count + 3); + int input_count = param_count + 3; + Node** buffer = zone()->NewArray(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(desc->GetMachineSignature()->parameter_count()); + int input_count = param_count + 4; + Node** buffer = zone()->NewArray(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(desc->GetMachineSignature()->parameter_count()); + int input_count = param_count + 3; + Node** buffer = zone()->NewArray(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_); diff --git a/src/compiler/raw-machine-assembler.h b/src/compiler/raw-machine-assembler.h index b76a2589e0..c58db112ea 100644 --- a/src/compiler/raw-machine-assembler.h +++ b/src/compiler/raw-machine-assembler.h @@ -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 diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc index 24fec96bfa..bb1c69bd87 100644 --- a/src/interpreter/bytecode-array-builder.cc +++ b/src/interpreter/bytecode-array-builder.cc @@ -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(-1); diff --git a/src/interpreter/bytecodes.h b/src/interpreter/bytecodes.h index fec6ecf6aa..c445749976 100644 --- a/src/interpreter/bytecodes.h +++ b/src/interpreter/bytecodes.h @@ -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) diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 565fa0c443..7a979a4a3e 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -165,7 +165,8 @@ void Interpreter::DoLdaFalse(compiler::InterpreterAssembler* assembler) { // // Load accumulator with value from register . 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 // // Add register 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 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 . 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 by accumulator. void Interpreter::DoDiv(compiler::InterpreterAssembler* assembler) { - // TODO(rmcilroy) Implement. - __ Dispatch(); + DoBinaryOp(Builtins::DIV, assembler); +} + + +// Mod +// +// Modulo register by accumulator. +void Interpreter::DoMod(compiler::InterpreterAssembler* assembler) { + DoBinaryOp(Builtins::MOD, assembler); } diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h index 64101de657..5c332d5598 100644 --- a/src/interpreter/interpreter.h +++ b/src/interpreter/interpreter.h @@ -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 handler_table); Isolate* isolate_; diff --git a/test/cctest/interpreter/test-interpreter.cc b/test/cctest/interpreter/test-interpreter.cc index 2302fdc9ac..2c5588513b 100644 --- a/test/cctest/interpreter/test-interpreter.cc +++ b/test/cctest/interpreter/test-interpreter.cc @@ -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 bytecode_array = builder.ToBytecodeArray(); + + InterpreterTester tester(handles.main_isolate(), bytecode_array); + InterpreterCallable callable(tester.GetCallable()); + Handle 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 bytecode_array = builder.ToBytecodeArray(); + + InterpreterTester tester(handles.main_isolate(), bytecode_array); + InterpreterCallable callable(tester.GetCallable()); + Handle 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 bytecode_array = builder.ToBytecodeArray(); + + InterpreterTester tester(handles.main_isolate(), bytecode_array); + InterpreterCallable callable(tester.GetCallable()); + Handle 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 bytecode_array = builder.ToBytecodeArray(); + + InterpreterTester tester(handles.main_isolate(), bytecode_array); + InterpreterCallable callable(tester.GetCallable()); + Handle 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 bytecode_array = builder.ToBytecodeArray(); + + InterpreterTester tester(handles.main_isolate(), bytecode_array); + InterpreterCallable callable(tester.GetCallable()); + Handle return_val = callable().ToHandleChecked(); + CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(21)); +} diff --git a/test/unittests/compiler/instruction-selector-unittest.cc b/test/unittests/compiler/instruction-selector-unittest.cc index 1636b7ee5b..d3cf985939 100644 --- a/test/unittests/compiler/instruction-selector-unittest.cc +++ b/test/unittests/compiler/instruction-selector-unittest.cc @@ -366,6 +366,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { ZoneVector int32_type(1, kMachInt32, zone()); ZoneVector 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); diff --git a/test/unittests/compiler/interpreter-assembler-unittest.cc b/test/unittests/compiler/interpreter-assembler-unittest.cc index bc5be263ff..03d80fd9f1 100644 --- a/test/unittests/compiler/interpreter-assembler-unittest.cc +++ b/test/unittests/compiler/interpreter-assembler-unittest.cc @@ -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 load_globals_matcher = m.IsLoad( + kMachAnyTagged, IsParameter(Linkage::kInterpreterContextParameter), + IsIntPtrConstant(Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); + Matcher load_builtins_matcher = m.IsLoad( + kMachAnyTagged, load_globals_matcher, + IsIntPtrConstant(GlobalObject::kBuiltinsOffset - kHeapObjectTag)); + Matcher function_matcher = + m.IsLoad(kMachAnyTagged, load_builtins_matcher, + IsIntPtrConstant( + JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::SUB) - + kHeapObjectTag)); + Matcher 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 diff --git a/test/unittests/compiler/node-test-utils.cc b/test/unittests/compiler/node-test-utils.cc index 4112e224a4..d2b9a7362c 100644 --- a/test/unittests/compiler/node-test-utils.cc +++ b/test/unittests/compiler/node-test-utils.cc @@ -1627,6 +1627,38 @@ Matcher IsCall(const Matcher& descriptor_matcher, } +Matcher IsCall(const Matcher& descriptor_matcher, + const Matcher& value0_matcher, + const Matcher& value1_matcher, + const Matcher& value2_matcher, + const Matcher& effect_matcher, + const Matcher& control_matcher) { + std::vector> 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 IsCall(const Matcher& descriptor_matcher, + const Matcher& value0_matcher, + const Matcher& value1_matcher, + const Matcher& value2_matcher, + const Matcher& value3_matcher, + const Matcher& effect_matcher, + const Matcher& control_matcher) { + std::vector> 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 IsCall(const Matcher& descriptor_matcher, const Matcher& value0_matcher, const Matcher& value1_matcher, diff --git a/test/unittests/compiler/node-test-utils.h b/test/unittests/compiler/node-test-utils.h index 0c6f3ab837..efbed95ded 100644 --- a/test/unittests/compiler/node-test-utils.h +++ b/test/unittests/compiler/node-test-utils.h @@ -105,6 +105,19 @@ Matcher IsCall(const Matcher& descriptor_matcher, const Matcher& value1_matcher, const Matcher& effect_matcher, const Matcher& control_matcher); +Matcher IsCall(const Matcher& descriptor_matcher, + const Matcher& value0_matcher, + const Matcher& value1_matcher, + const Matcher& value2_matcher, + const Matcher& effect_matcher, + const Matcher& control_matcher); +Matcher IsCall(const Matcher& descriptor_matcher, + const Matcher& value0_matcher, + const Matcher& value1_matcher, + const Matcher& value2_matcher, + const Matcher& value3_matcher, + const Matcher& effect_matcher, + const Matcher& control_matcher); Matcher IsCall(const Matcher& descriptor_matcher, const Matcher& value0_matcher, const Matcher& value1_matcher, diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc index aead34770c..72af0c4f53 100644 --- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -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();