Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Unified Diff: runtime/vm/code_generator.cc

Issue 221173011: Simplify handling of IC and megamorphic cache misses. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/code_generator.cc
===================================================================
--- runtime/vm/code_generator.cc (revision 34771)
+++ runtime/vm/code_generator.cc (working copy)
@@ -621,34 +621,6 @@
}
-// Resolves and compiles the target function of an instance call, updates
-// function cache of the receiver's class and returns the compiled code or null.
-// Only the number of named arguments is checked, but not the actual names.
-RawCode* ResolveCompileInstanceCallTarget(const Instance& receiver,
- const ICData& ic_data) {
- ArgumentsDescriptor
- arguments_descriptor(Array::Handle(ic_data.arguments_descriptor()));
- String& function_name = String::Handle(ic_data.target_name());
- ASSERT(function_name.IsSymbol());
-
- Function& function = Function::Handle();
- function = Resolver::ResolveDynamic(receiver,
- function_name,
- arguments_descriptor);
- if (function.IsNull()) {
- return Code::null();
- } else {
- if (!function.HasCode()) {
- const Error& error = Error::Handle(Compiler::CompileFunction(function));
- if (!error.IsNull()) {
- Exceptions::PropagateError(error);
- }
- }
- return function.CurrentCode();
- }
-}
-
-
// Result of an invoke may be an unhandled exception, in which case we
// rethrow it.
static void CheckResultError(const Object& result) {
@@ -679,24 +651,98 @@
}
+// An instance call of the form o.f(...) could not be resolved. Check if
+// there is a getter with the same name. If so, invoke it. If the value is
+// a closure, invoke it with the given arguments. If the value is a
+// non-closure, attempt to invoke "call" on it.
+static bool ResolveCallThroughGetter(const Instance& receiver,
+ const Class& receiver_class,
+ const String& target_name,
+ const Array& arguments_descriptor,
+ const ICData& ic_data,
+ Function* result) {
+ // 1. Check if there is a getter with the same name.
+ const String& getter_name = String::Handle(Field::GetterName(target_name));
+ const int kNumArguments = 1;
+ ArgumentsDescriptor args_desc(
+ Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
+ const Function& getter = Function::Handle(
+ Resolver::ResolveDynamicForReceiverClass(receiver_class,
+ getter_name,
+ args_desc));
+ if (getter.IsNull() || getter.IsMethodExtractor()) {
+ return false;
+ }
+
+ const Function& target_function =
+ Function::Handle(receiver_class.GetInvocationDispatcher(
+ target_name,
+ arguments_descriptor,
+ RawFunction::kInvokeFieldDispatcher));
+ ASSERT(!target_function.IsNull());
+ if (FLAG_trace_ic) {
+ OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
+ Class::Handle(receiver.clazz()).ToCString(),
+ receiver.GetClassId(),
+ target_function.ToCString());
+ }
+ *result = target_function.raw();
+ return true;
+}
+
+
+// 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 Class& receiver_class = Class::Handle(receiver.clazz());
+ const String& target_name = String::Handle(ic_data.target_name());
+
+ Function& result = Function::Handle();
+ if (!ResolveCallThroughGetter(receiver,
+ receiver_class,
+ target_name,
+ args_descriptor,
+ ic_data,
+ &result)) {
+ ArgumentsDescriptor desc(args_descriptor);
+ const Function& target_function =
+ Function::Handle(receiver_class.GetInvocationDispatcher(
+ target_name,
+ args_descriptor,
+ RawFunction::kNoSuchMethodDispatcher));
+ if (FLAG_trace_ic) {
+ OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
+ Class::Handle(receiver.clazz()).ToCString(),
+ receiver.GetClassId(),
+ target_function.ToCString());
+ }
+ result = target_function.raw();
+ }
+ return result.raw();
+}
+
static RawFunction* InlineCacheMissHandler(
const GrowableArray<const Instance*>& args,
const ICData& ic_data) {
const Instance& receiver = *args[0];
- const Code& target_code =
- Code::Handle(ResolveCompileInstanceCallTarget(receiver, ic_data));
- if (target_code.IsNull()) {
- // Let the megamorphic stub handle special cases: NoSuchMethod,
- // closure calls.
+ ArgumentsDescriptor
+ arguments_descriptor(Array::Handle(ic_data.arguments_descriptor()));
+ String& function_name = String::Handle(ic_data.target_name());
+ ASSERT(function_name.IsSymbol());
+ Function& target_function = Function::Handle(
+ Resolver::ResolveDynamic(receiver, function_name, arguments_descriptor));
+ if (target_function.IsNull()) {
if (FLAG_trace_ic) {
- OS::PrintErr("InlineCacheMissHandler NULL code for %s receiver: %s\n",
+ OS::PrintErr("InlineCacheMissHandler NULL function for %s receiver: %s\n",
String::Handle(ic_data.target_name()).ToCString(),
receiver.ToCString());
}
- return Function::null();
+ ic_data.set_is_closure_call(true);
+ target_function = InlineCacheMissHelper(receiver, ic_data);
}
- const Function& target_function =
- Function::Handle(target_code.function());
ASSERT(!target_function.IsNull());
if (args.length() == 1) {
ic_data.AddReceiverCheck(args[0]->GetClassId(), target_function);
@@ -834,9 +880,7 @@
// Arg1: ICData object.
// Arg2: Arguments descriptor array.
-// Returns: target instructions to call or null if the
-// InstanceFunctionLookup stub should be used (e.g., to invoke no such
-// method and implicit closures)..
+// 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));
@@ -852,62 +896,24 @@
}
ArgumentsDescriptor args_desc(descriptor);
- const Function& target = Function::Handle(
+ Function& target_function = Function::Handle(
Resolver::ResolveDynamicForReceiverClass(cls,
name,
args_desc));
-
- Instructions& instructions = Instructions::Handle();
- if (!target.IsNull()) {
- if (!target.HasCode()) {
- const Error& error = Error::Handle(Compiler::CompileFunction(target));
- if (!error.IsNull()) {
- Exceptions::PropagateError(error);
- }
- }
- ASSERT(target.HasCode());
- instructions = Code::Handle(target.CurrentCode()).instructions();
+ if (target_function.IsNull()) {
+ ic_data.set_is_closure_call(true);
+ target_function = InlineCacheMissHelper(receiver, ic_data);
}
- arguments.SetReturn(instructions);
- if (instructions.IsNull()) return;
+ ASSERT(!target_function.IsNull());
+ // 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);
- return;
+ cache.Insert(class_id, target_function);
+ arguments.SetReturn(target_function);
}
-// Updates IC data for two arguments. Used by the equality operation when
-// the control flow bypasses regular inline cache (null arguments).
-// Arg0: Receiver object.
-// Arg1: Argument after receiver.
-// Arg2: Target's name.
-// Arg3: ICData.
-DEFINE_RUNTIME_ENTRY(UpdateICDataTwoArgs, 4) {
- const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
- const Instance& arg1 = Instance::CheckedHandle(arguments.ArgAt(1));
- const String& target_name = String::CheckedHandle(arguments.ArgAt(2));
- const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(3));
- GrowableArray<const Instance*> args(2);
- args.Add(&receiver);
- args.Add(&arg1);
- const intptr_t kNumArguments = 2;
- ArgumentsDescriptor args_desc(
- Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
- const Function& target_function = Function::Handle(
- Resolver::ResolveDynamic(receiver,
- target_name,
- args_desc));
- ASSERT(!target_function.IsNull());
- GrowableArray<intptr_t> class_ids(kNumArguments);
- ASSERT(ic_data.num_args_tested() == kNumArguments);
- class_ids.Add(receiver.GetClassId());
- class_ids.Add(arg1.GetClassId());
- ic_data.AddCheck(class_ids, target_function);
-}
-
-
// Invoke appropriate noSuchMethod function.
// Arg0: receiver.
// Arg1: ic-data.
@@ -952,126 +958,6 @@
}
-// An instance call of the form o.f(...) could not be resolved. Check if
-// there is a getter with the same name. If so, invoke it. If the value is
-// a closure, invoke it with the given arguments. If the value is a
-// non-closure, attempt to invoke "call" on it.
-static bool ResolveCallThroughGetter(const Instance& receiver,
- const Class& receiver_class,
- const String& target_name,
- const Array& arguments_descriptor,
- const Array& arguments,
- const ICData& ic_data,
- Object* result) {
- // 1. Check if there is a getter with the same name.
- const String& getter_name = String::Handle(Field::GetterName(target_name));
- const int kNumArguments = 1;
- ArgumentsDescriptor args_desc(
- Array::Handle(ArgumentsDescriptor::New(kNumArguments)));
- const Function& getter = Function::Handle(
- Resolver::ResolveDynamicForReceiverClass(receiver_class,
- getter_name,
- args_desc));
- if (getter.IsNull() || getter.IsMethodExtractor()) {
- return false;
- }
-
- const Function& target_function =
- Function::Handle(receiver_class.GetInvocationDispatcher(
- target_name,
- arguments_descriptor,
- RawFunction::kInvokeFieldDispatcher));
- // Update IC data.
- ASSERT(!target_function.IsNull());
- ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
- if (FLAG_trace_ic) {
- OS::PrintErr("InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
- Class::Handle(receiver.clazz()).ToCString(),
- receiver.GetClassId(),
- target_function.ToCString());
- }
- *result = DartEntry::InvokeFunction(target_function,
- arguments,
- arguments_descriptor);
- CheckResultError(*result);
- return true;
-}
-
-
-// The IC miss handler has failed to find a (cacheable) instance function to
-// invoke. Handle three possibilities:
-//
-// 1. If the call was a getter o.f, there may be an instance function with
-// the same name. If so, create an implicit closure and return it.
-//
-// 2. If the call was an instance call o.f(...), there may be a getter with
-// the same name. If so, invoke it. If the value is a closure, invoke
-// it with the given arguments. If the value is a non-closure, attempt
-// to invoke "call" on it.
-//
-// 3. There is no such method.
-DEFINE_RUNTIME_ENTRY(InstanceFunctionLookup, 4) {
- const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
- const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1));
- const Array& args_descriptor = Array::CheckedHandle(arguments.ArgAt(2));
- const Array& args = Array::CheckedHandle(arguments.ArgAt(3));
-
- const Class& receiver_class = Class::Handle(receiver.clazz());
- const String& target_name = String::Handle(ic_data.target_name());
-
- Object& result = Object::Handle();
- if (!ResolveCallThroughGetter(receiver,
- receiver_class,
- target_name,
- args_descriptor,
- args,
- ic_data,
- &result)) {
- ArgumentsDescriptor desc(args_descriptor);
- const Function& target_function =
- Function::Handle(receiver_class.GetInvocationDispatcher(
- target_name,
- args_descriptor,
- RawFunction::kNoSuchMethodDispatcher));
- // Update IC data.
- ASSERT(!target_function.IsNull());
- intptr_t receiver_cid = receiver.GetClassId();
- if (ic_data.num_args_tested() == 1) {
- // In optimized code we may enter into here via the
- // MegamorphicCacheMissHandler since noSuchMethod dispatchers are not
- // inserted into the megamorphic cache. Therefore, we need to guard
- // against entering the same check twice into the ICData.
- // Note that num_args_tested == 1 in optimized code.
- // TODO(fschneider): Handle extraordinary cases like noSuchMethod and
- // implicit closure invocation properly in the megamorphic cache.
- const Function& target =
- Function::Handle(ic_data.GetTargetForReceiverClassId(receiver_cid));
- if (target.IsNull()) {
- ic_data.AddReceiverCheck(receiver_cid, target_function);
- }
- } else {
- // Operators calls have two or three arguments tested ([], []=, etc.)
- ASSERT(ic_data.num_args_tested() > 1);
- GrowableArray<intptr_t> class_ids(ic_data.num_args_tested());
- class_ids.Add(receiver_cid);
- for (intptr_t i = 1; i < ic_data.num_args_tested(); ++i) {
- class_ids.Add(Object::Handle(args.At(i)).GetClassId());
- }
- ic_data.AddCheck(class_ids, target_function);
- }
- if (FLAG_trace_ic) {
- OS::PrintErr("NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
- Class::Handle(receiver.clazz()).ToCString(),
- receiver_cid,
- target_function.ToCString());
- }
- result = DartEntry::InvokeFunction(target_function, args, args_descriptor);
- }
- CheckResultError(result);
- arguments.SetReturn(result);
-}
-
-
static bool CanOptimizeFunction(const Function& function, Isolate* isolate) {
const intptr_t kLowInvocationCount = -100000000;
if (isolate->debugger()->IsStepping() ||

Powered by Google App Engine
This is Rietveld 408576698