diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc index 923587480c8..8eee03d0c66 100644 --- a/runtime/vm/code_generator.cc +++ b/runtime/vm/code_generator.cc @@ -621,34 +621,6 @@ DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) { } -// Resolves and compiles the target function of an instance call, updates -// function cache of the receiver's class and returns the compiled code or null. -// Only the number of named arguments is checked, but not the actual names. -RawCode* ResolveCompileInstanceCallTarget(const Instance& receiver, - const ICData& ic_data) { - ArgumentsDescriptor - arguments_descriptor(Array::Handle(ic_data.arguments_descriptor())); - String& function_name = String::Handle(ic_data.target_name()); - ASSERT(function_name.IsSymbol()); - - Function& function = Function::Handle(); - function = Resolver::ResolveDynamic(receiver, - function_name, - arguments_descriptor); - if (function.IsNull()) { - return Code::null(); - } else { - if (!function.HasCode()) { - const Error& error = Error::Handle(Compiler::CompileFunction(function)); - if (!error.IsNull()) { - Exceptions::PropagateError(error); - } - } - return function.CurrentCode(); - } -} - - // Result of an invoke may be an unhandled exception, in which case we // rethrow it. static void CheckResultError(const Object& result) { @@ -679,24 +651,98 @@ DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) { } +// An instance call of the form o.f(...) could not be resolved. Check if +// there is a getter with the same name. If so, invoke it. If the value is +// a closure, invoke it with the given arguments. If the value is a +// non-closure, attempt to invoke "call" on it. +static bool ResolveCallThroughGetter(const Instance& receiver, + const Class& receiver_class, + const String& target_name, + const Array& arguments_descriptor, + const ICData& ic_data, + Function* result) { + // 1. Check if there is a getter with the same name. + const String& getter_name = String::Handle(Field::GetterName(target_name)); + const int kNumArguments = 1; + ArgumentsDescriptor args_desc( + Array::Handle(ArgumentsDescriptor::New(kNumArguments))); + const Function& getter = Function::Handle( + Resolver::ResolveDynamicForReceiverClass(receiver_class, + getter_name, + args_desc)); + if (getter.IsNull() || getter.IsMethodExtractor()) { + return false; + } + + const Function& target_function = + Function::Handle(receiver_class.GetInvocationDispatcher( + target_name, + arguments_descriptor, + RawFunction::kInvokeFieldDispatcher)); + ASSERT(!target_function.IsNull()); + if (FLAG_trace_ic) { + OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n", + Class::Handle(receiver.clazz()).ToCString(), + receiver.GetClassId(), + target_function.ToCString()); + } + *result = target_function.raw(); + return true; +} + + +// Handle other invocations (implicit closures, noSuchMethod). +RawFunction* InlineCacheMissHelper( + const Instance& receiver, + const ICData& ic_data) { + const Array& args_descriptor = Array::Handle(ic_data.arguments_descriptor()); + + const Class& receiver_class = Class::Handle(receiver.clazz()); + const String& target_name = String::Handle(ic_data.target_name()); + + Function& result = Function::Handle(); + if (!ResolveCallThroughGetter(receiver, + receiver_class, + target_name, + args_descriptor, + ic_data, + &result)) { + ArgumentsDescriptor desc(args_descriptor); + const Function& target_function = + Function::Handle(receiver_class.GetInvocationDispatcher( + target_name, + args_descriptor, + RawFunction::kNoSuchMethodDispatcher)); + if (FLAG_trace_ic) { + OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n", + Class::Handle(receiver.clazz()).ToCString(), + receiver.GetClassId(), + target_function.ToCString()); + } + result = target_function.raw(); + } + return result.raw(); +} + static RawFunction* InlineCacheMissHandler( const GrowableArray& args, const ICData& ic_data) { const Instance& receiver = *args[0]; - const Code& target_code = - Code::Handle(ResolveCompileInstanceCallTarget(receiver, ic_data)); - if (target_code.IsNull()) { - // Let the megamorphic stub handle special cases: NoSuchMethod, - // closure calls. + ArgumentsDescriptor + arguments_descriptor(Array::Handle(ic_data.arguments_descriptor())); + String& function_name = String::Handle(ic_data.target_name()); + ASSERT(function_name.IsSymbol()); + Function& target_function = Function::Handle( + Resolver::ResolveDynamic(receiver, function_name, arguments_descriptor)); + if (target_function.IsNull()) { if (FLAG_trace_ic) { - OS::PrintErr("InlineCacheMissHandler NULL code for %s receiver: %s\n", + OS::PrintErr("InlineCacheMissHandler NULL function for %s receiver: %s\n", String::Handle(ic_data.target_name()).ToCString(), receiver.ToCString()); } - return Function::null(); + ic_data.set_is_closure_call(true); + target_function = InlineCacheMissHelper(receiver, ic_data); } - const Function& target_function = - Function::Handle(target_code.function()); ASSERT(!target_function.IsNull()); if (args.length() == 1) { ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function); @@ -834,9 +880,7 @@ DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs, 3) { // Arg1: ICData object. // Arg2: Arguments descriptor array. -// Returns: target instructions to call or null if the -// InstanceFunctionLookup stub should be used (e.g., to invoke no such -// method and implicit closures).. +// Returns: target function to call. DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); @@ -852,59 +896,21 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { } ArgumentsDescriptor args_desc(descriptor); - const Function& target = Function::Handle( + Function& target_function = Function::Handle( Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc)); - - Instructions& instructions = Instructions::Handle(); - if (!target.IsNull()) { - if (!target.HasCode()) { - const Error& error = Error::Handle(Compiler::CompileFunction(target)); - if (!error.IsNull()) { - Exceptions::PropagateError(error); - } - } - ASSERT(target.HasCode()); - instructions = Code::Handle(target.CurrentCode()).instructions(); + if (target_function.IsNull()) { + ic_data.set_is_closure_call(true); + target_function = InlineCacheMissHelper(receiver, ic_data); } - arguments.SetReturn(instructions); - if (instructions.IsNull()) return; + ASSERT(!target_function.IsNull()); + // Insert function found into cache and return it. cache.EnsureCapacity(); const Smi& class_id = Smi::Handle(Smi::New(cls.id())); - cache.Insert(class_id, target); - return; -} - - -// Updates IC data for two arguments. Used by the equality operation when -// the control flow bypasses regular inline cache (null arguments). -// Arg0: Receiver object. -// Arg1: Argument after receiver. -// Arg2: Target's name. -// Arg3: ICData. -DEFINE_RUNTIME_ENTRY(UpdateICDataTwoArgs, 4) { - const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); - const Instance& arg1 = Instance::CheckedHandle(arguments.ArgAt(1)); - const String& target_name = String::CheckedHandle(arguments.ArgAt(2)); - const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(3)); - GrowableArray args(2); - args.Add(&receiver); - args.Add(&arg1); - const intptr_t kNumArguments = 2; - ArgumentsDescriptor args_desc( - Array::Handle(ArgumentsDescriptor::New(kNumArguments))); - const Function& target_function = Function::Handle( - Resolver::ResolveDynamic(receiver, - target_name, - args_desc)); - ASSERT(!target_function.IsNull()); - GrowableArray class_ids(kNumArguments); - ASSERT(ic_data.num_args_tested() == kNumArguments); - class_ids.Add(receiver.GetClassId()); - class_ids.Add(arg1.GetClassId()); - ic_data.AddCheck(class_ids, target_function); + cache.Insert(class_id, target_function); + arguments.SetReturn(target_function); } @@ -952,126 +958,6 @@ DEFINE_RUNTIME_ENTRY(InvokeNonClosure, 2) { } -// An instance call of the form o.f(...) could not be resolved. Check if -// there is a getter with the same name. If so, invoke it. If the value is -// a closure, invoke it with the given arguments. If the value is a -// non-closure, attempt to invoke "call" on it. -static bool ResolveCallThroughGetter(const Instance& receiver, - const Class& receiver_class, - const String& target_name, - const Array& arguments_descriptor, - const Array& arguments, - const ICData& ic_data, - Object* result) { - // 1. Check if there is a getter with the same name. - const String& getter_name = String::Handle(Field::GetterName(target_name)); - const int kNumArguments = 1; - ArgumentsDescriptor args_desc( - Array::Handle(ArgumentsDescriptor::New(kNumArguments))); - const Function& getter = Function::Handle( - Resolver::ResolveDynamicForReceiverClass(receiver_class, - getter_name, - args_desc)); - if (getter.IsNull() || getter.IsMethodExtractor()) { - return false; - } - - const Function& target_function = - Function::Handle(receiver_class.GetInvocationDispatcher( - target_name, - arguments_descriptor, - RawFunction::kInvokeFieldDispatcher)); - // Update IC data. - ASSERT(!target_function.IsNull()); - ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); - if (FLAG_trace_ic) { - OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n", - Class::Handle(receiver.clazz()).ToCString(), - receiver.GetClassId(), - target_function.ToCString()); - } - *result = DartEntry::InvokeFunction(target_function, - arguments, - arguments_descriptor); - CheckResultError(*result); - return true; -} - - -// The IC miss handler has failed to find a (cacheable) instance function to -// invoke. Handle three possibilities: -// -// 1. If the call was a getter o.f, there may be an instance function with -// the same name. If so, create an implicit closure and return it. -// -// 2. If the call was an instance call o.f(...), there may be a getter with -// the same name. If so, invoke it. If the value is a closure, invoke -// it with the given arguments. If the value is a non-closure, attempt -// to invoke "call" on it. -// -// 3. There is no such method. -DEFINE_RUNTIME_ENTRY(InstanceFunctionLookup, 4) { - const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); - const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); - const Array& args_descriptor = Array::CheckedHandle(arguments.ArgAt(2)); - const Array& args = Array::CheckedHandle(arguments.ArgAt(3)); - - const Class& receiver_class = Class::Handle(receiver.clazz()); - const String& target_name = String::Handle(ic_data.target_name()); - - Object& result = Object::Handle(); - if (!ResolveCallThroughGetter(receiver, - receiver_class, - target_name, - args_descriptor, - args, - ic_data, - &result)) { - ArgumentsDescriptor desc(args_descriptor); - const Function& target_function = - Function::Handle(receiver_class.GetInvocationDispatcher( - target_name, - args_descriptor, - RawFunction::kNoSuchMethodDispatcher)); - // Update IC data. - ASSERT(!target_function.IsNull()); - intptr_t receiver_cid = receiver.GetClassId(); - if (ic_data.num_args_tested() == 1) { - // In optimized code we may enter into here via the - // MegamorphicCacheMissHandler since noSuchMethod dispatchers are not - // inserted into the megamorphic cache. Therefore, we need to guard - // against entering the same check twice into the ICData. - // Note that num_args_tested == 1 in optimized code. - // TODO(fschneider): Handle extraordinary cases like noSuchMethod and - // implicit closure invocation properly in the megamorphic cache. - const Function& target = - Function::Handle(ic_data.GetTargetForReceiverClassId(receiver_cid)); - if (target.IsNull()) { - ic_data.AddReceiverCheck(receiver_cid, target_function); - } - } else { - // Operators calls have two or three arguments tested ([], []=, etc.) - ASSERT(ic_data.num_args_tested() > 1); - GrowableArray class_ids(ic_data.num_args_tested()); - class_ids.Add(receiver_cid); - for (intptr_t i = 1; i < ic_data.num_args_tested(); ++i) { - class_ids.Add(Object::Handle(args.At(i)).GetClassId()); - } - ic_data.AddCheck(class_ids, target_function); - } - if (FLAG_trace_ic) { - OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n", - Class::Handle(receiver.clazz()).ToCString(), - receiver_cid, - target_function.ToCString()); - } - result = DartEntry::InvokeFunction(target_function, args, args_descriptor); - } - CheckResultError(result); - arguments.SetReturn(result); -} - - static bool CanOptimizeFunction(const Function& function, Isolate* isolate) { const intptr_t kLowInvocationCount = -100000000; if (isolate->debugger()->IsStepping() || diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h index 61bbd050034..aeb63572081 100644 --- a/runtime/vm/code_generator.h +++ b/runtime/vm/code_generator.h @@ -28,7 +28,6 @@ DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerOneArg); DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerTwoArgs); DECLARE_RUNTIME_ENTRY(InlineCacheMissHandlerThreeArgs); DECLARE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs); -DECLARE_RUNTIME_ENTRY(InstanceFunctionLookup); DECLARE_RUNTIME_ENTRY(Instanceof); DECLARE_RUNTIME_ENTRY(TypeCheck); DECLARE_RUNTIME_ENTRY(BadTypeError); @@ -47,7 +46,6 @@ DECLARE_RUNTIME_ENTRY(Throw); DECLARE_RUNTIME_ENTRY(TraceFunctionEntry); DECLARE_RUNTIME_ENTRY(TraceFunctionExit); DECLARE_RUNTIME_ENTRY(DeoptimizeMaterialize); -DECLARE_RUNTIME_ENTRY(UpdateICDataTwoArgs); DECLARE_RUNTIME_ENTRY(UpdateFieldCid); #define DEOPT_REASONS(V) \ @@ -89,9 +87,6 @@ DEOPT_REASONS(DEFINE_ENUM_LIST) const char* DeoptReasonToText(intptr_t deopt_id); -RawCode* ResolveCompileInstanceCallTarget(const Instance& receiver, - const ICData& ic_data); - void DeoptimizeAt(const Code& optimized_code, uword pc); void DeoptimizeAll(); diff --git a/runtime/vm/instructions_arm_test.cc b/runtime/vm/instructions_arm_test.cc index 46dbb1c9549..a7232586993 100644 --- a/runtime/vm/instructions_arm_test.cc +++ b/runtime/vm/instructions_arm_test.cc @@ -16,7 +16,7 @@ namespace dart { #define __ assembler-> ASSEMBLER_TEST_GENERATE(Call, assembler) { - __ BranchLinkPatchable(&StubCode::InstanceFunctionLookupLabel()); + __ BranchLinkPatchable(&StubCode::InvokeDartCodeLabel()); __ Ret(); } @@ -27,13 +27,13 @@ ASSEMBLER_TEST_RUN(Call, test) { // before the end of the code buffer. CallPattern call(test->entry() + test->code().Size() - Instr::kInstrSize, test->code()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), call.TargetAddress()); } ASSEMBLER_TEST_GENERATE(Jump, assembler) { - __ BranchPatchable(&StubCode::InstanceFunctionLookupLabel()); + __ BranchPatchable(&StubCode::InvokeDartCodeLabel()); __ BranchPatchable(&StubCode::AllocateArrayLabel()); } @@ -47,7 +47,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { VirtualMemory::kReadWrite); EXPECT(status); JumpPattern jump1(test->entry(), test->code()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump1.TargetAddress()); JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(), test->code()); @@ -59,7 +59,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { jump2.SetTargetAddress(target1); EXPECT_EQ(StubCode::AllocateArrayLabel().address(), jump1.TargetAddress()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump2.TargetAddress()); } @@ -68,7 +68,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { ASSEMBLER_TEST_GENERATE(JumpARMv6, assembler) { // ARMv7 is the default. HostCPUFeatures::set_arm_version(ARMv6); - __ BranchPatchable(&StubCode::InstanceFunctionLookupLabel()); + __ BranchPatchable(&StubCode::InvokeDartCodeLabel()); __ BranchPatchable(&StubCode::AllocateArrayLabel()); HostCPUFeatures::set_arm_version(ARMv7); } @@ -84,7 +84,7 @@ ASSEMBLER_TEST_RUN(JumpARMv6, test) { VirtualMemory::kReadWrite); EXPECT(status); JumpPattern jump1(test->entry(), test->code()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump1.TargetAddress()); JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(), test->code()); @@ -96,7 +96,7 @@ ASSEMBLER_TEST_RUN(JumpARMv6, test) { jump2.SetTargetAddress(target1); EXPECT_EQ(StubCode::AllocateArrayLabel().address(), jump1.TargetAddress()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump2.TargetAddress()); HostCPUFeatures::set_arm_version(ARMv7); } diff --git a/runtime/vm/instructions_ia32_test.cc b/runtime/vm/instructions_ia32_test.cc index 637f72e6cef..43c804c1372 100644 --- a/runtime/vm/instructions_ia32_test.cc +++ b/runtime/vm/instructions_ia32_test.cc @@ -17,20 +17,20 @@ namespace dart { #define __ assembler-> ASSEMBLER_TEST_GENERATE(Call, assembler) { - __ call(&StubCode::InstanceFunctionLookupLabel()); + __ call(&StubCode::InvokeDartCodeLabel()); __ ret(); } ASSEMBLER_TEST_RUN(Call, test) { CallPattern call(test->entry()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), call.TargetAddress()); } ASSEMBLER_TEST_GENERATE(Jump, assembler) { - __ jmp(&StubCode::InstanceFunctionLookupLabel()); + __ jmp(&StubCode::InvokeDartCodeLabel()); __ jmp(&StubCode::AllocateArrayLabel()); __ ret(); } @@ -45,7 +45,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { VirtualMemory::kReadWrite); EXPECT(status); JumpPattern jump1(test->entry(), test->code()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump1.TargetAddress()); JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(), test->code()); @@ -57,7 +57,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { jump2.SetTargetAddress(target1); EXPECT_EQ(StubCode::AllocateArrayLabel().address(), jump1.TargetAddress()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump2.TargetAddress()); } diff --git a/runtime/vm/instructions_mips_test.cc b/runtime/vm/instructions_mips_test.cc index 4aff913d6e4..365395e9bd0 100644 --- a/runtime/vm/instructions_mips_test.cc +++ b/runtime/vm/instructions_mips_test.cc @@ -15,7 +15,7 @@ namespace dart { #define __ assembler-> ASSEMBLER_TEST_GENERATE(Call, assembler) { - __ BranchLinkPatchable(&StubCode::InstanceFunctionLookupLabel()); + __ BranchLinkPatchable(&StubCode::InvokeDartCodeLabel()); __ Ret(); } @@ -27,13 +27,13 @@ ASSEMBLER_TEST_RUN(Call, test) { // return jump. CallPattern call(test->entry() + test->code().Size() - (2*Instr::kInstrSize), test->code()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), call.TargetAddress()); } ASSEMBLER_TEST_GENERATE(Jump, assembler) { - __ BranchPatchable(&StubCode::InstanceFunctionLookupLabel()); + __ BranchPatchable(&StubCode::InvokeDartCodeLabel()); __ BranchPatchable(&StubCode::AllocateArrayLabel()); } @@ -47,7 +47,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { VirtualMemory::kReadWrite); EXPECT(status); JumpPattern jump1(test->entry(), test->code()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump1.TargetAddress()); JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(), test->code()); @@ -59,7 +59,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { jump2.SetTargetAddress(target1); EXPECT_EQ(StubCode::AllocateArrayLabel().address(), jump1.TargetAddress()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump2.TargetAddress()); } diff --git a/runtime/vm/instructions_x64_test.cc b/runtime/vm/instructions_x64_test.cc index 5cd4c8d0c11..c21777515ee 100644 --- a/runtime/vm/instructions_x64_test.cc +++ b/runtime/vm/instructions_x64_test.cc @@ -15,14 +15,14 @@ namespace dart { #define __ assembler-> ASSEMBLER_TEST_GENERATE(Call, assembler) { - __ call(&StubCode::InstanceFunctionLookupLabel()); + __ call(&StubCode::InvokeDartCodeLabel()); __ ret(); } ASSEMBLER_TEST_RUN(Call, test) { CallPattern call(test->entry(), test->code()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), call.TargetAddress()); } @@ -35,7 +35,7 @@ ASSEMBLER_TEST_GENERATE(Jump, assembler) { __ pushq(PP); __ LoadPoolPointer(PP); prologue_code_size = assembler->CodeSize(); - __ JmpPatchable(&StubCode::InstanceFunctionLookupLabel(), PP); + __ JmpPatchable(&StubCode::InvokeDartCodeLabel(), PP); __ JmpPatchable(&StubCode::AllocateArrayLabel(), PP); __ popq(PP); __ ret(); @@ -53,7 +53,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { EXPECT(status); JumpPattern jump1(test->entry() + prologue_code_size, test->code()); jump1.IsValid(); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump1.TargetAddress()); JumpPattern jump2((test->entry() + jump1.pattern_length_in_bytes() + prologue_code_size), @@ -66,7 +66,7 @@ ASSEMBLER_TEST_RUN(Jump, test) { jump2.SetTargetAddress(target1); EXPECT_EQ(StubCode::AllocateArrayLabel().address(), jump1.TargetAddress()); - EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(), + EXPECT_EQ(StubCode::InvokeDartCodeLabel().address(), jump2.TargetAddress()); } diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc index a1c4b44d82d..ce45fce2c27 100644 --- a/runtime/vm/stack_frame_test.cc +++ b/runtime/vm/stack_frame_test.cc @@ -261,17 +261,15 @@ TEST_CASE(ValidateNoSuchMethodStackFrameIteration) { "class StackFrame2Test {" " StackFrame2Test() {}" " noSuchMethod(Invocation im) {" - " /* We should have 8 general frames and 3 dart frames as follows:" + " /* We should have 6 general frames and 4 dart frames as follows:" " * exit frame" " * dart frame corresponding to StackFrame.frameCount" " * dart frame corresponding to StackFrame2Test.noSuchMethod" - " * entry frame" - " * exit frame" " * frame for instance function invocation stub calling noSuchMethod" " * dart frame corresponding to StackFrame2Test.testMain" " * entry frame" " */" - " StackFrame.equals(9, StackFrame.frameCount());" + " StackFrame.equals(6, StackFrame.frameCount());" " StackFrame.equals(4, StackFrame.dartFrameCount());" " StackFrame.validateFrame(0, \"StackFrame_validateFrame\");" " StackFrame.validateFrame(1, \"StackFrame2Test_noSuchMethod\");" diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h index 805c5d9d4ae..19f41a2d41a 100644 --- a/runtime/vm/stub_code.h +++ b/runtime/vm/stub_code.h @@ -27,7 +27,6 @@ class RawCode; V(CallNativeCFunction) \ V(AllocateArray) \ V(CallNoSuchMethodFunction) \ - V(InstanceFunctionLookup) \ V(CallStaticFunction) \ V(CallClosureFunction) \ V(FixCallersTarget) \ diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc index 1ba7a0e8ecd..8f690b9b6d4 100644 --- a/runtime/vm/stub_code_arm.cc +++ b/runtime/vm/stub_code_arm.cc @@ -437,40 +437,6 @@ static void PushArgumentsArray(Assembler* assembler) { } -// Input parameters: -// R5: ic-data. -// R4: arguments descriptor array. -// Note: The receiver object is the first argument to the function being -// called, the stub accesses the receiver from this location directly -// when trying to resolve the call. -void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { - __ EnterStubFrame(); - - // Load the receiver. - __ ldr(R2, FieldAddress(R4, ArgumentsDescriptor::count_offset())); - __ add(IP, FP, ShifterOperand(R2, LSL, 1)); // R2 is Smi. - __ ldr(R6, Address(IP, kParamEndSlotFromFp * kWordSize)); - - // Push space for the return value. - // Push the receiver. - // Push IC data object. - // Push arguments descriptor array. - __ LoadImmediate(IP, reinterpret_cast(Object::null())); - __ PushList((1 << R4) | (1 << R5) | (1 << R6) | (1 << IP)); - - // R2: Smi-tagged arguments array length. - PushArgumentsArray(assembler); - - __ CallRuntime(kInstanceFunctionLookupRuntimeEntry, 4); - - // Remove arguments. - __ Drop(4); - __ Pop(R0); // Get result into R0. - __ LeaveStubFrame(); - __ Ret(); -} - - DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, intptr_t deopt_reason, uword saved_registers_address); @@ -615,17 +581,18 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); // Remove arguments. __ Drop(3); - __ Pop(R0); // Get result into R0. + __ Pop(R0); // Get result into R0 (target function). // Restore IC data and arguments descriptor. __ PopList((1 << R4) | (1 << R5)); __ LeaveStubFrame(); - __ CompareImmediate(R0, reinterpret_cast(Object::null())); - __ Branch(&StubCode::InstanceFunctionLookupLabel(), EQ); - __ AddImmediate(R0, Instructions::HeaderSize() - kHeapObjectTag); - __ bx(R0); + // Tail-call to target function. + __ ldr(R2, FieldAddress(R0, Function::code_offset())); + __ ldr(R2, FieldAddress(R2, Code::instructions_offset())); + __ AddImmediate(R2, Instructions::HeaderSize() - kHeapObjectTag); + __ bx(R2); } @@ -1465,19 +1432,12 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( __ CallRuntime(handle_ic_miss, num_args + 1); // Remove the call arguments pushed earlier, including the IC data object. __ Drop(num_args + 1); - // Pop returned code object into R0 (null if not found). + // Pop returned function object into R0. // Restore arguments descriptor array and IC data array. __ PopList((1 << R0) | (1 << R4) | (1 << R5)); __ LeaveStubFrame(); Label call_target_function; - __ CompareImmediate(R0, reinterpret_cast(Object::null())); - __ b(&call_target_function, NE); - // NoSuchMethod or closure. - // Mark IC call that it may be a closure call that does not collect - // type feedback. - __ mov(IP, ShifterOperand(1)); - __ strb(IP, FieldAddress(R5, ICData::is_closure_call_offset())); - __ Branch(&StubCode::InstanceFunctionLookupLabel()); + __ b(&call_target_function); __ Bind(&found); // R6: pointer to an IC data check group. diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc index 44c7ca5601f..e32ddd25ac9 100644 --- a/runtime/vm/stub_code_ia32.cc +++ b/runtime/vm/stub_code_ia32.cc @@ -396,44 +396,6 @@ static void PushArgumentsArray(Assembler* assembler) { } -// Input parameters: -// ECX: ic-data. -// EDX: arguments descriptor array. -// Note: The receiver object is the first argument to the function being -// called, the stub accesses the receiver from this location directly -// when trying to resolve the call. -// Uses EDI. -void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { - __ EnterStubFrame(); - - const Immediate& raw_null = - Immediate(reinterpret_cast(Object::null())); - __ pushl(raw_null); // Space for the return value. - - // Push the receiver as an argument. Load the smi-tagged argument - // count into EDI to index the receiver in the stack. There are - // three words (null, stub's pc marker, saved fp) above the return - // address. - __ movl(EDI, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); - __ pushl(Address(ESP, EDI, TIMES_2, (3 * kWordSize))); - - __ pushl(ECX); // Pass IC data object. - __ pushl(EDX); // Pass arguments descriptor array. - - // Pass the call's arguments array. - __ movl(EDX, EDI); // Smi-tagged arguments array length. - PushArgumentsArray(assembler); - - __ CallRuntime(kInstanceFunctionLookupRuntimeEntry, 4); - - // Remove arguments. - __ Drop(4); - __ popl(EAX); // Get result into EAX. - __ LeaveFrame(); - __ ret(); -} - - DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, intptr_t deopt_reason, uword saved_registers_address); @@ -583,19 +545,15 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { __ popl(EAX); __ popl(EAX); __ popl(EAX); - __ popl(EAX); // Return value from the runtime call (instructions). + __ popl(EAX); // Return value from the runtime call (function). __ popl(EDX); // Restore arguments descriptor. __ popl(ECX); // Restore IC data. __ LeaveFrame(); - Label lookup; - __ cmpl(EAX, raw_null); - __ j(EQUAL, &lookup, Assembler::kNearJump); - __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); - __ jmp(EAX); - - __ Bind(&lookup); - __ jmp(&StubCode::InstanceFunctionLookupLabel()); + __ movl(EBX, FieldAddress(EAX, Function::code_offset())); + __ movl(EBX, FieldAddress(EBX, Code::instructions_offset())); + __ addl(EBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); + __ jmp(EBX); } @@ -1462,18 +1420,12 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( for (intptr_t i = 0; i < num_args + 1; i++) { __ popl(EAX); } - __ popl(EAX); // Pop returned code object into EAX (null if not found). + __ popl(EAX); // Pop returned function object into EAX. __ popl(ECX); // Restore IC data array. __ popl(EDX); // Restore arguments descriptor array. __ LeaveFrame(); Label call_target_function; - __ cmpl(EAX, raw_null); - __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); - // NoSuchMethod or closure. - // Mark IC call that it may be a closure call that does not collect - // type feedback. - __ movb(FieldAddress(ECX, ICData::is_closure_call_offset()), Immediate(1)); - __ jmp(&StubCode::InstanceFunctionLookupLabel()); + __ jmp(&call_target_function); __ Bind(&found); // EBX: Pointer to an IC data check group. diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc index ca88eca317b..3023f542114 100644 --- a/runtime/vm/stub_code_mips.cc +++ b/runtime/vm/stub_code_mips.cc @@ -492,46 +492,6 @@ static void PushArgumentsArray(Assembler* assembler) { } -// Input parameters: -// S5: ic-data. -// S4: arguments descriptor array. -// Note: The receiver object is the first argument to the function being -// called, the stub accesses the receiver from this location directly -// when trying to resolve the call. -void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { - __ TraceSimMsg("InstanceFunctionLookupStub"); - __ EnterStubFrame(); - - // Load the receiver. - __ lw(A1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); - __ sll(TMP, A1, 1); // A1 is Smi. - __ addu(TMP, FP, TMP); - __ lw(T1, Address(TMP, kParamEndSlotFromFp * kWordSize)); - - // Push space for the return value. - // Push the receiver. - // Push TMP data object. - // Push arguments descriptor array. - __ addiu(SP, SP, Immediate(-4 * kWordSize)); - __ LoadImmediate(TMP, reinterpret_cast(Object::null())); - __ sw(TMP, Address(SP, 3 * kWordSize)); - __ sw(T1, Address(SP, 2 * kWordSize)); - __ sw(S5, Address(SP, 1 * kWordSize)); - __ sw(S4, Address(SP, 0 * kWordSize)); - - // A1: Smi-tagged arguments array length. - PushArgumentsArray(assembler); - __ TraceSimMsg("InstanceFunctionLookupStub return"); - - __ CallRuntime(kInstanceFunctionLookupRuntimeEntry, 4); - - __ lw(V0, Address(SP, 4 * kWordSize)); // Get result into V0. - __ addiu(SP, SP, Immediate(5 * kWordSize)); // Remove arguments. - - __ LeaveStubFrameAndReturn(); -} - - DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, intptr_t deopt_reason, uword saved_registers_address); @@ -708,19 +668,17 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); - __ lw(T0, Address(SP, 3 * kWordSize)); // Get result. + __ lw(T0, Address(SP, 3 * kWordSize)); // Get result function. __ lw(S4, Address(SP, 4 * kWordSize)); // Restore argument descriptor. __ lw(S5, Address(SP, 5 * kWordSize)); // Restore IC data. __ addiu(SP, SP, Immediate(6 * kWordSize)); __ LeaveStubFrame(); - Label nonnull; - __ BranchNotEqual(T0, reinterpret_cast(Object::null()), &nonnull); - __ Branch(&StubCode::InstanceFunctionLookupLabel()); - __ Bind(&nonnull); - __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag); - __ jr(T0); + __ lw(T2, FieldAddress(T0, Function::code_offset())); + __ lw(T2, FieldAddress(T2, Code::instructions_offset())); + __ AddImmediate(T2, Instructions::HeaderSize() - kHeapObjectTag); + __ jr(T2); } @@ -1676,7 +1634,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( __ sw(S5, Address(SP, (num_slots - num_args - 4) * kWordSize)); __ CallRuntime(handle_ic_miss, num_args + 1); __ TraceSimMsg("NArgsCheckInlineCacheStub return"); - // Pop returned code object into T3 (null if not found). + // Pop returned function object into T3. // Restore arguments descriptor array and IC data array. __ lw(T3, Address(SP, (num_slots - 3) * kWordSize)); __ lw(S4, Address(SP, (num_slots - 2) * kWordSize)); @@ -1685,16 +1643,9 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( // and the arguments descriptor array. __ addiu(SP, SP, Immediate(num_slots * kWordSize)); __ LeaveStubFrame(); - Label call_target_function; - __ BranchNotEqual(T3, reinterpret_cast(Object::null()), - &call_target_function); - // NoSuchMethod or closure. - // Mark IC call that it may be a closure call that does not collect - // type feedback. - __ LoadImmediate(T6, 1); - __ Branch(&StubCode::InstanceFunctionLookupLabel()); - __ delay_slot()->sb(T6, FieldAddress(S5, ICData::is_closure_call_offset())); + Label call_target_function; + __ b(&call_target_function); __ Bind(&found); // T0: Pointer to an IC data check group. diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc index 5838b36ea48..e43c3229c59 100644 --- a/runtime/vm/stub_code_x64.cc +++ b/runtime/vm/stub_code_x64.cc @@ -381,40 +381,6 @@ static void PushArgumentsArray(Assembler* assembler) { } -// Input parameters: -// RBX: ic-data. -// R10: arguments descriptor array. -// Note: The receiver object is the first argument to the function being -// called, the stub accesses the receiver from this location directly -// when trying to resolve the call. -void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { - __ EnterStubFrame(); - __ PushObject(Object::null_object(), PP); // Space for the return value. - - // Push the receiver as an argument. Load the smi-tagged argument - // count into R13 to index the receiver in the stack. There are - // four words (null, stub's pc marker, saved pp, saved fp) above the return - // address. - __ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset())); - __ pushq(Address(RSP, R13, TIMES_4, (4 * kWordSize))); - - __ pushq(RBX); // Pass IC data object. - __ pushq(R10); // Pass arguments descriptor array. - - // Pass the call's arguments array. - __ movq(R10, R13); // Smi-tagged arguments array length. - PushArgumentsArray(assembler); - - __ CallRuntime(kInstanceFunctionLookupRuntimeEntry, 4); - - // Remove arguments. - __ Drop(4); - __ popq(RAX); // Get result into RAX. - __ LeaveStubFrame(); - __ ret(); -} - - DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, intptr_t deopt_reason, uword saved_registers_address); @@ -578,19 +544,15 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { __ popq(RAX); __ popq(RAX); __ popq(RAX); - __ popq(RAX); // Return value from the runtime call (instructions). + __ popq(RAX); // Return value from the runtime call (function). __ popq(R10); // Restore arguments descriptor. __ popq(RBX); // Restore IC data. __ LeaveStubFrame(); - Label lookup; - __ CompareObject(RAX, Object::null_object(), PP); - __ j(EQUAL, &lookup, Assembler::kNearJump); - __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); - __ jmp(RAX); - - __ Bind(&lookup); - __ jmp(&StubCode::InstanceFunctionLookupLabel()); + __ movq(RCX, FieldAddress(RAX, Function::code_offset())); + __ movq(RCX, FieldAddress(RCX, Code::instructions_offset())); + __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); + __ jmp(RCX); } @@ -766,11 +728,11 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { __ movq(CTX, FieldAddress(R13, Closure::context_offset())); // Load closure function code in RAX. - __ movq(RBX, FieldAddress(RAX, Function::code_offset())); + __ movq(RCX, FieldAddress(RAX, Function::code_offset())); // RAX: Function. // R10: Arguments descriptor array. - __ movq(RCX, FieldAddress(RBX, Code::instructions_offset())); + __ movq(RCX, FieldAddress(RCX, Code::instructions_offset())); __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); __ jmp(RCX); @@ -1446,18 +1408,12 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( for (intptr_t i = 0; i < num_args + 1; i++) { __ popq(RAX); } - __ popq(RAX); // Pop returned code object into RAX (null if not found). + __ popq(RAX); // Pop returned function object into RAX. __ popq(RBX); // Restore IC data array. __ popq(R10); // Restore arguments descriptor array. __ LeaveStubFrame(); Label call_target_function; - __ cmpq(RAX, R12); - __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); - // NoSuchMethod or closure. - // Mark IC call that it may be a closure call that does not collect - // type feedback. - __ movb(FieldAddress(RBX, ICData::is_closure_call_offset()), Immediate(1)); - __ jmp(&StubCode::InstanceFunctionLookupLabel()); + __ jmp(&call_target_function); __ Bind(&found); // R12: Pointer to an IC data check group.