Index: runtime/vm/code_generator.cc |
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
index bc33bca5998156f222e6cc78b0f023b858511200..9b3eb295c83059e52210650f7fca07def7f3d33b 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); |
@@ -1008,18 +1012,21 @@ DEFINE_RUNTIME_ENTRY(StaticCallMissHandlerTwoArgs, 3) { |
// Handle a miss of a megamorphic cache. |
// Arg0: Receiver. |
-// Arg1: ICData object. |
+// Arg1: ICData or MegamorphicCache. |
// Arg2: Arguments descriptor array. |
- |
// 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 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)); |
- Class& cls = Class::Handle(receiver.clazz()); |
+ const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
+ const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1)); |
+ const Array& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(2)); |
+ String& name = String::Handle(zone); |
+ 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(zone, receiver.clazz()); |
ASSERT(!cls.IsNull()); |
if (FLAG_trace_ic || FLAG_trace_ic_miss_in_optimized) { |
OS::PrintErr("Megamorphic IC miss, class=%s, function=%s\n", |
@@ -1027,41 +1034,70 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) { |
} |
ArgumentsDescriptor args_desc(descriptor); |
- Function& target_function = Function::Handle( |
+ Function& target_function = Function::Handle(zone, |
Resolver::ResolveDynamicForReceiverClass(cls, |
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); |
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); |
+ ic_data.AddReceiverCheck(receiver.GetClassId(), target_function); |
+ if (ic_data.NumberOfChecks() > FLAG_max_polymorphic_checks) { |
+ // Switch to megamorphic call. |
+ const MegamorphicCache& cache = MegamorphicCache::Handle(zone, |
+ 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(zone, caller_frame->LookupDartCode()); |
+ const Code& stub = |
+ Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code()); |
+ CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), |
+ code, ic_data, cache, stub); |
+ } |
+ } 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(zone, Smi::New(cls.id())); |
+ cache.Insert(class_id, target_function); |
+ } |
arguments.SetReturn(target_function); |
} |
// Invoke appropriate noSuchMethod or closure from getter. |
// Arg0: receiver |
-// Arg1: IC data |
+// Arg1: ICData or MegamorphicCache |
// Arg2: arguments descriptor array |
// Arg3: arguments array |
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 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()); |
+ const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0)); |
+ const Object& ic_data_or_cache = Object::Handle(zone, arguments.ArgAt(1)); |
+ const Array& orig_arguments_desc = |
+ Array::CheckedHandle(zone, arguments.ArgAt(2)); |
+ const Array& orig_arguments = Array::CheckedHandle(zone, arguments.ArgAt(3)); |
+ String& target_name = String::Handle(zone); |
+ 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(); |
+ Class& cls = Class::Handle(zone, receiver.clazz()); |
+ Function& function = Function::Handle(zone); |
// Dart distinguishes getters and regular methods and allows their calls |
// to mix with conversions, and its selectors are independent of arity. So do |
@@ -1069,7 +1105,7 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
// need for conversion, or there really is no such method. |
#define NO_SUCH_METHOD() \ |
- const Object& result = Object::Handle( \ |
+ const Object& result = Object::Handle(zone, \ |
DartEntry::InvokeNoSuchMethod(receiver, \ |
target_name, \ |
orig_arguments, \ |
@@ -1079,9 +1115,9 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
#define CLOSURIZE(some_function) \ |
const Function& closure_function = \ |
- Function::Handle(some_function.ImplicitClosureFunction()); \ |
+ Function::Handle(zone, some_function.ImplicitClosureFunction()); \ |
const Object& result = \ |
- Object::Handle(closure_function.ImplicitInstanceClosure(receiver)); \ |
+ Object::Handle(zone, closure_function.ImplicitInstanceClosure(receiver));\ |
arguments.SetReturn(result); \ |
const bool is_getter = Field::IsGetterName(target_name); |
@@ -1091,7 +1127,7 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
// encountered first on the inheritance chain. Or, |
// o#foo= (o.get:#set:foo) failed, closurize o.foo= if it exists. |
String& field_name = |
- String::Handle(Field::NameFromGetter(target_name)); |
+ String::Handle(zone, Field::NameFromGetter(target_name)); |
const bool is_extractor = field_name.CharAt(0) == '#'; |
if (is_extractor) { |
@@ -1143,14 +1179,15 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
// call method and with lazy dispatchers the field-invocation-dispatcher |
// would perform the closure call. |
const Object& result = |
- Object::Handle(DartEntry::InvokeClosure(orig_arguments, |
- orig_arguments_desc)); |
+ Object::Handle(zone, DartEntry::InvokeClosure(orig_arguments, |
+ orig_arguments_desc)); |
CheckResultError(result); |
arguments.SetReturn(result); |
return; |
} |
- const String& getter_name = String::Handle(Field::GetterName(target_name)); |
+ const String& getter_name = |
+ String::Handle(zone, Field::GetterName(target_name)); |
while (!cls.IsNull()) { |
function ^= cls.LookupDynamicFunction(target_name); |
if (!function.IsNull()) { |
@@ -1163,15 +1200,15 @@ DEFINE_RUNTIME_ENTRY(InvokeNoSuchMethodDispatcher, 4) { |
const Array& getter_arguments = Array::Handle(Array::New(1)); |
getter_arguments.SetAt(0, receiver); |
const Object& getter_result = |
- Object::Handle(DartEntry::InvokeFunction(function, |
- getter_arguments)); |
+ Object::Handle(zone, DartEntry::InvokeFunction(function, |
+ getter_arguments)); |
CheckResultError(getter_result); |
ASSERT(getter_result.IsNull() || getter_result.IsInstance()); |
orig_arguments.SetAt(0, getter_result); |
const Object& call_result = |
- Object::Handle(DartEntry::InvokeClosure(orig_arguments, |
- orig_arguments_desc)); |
+ Object::Handle(zone, DartEntry::InvokeClosure(orig_arguments, |
+ orig_arguments_desc)); |
CheckResultError(call_result); |
arguments.SetReturn(call_result); |
return; |