37abbb2e3d
This CL adds acquisiton of write lock and check for whether write lock is held when updating class functions, primarily populated during class finalization. Read locks will be added in successive CLs, so is extending of the locks coverage to all aspects of program structure changes. Bug: https://github.com/dart-lang/sdk/issues/36097 Change-Id: I3dba6bc23db4e45599a20717226210f12e7fd2b3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168140 Commit-Queue: Alexander Aprelev <aam@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
273 lines
11 KiB
C++
273 lines
11 KiB
C++
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/resolver.h"
|
|
|
|
#include "vm/dart_entry.h"
|
|
#include "vm/flags.h"
|
|
#include "vm/isolate.h"
|
|
#include "vm/log.h"
|
|
#include "vm/object.h"
|
|
#include "vm/object_store.h"
|
|
#include "vm/symbols.h"
|
|
|
|
namespace dart {
|
|
|
|
DEFINE_FLAG(bool, trace_resolving, false, "Trace resolving.");
|
|
|
|
// 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.
|
|
FunctionPtr 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);
|
|
}
|
|
|
|
static FunctionPtr ResolveDynamicAnyArgsWithCustomLookup(
|
|
Zone* zone,
|
|
const Class& receiver_class,
|
|
const String& function_name,
|
|
bool allow_add,
|
|
std::function<FunctionPtr(Class&, const String&)> lookup) {
|
|
Class& cls = Class::Handle(zone, receiver_class.raw());
|
|
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);
|
|
|
|
const String& demangled = String::Handle(
|
|
zone,
|
|
Function::IsDynamicInvocationForwarderName(function_name)
|
|
? Function::DemangleDynamicInvocationForwarderName(function_name)
|
|
: function_name.raw());
|
|
|
|
const bool is_getter = Field::IsGetterName(demangled);
|
|
String& demangled_getter_name = String::Handle();
|
|
if (is_getter) {
|
|
demangled_getter_name = Field::NameFromGetter(demangled);
|
|
}
|
|
|
|
const bool is_dyn_call = demangled.raw() != function_name.raw();
|
|
|
|
bool need_to_create_method_extractor = false;
|
|
while (!cls.IsNull()) {
|
|
if (is_dyn_call) {
|
|
// Try to find a dyn:* forwarder & return it.
|
|
function = cls.GetInvocationDispatcher(
|
|
function_name, Array::null_array(),
|
|
FunctionLayout::kDynamicInvocationForwarder,
|
|
/*create_if_absent=*/false);
|
|
}
|
|
if (!function.IsNull()) return function.raw();
|
|
|
|
function = lookup(cls, demangled);
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
// In JIT we might need to lazily create a dyn:* forwarder.
|
|
if (is_dyn_call && !function.IsNull()) {
|
|
function =
|
|
function.GetDynamicInvocationForwarder(function_name, allow_add);
|
|
}
|
|
#endif
|
|
if (!function.IsNull()) return function.raw();
|
|
|
|
// Getter invocation might actually be a method extraction.
|
|
if (is_getter) {
|
|
function = lookup(cls, demangled_getter_name);
|
|
if (!function.IsNull()) {
|
|
if (allow_add && FLAG_lazy_dispatchers) {
|
|
need_to_create_method_extractor = true;
|
|
break;
|
|
} else {
|
|
return Function::null();
|
|
}
|
|
}
|
|
}
|
|
cls = cls.SuperClass();
|
|
}
|
|
if (need_to_create_method_extractor) {
|
|
// We were looking for the getter but found a method with the same
|
|
// name. Create a method extractor and return it.
|
|
// Use GetMethodExtractor instead of CreateMethodExtractor to ensure
|
|
// nobody created method extractor since we last checked under ReadRwLocker.
|
|
function = function.GetMethodExtractor(demangled);
|
|
}
|
|
return function.raw();
|
|
}
|
|
|
|
static FunctionPtr ResolveDynamicForReceiverClassWithCustomLookup(
|
|
const Class& receiver_class,
|
|
const String& function_name,
|
|
const ArgumentsDescriptor& args_desc,
|
|
bool allow_add,
|
|
std::function<FunctionPtr(Class&, const String&)> lookup) {
|
|
Thread* thread = Thread::Current();
|
|
Zone* zone = thread->zone();
|
|
|
|
Function& function = Function::Handle(
|
|
zone, ResolveDynamicAnyArgsWithCustomLookup(
|
|
zone, receiver_class, function_name, allow_add, lookup));
|
|
|
|
if (function.IsNull() || !function.AreValidArguments(args_desc, NULL)) {
|
|
// 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()) {
|
|
// Obtain more detailed error message.
|
|
function.AreValidArguments(args_desc, &error_message);
|
|
}
|
|
THR_Print("ResolveDynamic error '%s': %s.\n", function_name.ToCString(),
|
|
error_message.ToCString());
|
|
}
|
|
return Function::null();
|
|
}
|
|
return function.raw();
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveDynamicForReceiverClass(
|
|
const Class& receiver_class,
|
|
const String& function_name,
|
|
const ArgumentsDescriptor& args_desc,
|
|
bool allow_add) {
|
|
return ResolveDynamicForReceiverClassWithCustomLookup(
|
|
receiver_class, function_name, args_desc, allow_add,
|
|
std::mem_fn(&Class::LookupDynamicFunctionUnsafe));
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveDynamicForReceiverClassAllowPrivate(
|
|
const Class& receiver_class,
|
|
const String& function_name,
|
|
const ArgumentsDescriptor& args_desc,
|
|
bool allow_add) {
|
|
return ResolveDynamicForReceiverClassWithCustomLookup(
|
|
receiver_class, function_name, args_desc, allow_add,
|
|
std::mem_fn(&Class::LookupDynamicFunctionAllowPrivate));
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveFunction(Zone* zone,
|
|
const Class& receiver_class,
|
|
const String& function_name) {
|
|
return ResolveDynamicAnyArgsWithCustomLookup(
|
|
zone, receiver_class, function_name, /*allow_add=*/false,
|
|
std::mem_fn(static_cast<FunctionPtr (Class::*)(const String&) const>(
|
|
&Class::LookupFunctionUnsafe)));
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveDynamicFunction(Zone* zone,
|
|
const Class& receiver_class,
|
|
const String& function_name) {
|
|
return ResolveDynamicAnyArgsWithCustomLookup(
|
|
zone, receiver_class, function_name, /*allow_add=*/false,
|
|
std::mem_fn(static_cast<FunctionPtr (Class::*)(const String&) const>(
|
|
&Class::LookupDynamicFunctionUnsafe)));
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveDynamicAnyArgs(Zone* zone,
|
|
const Class& receiver_class,
|
|
const String& function_name,
|
|
bool allow_add) {
|
|
return ResolveDynamicAnyArgsWithCustomLookup(
|
|
zone, receiver_class, function_name, allow_add,
|
|
std::mem_fn(&Class::LookupDynamicFunctionUnsafe));
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveDynamicAnyArgsAllowPrivate(
|
|
Zone* zone,
|
|
const Class& receiver_class,
|
|
const String& function_name,
|
|
bool allow_add) {
|
|
return ResolveDynamicAnyArgsWithCustomLookup(
|
|
zone, receiver_class, function_name, allow_add,
|
|
std::mem_fn(&Class::LookupDynamicFunctionAllowPrivate));
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveStatic(const Library& library,
|
|
const String& class_name,
|
|
const String& function_name,
|
|
intptr_t type_args_len,
|
|
intptr_t num_arguments,
|
|
const Array& argument_names) {
|
|
ASSERT(!library.IsNull());
|
|
Function& function = Function::Handle();
|
|
if (class_name.IsNull() || (class_name.Length() == 0)) {
|
|
// Check if we are referring to a top level function.
|
|
const Object& object = Object::Handle(library.ResolveName(function_name));
|
|
if (!object.IsNull() && object.IsFunction()) {
|
|
function ^= object.raw();
|
|
if (!function.AreValidArguments(type_args_len, num_arguments,
|
|
argument_names, NULL)) {
|
|
if (FLAG_trace_resolving) {
|
|
String& error_message = String::Handle();
|
|
// Obtain more detailed error message.
|
|
function.AreValidArguments(type_args_len, num_arguments,
|
|
argument_names, &error_message);
|
|
THR_Print("ResolveStatic error '%s': %s.\n",
|
|
function_name.ToCString(), error_message.ToCString());
|
|
}
|
|
function = Function::null();
|
|
}
|
|
} else {
|
|
if (FLAG_trace_resolving) {
|
|
THR_Print("ResolveStatic error: function '%s' not found.\n",
|
|
function_name.ToCString());
|
|
}
|
|
}
|
|
} else {
|
|
// Lookup class_name in the library's class dictionary to get at
|
|
// the dart class object. If class_name is not found in the dictionary
|
|
// ResolveStatic will return a NULL function object.
|
|
const Class& cls = Class::Handle(library.LookupClass(class_name));
|
|
if (!cls.IsNull()) {
|
|
function = ResolveStatic(cls, function_name, type_args_len, num_arguments,
|
|
argument_names);
|
|
}
|
|
if (FLAG_trace_resolving && function.IsNull()) {
|
|
THR_Print("ResolveStatic error: function '%s.%s' not found.\n",
|
|
class_name.ToCString(), function_name.ToCString());
|
|
}
|
|
}
|
|
return function.raw();
|
|
}
|
|
|
|
FunctionPtr Resolver::ResolveStatic(const Class& cls,
|
|
const String& function_name,
|
|
intptr_t type_args_len,
|
|
intptr_t num_arguments,
|
|
const Array& argument_names) {
|
|
ASSERT(!cls.IsNull());
|
|
if (FLAG_trace_resolving) {
|
|
THR_Print("ResolveStatic '%s'\n", function_name.ToCString());
|
|
}
|
|
const Function& function =
|
|
Function::Handle(cls.LookupStaticFunction(function_name));
|
|
if (function.IsNull() ||
|
|
!function.AreValidArguments(type_args_len, num_arguments, argument_names,
|
|
NULL)) {
|
|
// Return a null function to signal to the upper levels to throw a
|
|
// resolution error or maybe throw the error right here.
|
|
if (FLAG_trace_resolving) {
|
|
String& error_message = String::Handle(String::New("function not found"));
|
|
if (!function.IsNull()) {
|
|
// Obtain more detailed error message.
|
|
function.AreValidArguments(type_args_len, num_arguments, argument_names,
|
|
&error_message);
|
|
}
|
|
THR_Print("ResolveStatic error '%s': %s.\n", function_name.ToCString(),
|
|
error_message.ToCString());
|
|
}
|
|
return Function::null();
|
|
}
|
|
return function.raw();
|
|
}
|
|
|
|
} // namespace dart
|