Index: runtime/vm/code_generator.cc |
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
index bc33bca5998156f222e6cc78b0f023b858511200..e7c4225461e45dee005ea8fd4ab38bf8022105b1 100644 |
--- a/runtime/vm/code_generator.cc |
+++ b/runtime/vm/code_generator.cc |
@@ -61,6 +61,7 @@ DEFINE_FLAG(bool, trace_type_checks, false, "Trace runtime type checks."); |
DECLARE_FLAG(int, deoptimization_counter_threshold); |
DECLARE_FLAG(bool, trace_compiler); |
DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
+DECLARE_FLAG(int, max_polymorphic_checks); |
DEFINE_FLAG(bool, use_osr, true, "Use on-stack replacement."); |
DEFINE_FLAG(bool, trace_osr, false, "Trace attempts at on-stack replacement."); |
@@ -779,11 +780,9 @@ static bool ResolveCallThroughGetter(const Instance& receiver, |
// 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 Array& args_descriptor, |
+ const String& target_name) { |
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, |
@@ -828,7 +827,12 @@ static RawFunction* InlineCacheMissHandler( |
String::Handle(ic_data.target_name()).ToCString(), |
receiver.ToCString()); |
} |
- target_function = InlineCacheMissHelper(receiver, ic_data); |
+ const Array& args_descriptor = |
+ Array::Handle(ic_data.arguments_descriptor()); |
+ const String& target_name = String::Handle(ic_data.target_name()); |
+ target_function = InlineCacheMissHelper(receiver, |
+ args_descriptor, |
+ target_name); |
} |
if (target_function.IsNull()) { |
ASSERT(!FLAG_lazy_dispatchers); |
@@ -1014,11 +1018,15 @@ DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs, 3) { |
// 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)); |
+ const Object& ic_data_or_cache = Object::Handle(arguments.ArgAt(1)); |
const Array& descriptor = Array::CheckedHandle(arguments.ArgAt(2)); |
- const String& name = String::Handle(ic_data.target_name()); |
- const MegamorphicCache& cache = MegamorphicCache::Handle( |
- MegamorphicCacheTable::Lookup(isolate, name, descriptor)); |
+ String& name = String::Handle(); |
srdjan
2015/11/03 22:30:49
zone is already defined here, please use it for ha
rmacnak
2015/11/03 23:54:29
Done
|
+ if (ic_data_or_cache.IsICData()) { |
+ name = ICData::Cast(ic_data_or_cache).target_name(); |
+ } else { |
+ ASSERT(ic_data_or_cache.IsMegamorphicCache()); |
+ name = MegamorphicCache::Cast(ic_data_or_cache).target_name(); |
+ } |
Class& cls = Class::Handle(receiver.clazz()); |
ASSERT(!cls.IsNull()); |
if (FLAG_trace_ic || FLAG_trace_ic_miss_in_optimized) { |
@@ -1032,17 +1040,41 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { |
name, |
args_desc)); |
if (target_function.IsNull()) { |
- target_function = InlineCacheMissHelper(receiver, ic_data); |
+ target_function = InlineCacheMissHelper(receiver, descriptor, name); |
} |
if (target_function.IsNull()) { |
ASSERT(!FLAG_lazy_dispatchers); |
+ // TODO(rmacnak): Consider inserting null into the cache. |
arguments.SetReturn(target_function); |
return; |
} |
- // 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_function); |
+ |
+ if (ic_data_or_cache.IsICData()) { |
+ const ICData& ic_data = ICData::Cast(ic_data_or_cache); |
+ if (ic_data.NumberOfChecks() == FLAG_max_polymorphic_checks) { |
srdjan
2015/11/03 22:30:49
Use '>=', it is more reliable than '=='
rmacnak
2015/11/03 23:54:29
Done.
|
+ // Switch |
+ const MegamorphicCache& cache = MegamorphicCache::Handle( |
+ MegamorphicCacheTable::Lookup(isolate, name, descriptor)); |
+ DartFrameIterator iterator; |
+ StackFrame* miss_function_frame = iterator.NextFrame(); |
+ ASSERT(miss_function_frame->IsDartFrame()); |
+ StackFrame* caller_frame = iterator.NextFrame(); |
+ ASSERT(caller_frame->IsDartFrame()); |
+ const Code& code = Code::Handle(caller_frame->LookupDartCode()); |
+ const Code& stub = |
+ Code::Handle(StubCode::MegamorphicLookup_entry()->code()); |
+ CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), |
+ code, ic_data, cache, stub); |
+ } else { |
+ ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
+ } |
+ } else { |
+ const MegamorphicCache& cache = MegamorphicCache::Cast(ic_data_or_cache); |
+ // 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_function); |
+ } |
arguments.SetReturn(target_function); |
} |
@@ -1055,10 +1087,16 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { |
DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
ASSERT(!FLAG_lazy_dispatchers); |
const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0)); |
- const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1)); |
+ const Object& ic_data_or_cache = Object::Handle(arguments.ArgAt(1)); |
const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(2)); |
const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(3)); |
- const String& target_name = String::Handle(ic_data.target_name()); |
+ String& target_name = String::Handle(); |
+ if (ic_data_or_cache.IsICData()) { |
+ target_name = ICData::Cast(ic_data_or_cache).target_name(); |
+ } else { |
+ ASSERT(ic_data_or_cache.IsMegamorphicCache()); |
+ target_name = MegamorphicCache::Cast(ic_data_or_cache).target_name(); |
+ } |
Class& cls = Class::Handle(receiver.clazz()); |
Function& function = Function::Handle(); |