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:
+92
-206
@@ -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() ||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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\");"
|
||||
|
||||
@@ -27,7 +27,6 @@ class RawCode;
|
||||
V(CallNativeCFunction) \
|
||||
V(AllocateArray) \
|
||||
V(CallNoSuchMethodFunction) \
|
||||
V(InstanceFunctionLookup) \
|
||||
V(CallStaticFunction) \
|
||||
V(CallClosureFunction) \
|
||||
V(FixCallersTarget) \
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user