Simplify and improve handling of IC and megamorphic cache miss handling.

Instead of going back and forth from stub code to C++, perform
only the lookup in C++ and call target functions only from
stub code.

noSuchMethod and implicit closure invocations are now also work with
the megamorphic cache. Before they would go slow-case in the megamorphic case.

This CL eliminates the InstanceFunctionLookup stub that was previously
used to handle noSuchMethod and implicit closure invocations.

R=srdjan@google.com

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

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@34774 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
fschneider@google.com
2014-04-07 09:27:43 +00:00
parent e229ac6db2
commit 9ed4cf1cb6
12 changed files with 149 additions and 452 deletions
+92 -206
View File
@@ -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<const Instance*>& 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<const Instance*> 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<intptr_t> 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<intptr_t> 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() ||
-5
View File
@@ -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();
+8 -8
View File
@@ -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);
}
+5 -5
View File
@@ -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());
}
+5 -5
View File
@@ -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());
}
+5 -5
View File
@@ -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());
}
+2 -4
View File
@@ -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\");"
-1
View File
@@ -27,7 +27,6 @@ class RawCode;
V(CallNativeCFunction) \
V(AllocateArray) \
V(CallNoSuchMethodFunction) \
V(InstanceFunctionLookup) \
V(CallStaticFunction) \
V(CallClosureFunction) \
V(FixCallersTarget) \
+8 -48
View File
@@ -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<intptr_t>(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<intptr_t>(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<intptr_t>(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.
+7 -55
View File
@@ -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<intptr_t>(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.
+8 -57
View File
@@ -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<intptr_t>(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<int32_t>(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<int32_t>(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.
+9 -53
View File
@@ -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.