[Interpreter] Add intrinsic for Runtime::kInlineCall.
One of the top runtime calls in many workloads is Runtime_Call. Add an intrinsic for the interpreter to inline this runtime call. BUG=v8:4280 LOG=N Review-Url: https://codereview.chromium.org/2019433003 Cr-Commit-Position: refs/heads/master@{#36565}
This commit is contained in:
parent
66ac70932f
commit
aff90bc15b
@ -49,10 +49,10 @@ Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context,
|
||||
__ Switch(function_id, &abort, cases, labels, arraysize(cases));
|
||||
#define HANDLE_CASE(name, lower_case, expected_arg_count) \
|
||||
__ Bind(&lower_case); \
|
||||
if (FLAG_debug_code) { \
|
||||
if (FLAG_debug_code && expected_arg_count >= 0) { \
|
||||
AbortIfArgCountMismatch(expected_arg_count, arg_count); \
|
||||
} \
|
||||
result.Bind(name(first_arg_reg)); \
|
||||
result.Bind(name(first_arg_reg, arg_count, context)); \
|
||||
__ Goto(&end);
|
||||
INTRINSICS_LIST(HANDLE_CASE)
|
||||
#undef HANDLE_CASE
|
||||
@ -96,7 +96,8 @@ Node* IntrinsicsHelper::CompareInstanceType(Node* map, int type,
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IsJSReceiver(Node* input) {
|
||||
Node* IntrinsicsHelper::IsJSReceiver(Node* input, Node* arg_count,
|
||||
Node* context) {
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
|
||||
@ -119,7 +120,7 @@ Node* IntrinsicsHelper::IsJSReceiver(Node* input) {
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::IsArray(Node* input) {
|
||||
Node* IntrinsicsHelper::IsArray(Node* input, Node* arg_count, Node* context) {
|
||||
InterpreterAssembler::Variable return_value(assembler_,
|
||||
MachineRepresentation::kTagged);
|
||||
|
||||
@ -141,17 +142,39 @@ Node* IntrinsicsHelper::IsArray(Node* input) {
|
||||
return return_value.value();
|
||||
}
|
||||
|
||||
Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) {
|
||||
// First argument register contains the function target.
|
||||
Node* function = __ LoadRegister(args_reg);
|
||||
|
||||
// Receiver is the second runtime call argument.
|
||||
Node* receiver_reg = __ NextRegister(args_reg);
|
||||
Node* receiver_arg = __ RegisterLocation(receiver_reg);
|
||||
|
||||
// Subtract function and receiver from arg count.
|
||||
Node* function_and_receiver_count = __ Int32Constant(2);
|
||||
Node* target_args_count = __ Int32Sub(arg_count, function_and_receiver_count);
|
||||
|
||||
if (FLAG_debug_code) {
|
||||
InterpreterAssembler::Label arg_count_positive(assembler_);
|
||||
Node* comparison = __ Int32LessThan(target_args_count, __ Int32Constant(0));
|
||||
__ GotoUnless(comparison, &arg_count_positive);
|
||||
__ Abort(kWrongArgumentCountForInvokeIntrinsic);
|
||||
__ Goto(&arg_count_positive);
|
||||
__ Bind(&arg_count_positive);
|
||||
}
|
||||
|
||||
Node* result = __ CallJS(function, context, receiver_arg, target_args_count,
|
||||
TailCallMode::kDisallow);
|
||||
return result;
|
||||
}
|
||||
|
||||
void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
|
||||
InterpreterAssembler::Label match(assembler_), mismatch(assembler_),
|
||||
end(assembler_);
|
||||
InterpreterAssembler::Label match(assembler_);
|
||||
Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
|
||||
__ Branch(comparison, &match, &mismatch);
|
||||
__ Bind(&mismatch);
|
||||
__ GotoIf(comparison, &match);
|
||||
__ Abort(kWrongArgumentCountForInvokeIntrinsic);
|
||||
__ Goto(&end);
|
||||
__ Goto(&match);
|
||||
__ Bind(&match);
|
||||
__ Goto(&end);
|
||||
__ Bind(&end);
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
|
@ -20,7 +20,10 @@ namespace compiler {
|
||||
class Node;
|
||||
} // namespace compiler
|
||||
|
||||
// List of supported intrisics, with upper case name, lower case name and
|
||||
// expected number of arguments (-1 denoting argument count is variable).
|
||||
#define INTRINSICS_LIST(V) \
|
||||
V(Call, call, -1) \
|
||||
V(IsJSReceiver, is_js_receiver, 1) \
|
||||
V(IsArray, is_array, 1)
|
||||
|
||||
@ -47,8 +50,9 @@ class IntrinsicsHelper {
|
||||
void AbortIfArgCountMismatch(int expected, compiler::Node* actual);
|
||||
InterpreterAssembler* assembler_;
|
||||
|
||||
#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
|
||||
compiler::Node* name(compiler::Node* input);
|
||||
#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
|
||||
compiler::Node* name(compiler::Node* input, compiler::Node* arg_count, \
|
||||
compiler::Node* context);
|
||||
INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)
|
||||
#undef DECLARE_INTRINSIC_HELPER
|
||||
|
||||
|
@ -180,9 +180,8 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) {
|
||||
bool Interpreter::IsDispatchTableInitialized() {
|
||||
if (FLAG_trace_ignition || FLAG_trace_ignition_codegen ||
|
||||
FLAG_trace_ignition_dispatches) {
|
||||
// Regenerate table to add bytecode tracing operations,
|
||||
// print the assembly code generated by TurboFan,
|
||||
// or instrument handlers with dispatch counters.
|
||||
// Regenerate table to add bytecode tracing operations, print the assembly
|
||||
// code generated by TurboFan or instrument handlers with dispatch counters.
|
||||
return false;
|
||||
}
|
||||
return dispatch_table_[0] != nullptr;
|
||||
|
@ -100,7 +100,7 @@ bytecodes: [
|
||||
B(Mov), R(context), R(12),
|
||||
B(Mov), R(5), R(13),
|
||||
B(Mov), R(1), R(14),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(13), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(13), U8(2),
|
||||
B(Jump), U8(29),
|
||||
B(Star), R(14),
|
||||
B(LdaConstant), U8(5),
|
||||
@ -115,7 +115,7 @@ bytecodes: [
|
||||
B(Jump), U8(29),
|
||||
B(Mov), R(5), R(12),
|
||||
B(Mov), R(1), R(13),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(Star), R(6),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(6), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
@ -245,7 +245,7 @@ bytecodes: [
|
||||
B(Mov), R(context), R(13),
|
||||
B(Mov), R(5), R(14),
|
||||
B(Mov), R(1), R(15),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(14), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(14), U8(2),
|
||||
B(Jump), U8(29),
|
||||
B(Star), R(15),
|
||||
B(LdaConstant), U8(5),
|
||||
@ -260,7 +260,7 @@ bytecodes: [
|
||||
B(Jump), U8(29),
|
||||
B(Mov), R(5), R(13),
|
||||
B(Mov), R(1), R(14),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(13), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(13), U8(2),
|
||||
B(Star), R(6),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(6), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
@ -402,7 +402,7 @@ bytecodes: [
|
||||
B(Mov), R(context), R(12),
|
||||
B(Mov), R(5), R(13),
|
||||
B(Mov), R(1), R(14),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(13), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(13), U8(2),
|
||||
B(Jump), U8(29),
|
||||
B(Star), R(14),
|
||||
B(LdaConstant), U8(5),
|
||||
@ -417,7 +417,7 @@ bytecodes: [
|
||||
B(Jump), U8(29),
|
||||
B(Mov), R(5), R(12),
|
||||
B(Mov), R(1), R(13),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(Star), R(6),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(6), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
@ -549,7 +549,7 @@ bytecodes: [
|
||||
B(Mov), R(context), R(11),
|
||||
B(Mov), R(4), R(12),
|
||||
B(Mov), R(0), R(13),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(12), U8(2),
|
||||
B(Jump), U8(29),
|
||||
B(Star), R(13),
|
||||
B(LdaConstant), U8(7),
|
||||
@ -564,7 +564,7 @@ bytecodes: [
|
||||
B(Jump), U8(29),
|
||||
B(Mov), R(4), R(11),
|
||||
B(Mov), R(0), R(12),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(11), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(11), U8(2),
|
||||
B(Star), R(5),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(5), U8(1),
|
||||
B(JumpIfToBooleanFalse), U8(4),
|
||||
|
@ -489,7 +489,7 @@ bytecodes: [
|
||||
B(Mov), R(context), R(10),
|
||||
B(LdrContextSlot), R(1), U8(11), R(11),
|
||||
B(LdrContextSlot), R(1), U8(7), R(12),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(11), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(11), U8(2),
|
||||
B(Jump), U8(29),
|
||||
B(Star), R(12),
|
||||
B(LdaConstant), U8(11),
|
||||
@ -504,7 +504,7 @@ bytecodes: [
|
||||
B(Jump), U8(40),
|
||||
B(LdrContextSlot), R(1), U8(11), R(10),
|
||||
B(LdrContextSlot), R(1), U8(7), R(11),
|
||||
B(CallRuntime), U16(Runtime::k_Call), R(10), U8(2),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_Call), R(10), U8(2),
|
||||
B(StaContextSlot), R(1), U8(12),
|
||||
B(LdrContextSlot), R(1), U8(12), R(10),
|
||||
B(InvokeIntrinsic), U16(Runtime::k_IsJSReceiver), R(10), U8(1),
|
||||
|
@ -29,7 +29,7 @@ class InvokeIntrinsicHelper {
|
||||
builder.CallRuntime(function_id_, builder.Parameter(0), sizeof...(args))
|
||||
.Return();
|
||||
InterpreterTester tester(isolate_, builder.ToBytecodeArray());
|
||||
auto callable = tester.GetCallable<Handle<Object>>();
|
||||
auto callable = tester.GetCallable<A...>();
|
||||
return callable(args...).ToHandleChecked();
|
||||
}
|
||||
|
||||
@ -91,6 +91,28 @@ TEST(IsArray) {
|
||||
CHECK_EQ(*factory->false_value(), *helper.Invoke(helper.NewObject("42")));
|
||||
}
|
||||
|
||||
TEST(Call) {
|
||||
HandleAndZoneScope handles;
|
||||
Isolate* isolate = handles.main_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
InvokeIntrinsicHelper helper(isolate, handles.main_zone(),
|
||||
Runtime::kInlineCall);
|
||||
|
||||
CHECK_EQ(Smi::FromInt(20),
|
||||
*helper.Invoke(helper.NewObject("(function() { return this.x; })"),
|
||||
helper.NewObject("({ x: 20 })")));
|
||||
CHECK_EQ(Smi::FromInt(50),
|
||||
*helper.Invoke(helper.NewObject("(function(arg1) { return arg1; })"),
|
||||
factory->undefined_value(),
|
||||
handle(Smi::FromInt(50), isolate)));
|
||||
CHECK_EQ(
|
||||
Smi::FromInt(20),
|
||||
*helper.Invoke(
|
||||
helper.NewObject("(function(a, b, c) { return a + b + c; })"),
|
||||
factory->undefined_value(), handle(Smi::FromInt(10), isolate),
|
||||
handle(Smi::FromInt(7), isolate), handle(Smi::FromInt(3), isolate)));
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user