Files
sdk/runtime/vm/resolver.cc
T
Régis Crelier e2e290b4cf [VM/nnbd] Simplify NNBDMode enum class.
NNBDMode does not reflect the semantics (legacy or nnbd) of type tests anymore.
Instead, the semantics are derived from the value of the strong mode flag.
This required one function to be specialized, namely the implementation of
'null is Type' in weak mode in an opted-in library, which still requires
nnbd semantics although run in weak mode.
Relevant changes are in object.h and object.cc:
- methods NNBD_NullIsInstanceOf and NNBD_IsTopType are new.
- methods IsNullType, IsTopType, and IsNeverType are modified.

Change-Id: I36cd43d93d2cfabd110cbcc6b26487a583bb089d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/130444
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
2020-01-08 19:35:00 +00:00

255 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.
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);
}
RawFunction* Resolver::ResolveDynamicForReceiverClass(
const Class& receiver_class,
const String& function_name,
const ArgumentsDescriptor& args_desc,
bool allow_add) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Function& function = Function::Handle(
zone,
ResolveDynamicAnyArgs(zone, receiver_class, function_name, allow_add));
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib, 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(NNBDMode::kLegacyLib, args_desc,
&error_message);
}
THR_Print("ResolveDynamic error '%s': %s.\n", function_name.ToCString(),
error_message.ToCString());
}
return Function::null();
}
return function.raw();
}
RawFunction* Resolver::ResolveDynamicAnyArgs(Zone* zone,
const Class& receiver_class,
const String& function_name,
bool allow_add) {
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);
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);
#ifdef DART_PRECOMPILED_RUNTIME
// In precompiled mode, the non-dynamic version of the function may be
// tree-shaken away, so can't necessarily resolve the demanged name.
while (!cls.IsNull()) {
function = cls.GetInvocationDispatcher(
function_name, Array::null_array(),
RawFunction::kDynamicInvocationForwarder, /*create_if_absent=*/false);
if (!function.IsNull()) break;
cls = cls.SuperClass();
}
// Some functions don't require dynamic invocation forwarders, for example
// if there are no parameters or all the parameters are marked
// `generic-covariant` (meaning there's no work for the dynamic invocation
// 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, allow_add);
#else
function =
ResolveDynamicAnyArgs(zone, receiver_class, demangled, allow_add);
return function.IsNull() ? function.raw()
: function.GetDynamicInvocationForwarder(
function_name, allow_add);
#endif
}
// 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 function.raw();
}
// Getter invocation might actually be a method extraction.
if (is_getter && function.IsNull()) {
function = cls.LookupDynamicFunction(demangled);
if (!function.IsNull()) {
if (allow_add && FLAG_lazy_dispatchers) {
// 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.raw();
}
RawFunction* 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(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names, NULL)) {
if (FLAG_trace_resolving) {
String& error_message = String::Handle();
// Obtain more detailed error message.
function.AreValidArguments(NNBDMode::kLegacyLib, 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();
}
RawFunction* 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(NNBDMode::kLegacyLib, 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(NNBDMode::kLegacyLib, 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();
}
RawFunction* Resolver::ResolveStaticAllowPrivate(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("ResolveStaticAllowPrivate '%s'\n", function_name.ToCString());
}
const Function& function =
Function::Handle(cls.LookupStaticFunctionAllowPrivate(function_name));
if (function.IsNull() ||
!function.AreValidArguments(NNBDMode::kLegacyLib, 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(NNBDMode::kLegacyLib, type_args_len,
num_arguments, argument_names,
&error_message);
}
THR_Print("ResolveStaticAllowPrivate error '%s': %s.\n",
function_name.ToCString(), error_message.ToCString());
}
return Function::null();
}
return function.raw();
}
} // namespace dart