Index: vm/code_generator.cc |
=================================================================== |
--- vm/code_generator.cc (revision 700) |
+++ vm/code_generator.cc (working copy) |
@@ -7,10 +7,10 @@ |
#include "vm/code_index_table.h" |
#include "vm/code_patcher.h" |
#include "vm/compiler.h" |
+#include "vm/dart_api_impl.h" |
#include "vm/dart_entry.h" |
#include "vm/exceptions.h" |
#include "vm/ic_data.h" |
-#include "vm/ic_stubs.h" |
#include "vm/object_store.h" |
#include "vm/resolver.h" |
#include "vm/runtime_entry.h" |
@@ -421,6 +421,7 @@ |
// Returns: RawCode object or NULL (method not found or not compileable). |
// This is called by the megamorphic stub when instance call does not need to be |
// patched. |
+// Used by megamorphic lookup/no-such-method-handling. |
DEFINE_RUNTIME_ENTRY(ResolveCompileInstanceFunction, 1) { |
ASSERT(arguments.Count() == |
kResolveCompileInstanceFunctionRuntimeEntry.argument_count()); |
@@ -430,100 +431,44 @@ |
} |
-// Resolve instance call and patch it to jump to IC stub or megamorphic stub. |
-// After patching the caller's instance call instruction, that call will |
-// be reexecuted and ran through the created IC stub. The null receivers |
-// have special handling, i.e., they lead to megamorphic lookup that implements |
-// the appropriate null behavior. |
-// Arg0: receiver object. |
-DEFINE_RUNTIME_ENTRY(ResolvePatchInstanceCall, 1) { |
+// Handles inline cache misses bu updating the IC data array of the call |
regis
2011/10/25 18:06:27
bu -> by
srdjan
2011/10/25 18:28:50
Done.
|
+// site. |
+// Arg0: Receiver object. |
+// Returns: target function with compiled code or 0. |
+// Modifies the instance call to hold the updated IC data array. |
+DEFINE_RUNTIME_ENTRY(InlineCacheMissHandler, 1) { |
ASSERT(arguments.Count() == |
- kResolvePatchInstanceCallRuntimeEntry.argument_count()); |
+ kInlineCacheMissHandlerRuntimeEntry.argument_count()); |
const Instance& receiver = Instance::CheckedHandle(arguments.At(0)); |
- const Code& code = Code::Handle(ResolveCompileInstanceCallTarget(receiver)); |
+ const Code& target_code = |
+ Code::Handle(ResolveCompileInstanceCallTarget(receiver)); |
+ if (target_code.IsNull()) { |
+ // Let the megamorphic stub handle special cases: NoSuchMethod, |
+ // closure calls. |
+ arguments.SetReturn(target_code); |
+ return; |
+ } |
+ const Function& target_function = |
+ Function::Handle(target_code.function()); |
+ ASSERT(!target_function.IsNull()); |
+ if (receiver.IsNull()) { |
+ // Null dispatch is slow (e.g., (null).toCString()). The only |
+ // fast execution with null receiver is the "==" operator. |
+ // Special handling so that we do not pollute the inline cache with null |
+ // classes. |
+ arguments.SetReturn(target_function); |
+ return; |
+ } |
DartFrameIterator iterator; |
DartFrame* caller_frame = iterator.NextFrame(); |
- String& function_name = String::Handle(); |
- if ((!receiver.IsNull() && code.IsNull()) || !FLAG_inline_cache) { |
- // We did not find a method; it means either that we need to invoke |
- // noSuchMethod or that we have encountered a situation with implicit |
- // closures. All these cases are handled by the megamorphic lookup stub. |
- CodePatcher::PatchInstanceCallAt( |
- caller_frame->pc(), StubCode::MegamorphicLookupEntryPoint()); |
- if (FLAG_trace_ic) { |
- OS::Print("IC: cannot find function at 0x%x -> megamorphic lookup.\n", |
- caller_frame->pc()); |
- } |
- if (FLAG_trace_patching) { |
- OS::Print("ResolvePatchInstanceCall: patching 0x%x to megamorphic\n", |
- caller_frame->pc()); |
- } |
- } else { |
- int num_arguments = -1; |
- int num_named_arguments = -1; |
- uword caller_target = 0; |
- CodePatcher::GetInstanceCallAt(caller_frame->pc(), |
- &function_name, |
- &num_arguments, |
- &num_named_arguments, |
- &caller_target); |
- // If caller_target is not in CallInstanceFunction stub (resolve call) |
- // then it must be pointing to an IC stub. |
- const Class& receiver_class = Class::ZoneHandle(receiver.clazz()); |
- const bool ic_miss = |
- !StubCode::InCallInstanceFunctionStubCode(caller_target); |
- GrowableArray<const Class*> classes; |
- GrowableArray<const Function*> targets; |
- if (ic_miss) { |
- bool is_ic = |
- ICStubs::RecognizeICStub(caller_target, &classes, &targets); |
- ASSERT(is_ic); |
- ASSERT(classes.length() == targets.length()); |
- // The returned classes array can be empty if the first patch occured |
- // with a null class. 'receiver_class' should not exists. |
- ASSERT(ICStubs::IndexOfClass(classes, receiver_class) < 0); |
- ASSERT(!code.IsNull()); |
- ASSERT(!receiver_class.IsNullClass()); |
- const Function& function = Function::ZoneHandle(code.function()); |
- targets.Add(&function); |
- classes.Add(&receiver_class); |
- } else { |
- // First patch of instance call. |
- // Do not add classes for null receiver. For first IC patch it means that |
- // the IC will always miss and jump to megamorphic lookup (null handling). |
- if (!receiver_class.IsNullClass()) { |
- ASSERT(!code.IsNull()); |
- const Function& function = Function::ZoneHandle(code.function()); |
- targets.Add(&function); |
- classes.Add(&receiver_class); |
- } |
- } |
- const Code& ic_code = Code::Handle(ICStubs::GetICStub(classes, targets)); |
- if (FLAG_trace_ic) { |
- CodeIndexTable* ci_table = Isolate::Current()->code_index_table(); |
- ASSERT(ci_table != NULL); |
- const Function& caller = |
- Function::Handle(ci_table->LookupFunction(caller_frame->pc())); |
- const char* patch_kind = ic_miss ? "miss" : "patch"; |
- OS::Print("IC %s at 0x%x '%s' (receiver:'%s' function:'%s')", |
- patch_kind, |
- caller_frame->pc(), |
- String::Handle(caller.name()).ToCString(), |
- receiver.ToCString(), |
- function_name.ToCString()); |
- OS::Print(" patched to 0x%x\n", ic_code.EntryPoint()); |
- if (ic_miss) { |
- for (int i = 0; i < classes.length(); i++) { |
- OS::Print(" IC Miss on %s\n", classes[i]->ToCString()); |
- } |
- } |
- } |
- CodePatcher::PatchInstanceCallAt(caller_frame->pc(), ic_code.EntryPoint()); |
- if (FLAG_trace_patching) { |
- OS::Print("ResolvePatchInstanceCall: patching 0x%x to ic 0x%x\n", |
- caller_frame->pc(), ic_code.EntryPoint()); |
- } |
- } |
+ ICData ic_data(Array::Handle( |
+ CodePatcher::GetInstanceCallIcDataAt(caller_frame->pc()))); |
+ GrowableArray<const Class*> classes; |
+ classes.Add(&Class::ZoneHandle(receiver.clazz())); |
+ ic_data.AddCheck(classes, target_function); |
+ CodePatcher::SetInstanceCallIcDataAt(caller_frame->pc(), |
+ Array::ZoneHandle(ic_data.data())); |
+ arguments.SetReturn(target_function); |
} |
@@ -797,32 +742,6 @@ |
} |
-static void DisableOldCode(const Function& function, |
- const Code& old_code, |
- const Code& new_code) { |
- const Array& class_ic_stubs = Array::Handle(old_code.class_ic_stubs()); |
- if (function.IsClosureFunction()) { |
- // Nothing to do, code may not have inline caches. |
- ASSERT(class_ic_stubs.Length() == 0); |
- return; |
- } |
- if (function.is_static() || function.IsConstructor()) { |
- ASSERT(class_ic_stubs.Length() == 0); |
- return; |
- } |
- Code& ic_stub = Code::Handle(); |
- for (int i = 0; i < class_ic_stubs.Length(); i += 2) { |
- // i: array of classes, i + 1: ic stub code. |
- ic_stub ^= class_ic_stubs.At(i + 1); |
- ICStubs::PatchTargets(ic_stub.EntryPoint(), |
- old_code.EntryPoint(), |
- new_code.EntryPoint()); |
- } |
- new_code.set_class_ic_stubs(class_ic_stubs); |
- old_code.set_class_ic_stubs(Array::Handle(Array::Empty())); |
-} |
- |
- |
// Only unoptimized code has invocation counter threshold checking. |
// Once the invocation counter threshold is reached any entry into the |
// unoptimized code is redirected to this function. |
@@ -838,7 +757,6 @@ |
const Code& optimized_code = Code::Handle(function.code()); |
ASSERT(!optimized_code.IsNull()); |
ASSERT(!unoptimized_code.IsNull()); |
- DisableOldCode(function, unoptimized_code, optimized_code); |
} else { |
// TODO(5442338): Abort as this should not happen. |
function.set_invocation_counter(0); |
@@ -930,8 +848,6 @@ |
// Get unoptimized code. Compilation restores (reenables) the entry of |
// unoptimized code. |
Compiler::CompileFunction(function); |
- |
- DisableOldCode(function, optimized_code, unoptimized_code); |
} |
// TODO(srdjan): Handle better complex cases, e.g. when an older optimized |
// code is alive on frame and gets deoptimized after the function was |