Chromium Code Reviews| Index: runtime/vm/code_generator.cc |
| diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc |
| index bc33bca5998156f222e6cc78b0f023b858511200..4557cb727371d3a4326f99286425b81e34db4db1 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,72 @@ 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); |
| + // 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) { |
| + // Switch |
| + 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); |
|
Florian Schneider
2015/11/04 01:27:10
I think target_function should be inserted in the
rmacnak
2015/11/04 01:50:22
Done.
|
| + } 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(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 +1107,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 +1117,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 +1129,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 +1181,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 +1202,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; |