Revert "[vm] Repair the resolver abstraction."

This reverts commit 3fd124db1f.

Reason for revert: Provokes existing bug in hot reload call site reset

Original change's description:
> [vm] Repair the resolver abstraction.
> 
>  - Move resolution logic that accumulated in the runtime entries into Resolver.
>  - Improve NoSuchMethodError for closures when --no-lazy-dispatchers
>  - Fix concurrent modification of Null class by nullability propagation.
> 
> Change-Id: Id979459bea43d318a4bb8fd904ef7f23e2711342
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97846
> Commit-Queue: Ryan Macnak <rmacnak@google.com>
> Reviewed-by: Régis Crelier <regis@google.com>

TBR=rmacnak@google.com,alexmarkov@google.com,asiva@google.com,regis@google.com

Change-Id: Ife28f28fff7394dca3fc27e2745370030572720e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98427
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak
2019-04-01 21:57:06 +00:00
committed by commit-bot@chromium.org
parent dd7a6320e3
commit e979895efb
10 changed files with 247 additions and 278 deletions
+16 -1
View File
@@ -241,7 +241,22 @@ RawObject* CompilationTraceLoader::CompileTriple(const char* uri_cstr,
field_ = cls_.LookupFieldAllowPrivate(function_name2_);
if (!function_.IsNull() && !function_.is_static()) {
// Maybe this was a method extractor.
// TODO(rmacnak)
function2_ =
Resolver::ResolveDynamicAnyArgs(zone_, cls_, function_name_);
if (!function2_.IsNull()) {
error_ = CompileFunction(function2_);
if (error_.IsError()) {
if (FLAG_trace_compilation_trace) {
THR_Print(
"Compilation trace: error compiling extractor %s for "
"%s,%s,%s (%s)\n",
function2_.ToCString(), uri_.ToCString(),
class_name_.ToCString(), function_name_.ToCString(),
Error::Cast(error_).ToErrorCString());
}
return error_.raw();
}
}
}
}
if (field_.IsNull() && is_getter) {
+4 -1
View File
@@ -503,7 +503,10 @@ FlowGraph::ToCheck FlowGraph::CheckForInstanceCall(
#else
const Class& null_class =
Class::Handle(zone(), isolate()->object_store()->null_class());
if (Resolver::HasDefinition(zone(), null_class, method_name)) {
const Function& target = Function::Handle(
zone(),
Resolver::ResolveDynamicAnyArgs(zone(), null_class, method_name));
if (!target.IsNull()) {
return ToCheck::kCheckCid;
}
#endif
@@ -310,12 +310,11 @@ void FlowGraphTypePropagator::CheckNonNullSelector(
// Nothing to do if type is already non-nullable.
return;
}
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Class& null_class =
Class::Handle(zone, thread->isolate()->object_store()->null_class());
if (!Resolver::HasDefinition(zone, null_class, function_name)) {
Class::Handle(Isolate::Current()->object_store()->null_class());
const Function& target = Function::Handle(Resolver::ResolveDynamicAnyArgs(
Thread::Current()->zone(), null_class, function_name));
if (target.IsNull()) {
// If the selector is not defined on Null, we can propagate non-nullness.
CompileType* type = TypeOf(receiver);
if (type->is_nullable()) {
+1 -8
View File
@@ -267,14 +267,7 @@ RawObject* DartEntry::InvokeClosure(const Array& arguments,
}
// No compatible method or getter so invoke noSuchMethod.
String& function_name = String::Handle(zone);
if (instance.IsClosure()) {
function_name = Function::Handle(zone, Closure::Cast(instance).function())
.QualifiedUserVisibleName();
} else {
function_name = Symbols::Call().raw();
}
return InvokeNoSuchMethod(instance, function_name, arguments,
return InvokeNoSuchMethod(instance, Symbols::Call(), arguments,
arguments_descriptor);
}
-1
View File
@@ -47,7 +47,6 @@ class ArgumentsDescriptor : public ValueObject {
bool MatchesNameAt(intptr_t i, const String& other) const;
// Returns array of argument names in the arguments order.
RawArray* GetArgumentNames() const;
const Array& array() const { return array_; }
// Generated code support.
static intptr_t type_args_len_offset();
+60 -84
View File
@@ -3094,11 +3094,13 @@ RawFunction* Function::GetDynamicInvocationForwarder(
}
// Check if function actually needs a dynamic invocation forwarder.
if ((kind() == RawFunction::kInvokeFieldDispatcher) ||
!kernel::NeedsDynamicInvocationForwarder(*this)) {
if (!kernel::NeedsDynamicInvocationForwarder(*this)) {
result = raw();
} else if (allow_add) {
result = CreateDynamicInvocationForwarder(mangled_name);
}
if (allow_add) {
owner.AddInvocationDispatcher(mangled_name, Array::null_array(), result);
}
@@ -3323,7 +3325,7 @@ RawObject* Class::InvokeGetter(const String& getter_name,
if (field.IsNull() || field.IsUninitialized()) {
const String& internal_getter_name =
String::Handle(zone, Field::GetterSymbol(getter_name));
String::Handle(zone, Field::GetterName(getter_name));
Function& getter =
Function::Handle(zone, LookupStaticFunction(internal_getter_name));
@@ -3380,7 +3382,7 @@ RawObject* Class::InvokeSetter(const String& setter_name,
// Check for real fields and user-defined setters.
const Field& field = Field::Handle(zone, LookupStaticField(setter_name));
const String& internal_setter_name =
String::Handle(zone, Field::SetterSymbol(setter_name));
String::Handle(zone, Field::SetterName(setter_name));
if (!field.IsNull() && check_is_entrypoint) {
CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kSetterOnly));
@@ -3440,15 +3442,13 @@ RawObject* Class::InvokeSetter(const String& setter_name,
return value.raw();
}
RawObject* Class::Invoke(const String& function_name_in,
RawObject* Class::Invoke(const String& function_name,
const Array& args,
const Array& arg_names,
bool respect_reflectable,
bool check_is_entrypoint) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const String& function_name =
String::Handle(zone, Symbols::New(thread, function_name_in));
// TODO(regis): Support invocation of generic functions with type arguments.
const int kTypeArgsLen = 0;
@@ -10956,12 +10956,12 @@ RawObject* Library::InvokeGetter(const String& getter_name,
// owner class.
const Class& klass = Class::Handle(field.Owner());
const String& internal_getter_name =
String::Handle(Field::GetterSymbol(getter_name));
String::Handle(Field::GetterName(getter_name));
getter = klass.LookupStaticFunction(internal_getter_name);
} else {
// No field found. Check for a getter in the lib.
const String& internal_getter_name =
String::Handle(Field::GetterSymbol(getter_name));
String::Handle(Field::GetterName(getter_name));
obj = LookupLocalOrReExportObject(internal_getter_name);
if (obj.IsFunction()) {
getter = Function::Cast(obj).raw();
@@ -11012,7 +11012,7 @@ RawObject* Library::InvokeSetter(const String& setter_name,
bool check_is_entrypoint) const {
Object& obj = Object::Handle(LookupLocalOrReExportObject(setter_name));
const String& internal_setter_name =
String::Handle(Field::SetterSymbol(setter_name));
String::Handle(Field::SetterName(setter_name));
AbstractType& setter_type = AbstractType::Handle();
AbstractType& argument_type = AbstractType::Handle(value.GetType(Heap::kOld));
if (obj.IsField()) {
@@ -11070,22 +11070,16 @@ RawObject* Library::InvokeSetter(const String& setter_name,
return DartEntry::InvokeFunction(setter, args);
}
RawObject* Library::Invoke(const String& function_name_in,
RawObject* Library::Invoke(const String& function_name,
const Array& args,
const Array& arg_names,
bool respect_reflectable,
bool check_is_entrypoint) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const String& function_name =
String::Handle(zone, Symbols::New(thread, function_name_in));
// TODO(regis): Support invocation of generic functions with type arguments.
const int kTypeArgsLen = 0;
Function& function = Function::Handle(zone);
Object& obj =
Object::Handle(zone, LookupLocalOrReExportObject(function_name));
Function& function = Function::Handle();
Object& obj = Object::Handle(LookupLocalOrReExportObject(function_name));
if (obj.IsFunction()) {
function ^= obj.raw();
}
@@ -11096,39 +11090,37 @@ RawObject* Library::Invoke(const String& function_name_in,
if (function.IsNull()) {
// Didn't find a method: try to find a getter and invoke call on its result.
const Object& getter_result = Object::Handle(
zone, InvokeGetter(function_name, false, respect_reflectable,
check_is_entrypoint));
const Object& getter_result = Object::Handle(InvokeGetter(
function_name, false, respect_reflectable, check_is_entrypoint));
if (getter_result.raw() != Object::sentinel().raw()) {
if (check_is_entrypoint) {
CHECK_ERROR(EntryPointFieldInvocationError(function_name));
}
// Make room for the closure (receiver) in arguments.
intptr_t numArgs = args.Length();
const Array& call_args = Array::Handle(zone, Array::New(numArgs + 1));
Object& temp = Object::Handle(zone);
const Array& call_args = Array::Handle(Array::New(numArgs + 1));
Object& temp = Object::Handle();
for (int i = 0; i < numArgs; i++) {
temp = args.At(i);
call_args.SetAt(i + 1, temp);
}
call_args.SetAt(0, getter_result);
const Array& call_args_descriptor_array =
Array::Handle(zone, ArgumentsDescriptor::New(
kTypeArgsLen, call_args.Length(), arg_names));
Array::Handle(ArgumentsDescriptor::New(
kTypeArgsLen, call_args.Length(), arg_names));
// Call closure.
return DartEntry::InvokeClosure(call_args, call_args_descriptor_array);
}
}
const Array& args_descriptor_array = Array::Handle(
zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
ArgumentsDescriptor args_descriptor(args_descriptor_array);
const TypeArguments& type_args = Object::null_type_arguments();
if (function.IsNull() || !function.AreValidArguments(args_descriptor, NULL) ||
(respect_reflectable && !function.is_reflectable())) {
return ThrowNoSuchMethod(
AbstractType::Handle(zone,
Class::Handle(zone, toplevel_class()).RareType()),
AbstractType::Handle(Class::Handle(toplevel_class()).RareType()),
function_name, args, arg_names, InvocationMirror::kTopLevel,
InvocationMirror::kMethod);
}
@@ -13452,14 +13444,20 @@ bool ICData::AddSmiSmiCheckForFastSmiStubs() const {
bool is_smi_two_args_op = false;
ASSERT(NumArgsTested() == 2);
const String& name = String::Handle(target_name());
const Class& smi_class = Class::Handle(Smi::Class());
Zone* zone = Thread::Current()->zone();
const String& name = String::Handle(zone, target_name());
const Class& smi_class = Class::Handle(zone, Smi::Class());
const ArgumentsDescriptor& args_desc =
ArgumentsDescriptor(Array::Handle(zone, arguments_descriptor()));
Function& smi_op_target = Function::Handle(
zone,
Resolver::ResolveDynamicForReceiverClass(smi_class, name, args_desc));
Function& smi_op_target =
Function::Handle(Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
#if !defined(DART_PRECOMPILED_RUNTIME)
if (smi_op_target.IsNull() &&
Function::IsDynamicInvocationForwarderName(name)) {
const String& demangled =
String::Handle(Function::DemangleDynamicInvocationForwarderName(name));
smi_op_target = Resolver::ResolveDynamicAnyArgs(zone, smi_class, demangled);
}
#endif
if (NumberOfChecksIs(0)) {
GrowableArray<intptr_t> class_ids(2);
@@ -15871,14 +15869,9 @@ RawObject* Instance::InvokeGetter(const String& getter_name,
}
const String& internal_getter_name =
String::Handle(zone, Field::GetterSymbol(getter_name));
const intptr_t kTypeArgsLen = 0;
const intptr_t kNumArgs = 1;
const ArgumentsDescriptor& args_desc = ArgumentsDescriptor(
Array::Handle(zone, ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs)));
Function& function =
Function::Handle(zone, Resolver::ResolveDynamicForReceiverClass(
klass, internal_getter_name, args_desc));
String::Handle(zone, Field::GetterName(getter_name));
Function& function = Function::Handle(
zone, Resolver::ResolveDynamicAnyArgs(zone, klass, internal_getter_name));
if (!function.IsNull() && check_is_entrypoint) {
// The getter must correspond to either an entry-point field or a getter
@@ -15896,12 +15889,7 @@ RawObject* Instance::InvokeGetter(const String& getter_name,
// Check for method extraction when method extractors are not created.
if (function.IsNull() && !FLAG_lazy_dispatchers) {
const intptr_t kGetterNumArgs = 1;
const ArgumentsDescriptor& getter_args_desc =
ArgumentsDescriptor(Array::Handle(
zone, ArgumentsDescriptor::New(kTypeArgsLen, kGetterNumArgs)));
function = Resolver::ResolveDynamicForReceiverClass(klass, getter_name,
getter_args_desc);
function = Resolver::ResolveDynamicAnyArgs(zone, klass, getter_name);
if (!function.IsNull() && check_is_entrypoint) {
CHECK_ERROR(function.VerifyClosurizedEntryPoint());
@@ -15914,6 +15902,8 @@ RawObject* Instance::InvokeGetter(const String& getter_name,
}
}
const int kTypeArgsLen = 0;
const int kNumArgs = 1;
const Array& args = Array::Handle(zone, Array::New(kNumArgs));
args.SetAt(0, *this);
const Array& args_descriptor = Array::Handle(
@@ -15937,14 +15927,9 @@ RawObject* Instance::InvokeSetter(const String& setter_name,
}
const String& internal_setter_name =
String::Handle(zone, Field::SetterSymbol(setter_name));
const intptr_t kTypeArgsLen = 0;
const intptr_t kNumArgs = 2;
const ArgumentsDescriptor& args_desc = ArgumentsDescriptor(
Array::Handle(zone, ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs)));
const Function& setter =
Function::Handle(zone, Resolver::ResolveDynamicForReceiverClass(
klass, internal_setter_name, args_desc));
String::Handle(zone, Field::SetterName(setter_name));
const Function& setter = Function::Handle(
zone, Resolver::ResolveDynamicAnyArgs(zone, klass, internal_setter_name));
if (check_is_entrypoint) {
// The setter must correspond to either an entry-point field or a setter
@@ -15960,6 +15945,8 @@ RawObject* Instance::InvokeSetter(const String& setter_name,
}
}
const int kTypeArgsLen = 0;
const int kNumArgs = 2;
const Array& args = Array::Handle(zone, Array::New(kNumArgs));
args.SetAt(0, *this);
args.SetAt(1, value);
@@ -15971,51 +15958,46 @@ RawObject* Instance::InvokeSetter(const String& setter_name,
type_args);
}
RawObject* Instance::Invoke(const String& function_name_in,
RawObject* Instance::Invoke(const String& function_name,
const Array& args,
const Array& arg_names,
bool respect_reflectable,
bool check_is_entrypoint) const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const String& function_name =
String::Handle(zone, Symbols::New(thread, function_name_in));
Zone* zone = Thread::Current()->zone();
Class& klass = Class::Handle(zone, clazz());
// TODO(regis): Support invocation of generic functions with type arguments.
const intptr_t kTypeArgsLen = 0;
const Array& args_descriptor = Array::Handle(
zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
Function& function = Function::Handle(
zone, Resolver::ResolveDynamicForReceiverClass(
klass, function_name, ArgumentsDescriptor(args_descriptor)));
zone, Resolver::ResolveDynamicAnyArgs(zone, klass, function_name));
if (!function.IsNull() && check_is_entrypoint) {
CHECK_ERROR(function.VerifyCallEntryPoint());
}
// TODO(regis): Support invocation of generic functions with type arguments.
const int kTypeArgsLen = 0;
const Array& args_descriptor = Array::Handle(
zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
TypeArguments& type_args = TypeArguments::Handle(zone);
if (klass.NumTypeArguments() > 0) {
type_args ^= GetTypeArguments();
}
if (function.IsNull() && !FLAG_lazy_dispatchers) {
if (function.IsNull()) {
// Didn't find a method: try to find a getter and invoke call on its result.
const String& getter_name =
String::Handle(zone, Field::GetterSymbol(function_name));
const int kGetterNumArgs = 1;
const Array& getter_args_descriptor = Array::Handle(
zone, ArgumentsDescriptor::New(kTypeArgsLen, kGetterNumArgs));
function = Resolver::ResolveDynamicForReceiverClass(
klass, getter_name, ArgumentsDescriptor(getter_args_descriptor));
String::Handle(zone, Field::GetterName(function_name));
function = Resolver::ResolveDynamicAnyArgs(zone, klass, getter_name);
if (!function.IsNull()) {
if (check_is_entrypoint) {
CHECK_ERROR(EntryPointFieldInvocationError(function_name));
}
ASSERT(function.kind() != RawFunction::kMethodExtractor);
// Invoke the getter.
const Array& getter_args =
Array::Handle(zone, Array::New(kGetterNumArgs));
const int kNumArgs = 1;
const Array& getter_args = Array::Handle(zone, Array::New(kNumArgs));
getter_args.SetAt(0, *this);
const Array& getter_args_descriptor = Array::Handle(
zone, ArgumentsDescriptor::New(kTypeArgsLen, getter_args.Length()));
const Object& getter_result = Object::Handle(
zone, InvokeInstanceFunction(*this, function, getter_name,
getter_args, getter_args_descriptor,
@@ -22000,12 +21982,6 @@ RawError* VerifyEntryPoint(
}
#endif
if (!is_marked_entrypoint) {
if (member.IsFunction() &&
Function::Cast(member).kind() == RawFunction::kInvokeFieldDispatcher) {
return EntryPointFieldInvocationError(
String::Handle(Function::Cast(member).name()));
}
const char* member_cstring =
member.IsFunction()
? OS::SCreate(
+6 -8
View File
@@ -711,15 +711,13 @@ void ICData::Reset(Zone* zone) const {
if (IsImmutable()) {
return;
}
const String& name = String::Handle(zone, target_name());
const Class& smi_class = Class::Handle(zone, Smi::Class());
const ArgumentsDescriptor& args_desc =
ArgumentsDescriptor(Array::Handle(zone, arguments_descriptor()));
Zone* zone = Thread::Current()->zone();
const String& name = String::Handle(target_name());
const Class& smi_class = Class::Handle(Smi::Class());
const Function& smi_op_target = Function::Handle(
zone,
Resolver::ResolveDynamicForReceiverClass(smi_class, name, args_desc));
Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
GrowableArray<intptr_t> class_ids(2);
Function& target = Function::Handle(zone);
Function& target = Function::Handle();
GetCheckAt(0, &class_ids, &target);
if ((target.raw() == smi_op_target.raw()) && (class_ids[0] == kSmiCid) &&
(class_ids[1] == kSmiCid)) {
@@ -727,7 +725,7 @@ void ICData::Reset(Zone* zone) const {
// count.
ClearCountAt(0);
WriteSentinelAt(1);
const Array& array = Array::Handle(zone, entries());
const Array& array = Array::Handle(entries());
array.Truncate(2 * TestEntryLength());
return;
}
+55 -143
View File
@@ -16,20 +16,16 @@ namespace dart {
DEFINE_FLAG(bool, trace_resolving, false, "Trace resolving.");
// Find the target of an instance call, which might be
// - a user-defined method
// - a method extractor (getter call to user-defined regular method)
// - an invoke field dispatcher (regular method call to user-defined getter)
// - a dynamic invocation forwarder (dynamic call to one of the above)
// - a no-such-method dispatcher (no target or target with wrong number of
// positional arguments)
//
// Positional arguments are checked here: the number of positional arguments
// doesn't match the target, a no-such-method-dispatcher will be returned.
// Named arguments are checked in the target's prologue.
// The actual names of named arguments are not checked by the dynamic resolver,
// but by the method entry code. It is important that the dynamic resolver
// checks that no named arguments are passed to a method that does not accept
// them, since the entry code of such a method does not check for named
// arguments. The dynamic resolver actually checks that a valid number of named
// arguments is passed in.
RawFunction* Resolver::ResolveDynamic(const Instance& receiver,
const String& function_name,
const ArgumentsDescriptor& args_desc) {
// Figure out type of receiver first.
const Class& cls = Class::Handle(receiver.clazz());
return ResolveDynamicForReceiverClass(cls, function_name, args_desc);
}
@@ -42,54 +38,46 @@ RawFunction* Resolver::ResolveDynamicForReceiverClass(
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
if (FLAG_trace_resolving) {
THR_Print("ResolveDynamic '%s' for class %s\n", function_name.ToCString(),
String::Handle(zone, receiver_class.Name()).ToCString());
}
Function& function = Function::Handle(
zone, ResolveDynamicAnyArgs(zone, receiver_class, function_name,
args_desc, allow_add));
zone,
ResolveDynamicAnyArgs(zone, receiver_class, function_name, allow_add));
if (function.IsNull() || !function.AreValidArguments(args_desc, NULL)) {
if (FLAG_lazy_dispatchers) {
String& demangled = String::Handle(zone);
if (Function::IsDynamicInvocationForwarderName(function_name)) {
demangled =
Function::DemangleDynamicInvocationForwarderName(function_name);
} else {
demangled = function_name.raw();
}
function = receiver_class.GetInvocationDispatcher(
demangled, args_desc.array(), RawFunction::kNoSuchMethodDispatcher,
allow_add);
// Return a null function to signal to the upper levels to dispatch to
// "noSuchMethod" function.
if (FLAG_trace_resolving) {
String& error_message =
String::Handle(zone, Symbols::New(thread, "function not found"));
if (!function.IsNull()) {
function.set_is_reflectable(true);
// Obtain more detailed error message.
function.AreValidArguments(args_desc, &error_message);
}
} else {
function = Function::null();
THR_Print("ResolveDynamic error '%s': %s.\n", function_name.ToCString(),
error_message.ToCString());
}
return Function::null();
}
// FLAG_lazy_dispatchers && allow_add -> !function.IsNull()
ASSERT(!function.IsNull() || !FLAG_lazy_dispatchers || !allow_add);
if (FLAG_trace_resolving) {
THR_Print("ResolveDynamic result: %s\n", function.ToCString());
}
return function.raw();
}
RawFunction* Resolver::ResolveDynamicAnyArgs(
Zone* zone,
const Class& receiver_class,
const String& function_name,
const ArgumentsDescriptor& args_desc,
bool allow_add) {
RawFunction* Resolver::ResolveDynamicAnyArgs(Zone* zone,
const Class& receiver_class,
const String& function_name,
bool allow_add) {
Class& cls = Class::Handle(zone, receiver_class.raw());
String& demangled = String::Handle(zone);
if (FLAG_trace_resolving) {
THR_Print("ResolveDynamic '%s' for class %s\n", function_name.ToCString(),
String::Handle(zone, cls.Name()).ToCString());
}
Function& function = Function::Handle(zone);
String& demangled = String::Handle(zone);
const bool is_getter = Field::IsGetterName(function_name);
if (is_getter) {
demangled ^= Field::NameFromGetter(function_name);
}
if (Function::IsDynamicInvocationForwarderName(function_name)) {
demangled ^=
Function::DemangleDynamicInvocationForwarderName(function_name);
@@ -109,118 +97,42 @@ RawFunction* Resolver::ResolveDynamicAnyArgs(
// forwarder to do, see `kernel::DynamicInvocationForwarder`). For these
// functions, we won't have built a `dyn:` version, but it's safe to just
// return the original version directly.
return !function.IsNull()
? function.raw()
: ResolveDynamicAnyArgs(zone, receiver_class, demangled,
args_desc, allow_add);
return !function.IsNull() ? function.raw()
: ResolveDynamicAnyArgs(zone, receiver_class,
demangled, allow_add);
#else
function = ResolveDynamicAnyArgs(zone, receiver_class, demangled, args_desc,
allow_add);
if (function.IsNull() || !function.AreValidArguments(args_desc, NULL)) {
return Function::null();
}
return function.GetDynamicInvocationForwarder(function_name, allow_add);
function =
ResolveDynamicAnyArgs(zone, receiver_class, demangled, allow_add);
return function.IsNull() ? function.raw()
: function.GetDynamicInvocationForwarder(
function_name, allow_add);
#endif
}
const bool is_getter = Field::IsGetterName(function_name);
const bool is_setter = Field::IsSetterName(function_name);
if (is_getter) {
demangled = Field::NameFromGetter(function_name);
} else if (!is_setter) {
demangled = Field::GetterSymbol(function_name);
}
// Now look for an instance function whose name matches function_name
// in the class.
while (!cls.IsNull()) {
function = cls.LookupDynamicFunction(function_name);
function ^= cls.LookupDynamicFunction(function_name);
if (!function.IsNull()) {
return function.raw();
}
if (is_getter) {
// Getter invocation might actually be a method extraction.
ASSERT(!Field::IsGetterName(demangled));
function = cls.LookupDynamicFunction(demangled);
if (!function.IsNull()) {
if (FLAG_lazy_dispatchers && allow_add) {
return function.CreateMethodExtractor(function_name);
} else {
return Function::null();
}
}
} else if (!is_setter) {
// Regular invocation might actually be call-through-getter.
ASSERT(Field::IsGetterName(demangled));
function = cls.LookupDynamicFunction(demangled);
if (!function.IsNull()) {
if (FLAG_lazy_dispatchers && allow_add) {
bool is_reflectable = function.is_reflectable();
function = cls.GetInvocationDispatcher(
function_name, args_desc.array(),
RawFunction::kInvokeFieldDispatcher, allow_add);
function.set_is_reflectable(is_reflectable);
// Getter invocation might actually be a method extraction.
if (FLAG_lazy_dispatchers) {
if (is_getter && function.IsNull()) {
function ^= cls.LookupDynamicFunction(demangled);
if (!function.IsNull() && allow_add) {
// We were looking for the getter but found a method with the same
// name. Create a method extractor and return it.
// The extractor does not exist yet, so using GetMethodExtractor is
// not necessary here.
function ^= function.CreateMethodExtractor(function_name);
return function.raw();
} else {
return Function::null();
}
}
}
cls = cls.SuperClass();
}
return Function::null();
}
bool Resolver::HasDefinition(Zone* zone,
const Class& receiver_class,
const String& function_name) {
String& demangled = String::Handle(zone);
if (Function::IsDynamicInvocationForwarderName(function_name)) {
demangled = Function::DemangleDynamicInvocationForwarderName(function_name);
return HasDefinition(zone, receiver_class, demangled);
}
const bool is_getter = Field::IsGetterName(function_name);
const bool is_setter = Field::IsSetterName(function_name);
if (is_getter) {
demangled = Field::NameFromGetter(function_name);
} else if (!is_setter) {
demangled = Field::GetterSymbol(function_name);
}
Class& cls = Class::Handle(zone, receiver_class.raw());
Function& function = Function::Handle(zone);
// Now look for an instance function whose name matches function_name
// in the class.
while (!cls.IsNull()) {
function = cls.LookupDynamicFunction(function_name);
if (!function.IsNull()) {
return true;
}
if (is_getter) {
// Getter invocation might actually be a method extraction.
ASSERT(!Field::IsGetterName(demangled));
function = cls.LookupDynamicFunction(demangled);
if (!function.IsNull()) {
return true;
}
} else if (!is_setter) {
// Regular invocation might actually be call-through-getter.
ASSERT(Field::IsGetterName(demangled));
function = cls.LookupDynamicFunction(demangled);
if (!function.IsNull()) {
return true;
}
}
cls = cls.SuperClass();
}
// NoSuchMethod
return false;
return function.raw();
}
RawFunction* Resolver::ResolveStatic(const Library& library,
+5 -19
View File
@@ -34,16 +34,11 @@ class Resolver : public AllStatic {
const ArgumentsDescriptor& args_desc,
bool allow_add = true);
// Answers whether the receiver class has a definition for given selector
// other than noSuchMethod. Helper threads such as the background compiler
// must use this instead of checking for null answer from ResolveDynamicX
// because a helper thread cannot safely use 'allow_add = true' because it
// may concurrently mutate a class, and 'allow_add = false' will give false
/// negatives if lazy dispatchers are disabled or a lazy dispatcher hasn't
// been created yet.
static bool HasDefinition(Zone* zone,
const Class& receiver_class,
const String& function_name);
// If 'allow_add' is true we may add a function to the class during lookup.
static RawFunction* ResolveDynamicAnyArgs(Zone* zone,
const Class& receiver_class,
const String& function_name,
bool allow_add = true);
// Resolve specified dart static function. If library.IsNull, use
// either application library or core library if no application library
@@ -73,15 +68,6 @@ class Resolver : public AllStatic {
intptr_t type_args_len,
intptr_t num_arguments,
const Array& argument_names);
private:
// If 'allow_add' is true we may add a function to the class during lookup.
static RawFunction* ResolveDynamicAnyArgs(
Zone* zone,
const Class& receiver_class,
const String& function_name,
const ArgumentsDescriptor& args_desc,
bool allow_add = true);
};
} // namespace dart
+96 -8
View File
@@ -1019,6 +1019,78 @@ DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
#endif
}
// 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,
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 kTypeArgsLen = 0;
const int kNumArguments = 1;
ArgumentsDescriptor args_desc(
Array::Handle(ArgumentsDescriptor::New(kTypeArgsLen, 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, FLAG_lazy_dispatchers));
ASSERT(!target_function.IsNull() || !FLAG_lazy_dispatchers);
if (FLAG_trace_ic) {
OS::PrintErr(
"InvokeField IC miss: adding <%s> id:%" Pd " -> <%s>\n",
Class::Handle(receiver.clazz()).ToCString(), receiver.GetClassId(),
target_function.IsNull() ? "null" : target_function.ToCString());
}
*result = target_function.raw();
return true;
}
// Handle other invocations (implicit closures, noSuchMethod).
RawFunction* InlineCacheMissHelper(const Instance& receiver,
const Array& args_descriptor,
const String& target_name) {
const Class& receiver_class = Class::Handle(receiver.clazz());
// Handle noSuchMethod for dyn:methodName by getting a noSuchMethod dispatcher
// (or a call-through getter for methodName).
if (Function::IsDynamicInvocationForwarderName(target_name)) {
const String& demangled = String::Handle(
Function::DemangleDynamicInvocationForwarderName(target_name));
return InlineCacheMissHelper(receiver, args_descriptor, demangled);
}
Function& result = Function::Handle();
if (!ResolveCallThroughGetter(receiver, receiver_class, target_name,
args_descriptor, &result)) {
ArgumentsDescriptor desc(args_descriptor);
const Function& target_function =
Function::Handle(receiver_class.GetInvocationDispatcher(
target_name, args_descriptor, RawFunction::kNoSuchMethodDispatcher,
FLAG_lazy_dispatchers));
if (FLAG_trace_ic) {
OS::PrintErr(
"NoSuchMethod IC miss: adding <%s> id:%" Pd " -> <%s>\n",
Class::Handle(receiver.clazz()).ToCString(), receiver.GetClassId(),
target_function.IsNull() ? "null" : target_function.ToCString());
}
result = target_function.raw();
}
// May be null if --no-lazy-dispatchers, in which case dispatch will be
// handled by InvokeNoSuchMethodDispatcher.
ASSERT(!result.IsNull() || !FLAG_lazy_dispatchers);
return result.raw();
}
// Perform the subtype and return constant function based on the result.
static RawFunction* ComputeTypeCheckTarget(const Instance& receiver,
const AbstractType& type,
@@ -1059,6 +1131,11 @@ static RawFunction* InlineCacheMissHandler(
String::Handle(ic_data.target_name()).ToCString(),
receiver.ToCString());
}
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);
@@ -1208,8 +1285,7 @@ static bool IsSingleTarget(Isolate* isolate,
intptr_t lower_cid,
intptr_t upper_cid,
const Function& target,
const String& name,
const ArgumentsDescriptor& args_desc) {
const String& name) {
Class& cls = Class::Handle(zone);
ClassTable* table = isolate->class_table();
Function& other_target = Function::Handle(zone);
@@ -1218,8 +1294,8 @@ static bool IsSingleTarget(Isolate* isolate,
cls = table->At(cid);
if (cls.is_abstract()) continue;
if (!cls.is_allocated()) continue;
other_target = Resolver::ResolveDynamicForReceiverClass(
cls, name, args_desc, false /* allow_add */);
other_target =
Resolver::ResolveDynamicAnyArgs(zone, cls, name, false /* allow_add */);
if (other_target.raw() != target.raw()) {
return false;
}
@@ -1271,6 +1347,9 @@ DEFINE_RUNTIME_ENTRY(SingleTargetMiss, 1) {
ArgumentsDescriptor args_desc(descriptor);
Function& target_function = Function::Handle(
zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc));
if (target_function.IsNull()) {
target_function = InlineCacheMissHelper(receiver, descriptor, name);
}
if (target_function.IsNull()) {
ASSERT(!FLAG_lazy_dispatchers);
} else {
@@ -1292,7 +1371,7 @@ DEFINE_RUNTIME_ENTRY(SingleTargetMiss, 1) {
}
if (IsSingleTarget(isolate, zone, unchecked_lower, unchecked_upper,
target_function, name, args_desc)) {
target_function, name)) {
cache.set_lower_limit(lower);
cache.set_upper_limit(upper);
// Return the ICData. The single target stub will jump to continue in the
@@ -1342,6 +1421,9 @@ DEFINE_RUNTIME_ENTRY(UnlinkedCall, 2) {
ArgumentsDescriptor args_desc(descriptor);
Function& target_function = Function::Handle(
zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc));
if (target_function.IsNull()) {
target_function = InlineCacheMissHelper(receiver, descriptor, name);
}
if (target_function.IsNull()) {
ASSERT(!FLAG_lazy_dispatchers);
} else {
@@ -1422,6 +1504,9 @@ DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) {
ArgumentsDescriptor args_desc(descriptor);
Function& target_function = Function::Handle(
zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc));
if (target_function.IsNull()) {
target_function = InlineCacheMissHelper(receiver, descriptor, name);
}
if (target_function.IsNull()) {
ASSERT(!FLAG_lazy_dispatchers);
} else {
@@ -1438,8 +1523,7 @@ DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) {
upper = old_expected_cid.Value();
}
if (IsSingleTarget(isolate, zone, lower, upper, target_function, name,
args_desc)) {
if (IsSingleTarget(isolate, zone, lower, upper, target_function, name)) {
const SingleTargetCache& cache =
SingleTargetCache::Handle(SingleTargetCache::New());
const Code& code = Code::Handle(target_function.CurrentCode());
@@ -1500,6 +1584,7 @@ DEFINE_RUNTIME_ENTRY(MegamorphicCacheMissHandler, 3) {
Function& target_function = Function::Handle(
zone, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc));
if (target_function.IsNull()) {
target_function = InlineCacheMissHelper(receiver, descriptor, name);
if (target_function.IsNull()) {
ASSERT(!FLAG_lazy_dispatchers);
arguments.SetReturn(target_function);
@@ -1591,7 +1676,10 @@ DEFINE_RUNTIME_ENTRY(InterpretedInterfaceCallMissHandler, 3) {
// TODO(regis): In order to substitute 'simple_instance_of_function', the 2nd
// arg to the call, the type, is needed.
ASSERT(!target_function.IsNull() && FLAG_lazy_dispatchers);
if (target_function.IsNull()) {
target_function = InlineCacheMissHelper(receiver, arg_desc, target_name);
}
ASSERT(!target_function.IsNull());
arguments.SetReturn(target_function);
#endif
}