dart-sdk/runtime/lib/mirrors.cc
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

1765 lines
68 KiB
C++

// Copyright (c) 2012, 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 "lib/mirrors.h"
#include "lib/invocation_mirror.h"
#include "vm/bootstrap_natives.h"
#include "vm/class_finalizer.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/exceptions.h"
#include "vm/kernel.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/port.h"
#include "vm/symbols.h"
namespace dart {
#if !defined(DART_PRECOMPILED_RUNTIME)
#define RETURN_OR_PROPAGATE(expr) \
RawObject* result = expr; \
if (RawObject::IsErrorClassId(result->GetClassIdMayBeSmi())) { \
Exceptions::PropagateError(Error::Handle(Error::RawCast(result))); \
} \
return result;
static RawInstance* CreateMirror(const String& mirror_class_name,
const Array& constructor_arguments) {
const Library& mirrors_lib = Library::Handle(Library::MirrorsLibrary());
const String& constructor_name = Symbols::DotUnder();
const Object& result = Object::Handle(DartLibraryCalls::InstanceCreate(
mirrors_lib, mirror_class_name, constructor_name, constructor_arguments));
if (result.IsError()) {
Exceptions::PropagateError(Error::Cast(result));
}
return Instance::Cast(result).raw();
}
// Conventions:
// * For throwing a NSM in a class klass we use its runtime type as receiver,
// i.e., klass.RareType().
// * For throwing a NSM in a library, we just pass the null instance as
// receiver.
static void ThrowNoSuchMethod(const Instance& receiver,
const String& function_name,
const Array& arguments,
const Array& argument_names,
const InvocationMirror::Level level,
const InvocationMirror::Kind kind) {
const Smi& invocation_type =
Smi::Handle(Smi::New(InvocationMirror::EncodeType(level, kind)));
const Array& args = Array::Handle(Array::New(6));
args.SetAt(0, receiver);
args.SetAt(1, function_name);
args.SetAt(2, invocation_type);
// TODO(regis): Support invocation of generic functions with type arguments.
args.SetAt(3, Object::null_type_arguments());
args.SetAt(4, arguments);
args.SetAt(5, argument_names);
const Library& libcore = Library::Handle(Library::CoreLibrary());
const Class& NoSuchMethodError =
Class::Handle(libcore.LookupClass(Symbols::NoSuchMethodError()));
const Function& throwNew = Function::Handle(
NoSuchMethodError.LookupFunctionAllowPrivate(Symbols::ThrowNew()));
const Object& result =
Object::Handle(DartEntry::InvokeFunction(throwNew, args));
ASSERT(result.IsError());
Exceptions::PropagateError(Error::Cast(result));
UNREACHABLE();
}
static void EnsureConstructorsAreCompiled(const Function& func) {
// Only generative constructors can have initializing formals.
if (!func.IsGenerativeConstructor()) return;
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Class& cls = Class::Handle(zone, func.Owner());
const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
func.EnsureHasCode();
}
static RawInstance* CreateParameterMirrorList(const Function& func,
const Instance& owner_mirror) {
HANDLESCOPE(Thread::Current());
const intptr_t implicit_param_count = func.NumImplicitParameters();
const intptr_t non_implicit_param_count =
func.NumParameters() - implicit_param_count;
const intptr_t index_of_first_optional_param =
non_implicit_param_count - func.NumOptionalParameters();
const intptr_t index_of_first_named_param =
non_implicit_param_count - func.NumOptionalNamedParameters();
const Array& results = Array::Handle(Array::New(non_implicit_param_count));
const Array& args = Array::Handle(Array::New(9));
Smi& pos = Smi::Handle();
String& name = String::Handle();
Instance& param = Instance::Handle();
Bool& is_final = Bool::Handle();
Object& default_value = Object::Handle();
Object& metadata = Object::Handle();
// We force compilation of constructors to ensure the types of initializing
// formals have been corrected. We do not force the compilation of all types
// of functions because some have no body, e.g. signature functions.
EnsureConstructorsAreCompiled(func);
bool has_extra_parameter_info = true;
if (non_implicit_param_count == 0) {
has_extra_parameter_info = false;
}
if (func.IsImplicitConstructor()) {
// This covers the default constructor and forwarding constructors.
has_extra_parameter_info = false;
}
if (func.IsSignatureFunction() &&
(func.token_pos() == TokenPosition::kNoSource)) {
// Signature functions (except those describing typedefs) get canonicalized,
// hence do not have a token position, and therefore cannot be reparsed.
has_extra_parameter_info = false;
}
Array& param_descriptor = Array::Handle();
if (has_extra_parameter_info) {
// Reparse the function for the following information:
// * The default value of a parameter.
// * Whether a parameters has been declared as final.
// * Any metadata associated with the parameter.
Object& result = Object::Handle(kernel::BuildParameterDescriptor(func));
if (result.IsError()) {
Exceptions::PropagateError(Error::Cast(result));
UNREACHABLE();
}
param_descriptor ^= result.raw();
ASSERT(param_descriptor.Length() ==
(Parser::kParameterEntrySize * non_implicit_param_count));
}
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
args.SetAt(2, owner_mirror);
if (!has_extra_parameter_info) {
is_final = Bool::True().raw();
default_value = Object::null();
metadata = Object::null();
}
for (intptr_t i = 0; i < non_implicit_param_count; i++) {
pos = Smi::New(i);
name = func.ParameterNameAt(implicit_param_count + i);
if (has_extra_parameter_info) {
is_final ^= param_descriptor.At(i * Parser::kParameterEntrySize +
Parser::kParameterIsFinalOffset);
default_value = param_descriptor.At(i * Parser::kParameterEntrySize +
Parser::kParameterDefaultValueOffset);
metadata = param_descriptor.At(i * Parser::kParameterEntrySize +
Parser::kParameterMetadataOffset);
}
ASSERT(default_value.IsNull() || default_value.IsInstance());
// Arguments 0 (referent) and 2 (owner) are the same for all parameters. See
// above.
args.SetAt(1, name);
args.SetAt(3, pos);
args.SetAt(4, Bool::Get(i >= index_of_first_optional_param));
args.SetAt(5, Bool::Get(i >= index_of_first_named_param));
args.SetAt(6, is_final);
args.SetAt(7, default_value);
args.SetAt(8, metadata);
param = CreateMirror(Symbols::_ParameterMirror(), args);
results.SetAt(i, param);
}
results.MakeImmutable();
return results.raw();
}
static RawInstance* CreateTypeVariableMirror(const TypeParameter& param,
const Instance& owner_mirror) {
const Array& args = Array::Handle(Array::New(3));
args.SetAt(0, param);
args.SetAt(1, String::Handle(param.name()));
args.SetAt(2, owner_mirror);
return CreateMirror(Symbols::_TypeVariableMirror(), args);
}
// We create a list in native code and let Dart code create the type mirror
// object and the ordered map.
static RawInstance* CreateTypeVariableList(const Class& cls) {
const TypeArguments& args = TypeArguments::Handle(cls.type_parameters());
if (args.IsNull()) {
return Object::empty_array().raw();
}
const Array& result = Array::Handle(Array::New(args.Length() * 2));
TypeParameter& type = TypeParameter::Handle();
String& name = String::Handle();
for (intptr_t i = 0; i < args.Length(); i++) {
type ^= args.TypeAt(i);
ASSERT(type.IsTypeParameter());
ASSERT(type.IsFinalized());
name = type.name();
result.SetAt(2 * i, name);
result.SetAt(2 * i + 1, type);
}
return result.raw();
}
static RawInstance* CreateTypedefMirror(const Class& cls,
const AbstractType& type,
const Bool& is_declaration,
const Instance& owner_mirror) {
const Array& args = Array::Handle(Array::New(6));
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
args.SetAt(1, type);
args.SetAt(2, String::Handle(cls.Name()));
args.SetAt(3, Bool::Get(cls.IsGeneric()));
args.SetAt(4, cls.IsGeneric() ? is_declaration : Bool::False());
args.SetAt(5, owner_mirror);
return CreateMirror(Symbols::_TypedefMirror(), args);
}
static RawInstance* CreateFunctionTypeMirror(const AbstractType& type) {
ASSERT(type.IsFunctionType());
const Class& cls = Class::Handle(Type::Cast(type).type_class());
const Function& func = Function::Handle(Type::Cast(type).signature());
const Array& args = Array::Handle(Array::New(3));
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
args.SetAt(1, MirrorReference::Handle(MirrorReference::New(func)));
args.SetAt(2, type);
return CreateMirror(Symbols::_FunctionTypeMirror(), args);
}
static RawInstance* CreateMethodMirror(const Function& func,
const Instance& owner_mirror,
const AbstractType& instantiator) {
const Array& args = Array::Handle(Array::New(6));
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
String& name = String::Handle(func.name());
name = String::ScrubNameRetainPrivate(name, func.is_extension_member());
args.SetAt(1, name);
args.SetAt(2, owner_mirror);
args.SetAt(3, instantiator);
args.SetAt(4, Bool::Get(func.is_static()));
intptr_t kind_flags = 0;
kind_flags |=
(static_cast<intptr_t>(func.is_abstract()) << Mirrors::kAbstract);
kind_flags |=
(static_cast<intptr_t>(func.IsGetterFunction()) << Mirrors::kGetter);
kind_flags |=
(static_cast<intptr_t>(func.IsSetterFunction()) << Mirrors::kSetter);
bool is_ctor = (func.kind() == RawFunction::kConstructor);
kind_flags |= (static_cast<intptr_t>(is_ctor) << Mirrors::kConstructor);
kind_flags |= (static_cast<intptr_t>(is_ctor && func.is_const())
<< Mirrors::kConstCtor);
kind_flags |=
(static_cast<intptr_t>(is_ctor && func.IsGenerativeConstructor())
<< Mirrors::kGenerativeCtor);
kind_flags |= (static_cast<intptr_t>(is_ctor && func.is_redirecting())
<< Mirrors::kRedirectingCtor);
kind_flags |= (static_cast<intptr_t>(is_ctor && func.IsFactory())
<< Mirrors::kFactoryCtor);
kind_flags |=
(static_cast<intptr_t>(func.is_external()) << Mirrors::kExternal);
bool is_synthetic = func.is_no_such_method_forwarder();
kind_flags |= (static_cast<intptr_t>(is_synthetic) << Mirrors::kSynthetic);
kind_flags |= (static_cast<intptr_t>(func.is_extension_member())
<< Mirrors::kExtensionMember);
args.SetAt(5, Smi::Handle(Smi::New(kind_flags)));
return CreateMirror(Symbols::_MethodMirror(), args);
}
static RawInstance* CreateVariableMirror(const Field& field,
const Instance& owner_mirror) {
const MirrorReference& field_ref =
MirrorReference::Handle(MirrorReference::New(field));
const String& name = String::Handle(field.name());
const Array& args = Array::Handle(Array::New(8));
args.SetAt(0, field_ref);
args.SetAt(1, name);
args.SetAt(2, owner_mirror);
args.SetAt(3, Object::null_instance()); // Null for type.
args.SetAt(4, Bool::Get(field.is_static()));
args.SetAt(5, Bool::Get(field.is_final()));
args.SetAt(6, Bool::Get(field.is_const()));
args.SetAt(7, Bool::Get(field.is_extension_member()));
return CreateMirror(Symbols::_VariableMirror(), args);
}
static RawInstance* CreateClassMirror(const Class& cls,
const AbstractType& type,
const Bool& is_declaration,
const Instance& owner_mirror) {
if (type.IsTypeRef()) {
AbstractType& ref_type = AbstractType::Handle(TypeRef::Cast(type).type());
ASSERT(!ref_type.IsTypeRef());
ASSERT(ref_type.IsCanonical());
return CreateClassMirror(cls, ref_type, is_declaration, owner_mirror);
}
ASSERT(!cls.IsDynamicClass() && !cls.IsVoidClass());
ASSERT(!type.IsNull());
ASSERT(type.IsFinalized());
if (cls.IsTypedefClass()) {
return CreateTypedefMirror(cls, type, is_declaration, owner_mirror);
}
const Array& args = Array::Handle(Array::New(9));
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
args.SetAt(1, type);
args.SetAt(2, String::Handle(cls.Name()));
args.SetAt(3, owner_mirror);
args.SetAt(4, Bool::Get(cls.is_abstract()));
args.SetAt(5, Bool::Get(cls.IsGeneric()));
args.SetAt(6, Bool::Get(cls.is_transformed_mixin_application()));
args.SetAt(7, cls.NumTypeParameters() == 0 ? Bool::False() : is_declaration);
args.SetAt(8, Bool::Get(cls.is_enum_class()));
return CreateMirror(Symbols::_ClassMirror(), args);
}
static bool IsCensoredLibrary(const String& url) {
static const char* const censored_libraries[] = {
"dart:_builtin",
"dart:_vmservice",
"dart:vmservice_io",
};
for (const char* censored_library : censored_libraries) {
if (url.Equals(censored_library)) {
return true;
}
}
if (!Api::IsFfiEnabled() && url.Equals(Symbols::DartFfi())) {
return true;
}
return false;
}
static RawInstance* CreateLibraryMirror(Thread* thread, const Library& lib) {
Zone* zone = thread->zone();
ASSERT(!lib.IsNull());
const Array& args = Array::Handle(zone, Array::New(3));
args.SetAt(0, MirrorReference::Handle(zone, MirrorReference::New(lib)));
String& str = String::Handle(zone);
str = lib.name();
args.SetAt(1, str);
str = lib.url();
if (IsCensoredLibrary(str)) {
// Censored library (grumble).
return Instance::null();
}
args.SetAt(2, str);
return CreateMirror(Symbols::_LibraryMirror(), args);
}
static RawInstance* CreateCombinatorMirror(const Object& identifiers,
bool is_show) {
const Array& args = Array::Handle(Array::New(2));
args.SetAt(0, identifiers);
args.SetAt(1, Bool::Get(is_show));
return CreateMirror(Symbols::_CombinatorMirror(), args);
}
static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
const Instance& importer,
const Library& importee,
const Array& show_names,
const Array& hide_names,
const Object& metadata,
const LibraryPrefix& prefix,
const String& prefix_name,
const bool is_import,
const bool is_deferred) {
const Instance& importee_mirror =
Instance::Handle(CreateLibraryMirror(thread, importee));
if (importee_mirror.IsNull()) {
// Imported library is censored: censor the import.
return Instance::null();
}
intptr_t n = show_names.IsNull() ? 0 : show_names.Length();
intptr_t m = hide_names.IsNull() ? 0 : hide_names.Length();
const Array& combinators = Array::Handle(Array::New(n + m));
Object& t = Object::Handle();
intptr_t i = 0;
for (intptr_t j = 0; j < n; j++) {
t = show_names.At(j);
t = CreateCombinatorMirror(t, true);
combinators.SetAt(i++, t);
}
for (intptr_t j = 0; j < m; j++) {
t = hide_names.At(j);
t = CreateCombinatorMirror(t, false);
combinators.SetAt(i++, t);
}
const Array& args = Array::Handle(Array::New(7));
args.SetAt(0, importer);
if (importee.Loaded() || prefix.IsNull()) {
// A native extension is never "loaded" by the embedder. Use the fact that
// it doesn't have an prefix where asa deferred import does to distinguish
// it from a deferred import. It will appear like an empty library.
args.SetAt(1, importee_mirror);
} else {
args.SetAt(1, prefix);
}
args.SetAt(2, combinators);
args.SetAt(3, prefix_name);
args.SetAt(4, Bool::Get(is_import));
args.SetAt(5, Bool::Get(is_deferred));
args.SetAt(6, metadata);
return CreateMirror(Symbols::_LibraryDependencyMirror(), args);
}
static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
const Instance& importer,
const Namespace& ns,
const LibraryPrefix& prefix,
const bool is_import,
const bool is_deferred) {
const Library& importee = Library::Handle(ns.library());
const Array& show_names = Array::Handle(ns.show_names());
const Array& hide_names = Array::Handle(ns.hide_names());
Object& metadata = Object::Handle(ns.GetMetadata());
if (metadata.IsError()) {
Exceptions::PropagateError(Error::Cast(metadata));
UNREACHABLE();
}
auto& prefix_name = String::Handle();
if (!prefix.IsNull()) {
prefix_name = prefix.name();
}
return CreateLibraryDependencyMirror(thread, importer, importee, show_names,
hide_names, metadata, prefix,
prefix_name, is_import, is_deferred);
}
static RawGrowableObjectArray* CreateBytecodeLibraryDependencies(
Thread* thread,
const Library& lib,
const Instance& lib_mirror) {
ASSERT(lib.is_declared_in_bytecode());
// Make sure top level class (containing annotations) is fully loaded.
lib.EnsureTopLevelClassIsFinalized();
const auto& deps = GrowableObjectArray::Handle(GrowableObjectArray::New());
Array& metadata = Array::Handle(lib.GetExtendedMetadata(lib, 1));
if (metadata.Length() == 0) {
return deps.raw();
}
// Library has the only element in the extended metadata.
metadata ^= metadata.At(0);
if (metadata.IsNull()) {
return deps.raw();
}
auto& desc = Array::Handle();
auto& target_uri = String::Handle();
auto& importee = Library::Handle();
auto& is_export = Bool::Handle();
auto& is_deferred = Bool::Handle();
auto& prefix_name = String::Handle();
auto& show_names = Array::Handle();
auto& hide_names = Array::Handle();
auto& dep_metadata = Instance::Handle();
auto& dep = Instance::Handle();
const auto& no_prefix = LibraryPrefix::Handle();
for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
desc ^= metadata.At(i);
// Each dependency is represented as an array with the following layout:
// [0] = target library URI (String)
// [1] = is_export (bool)
// [2] = is_deferred (bool)
// [3] = prefix (String or null)
// [4] = list of show names (List<String>)
// [5] = list of hide names (List<String>)
// [6] = annotations
// The library dependencies are encoded by getLibraryAnnotations(),
// pkg/vm/lib/bytecode/gen_bytecode.dart.
target_uri ^= desc.At(0);
is_export ^= desc.At(1);
is_deferred ^= desc.At(2);
prefix_name ^= desc.At(3);
show_names ^= desc.At(4);
hide_names ^= desc.At(5);
dep_metadata ^= desc.At(6);
importee = Library::LookupLibrary(thread, target_uri);
if (importee.IsNull()) {
continue;
}
ASSERT(importee.Loaded());
dep = CreateLibraryDependencyMirror(
thread, lib_mirror, importee, show_names, hide_names, dep_metadata,
no_prefix, prefix_name, !is_export.value(), is_deferred.value());
if (!dep.IsNull()) {
deps.Add(dep);
}
}
return deps.raw();
}
DEFINE_NATIVE_ENTRY(LibraryMirror_fromPrefix, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(LibraryPrefix, prefix,
arguments->NativeArgAt(0));
const Library& deferred_lib = Library::Handle(prefix.GetLibrary(0));
if (!deferred_lib.Loaded()) {
return Instance::null();
}
return CreateLibraryMirror(thread, deferred_lib);
}
DEFINE_NATIVE_ENTRY(LibraryMirror_libraryDependencies, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, lib_mirror, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Library& lib = Library::Handle(ref.GetLibraryReferent());
if (lib.is_declared_in_bytecode()) {
return CreateBytecodeLibraryDependencies(thread, lib, lib_mirror);
}
Array& ports = Array::Handle();
Namespace& ns = Namespace::Handle();
Instance& dep = Instance::Handle();
LibraryPrefix& prefix = LibraryPrefix::Handle();
GrowableObjectArray& deps =
GrowableObjectArray::Handle(GrowableObjectArray::New());
// Unprefixed imports.
ports = lib.imports();
for (intptr_t i = 0; i < ports.Length(); i++) {
ns ^= ports.At(i);
if (!ns.IsNull()) {
dep = CreateLibraryDependencyMirror(thread, lib_mirror, ns, prefix, true,
false);
if (!dep.IsNull()) {
deps.Add(dep);
}
}
}
// Exports.
ports = lib.exports();
for (intptr_t i = 0; i < ports.Length(); i++) {
ns ^= ports.At(i);
dep = CreateLibraryDependencyMirror(thread, lib_mirror, ns, prefix, false,
false);
if (!dep.IsNull()) {
deps.Add(dep);
}
}
// Prefixed imports.
DictionaryIterator entries(lib);
Object& entry = Object::Handle();
while (entries.HasNext()) {
entry = entries.GetNext();
if (entry.IsLibraryPrefix()) {
prefix ^= entry.raw();
ports = prefix.imports();
for (intptr_t i = 0; i < ports.Length(); i++) {
ns ^= ports.At(i);
if (!ns.IsNull()) {
dep = CreateLibraryDependencyMirror(thread, lib_mirror, ns, prefix,
true, prefix.is_deferred_load());
if (!dep.IsNull()) {
deps.Add(dep);
}
}
}
}
}
return deps.raw();
}
static RawInstance* CreateTypeMirror(const AbstractType& type) {
if (type.IsTypeRef()) {
AbstractType& ref_type = AbstractType::Handle(TypeRef::Cast(type).type());
ASSERT(!ref_type.IsTypeRef());
ASSERT(ref_type.IsCanonical());
return CreateTypeMirror(ref_type);
}
ASSERT(type.IsFinalized());
ASSERT(type.IsCanonical() || type.IsTypeParameter());
if (type.IsFunctionType()) {
const Class& scope_class = Class::Handle(Type::Cast(type).type_class());
if (scope_class.IsTypedefClass()) {
return CreateTypedefMirror(scope_class, type, Bool::False(),
Object::null_instance());
} else {
return CreateFunctionTypeMirror(type);
}
}
if (type.HasTypeClass()) {
const Class& cls = Class::Handle(type.type_class());
// Handle void and dynamic types.
if (cls.IsVoidClass()) {
Array& args = Array::Handle(Array::New(1));
args.SetAt(0, Symbols::Void());
return CreateMirror(Symbols::_SpecialTypeMirror(), args);
} else if (cls.IsDynamicClass()) {
Array& args = Array::Handle(Array::New(1));
args.SetAt(0, Symbols::Dynamic());
return CreateMirror(Symbols::_SpecialTypeMirror(), args);
}
// TODO(regis): Until mirrors reflect nullability, force kLegacy, except for
// Null type, which should remain nullable.
if (!type.IsNullType()) {
const Type& legacy_type = Type::Handle(
Type::Cast(type).ToNullability(Nullability::kLegacy, Heap::kOld));
return CreateClassMirror(cls, legacy_type, Bool::False(),
Object::null_instance());
}
return CreateClassMirror(cls, type, Bool::False(), Object::null_instance());
} else if (type.IsTypeParameter()) {
// TODO(regis): Until mirrors reflect nullability, force kLegacy.
const TypeParameter& legacy_type =
TypeParameter::Handle(TypeParameter::Cast(type).ToNullability(
Nullability::kLegacy, Heap::kOld));
return CreateTypeVariableMirror(legacy_type, Object::null_instance());
}
UNREACHABLE();
return Instance::null();
}
static RawInstance* CreateIsolateMirror() {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
const String& debug_name = String::Handle(String::New(isolate->name()));
const Library& root_library =
Library::Handle(thread->zone(), isolate->object_store()->root_library());
const Instance& root_library_mirror =
Instance::Handle(CreateLibraryMirror(thread, root_library));
const Array& args = Array::Handle(Array::New(2));
args.SetAt(0, debug_name);
args.SetAt(1, root_library_mirror);
return CreateMirror(Symbols::_IsolateMirror(), args);
}
static void VerifyMethodKindShifts() {
#ifdef DEBUG
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Library& lib = Library::Handle(zone, Library::MirrorsLibrary());
const Class& cls = Class::Handle(
zone, lib.LookupClassAllowPrivate(Symbols::_MethodMirror()));
Error& error = Error::Handle(zone);
error ^= cls.EnsureIsFinalized(thread);
ASSERT(error.IsNull());
Field& field = Field::Handle(zone);
Smi& value = Smi::Handle(zone);
String& fname = String::Handle(zone);
#define CHECK_KIND_SHIFT(name) \
fname ^= String::New(#name); \
field = cls.LookupField(fname); \
ASSERT(!field.IsNull()); \
if (field.IsUninitialized()) { \
error ^= field.InitializeStatic(); \
ASSERT(error.IsNull()); \
} \
value ^= field.StaticValue(); \
ASSERT(value.Value() == Mirrors::name);
MIRRORS_KIND_SHIFT_LIST(CHECK_KIND_SHIFT)
#undef CHECK_KIND_SHIFT
#endif
}
static RawAbstractType* InstantiateType(const AbstractType& type,
const AbstractType& instantiator) {
// Generic function type parameters are not reified, but mapped to dynamic,
// i.e. all function type parameters are free with a null vector.
ASSERT(type.IsFinalized());
ASSERT(type.IsCanonical() || type.IsTypeParameter());
if (type.IsInstantiated()) {
return type.Canonicalize();
}
TypeArguments& instantiator_type_args = TypeArguments::Handle();
if (!instantiator.IsNull()) {
ASSERT(instantiator.IsFinalized());
instantiator_type_args = instantiator.arguments();
}
AbstractType& result = AbstractType::Handle(type.InstantiateFrom(
NNBDMode::kLegacyLib, instantiator_type_args,
Object::null_type_arguments(), kAllFree, NULL, Heap::kOld));
ASSERT(result.IsFinalized());
return result.Canonicalize();
}
DEFINE_NATIVE_ENTRY(MirrorSystem_libraries, 0, 0) {
const GrowableObjectArray& libraries =
GrowableObjectArray::Handle(zone, isolate->object_store()->libraries());
const intptr_t num_libraries = libraries.Length();
const GrowableObjectArray& library_mirrors = GrowableObjectArray::Handle(
zone, GrowableObjectArray::New(num_libraries));
Library& library = Library::Handle(zone);
Instance& library_mirror = Instance::Handle(zone);
for (int i = 0; i < num_libraries; i++) {
library ^= libraries.At(i);
library_mirror = CreateLibraryMirror(thread, library);
if (!library_mirror.IsNull() && library.Loaded()) {
library_mirrors.Add(library_mirror);
}
}
return library_mirrors.raw();
}
DEFINE_NATIVE_ENTRY(MirrorSystem_isolate, 0, 0) {
VerifyMethodKindShifts();
return CreateIsolateMirror();
}
static void ThrowLanguageError(const char* message) {
const Error& error =
Error::Handle(LanguageError::New(String::Handle(String::New(message))));
Exceptions::PropagateError(error);
}
DEFINE_NATIVE_ENTRY(IsolateMirror_loadUri, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(0));
if (!isolate->HasTagHandler()) {
ThrowLanguageError("no library handler registered");
}
NoReloadScope no_reload(isolate, thread);
// Canonicalize library URI.
String& canonical_uri = String::Handle(zone);
if (uri.StartsWith(Symbols::DartScheme())) {
canonical_uri = uri.raw();
} else {
isolate->BlockClassFinalization();
const Object& result = Object::Handle(
zone,
isolate->CallTagHandler(
Dart_kCanonicalizeUrl,
Library::Handle(zone, isolate->object_store()->root_library()),
uri));
isolate->UnblockClassFinalization();
if (result.IsError()) {
if (result.IsLanguageError()) {
Exceptions::ThrowCompileTimeError(LanguageError::Cast(result));
}
Exceptions::PropagateError(Error::Cast(result));
} else if (!result.IsString()) {
ThrowLanguageError("library handler failed URI canonicalization");
}
canonical_uri ^= result.raw();
}
// Return the existing library if it has already been loaded.
Library& library =
Library::Handle(zone, Library::LookupLibrary(thread, canonical_uri));
if (!library.IsNull()) {
return CreateLibraryMirror(thread, library);
}
// Request the embedder to load the library.
isolate->BlockClassFinalization();
Object& result = Object::Handle(
zone, isolate->CallTagHandler(
Dart_kImportTag,
Library::Handle(zone, isolate->object_store()->root_library()),
canonical_uri));
isolate->UnblockClassFinalization();
if (result.IsError()) {
if (result.IsLanguageError()) {
Exceptions::ThrowCompileTimeError(LanguageError::Cast(result));
}
Exceptions::PropagateError(Error::Cast(result));
}
// This code assumes a synchronous tag handler (which dart::bin and tonic
// provide). Strictly though we should complete a future in response to
// Dart_FinalizeLoading.
if (!ClassFinalizer::ProcessPendingClasses()) {
Exceptions::PropagateError(Error::Handle(thread->sticky_error()));
}
// Prefer the tag handler's idea of which library is represented by the URI.
if (result.IsLibrary()) {
return CreateLibraryMirror(thread, Library::Cast(result));
}
if (result.IsNull()) {
library = Library::LookupLibrary(thread, canonical_uri);
if (!library.IsNull()) {
return CreateLibraryMirror(thread, library);
}
}
FATAL("Non-library from tag handler");
}
DEFINE_NATIVE_ENTRY(Mirrors_makeLocalClassMirror, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
ASSERT(type.IsFinalized());
ASSERT(type.HasTypeClass());
const Class& cls = Class::Handle(type.type_class());
ASSERT(!cls.IsNull());
if (cls.IsDynamicClass() || cls.IsVoidClass() || cls.IsTypedefClass()) {
Exceptions::ThrowArgumentError(type);
UNREACHABLE();
}
return CreateClassMirror(cls, AbstractType::Handle(cls.DeclarationType()),
Bool::True(), // is_declaration
Object::null_instance());
}
DEFINE_NATIVE_ENTRY(Mirrors_makeLocalTypeMirror, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
return CreateTypeMirror(type);
}
DEFINE_NATIVE_ENTRY(Mirrors_instantiateGenericType, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(1));
ASSERT(type.HasTypeClass());
const Class& clz = Class::Handle(type.type_class());
if (!clz.IsGeneric()) {
const Array& error_args = Array::Handle(Array::New(3));
error_args.SetAt(0, type);
error_args.SetAt(1, String::Handle(String::New("key")));
error_args.SetAt(2, String::Handle(String::New(
"Type must be a generic class or function.")));
Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args);
UNREACHABLE();
}
if (clz.NumTypeParameters() != args.Length()) {
const Array& error_args = Array::Handle(Array::New(3));
error_args.SetAt(0, args);
error_args.SetAt(1, String::Handle(String::New("typeArguments")));
error_args.SetAt(2, String::Handle(String::New(
"Number of type arguments does not match.")));
Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args);
UNREACHABLE();
}
intptr_t num_expected_type_arguments = args.Length();
TypeArguments& type_args_obj = TypeArguments::Handle();
type_args_obj = TypeArguments::New(num_expected_type_arguments);
AbstractType& type_arg = AbstractType::Handle();
Instance& instance = Instance::Handle();
for (intptr_t i = 0; i < args.Length(); i++) {
instance ^= args.At(i);
if (!instance.IsType()) {
const Array& error_args = Array::Handle(Array::New(3));
error_args.SetAt(0, args);
error_args.SetAt(1, String::Handle(String::New("typeArguments")));
error_args.SetAt(2, String::Handle(String::New(
"Type arguments must be instances of Type.")));
Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args);
UNREACHABLE();
}
type_arg ^= args.At(i);
type_args_obj.SetTypeAt(i, type_arg);
}
Type& instantiated_type =
Type::Handle(Type::New(clz, type_args_obj, TokenPosition::kNoSource));
instantiated_type ^= ClassFinalizer::FinalizeType(clz, instantiated_type);
return instantiated_type.raw();
}
DEFINE_NATIVE_ENTRY(Mirrors_mangleName, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Library& lib = Library::Handle(ref.GetLibraryReferent());
return lib.IsPrivate(name) ? lib.PrivateName(name) : name.raw();
}
DEFINE_NATIVE_ENTRY(MirrorReference_equals, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, a, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, b, arguments->NativeArgAt(1));
return Bool::Get(a.referent() == b.referent()).raw();
}
DEFINE_NATIVE_ENTRY(DeclarationMirror_metadata, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(0));
Object& decl = Object::Handle();
if (reflectee.IsMirrorReference()) {
const MirrorReference& decl_ref = MirrorReference::Cast(reflectee);
decl = decl_ref.referent();
} else if (reflectee.IsTypeParameter()) {
decl = reflectee.raw();
} else {
UNREACHABLE();
}
Class& klass = Class::Handle();
Library& library = Library::Handle();
if (decl.IsClass()) {
klass ^= decl.raw();
library = klass.library();
} else if (decl.IsFunction() && !Function::Cast(decl).IsSignatureFunction()) {
klass = Function::Cast(decl).origin();
library = klass.library();
} else if (decl.IsField()) {
klass = Field::Cast(decl).Origin();
library = klass.library();
} else if (decl.IsLibrary()) {
library ^= decl.raw();
} else if (decl.IsTypeParameter()) {
if (TypeParameter::Cast(decl).IsFunctionTypeParameter()) {
// TODO(regis): Fully support generic functions.
return Object::empty_array().raw();
}
klass = TypeParameter::Cast(decl).parameterized_class();
library = klass.library();
} else {
return Object::empty_array().raw();
}
const Object& metadata = Object::Handle(library.GetMetadata(decl));
if (metadata.IsError()) {
Exceptions::PropagateError(Error::Cast(metadata));
}
return metadata.raw();
}
DEFINE_NATIVE_ENTRY(FunctionTypeMirror_call_method, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner_mirror,
arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
// TODO(rmacnak): Return get:call() method on class _Closure instead?
// This now returns the result of invoking that call getter.
const Function& func = Function::Handle(ref.GetFunctionReferent());
ASSERT(!func.IsNull());
return CreateMethodMirror(func, owner_mirror, AbstractType::Handle());
}
DEFINE_NATIVE_ENTRY(FunctionTypeMirror_parameters, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Function& func = Function::Handle(ref.GetFunctionReferent());
return CreateParameterMirrorList(func, owner);
}
DEFINE_NATIVE_ENTRY(FunctionTypeMirror_return_type, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Function& func = Function::Handle(ref.GetFunctionReferent());
ASSERT(!func.IsNull());
AbstractType& type = AbstractType::Handle(func.result_type());
// Signatures of function types are instantiated, but not canonical.
return type.Canonicalize();
}
DEFINE_NATIVE_ENTRY(ClassMirror_libraryUri, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Class& klass = Class::Handle(ref.GetClassReferent());
const Library& library = Library::Handle(klass.library());
ASSERT(!library.IsNull());
return library.url();
}
DEFINE_NATIVE_ENTRY(ClassMirror_supertype, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
ASSERT(type.IsFinalized());
const Class& cls = Class::Handle(type.type_class());
const AbstractType& super_type = AbstractType::Handle(cls.super_type());
ASSERT(super_type.IsNull() || super_type.IsFinalized());
return super_type.raw();
}
DEFINE_NATIVE_ENTRY(ClassMirror_supertype_instantiated, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
ASSERT(type.IsFinalized());
const Class& cls = Class::Handle(type.type_class());
const AbstractType& super_type = AbstractType::Handle(cls.super_type());
return InstantiateType(super_type, type);
}
DEFINE_NATIVE_ENTRY(ClassMirror_interfaces, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
ASSERT(type.IsFinalized());
const Class& cls = Class::Handle(type.type_class());
const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
return cls.interfaces();
}
DEFINE_NATIVE_ENTRY(ClassMirror_interfaces_instantiated, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
ASSERT(type.IsFinalized());
const Class& cls = Class::Handle(type.type_class());
const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
Array& interfaces = Array::Handle(cls.interfaces());
Array& interfaces_inst = Array::Handle(Array::New(interfaces.Length()));
AbstractType& interface = AbstractType::Handle();
for (int i = 0; i < interfaces.Length(); i++) {
interface ^= interfaces.At(i);
interface = InstantiateType(interface, type);
interfaces_inst.SetAt(i, interface);
}
return interfaces_inst.raw();
}
DEFINE_NATIVE_ENTRY(ClassMirror_mixin, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
ASSERT(type.IsFinalized());
const Class& cls = Class::Handle(type.type_class());
AbstractType& mixin_type = AbstractType::Handle();
if (cls.is_transformed_mixin_application()) {
const Array& interfaces = Array::Handle(cls.interfaces());
mixin_type ^= interfaces.At(interfaces.Length() - 1);
}
ASSERT(mixin_type.IsNull() || mixin_type.IsFinalized());
return mixin_type.raw();
}
DEFINE_NATIVE_ENTRY(ClassMirror_mixin_instantiated, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, instantiator,
arguments->NativeArgAt(1));
ASSERT(type.IsFinalized());
const Class& cls = Class::Handle(type.type_class());
AbstractType& mixin_type = AbstractType::Handle();
if (cls.is_transformed_mixin_application()) {
const Array& interfaces = Array::Handle(cls.interfaces());
mixin_type ^= interfaces.At(interfaces.Length() - 1);
}
if (mixin_type.IsNull()) {
return mixin_type.raw();
}
return InstantiateType(mixin_type, instantiator);
}
DEFINE_NATIVE_ENTRY(ClassMirror_members, 0, 3) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner_mirror,
arguments->NativeArgAt(0));
GET_NATIVE_ARGUMENT(AbstractType, owner_instantiator,
arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
const Class& klass = Class::Handle(ref.GetClassReferent());
const Error& error = Error::Handle(klass.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
const Array& fields = Array::Handle(klass.fields());
const intptr_t num_fields = fields.Length();
const Array& functions = Array::Handle(klass.functions());
const intptr_t num_functions = functions.Length();
Instance& member_mirror = Instance::Handle();
const GrowableObjectArray& member_mirrors = GrowableObjectArray::Handle(
GrowableObjectArray::New(num_fields + num_functions));
Field& field = Field::Handle();
for (intptr_t i = 0; i < num_fields; i++) {
field ^= fields.At(i);
if (field.is_reflectable()) {
member_mirror = CreateVariableMirror(field, owner_mirror);
member_mirrors.Add(member_mirror);
}
}
Function& func = Function::Handle();
for (intptr_t i = 0; i < num_functions; i++) {
func ^= functions.At(i);
if (func.is_reflectable() &&
(func.kind() == RawFunction::kRegularFunction ||
func.kind() == RawFunction::kGetterFunction ||
func.kind() == RawFunction::kSetterFunction)) {
member_mirror =
CreateMethodMirror(func, owner_mirror, owner_instantiator);
member_mirrors.Add(member_mirror);
}
}
return member_mirrors.raw();
}
DEFINE_NATIVE_ENTRY(ClassMirror_constructors, 0, 3) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner_mirror,
arguments->NativeArgAt(0));
GET_NATIVE_ARGUMENT(AbstractType, owner_instantiator,
arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
const Class& klass = Class::Handle(ref.GetClassReferent());
const Error& error = Error::Handle(klass.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
const Array& functions = Array::Handle(klass.functions());
const intptr_t num_functions = functions.Length();
Instance& constructor_mirror = Instance::Handle();
const GrowableObjectArray& constructor_mirrors =
GrowableObjectArray::Handle(GrowableObjectArray::New(num_functions));
Function& func = Function::Handle();
for (intptr_t i = 0; i < num_functions; i++) {
func ^= functions.At(i);
if (func.is_reflectable() && func.kind() == RawFunction::kConstructor) {
constructor_mirror =
CreateMethodMirror(func, owner_mirror, owner_instantiator);
constructor_mirrors.Add(constructor_mirror);
}
}
return constructor_mirrors.raw();
}
DEFINE_NATIVE_ENTRY(LibraryMirror_members, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner_mirror,
arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Library& library = Library::Handle(zone, ref.GetLibraryReferent());
library.EnsureTopLevelClassIsFinalized();
Instance& member_mirror = Instance::Handle(zone);
const GrowableObjectArray& member_mirrors =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
Object& entry = Object::Handle(zone);
DictionaryIterator entries(library);
Error& error = Error::Handle(zone);
AbstractType& type = AbstractType::Handle(zone);
while (entries.HasNext()) {
entry = entries.GetNext();
if (entry.IsClass()) {
const Class& klass = Class::Cast(entry);
// We filter out dynamic.
// TODO(12478): Should not need to filter out dynamic.
if (!klass.IsDynamicClass()) {
error = klass.EnsureIsFinalized(thread);
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
type = klass.DeclarationType();
member_mirror = CreateClassMirror(klass, type,
Bool::True(), // is_declaration
owner_mirror);
member_mirrors.Add(member_mirror);
}
} else if (entry.IsField()) {
const Field& field = Field::Cast(entry);
if (field.is_reflectable()) {
member_mirror = CreateVariableMirror(field, owner_mirror);
member_mirrors.Add(member_mirror);
}
} else if (entry.IsFunction()) {
const Function& func = Function::Cast(entry);
if (func.is_reflectable() &&
(func.kind() == RawFunction::kRegularFunction ||
func.kind() == RawFunction::kGetterFunction ||
func.kind() == RawFunction::kSetterFunction)) {
member_mirror =
CreateMethodMirror(func, owner_mirror, AbstractType::Handle());
member_mirrors.Add(member_mirror);
}
}
}
return member_mirrors.raw();
}
DEFINE_NATIVE_ENTRY(ClassMirror_type_variables, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Class& klass = Class::Handle(ref.GetClassReferent());
const Error& error = Error::Handle(zone, klass.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
return CreateTypeVariableList(klass);
}
DEFINE_NATIVE_ENTRY(ClassMirror_type_arguments, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
const Class& cls = Class::Handle(type.type_class());
const intptr_t num_params = cls.NumTypeParameters();
if (num_params == 0) {
return Object::empty_array().raw();
}
const Array& result = Array::Handle(Array::New(num_params));
AbstractType& arg_type = AbstractType::Handle();
Instance& type_mirror = Instance::Handle();
const TypeArguments& args = TypeArguments::Handle(type.arguments());
// Handle argument lists that have been optimized away, because either no
// arguments have been provided, or all arguments are dynamic. Return a list
// of typemirrors on dynamic in this case.
if (args.IsNull()) {
arg_type = Object::dynamic_type().raw();
type_mirror = CreateTypeMirror(arg_type);
for (intptr_t i = 0; i < num_params; i++) {
result.SetAt(i, type_mirror);
}
return result.raw();
}
ASSERT(args.Length() >= num_params);
const intptr_t num_inherited_args = args.Length() - num_params;
for (intptr_t i = 0; i < num_params; i++) {
arg_type = args.TypeAt(i + num_inherited_args);
type_mirror = CreateTypeMirror(arg_type);
result.SetAt(i, type_mirror);
}
return result.raw();
}
DEFINE_NATIVE_ENTRY(TypeVariableMirror_owner, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(TypeParameter, param, arguments->NativeArgAt(0));
Class& owner = Class::Handle(param.parameterized_class());
AbstractType& type = AbstractType::Handle();
if (owner.IsNull()) {
// TODO(regis): Fully support generic functions. For now, reify function
// type parameters to dynamic and map their function owner to Null class.
ASSERT(param.IsFunctionTypeParameter());
type = Type::NullType();
owner = type.type_class();
} else {
type = owner.DeclarationType();
}
return CreateClassMirror(owner, type,
Bool::True(), // is_declaration
Instance::null_instance());
}
DEFINE_NATIVE_ENTRY(TypeVariableMirror_upper_bound, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(TypeParameter, param, arguments->NativeArgAt(0));
return param.bound();
}
DEFINE_NATIVE_ENTRY(TypedefMirror_declaration, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
ASSERT(type.IsFunctionType());
const Class& cls = Class::Handle(type.type_class());
ASSERT(cls.IsTypedefClass());
return CreateTypedefMirror(cls, AbstractType::Handle(cls.DeclarationType()),
Bool::True(), // is_declaration
Object::null_instance());
}
DEFINE_NATIVE_ENTRY(InstanceMirror_invoke, 0, 5) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(String, function_name,
arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4));
RETURN_OR_PROPAGATE(reflectee.Invoke(function_name, args, arg_names));
}
DEFINE_NATIVE_ENTRY(InstanceMirror_invokeGetter, 0, 3) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(String, getter_name, arguments->NativeArgAt(2));
RETURN_OR_PROPAGATE(reflectee.InvokeGetter(getter_name));
}
DEFINE_NATIVE_ENTRY(InstanceMirror_invokeSetter, 0, 4) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(String, setter_name, arguments->NativeArgAt(2));
GET_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(3));
RETURN_OR_PROPAGATE(reflectee.InvokeSetter(setter_name, value));
}
DEFINE_NATIVE_ENTRY(InstanceMirror_computeType, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
const AbstractType& type = AbstractType::Handle(instance.GetType(Heap::kNew));
// The static type of null is specified to be the bottom type, however, the
// runtime type of null is the Null type, which we correctly return here.
return type.Canonicalize();
}
DEFINE_NATIVE_ENTRY(ClosureMirror_function, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, closure, arguments->NativeArgAt(0));
ASSERT(!closure.IsNull());
Function& function = Function::Handle();
bool callable = closure.IsCallable(&function);
if (callable) {
const Function& parent = Function::Handle(function.parent_function());
if (function.IsImplicitClosureFunction() || parent.is_extension_member()) {
// The VM uses separate Functions for tear-offs, but the mirrors consider
// the tear-offs to be the same as the torn-off methods. Avoid handing out
// a reference to the tear-off here to avoid a special case in the
// the equality test.
// In the case of extension methods also we avoid handing out a reference
// to the tear-off and instead get the parent function of the
// anonymous closure.
function = parent.raw();
}
Type& instantiator = Type::Handle();
if (closure.IsClosure()) {
const TypeArguments& arguments = TypeArguments::Handle(
Closure::Cast(closure).instantiator_type_arguments());
// TODO(regis): Mirrors need work to properly support generic functions.
// The 'instantiator' created below should not be a type, but two type
// argument vectors: instantiator_type_arguments and
// function_type_arguments.
const Class& cls =
Class::Handle(Isolate::Current()->object_store()->object_class());
instantiator = Type::New(cls, arguments, TokenPosition::kNoSource);
instantiator.SetIsFinalized();
}
return CreateMethodMirror(function, Instance::null_instance(),
instantiator);
}
return Instance::null();
}
DEFINE_NATIVE_ENTRY(ClassMirror_invoke, 0, 5) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Class& klass = Class::Handle(ref.GetClassReferent());
GET_NON_NULL_NATIVE_ARGUMENT(String, function_name,
arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4));
RETURN_OR_PROPAGATE(klass.Invoke(function_name, args, arg_names));
}
DEFINE_NATIVE_ENTRY(ClassMirror_invokeGetter, 0, 3) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Class& klass = Class::Handle(ref.GetClassReferent());
const Error& error = Error::Handle(zone, klass.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
GET_NON_NULL_NATIVE_ARGUMENT(String, getter_name, arguments->NativeArgAt(2));
RETURN_OR_PROPAGATE(klass.InvokeGetter(getter_name, true));
}
DEFINE_NATIVE_ENTRY(ClassMirror_invokeSetter, 0, 4) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Class& klass = Class::Handle(ref.GetClassReferent());
GET_NON_NULL_NATIVE_ARGUMENT(String, setter_name, arguments->NativeArgAt(2));
GET_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(3));
RETURN_OR_PROPAGATE(klass.InvokeSetter(setter_name, value));
}
DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 0, 5) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Class& klass = Class::Handle(ref.GetClassReferent());
GET_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(String, constructor_name,
arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Array, explicit_args, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4));
const Error& error = Error::Handle(zone, klass.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
}
// By convention, the static function implementing a named constructor 'C'
// for class 'A' is labeled 'A.C', and the static function implementing the
// unnamed constructor for class 'A' is labeled 'A.'.
// This convention prevents users from explicitly calling constructors.
const String& klass_name = String::Handle(klass.Name());
String& external_constructor_name = String::Handle(klass_name.raw());
String& internal_constructor_name =
String::Handle(String::Concat(klass_name, Symbols::Dot()));
if (!constructor_name.IsNull() && constructor_name.Length() > 0) {
internal_constructor_name =
String::Concat(internal_constructor_name, constructor_name);
external_constructor_name = internal_constructor_name.raw();
}
Function& lookup_constructor =
Function::Handle(klass.LookupFunction(internal_constructor_name));
if (lookup_constructor.IsNull() ||
(lookup_constructor.kind() != RawFunction::kConstructor) ||
!lookup_constructor.is_reflectable()) {
ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
external_constructor_name, explicit_args, arg_names,
InvocationMirror::kConstructor,
InvocationMirror::kMethod);
UNREACHABLE();
}
if (klass.is_abstract() && !lookup_constructor.IsFactory()) {
const Array& error_args = Array::Handle(Array::New(3));
error_args.SetAt(0, klass_name);
// 1 = script url
// 2 = token position
Exceptions::ThrowByType(Exceptions::kAbstractClassInstantiation,
error_args);
UNREACHABLE();
}
ASSERT(!type.IsNull());
TypeArguments& type_arguments = TypeArguments::Handle(type.arguments());
if (!type.IsInstantiated()) {
// Must have been a declaration type.
AbstractType& rare_type = AbstractType::Handle(klass.RareType());
ASSERT(rare_type.IsInstantiated());
type_arguments = rare_type.arguments();
}
Class& redirected_klass = Class::Handle(klass.raw());
Function& redirected_constructor = Function::Handle(lookup_constructor.raw());
if (lookup_constructor.IsRedirectingFactory()) {
// Redirecting factory must be resolved.
ASSERT(lookup_constructor.RedirectionTarget() != Function::null());
Type& redirect_type = Type::Handle(lookup_constructor.RedirectionType());
if (!redirect_type.IsInstantiated()) {
// The type arguments of the redirection type are instantiated from the
// type arguments of the type reflected by the class mirror.
ASSERT(redirect_type.IsInstantiated(kFunctions));
redirect_type ^= redirect_type.InstantiateFrom(
NNBDMode::kLegacyLib, type_arguments, Object::null_type_arguments(),
kNoneFree, NULL, Heap::kOld);
redirect_type ^= redirect_type.Canonicalize();
}
type = redirect_type.raw();
type_arguments = redirect_type.arguments();
redirected_constructor = lookup_constructor.RedirectionTarget();
ASSERT(!redirected_constructor.IsNull());
redirected_klass = type.type_class();
}
const intptr_t num_explicit_args = explicit_args.Length();
const intptr_t num_implicit_args = 1;
const Array& args =
Array::Handle(Array::New(num_implicit_args + num_explicit_args));
// Copy over the explicit arguments.
Object& explicit_argument = Object::Handle();
for (int i = 0; i < num_explicit_args; i++) {
explicit_argument = explicit_args.At(i);
args.SetAt(i + num_implicit_args, explicit_argument);
}
const int kTypeArgsLen = 0;
const Array& args_descriptor_array = Array::Handle(
ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
ArgumentsDescriptor args_descriptor(args_descriptor_array);
if (!redirected_constructor.AreValidArguments(NNBDMode::kLegacyLib,
args_descriptor, NULL)) {
external_constructor_name = redirected_constructor.name();
ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
external_constructor_name, explicit_args, arg_names,
InvocationMirror::kConstructor,
InvocationMirror::kMethod);
UNREACHABLE();
}
const Object& type_error =
Object::Handle(redirected_constructor.DoArgumentTypesMatch(
NNBDMode::kLegacyLib, args, args_descriptor, type_arguments));
if (!type_error.IsNull()) {
Exceptions::PropagateError(Error::Cast(type_error));
UNREACHABLE();
}
Instance& new_object = Instance::Handle();
if (redirected_constructor.IsGenerativeConstructor()) {
// Constructors get the uninitialized object.
// Note we have delayed allocation until after the function
// type and argument matching checks.
new_object = Instance::New(redirected_klass);
if (!type_arguments.IsNull()) {
// The type arguments will be null if the class has no type parameters, in
// which case the following call would fail because there is no slot
// reserved in the object for the type vector.
new_object.SetTypeArguments(type_arguments);
}
args.SetAt(0, new_object);
} else {
// Factories get type arguments.
args.SetAt(0, type_arguments);
}
// Invoke the constructor and return the new object.
const Object& result = Object::Handle(DartEntry::InvokeFunction(
redirected_constructor, args, args_descriptor_array));
if (result.IsError()) {
Exceptions::PropagateError(Error::Cast(result));
UNREACHABLE();
}
// Factories may return null.
ASSERT(result.IsInstance() || result.IsNull());
if (redirected_constructor.IsGenerativeConstructor()) {
return new_object.raw();
} else {
return result.raw();
}
}
DEFINE_NATIVE_ENTRY(LibraryMirror_invoke, 0, 5) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Library& library = Library::Handle(ref.GetLibraryReferent());
GET_NON_NULL_NATIVE_ARGUMENT(String, function_name,
arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4));
RETURN_OR_PROPAGATE(library.Invoke(function_name, args, arg_names));
}
DEFINE_NATIVE_ENTRY(LibraryMirror_invokeGetter, 0, 3) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Library& library = Library::Handle(ref.GetLibraryReferent());
GET_NON_NULL_NATIVE_ARGUMENT(String, getter_name, arguments->NativeArgAt(2));
RETURN_OR_PROPAGATE(library.InvokeGetter(getter_name, true));
}
DEFINE_NATIVE_ENTRY(LibraryMirror_invokeSetter, 0, 4) {
// Argument 0 is the mirror, which is unused by the native. It exists
// because this native is an instance method in order to be polymorphic
// with its cousins.
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Library& library = Library::Handle(ref.GetLibraryReferent());
GET_NON_NULL_NATIVE_ARGUMENT(String, setter_name, arguments->NativeArgAt(2));
GET_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(3));
RETURN_OR_PROPAGATE(library.InvokeSetter(setter_name, value));
}
DEFINE_NATIVE_ENTRY(MethodMirror_owner, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
GET_NATIVE_ARGUMENT(AbstractType, instantiator, arguments->NativeArgAt(1));
const Function& func = Function::Handle(ref.GetFunctionReferent());
if (func.IsNonImplicitClosureFunction()) {
return CreateMethodMirror(Function::Handle(func.parent_function()),
Object::null_instance(), instantiator);
}
const Class& owner = Class::Handle(func.Owner());
if (owner.IsTopLevel()) {
return CreateLibraryMirror(thread, Library::Handle(owner.library()));
}
AbstractType& type = AbstractType::Handle(owner.DeclarationType());
return CreateClassMirror(owner, type, Bool::True(), Object::null_instance());
}
DEFINE_NATIVE_ENTRY(MethodMirror_parameters, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Function& func = Function::Handle(ref.GetFunctionReferent());
return CreateParameterMirrorList(func, owner);
}
DEFINE_NATIVE_ENTRY(MethodMirror_return_type, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Function& func = Function::Handle(ref.GetFunctionReferent());
GET_NATIVE_ARGUMENT(AbstractType, instantiator, arguments->NativeArgAt(1));
// We handle constructors in Dart code.
ASSERT(!func.IsGenerativeConstructor());
AbstractType& type = AbstractType::Handle(func.result_type());
type = type.Canonicalize(); // Instantiated signatures are not canonical.
return InstantiateType(type, instantiator);
}
DEFINE_NATIVE_ENTRY(MethodMirror_source, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Function& func = Function::Handle(ref.GetFunctionReferent());
return func.GetSource();
}
static RawInstance* CreateSourceLocation(const String& uri,
intptr_t line,
intptr_t column) {
const Array& args = Array::Handle(Array::New(3));
args.SetAt(0, uri);
args.SetAt(1, Smi::Handle(Smi::New(line)));
args.SetAt(2, Smi::Handle(Smi::New(column)));
return CreateMirror(Symbols::_SourceLocation(), args);
}
DEFINE_NATIVE_ENTRY(DeclarationMirror_location, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(0));
Object& decl = Object::Handle(zone);
if (reflectee.IsMirrorReference()) {
const MirrorReference& decl_ref = MirrorReference::Cast(reflectee);
decl = decl_ref.referent();
} else if (reflectee.IsTypeParameter()) {
decl = reflectee.raw();
} else {
UNREACHABLE();
}
Script& script = Script::Handle(zone);
TokenPosition token_pos = TokenPosition::kNoSource;
if (decl.IsFunction()) {
const Function& func = Function::Cast(decl);
if (func.IsImplicitConstructor() || func.IsSignatureFunction()) {
// These are synthetic methods; they have no source.
return Instance::null();
}
script = func.script();
token_pos = func.token_pos();
} else if (decl.IsClass()) {
const Class& cls = Class::Cast(decl);
const bool is_typedef = cls.IsTypedefClass();
if (cls.is_synthesized_class() && !is_typedef && !cls.is_enum_class()) {
return Instance::null(); // Synthetic.
}
script = cls.script();
token_pos = cls.token_pos();
} else if (decl.IsField()) {
const Field& field = Field::Cast(decl);
script = field.Script();
token_pos = field.token_pos();
} else if (decl.IsTypeParameter()) {
const TypeParameter& type_var = TypeParameter::Cast(decl);
if (type_var.IsFunctionTypeParameter()) {
// TODO(regis): Support generic functions.
return Instance::null();
}
const Class& owner = Class::Handle(zone, type_var.parameterized_class());
script = owner.script();
token_pos = type_var.token_pos();
} else if (decl.IsLibrary()) {
const Library& lib = Library::Cast(decl);
if (lib.raw() == Library::NativeWrappersLibrary()) {
return Instance::null(); // No source.
}
const Array& scripts = Array::Handle(zone, lib.LoadedScripts());
ASSERT(scripts.Length() > 0);
script ^= scripts.At(scripts.Length() - 1);
ASSERT(!script.IsNull());
const String& uri = String::Handle(zone, script.url());
return CreateSourceLocation(uri, 1, 1);
}
ASSERT(!script.IsNull());
if (token_pos == TokenPosition::kNoSource) {
return Instance::null();
}
const String& uri = String::Handle(zone, script.url());
intptr_t from_line = 0;
intptr_t from_col = 0;
if (script.HasSource()) {
script.GetTokenLocation(token_pos, &from_line, &from_col);
} else {
// Avoid the slow path of printing the token stream when precise source
// information is not available.
script.GetTokenLocation(token_pos, &from_line, NULL);
}
// We should always have at least the line number.
ASSERT(from_line != 0);
return CreateSourceLocation(uri, from_line, from_col);
}
DEFINE_NATIVE_ENTRY(TypedefMirror_referent, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
ASSERT(type.IsFunctionType());
const Class& cls = Class::Handle(type.type_class());
ASSERT(cls.IsTypedefClass());
const Function& sig_func = Function::Handle(cls.signature_function());
Type& referent_type = Type::Handle(sig_func.SignatureType());
ASSERT(cls.raw() == referent_type.type_class());
referent_type ^= InstantiateType(referent_type, type);
return CreateFunctionTypeMirror(referent_type);
}
DEFINE_NATIVE_ENTRY(ParameterMirror_type, 0, 3) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, pos, arguments->NativeArgAt(1));
GET_NATIVE_ARGUMENT(AbstractType, instantiator, arguments->NativeArgAt(2));
const Function& func = Function::Handle(ref.GetFunctionReferent());
AbstractType& type = AbstractType::Handle(
func.ParameterTypeAt(func.NumImplicitParameters() + pos.Value()));
type = type.Canonicalize(); // Instantiated signatures are not canonical.
return InstantiateType(type, instantiator);
}
DEFINE_NATIVE_ENTRY(VariableMirror_type, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
const Field& field = Field::Handle(ref.GetFieldReferent());
GET_NATIVE_ARGUMENT(AbstractType, instantiator, arguments->NativeArgAt(1));
const AbstractType& type = AbstractType::Handle(field.type());
return InstantiateType(type, instantiator);
}
DEFINE_NATIVE_ENTRY(TypeMirror_subtypeTest, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, a, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, b, arguments->NativeArgAt(1));
return Bool::Get(a.IsSubtypeOf(NNBDMode::kLegacyLib, b, Heap::kNew)).raw();
}
#endif // !DART_PRECOMPILED_RUNTIME
} // namespace dart