| 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;
|
|
|