[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:
rmcilroy 2016-05-27 15:29:01 -07:00 committed by Commit bot
parent 66ac70932f
commit aff90bc15b
6 changed files with 75 additions and 27 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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),

View File

@ -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),

View File

@ -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