0920ac883c
Closures created via Closure::New() set the delayed type arguments to
the null type argument vector for non-generic closure functions and to
the empty type argument vector for generic closure functions. However,
closures created via the method extractor stub would always have the
empty type argument vector for delayed type arguments. Make the two
consistent by creating two method extractor stubs, one for generic
extracted methods and one for non-generic ones.
With this change, Closure::IsGeneric simply compares the delayed type
arguments against the empty type argument vector. This change also makes
method extraction for non-generic functions slightly faster, since the
delayed type arguments field is not changed post-allocation.
The old version of Closure::IsGeneric was the only use of
Closure::NumTypeParameters, so remove the latter method.
Related cleanups:
* Use similar checks for Class::IsGeneric and FunctionType::IsGeneric,
since they only have non-null type_parameters fields when generic.
For Class::IsGeneric, this avoids having to fetch the current thread
if the class declaration has been loaded.
* Refactor methods that read packed fields in FunctionType into two
methods, a static method that takes a FunctionTypePtr and an instance
method that calls the static method. Replace the methods in Function
that also directly read FunctionType packed fields with delegations to
the static methods.
* Rework Closure_equals to avoid unneeded handle allocation in certain
cases for non-equal closures.
* Replace cases that allocates a handle for the closure function only
for retrieving the signature with calls to Closure::signature().
TEST=language_2/closure/tearoff_dynamic_test
language_2/regress/regress45890_test
Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-x64-try,vm-kernel-linux-debug-x64c-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-nnbd-linux-release-simarm-try,vm-kernel-nnbd-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-nnbd-linux-release-simarm64-try,vm-kernel-linux-debug-simarm64c-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-simarm_x64-try
Change-Id: I29c8859c3350ed7b3f1a8f71d82a4393496b7c2b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/206820
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
583 lines
22 KiB
C++
583 lines
22 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/bootstrap_natives.h"
|
|
|
|
#include "lib/invocation_mirror.h"
|
|
#include "vm/code_patcher.h"
|
|
#include "vm/exceptions.h"
|
|
#include "vm/heap/heap.h"
|
|
#include "vm/native_entry.h"
|
|
#include "vm/object.h"
|
|
#include "vm/object_store.h"
|
|
#include "vm/resolver.h"
|
|
#include "vm/stack_frame.h"
|
|
#include "vm/symbols.h"
|
|
|
|
namespace dart {
|
|
|
|
DEFINE_NATIVE_ENTRY(DartAsync_fatal, 0, 1) {
|
|
// The dart:async library code entered an unrecoverable state.
|
|
const Instance& instance =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const char* msg = instance.ToCString();
|
|
OS::PrintErr("Fatal error in dart:async: %s\n", msg);
|
|
FATAL("%s", msg);
|
|
return Object::null();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_equals, 0, 1) {
|
|
// Implemented in the flow graph builder.
|
|
UNREACHABLE();
|
|
return Object::null();
|
|
}
|
|
|
|
static intptr_t GetHash(Isolate* isolate, const ObjectPtr obj) {
|
|
#if defined(HASH_IN_OBJECT_HEADER)
|
|
return Object::GetCachedHash(obj);
|
|
#else
|
|
Heap* heap = isolate->group()->heap();
|
|
ASSERT(obj->IsDartInstance());
|
|
return heap->GetHash(obj);
|
|
#endif
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_getHash, 0, 1) {
|
|
// Please note that no handle is created for the argument.
|
|
// This is safe since the argument is only used in a tail call.
|
|
// The performance benefit is more than 5% when using hashCode.
|
|
return Smi::New(GetHash(isolate, arguments->NativeArgAt(0)));
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_setHashIfNotSetYet, 0, 2) {
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Smi, hash, arguments->NativeArgAt(1));
|
|
#if defined(HASH_IN_OBJECT_HEADER)
|
|
return Smi::New(
|
|
Object::SetCachedHashIfNotSet(arguments->NativeArgAt(0), hash.Value()));
|
|
#else
|
|
const Instance& instance =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
Heap* heap = thread->heap();
|
|
return Smi::New(heap->SetHashIfNotSet(instance.ptr(), hash.Value()));
|
|
#endif
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_toString, 0, 1) {
|
|
const Instance& instance =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
if (instance.IsString()) {
|
|
return instance.ptr();
|
|
}
|
|
if (instance.IsAbstractType()) {
|
|
return AbstractType::Cast(instance).UserVisibleName();
|
|
}
|
|
const char* c_str = instance.ToCString();
|
|
return String::New(c_str);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_runtimeType, 0, 1) {
|
|
const Instance& instance =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
if (instance.IsString()) {
|
|
return Type::StringType();
|
|
} else if (instance.IsInteger()) {
|
|
return Type::IntType();
|
|
} else if (instance.IsDouble()) {
|
|
return Type::Double();
|
|
} else if (instance.IsType() || instance.IsFunctionType()) {
|
|
return Type::DartTypeType();
|
|
}
|
|
return instance.GetType(Heap::kNew);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_haveSameRuntimeType, 0, 2) {
|
|
const Instance& left =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const Instance& right =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
|
|
const intptr_t left_cid = left.GetClassId();
|
|
const intptr_t right_cid = right.GetClassId();
|
|
|
|
if (left_cid != right_cid) {
|
|
if (IsIntegerClassId(left_cid)) {
|
|
return Bool::Get(IsIntegerClassId(right_cid)).ptr();
|
|
} else if (IsStringClassId(left_cid)) {
|
|
return Bool::Get(IsStringClassId(right_cid)).ptr();
|
|
} else if (IsTypeClassId(left_cid)) {
|
|
return Bool::Get(IsTypeClassId(right_cid)).ptr();
|
|
} else {
|
|
return Bool::False().ptr();
|
|
}
|
|
}
|
|
|
|
const Class& cls = Class::Handle(left.clazz());
|
|
if (cls.IsClosureClass()) {
|
|
const auto& left_closure = Closure::Cast(left);
|
|
const auto& right_closure = Closure::Cast(right);
|
|
// If all the components that make up the instantiated signature are equal,
|
|
// then no need to instantiate.
|
|
if (left_closure.signature() == right_closure.signature() &&
|
|
left_closure.function_type_arguments() ==
|
|
right_closure.function_type_arguments() &&
|
|
left_closure.delayed_type_arguments() ==
|
|
right_closure.delayed_type_arguments() &&
|
|
left_closure.instantiator_type_arguments() ==
|
|
right_closure.instantiator_type_arguments()) {
|
|
return Bool::True().ptr();
|
|
}
|
|
const AbstractType& left_type =
|
|
AbstractType::Handle(zone, left.GetType(Heap::kNew));
|
|
const AbstractType& right_type =
|
|
AbstractType::Handle(zone, right.GetType(Heap::kNew));
|
|
return Bool::Get(
|
|
left_type.IsEquivalent(right_type, TypeEquality::kSyntactical))
|
|
.ptr();
|
|
}
|
|
|
|
if (!cls.IsGeneric()) {
|
|
return Bool::True().ptr();
|
|
}
|
|
|
|
if (left.GetTypeArguments() == right.GetTypeArguments()) {
|
|
return Bool::True().ptr();
|
|
}
|
|
const TypeArguments& left_type_arguments =
|
|
TypeArguments::Handle(zone, left.GetTypeArguments());
|
|
const TypeArguments& right_type_arguments =
|
|
TypeArguments::Handle(zone, right.GetTypeArguments());
|
|
const intptr_t num_type_args = cls.NumTypeArguments();
|
|
const intptr_t num_type_params = cls.NumTypeParameters();
|
|
return Bool::Get(left_type_arguments.IsSubvectorEquivalent(
|
|
right_type_arguments, num_type_args - num_type_params,
|
|
num_type_params, TypeEquality::kSyntactical))
|
|
.ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_instanceOf, 0, 4) {
|
|
const Instance& instance =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const TypeArguments& instantiator_type_arguments =
|
|
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
const TypeArguments& function_type_arguments =
|
|
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(2));
|
|
const AbstractType& type =
|
|
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(3));
|
|
ASSERT(type.IsFinalized());
|
|
const bool is_instance_of = instance.IsInstanceOf(
|
|
type, instantiator_type_arguments, function_type_arguments);
|
|
if (FLAG_trace_type_checks) {
|
|
const char* result_str = is_instance_of ? "true" : "false";
|
|
OS::PrintErr("Native Object.instanceOf: result %s\n", result_str);
|
|
const AbstractType& instance_type =
|
|
AbstractType::Handle(zone, instance.GetType(Heap::kNew));
|
|
OS::PrintErr(" instance type: %s\n",
|
|
String::Handle(zone, instance_type.Name()).ToCString());
|
|
OS::PrintErr(" test type: %s\n",
|
|
String::Handle(zone, type.Name()).ToCString());
|
|
}
|
|
return Bool::Get(is_instance_of).ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Object_simpleInstanceOf, 0, 2) {
|
|
// This native is only called when the right hand side passes
|
|
// SimpleInstanceOfType and it is a non-negative test.
|
|
const Instance& instance =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const AbstractType& type =
|
|
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
ASSERT(type.IsFinalized());
|
|
ASSERT(type.IsInstantiated());
|
|
const bool is_instance_of = instance.IsInstanceOf(
|
|
type, Object::null_type_arguments(), Object::null_type_arguments());
|
|
return Bool::Get(is_instance_of).ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(AbstractType_toString, 0, 1) {
|
|
const AbstractType& type =
|
|
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
return type.UserVisibleName();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Type_getHashCode, 0, 1) {
|
|
const Type& type = Type::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
intptr_t hash_val = type.Hash();
|
|
ASSERT(hash_val > 0);
|
|
ASSERT(Smi::IsValid(hash_val));
|
|
return Smi::New(hash_val);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Type_equality, 0, 2) {
|
|
const Type& type = Type::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const Instance& other =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
if (type.ptr() == other.ptr()) {
|
|
return Bool::True().ptr();
|
|
}
|
|
return Bool::Get(type.IsEquivalent(other, TypeEquality::kSyntactical)).ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(FunctionType_getHashCode, 0, 1) {
|
|
const FunctionType& type =
|
|
FunctionType::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
intptr_t hash_val = type.Hash();
|
|
ASSERT(hash_val > 0);
|
|
ASSERT(Smi::IsValid(hash_val));
|
|
return Smi::New(hash_val);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(FunctionType_equality, 0, 2) {
|
|
const FunctionType& type =
|
|
FunctionType::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const Instance& other =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
if (type.ptr() == other.ptr()) {
|
|
return Bool::True().ptr();
|
|
}
|
|
return Bool::Get(type.IsEquivalent(other, TypeEquality::kSyntactical)).ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 0, 1) {
|
|
const LibraryPrefix& prefix =
|
|
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
return Bool::Get(isolate->IsPrefixLoaded(prefix)).ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(LibraryPrefix_setLoaded, 0, 1) {
|
|
const LibraryPrefix& prefix =
|
|
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
isolate->SetPrefixIsLoaded(prefix);
|
|
return Instance::null();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(LibraryPrefix_loadingUnit, 0, 1) {
|
|
const LibraryPrefix& prefix =
|
|
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const Library& target = Library::Handle(zone, prefix.GetLibrary(0));
|
|
const LoadingUnit& unit = LoadingUnit::Handle(zone, target.loading_unit());
|
|
return Smi::New(unit.IsNull() ? LoadingUnit::kIllegalId : unit.id());
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(LibraryPrefix_issueLoad, 0, 1) {
|
|
const Smi& id = Smi::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
Array& units =
|
|
Array::Handle(zone, isolate->group()->object_store()->loading_units());
|
|
if (units.IsNull()) {
|
|
// Not actually split.
|
|
const Library& lib = Library::Handle(zone, Library::CoreLibrary());
|
|
const String& sel = String::Handle(zone, String::New("_completeLoads"));
|
|
const Function& func =
|
|
Function::Handle(zone, lib.LookupFunctionAllowPrivate(sel));
|
|
ASSERT(!func.IsNull());
|
|
const Array& args = Array::Handle(zone, Array::New(3));
|
|
args.SetAt(0, id);
|
|
args.SetAt(1, String::Handle(zone));
|
|
args.SetAt(2, Bool::Get(false));
|
|
return DartEntry::InvokeFunction(func, args);
|
|
}
|
|
ASSERT(id.Value() != LoadingUnit::kIllegalId);
|
|
LoadingUnit& unit = LoadingUnit::Handle(zone);
|
|
unit ^= units.At(id.Value());
|
|
return unit.IssueLoad();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Internal_has63BitSmis, 0, 0) {
|
|
#if defined(ARCH_IS_64_BIT) && !defined(DART_COMPRESSED_POINTERS)
|
|
return Bool::True().ptr();
|
|
#else
|
|
return Bool::False().ptr();
|
|
#endif // defined(ARCH_IS_64_BIT)
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Internal_unsafeCast, 0, 1) {
|
|
UNREACHABLE(); // Should be erased at Kernel translation time.
|
|
return arguments->NativeArgAt(0);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Internal_nativeEffect, 0, 1) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Internal_reachabilityFence, 0, 1) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Internal_collectAllGarbage, 0, 0) {
|
|
isolate->group()->heap()->CollectAllGarbage();
|
|
return Object::null();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Internal_deoptimizeFunctionsOnStack, 0, 0) {
|
|
DeoptimizeFunctionsOnStack();
|
|
return Object::null();
|
|
}
|
|
|
|
static bool ExtractInterfaceTypeArgs(Zone* zone,
|
|
const Class& instance_cls,
|
|
const TypeArguments& instance_type_args,
|
|
const Class& interface_cls,
|
|
TypeArguments* interface_type_args) {
|
|
Class& cur_cls = Class::Handle(zone, instance_cls.ptr());
|
|
// The following code is a specialization of Class::IsSubtypeOf().
|
|
Array& interfaces = Array::Handle(zone);
|
|
AbstractType& interface = AbstractType::Handle(zone);
|
|
Class& cur_interface_cls = Class::Handle(zone);
|
|
TypeArguments& cur_interface_type_args = TypeArguments::Handle(zone);
|
|
while (true) {
|
|
// Additional subtyping rules related to 'FutureOr' are not applied.
|
|
if (cur_cls.ptr() == interface_cls.ptr()) {
|
|
*interface_type_args = instance_type_args.ptr();
|
|
return true;
|
|
}
|
|
interfaces = cur_cls.interfaces();
|
|
for (intptr_t i = 0; i < interfaces.Length(); i++) {
|
|
interface ^= interfaces.At(i);
|
|
ASSERT(interface.IsFinalized());
|
|
cur_interface_cls = interface.type_class();
|
|
cur_interface_type_args = interface.arguments();
|
|
if (!cur_interface_type_args.IsNull() &&
|
|
!cur_interface_type_args.IsInstantiated()) {
|
|
cur_interface_type_args = cur_interface_type_args.InstantiateFrom(
|
|
instance_type_args, Object::null_type_arguments(), kNoneFree,
|
|
Heap::kNew);
|
|
}
|
|
if (ExtractInterfaceTypeArgs(zone, cur_interface_cls,
|
|
cur_interface_type_args, interface_cls,
|
|
interface_type_args)) {
|
|
return true;
|
|
}
|
|
}
|
|
cur_cls = cur_cls.SuperClass();
|
|
if (cur_cls.IsNull()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// for documentation see pkg/dart_internal/lib/extract_type_arguments.dart
|
|
DEFINE_NATIVE_ENTRY(Internal_extractTypeArguments, 0, 2) {
|
|
const Instance& instance =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const Instance& extract =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
|
|
Class& interface_cls = Class::Handle(zone);
|
|
intptr_t num_type_args = 0;
|
|
if (arguments->NativeTypeArgCount() >= 1) {
|
|
const AbstractType& function_type_arg =
|
|
AbstractType::Handle(zone, arguments->NativeTypeArgAt(0));
|
|
if (function_type_arg.IsType() &&
|
|
(function_type_arg.arguments() == TypeArguments::null())) {
|
|
interface_cls = function_type_arg.type_class();
|
|
num_type_args = interface_cls.NumTypeParameters();
|
|
}
|
|
}
|
|
if (num_type_args == 0) {
|
|
Exceptions::ThrowArgumentError(String::Handle(
|
|
zone,
|
|
String::New(
|
|
"single function type argument must specify a generic class")));
|
|
}
|
|
if (instance.IsNull()) {
|
|
Exceptions::ThrowArgumentError(instance);
|
|
}
|
|
// Function 'extract' must be generic and accept the same number of type args,
|
|
// unless we execute Dart 1.0 code.
|
|
if (extract.IsNull() || !extract.IsClosure() ||
|
|
((num_type_args > 0) && // Dart 1.0 if num_type_args == 0.
|
|
(Function::Handle(zone, Closure::Cast(extract).function())
|
|
.NumTypeParameters() != num_type_args))) {
|
|
Exceptions::ThrowArgumentError(String::Handle(
|
|
zone,
|
|
String::New("argument 'extract' is not a generic function or not one "
|
|
"accepting the correct number of type arguments")));
|
|
}
|
|
TypeArguments& extracted_type_args = TypeArguments::Handle(zone);
|
|
if (num_type_args > 0) {
|
|
// The passed instance must implement interface_cls.
|
|
TypeArguments& interface_type_args = TypeArguments::Handle(zone);
|
|
interface_type_args = TypeArguments::New(num_type_args);
|
|
Class& instance_cls = Class::Handle(zone, instance.clazz());
|
|
TypeArguments& instance_type_args = TypeArguments::Handle(zone);
|
|
if (instance_cls.NumTypeArguments() > 0) {
|
|
instance_type_args = instance.GetTypeArguments();
|
|
}
|
|
if (!ExtractInterfaceTypeArgs(zone, instance_cls, instance_type_args,
|
|
interface_cls, &interface_type_args)) {
|
|
Exceptions::ThrowArgumentError(String::Handle(
|
|
zone, String::New("type of argument 'instance' is not a subtype of "
|
|
"the function type argument")));
|
|
}
|
|
if (!interface_type_args.IsNull()) {
|
|
extracted_type_args = TypeArguments::New(num_type_args);
|
|
const intptr_t offset = interface_cls.NumTypeArguments() - num_type_args;
|
|
AbstractType& type_arg = AbstractType::Handle(zone);
|
|
for (intptr_t i = 0; i < num_type_args; i++) {
|
|
type_arg = interface_type_args.TypeAt(offset + i);
|
|
extracted_type_args.SetTypeAt(i, type_arg);
|
|
}
|
|
extracted_type_args =
|
|
extracted_type_args.Canonicalize(thread, nullptr); // Can be null.
|
|
}
|
|
}
|
|
// Call the closure 'extract'.
|
|
Array& args_desc = Array::Handle(zone);
|
|
Array& args = Array::Handle(zone);
|
|
if (extracted_type_args.IsNull()) {
|
|
args_desc = ArgumentsDescriptor::NewBoxed(0, 1);
|
|
args = Array::New(1);
|
|
args.SetAt(0, extract);
|
|
} else {
|
|
args_desc = ArgumentsDescriptor::NewBoxed(num_type_args, 1);
|
|
args = Array::New(2);
|
|
args.SetAt(0, extracted_type_args);
|
|
args.SetAt(1, extract);
|
|
}
|
|
const Object& result =
|
|
Object::Handle(zone, DartEntry::InvokeClosure(thread, args, args_desc));
|
|
if (result.IsError()) {
|
|
Exceptions::PropagateError(Error::Cast(result));
|
|
UNREACHABLE();
|
|
}
|
|
return result.ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(Internal_prependTypeArguments, 0, 4) {
|
|
const TypeArguments& function_type_arguments =
|
|
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const TypeArguments& parent_type_arguments =
|
|
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_parent_len, arguments->NativeArgAt(2));
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_len, arguments->NativeArgAt(3));
|
|
return function_type_arguments.Prepend(
|
|
zone, parent_type_arguments, smi_parent_len.Value(), smi_len.Value());
|
|
}
|
|
|
|
// Check that a set of type arguments satisfy the type parameter bounds on a
|
|
// closure.
|
|
// Arg0: Closure object
|
|
// Arg1: Type arguments to function
|
|
DEFINE_NATIVE_ENTRY(Internal_boundsCheckForPartialInstantiation, 0, 2) {
|
|
const Closure& closure =
|
|
Closure::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const Function& target = Function::Handle(zone, closure.function());
|
|
ASSERT(target.IsGeneric()); // No need to check bounds for non-generics.
|
|
const TypeParameters& type_params =
|
|
TypeParameters::Handle(zone, target.type_parameters());
|
|
if (type_params.IsNull() || type_params.AllDynamicBounds()) {
|
|
// The function is not generic or the bounds are all dynamic.
|
|
return Object::null();
|
|
}
|
|
|
|
const TypeArguments& type_args_to_check =
|
|
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
|
|
// This should be guaranteed by the front-end.
|
|
ASSERT(type_args_to_check.IsNull() ||
|
|
type_params.Length() <= type_args_to_check.Length());
|
|
|
|
// The bounds on the closure may need instantiation.
|
|
const TypeArguments& instantiator_type_args =
|
|
TypeArguments::Handle(zone, closure.instantiator_type_arguments());
|
|
const TypeArguments& function_type_args =
|
|
TypeArguments::Handle(zone, closure.function_type_arguments());
|
|
|
|
AbstractType& supertype = AbstractType::Handle(zone);
|
|
AbstractType& subtype = AbstractType::Handle(zone);
|
|
for (intptr_t i = 0; i < type_params.Length(); ++i) {
|
|
supertype = type_params.BoundAt(i);
|
|
subtype = type_args_to_check.IsNull() ? Object::dynamic_type().ptr()
|
|
: type_args_to_check.TypeAt(i);
|
|
|
|
ASSERT(!subtype.IsNull());
|
|
ASSERT(!supertype.IsNull());
|
|
|
|
// The supertype may not be instantiated.
|
|
if (!AbstractType::InstantiateAndTestSubtype(
|
|
&subtype, &supertype, instantiator_type_args, function_type_args)) {
|
|
// Throw a dynamic type error.
|
|
TokenPosition location = TokenPosition::kNoSource;
|
|
{
|
|
DartFrameIterator iterator(Thread::Current(),
|
|
StackFrameIterator::kNoCrossThreadIteration);
|
|
StackFrame* caller_frame = iterator.NextFrame();
|
|
ASSERT(caller_frame != NULL);
|
|
location = caller_frame->GetTokenPos();
|
|
}
|
|
const auto& parameter_name = String::Handle(zone, type_params.NameAt(i));
|
|
Exceptions::CreateAndThrowTypeError(location, subtype, supertype,
|
|
parameter_name);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
return Object::null();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(InvocationMirror_unpackTypeArguments, 0, 2) {
|
|
const TypeArguments& type_arguments =
|
|
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
const Smi& num_type_arguments =
|
|
Smi::CheckedHandle(zone, arguments->NativeArgAt(1));
|
|
bool all_dynamic = type_arguments.IsNull();
|
|
const intptr_t len =
|
|
all_dynamic ? num_type_arguments.Value() : type_arguments.Length();
|
|
const Array& type_list = Array::Handle(
|
|
zone, Array::New(len, Type::Handle(zone, Type::DartTypeType())));
|
|
AbstractType& type = AbstractType::Handle(zone);
|
|
for (intptr_t i = 0; i < len; i++) {
|
|
if (all_dynamic) {
|
|
type_list.SetAt(i, Object::dynamic_type());
|
|
} else {
|
|
type = type_arguments.TypeAt(i);
|
|
type_list.SetAt(i, type);
|
|
}
|
|
}
|
|
type_list.MakeImmutable();
|
|
return type_list.ptr();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(NoSuchMethodError_existingMethodSignature, 0, 3) {
|
|
const Instance& receiver =
|
|
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
GET_NON_NULL_NATIVE_ARGUMENT(String, method_name, arguments->NativeArgAt(1));
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Smi, invocation_type, arguments->NativeArgAt(2));
|
|
InvocationMirror::Level level;
|
|
InvocationMirror::Kind kind;
|
|
InvocationMirror::DecodeType(invocation_type.Value(), &level, &kind);
|
|
|
|
Function& function = Function::Handle(zone);
|
|
if (receiver.IsType()) {
|
|
const auto& cls = Class::Handle(zone, Type::Cast(receiver).type_class());
|
|
const auto& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
|
|
if (!error.IsNull()) {
|
|
Exceptions::PropagateError(error);
|
|
UNREACHABLE();
|
|
}
|
|
if (level == InvocationMirror::kConstructor) {
|
|
function = cls.LookupConstructor(method_name);
|
|
if (function.IsNull()) {
|
|
function = cls.LookupFactory(method_name);
|
|
}
|
|
} else {
|
|
function = cls.LookupStaticFunction(method_name);
|
|
}
|
|
} else if (receiver.IsClosure()) {
|
|
function = Closure::Cast(receiver).function();
|
|
} else {
|
|
auto& cls = Class::Handle(zone, receiver.clazz());
|
|
if (level == InvocationMirror::kSuper) {
|
|
cls = cls.SuperClass();
|
|
}
|
|
function = Resolver::ResolveDynamicAnyArgs(zone, cls, method_name,
|
|
/*allow_add=*/false);
|
|
}
|
|
if (!function.IsNull()) {
|
|
return function.UserVisibleSignature();
|
|
}
|
|
return String::null();
|
|
}
|
|
|
|
} // namespace dart
|