|  | // 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/bytecode_reader.h" | 
|  | #include "vm/code_patcher.h" | 
|  | #include "vm/dart_entry.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. | 
|  | intptr_t hash = GetHash(isolate, arguments->NativeArgAt(0)); | 
|  | if (LIKELY(hash != 0)) { | 
|  | return Smi::New(hash); | 
|  | } | 
|  |  | 
|  | const Instance& instance = | 
|  | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); | 
|  | return instance.IdentityHashCode(arguments->thread()); | 
|  | } | 
|  |  | 
|  | 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.IsAbstractType()) { | 
|  | return Type::DartTypeType(); | 
|  | } else if (IsArrayClassId(instance.GetClassId())) { | 
|  | const auto& cls = Class::Handle( | 
|  | zone, thread->isolate_group()->object_store()->list_class()); | 
|  | auto& type_arguments = | 
|  | TypeArguments::Handle(zone, instance.GetTypeArguments()); | 
|  | type_arguments = type_arguments.FromInstanceTypeArguments(thread, cls); | 
|  | const auto& type = Type::Handle( | 
|  | zone, | 
|  | Type::New(cls, type_arguments, Nullability::kNonNullable, Heap::kNew)); | 
|  | type.SetIsFinalized(); | 
|  | return type.Canonicalize(thread); | 
|  | } | 
|  |  | 
|  | return instance.GetType(Heap::kNew); | 
|  | } | 
|  |  | 
|  | static bool HaveSameRuntimeTypeHelper(Zone* zone, | 
|  | const Instance& left, | 
|  | const Instance& right) { | 
|  | const intptr_t left_cid = left.GetClassId(); | 
|  | const intptr_t right_cid = right.GetClassId(); | 
|  |  | 
|  | if (left_cid != right_cid) { | 
|  | if (IsIntegerClassId(left_cid)) { | 
|  | return IsIntegerClassId(right_cid); | 
|  | } else if (IsStringClassId(left_cid)) { | 
|  | return IsStringClassId(right_cid); | 
|  | } else if (IsTypeClassId(left_cid)) { | 
|  | return IsTypeClassId(right_cid); | 
|  | } else if (IsArrayClassId(left_cid)) { | 
|  | if (!IsArrayClassId(right_cid)) { | 
|  | return false; | 
|  | } | 
|  | // Still need to check type arguments. | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (left_cid == kClosureCid) { | 
|  | 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.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()) { | 
|  | const auto& left_fun = Function::Handle(zone, left_closure.function()); | 
|  | const auto& right_fun = Function::Handle(zone, right_closure.function()); | 
|  | if (left_fun.signature() == right_fun.signature()) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | const AbstractType& left_type = | 
|  | AbstractType::Handle(zone, left.GetType(Heap::kNew)); | 
|  | const AbstractType& right_type = | 
|  | AbstractType::Handle(zone, right.GetType(Heap::kNew)); | 
|  | return left_type.IsEquivalent(right_type, TypeEquality::kSyntactical); | 
|  | } | 
|  |  | 
|  | if (left_cid == kRecordCid) { | 
|  | const auto& left_record = Record::Cast(left); | 
|  | const auto& right_record = Record::Cast(right); | 
|  | if (left_record.shape() != right_record.shape()) { | 
|  | return false; | 
|  | } | 
|  | Instance& left_field = Instance::Handle(zone); | 
|  | Instance& right_field = Instance::Handle(zone); | 
|  | const intptr_t num_fields = left_record.num_fields(); | 
|  | for (intptr_t i = 0; i < num_fields; ++i) { | 
|  | left_field ^= left_record.FieldAt(i); | 
|  | right_field ^= right_record.FieldAt(i); | 
|  | if (!HaveSameRuntimeTypeHelper(zone, left_field, right_field)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | const Class& cls = Class::Handle(zone, left.clazz()); | 
|  | if (!cls.IsGeneric()) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (left.GetTypeArguments() == right.GetTypeArguments()) { | 
|  | return true; | 
|  | } | 
|  | 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 left_type_arguments.IsSubvectorEquivalent( | 
|  | right_type_arguments, num_type_args - num_type_params, num_type_params, | 
|  | TypeEquality::kSyntactical); | 
|  | } | 
|  |  | 
|  | 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)); | 
|  | return Bool::Get(HaveSameRuntimeTypeHelper(zone, left, right)).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) { | 
|  | LogBlock lb; | 
|  | const char* result_str = is_instance_of ? "true" : "false"; | 
|  | THR_Print("Native Object.instanceOf: result %s\n", result_str); | 
|  | const AbstractType& instance_type = | 
|  | AbstractType::Handle(zone, instance.GetType(Heap::kNew)); | 
|  | THR_Print("  instance type: %s\n", instance_type.NameCString()); | 
|  | THR_Print("  test type: %s\n", type.NameCString()); | 
|  | } | 
|  | 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(AbstractType_getHashCode, 0, 1) { | 
|  | const AbstractType& type = | 
|  | AbstractType::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(AbstractType_equality, 0, 2) { | 
|  | const AbstractType& type = | 
|  | AbstractType::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(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(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_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_collectAllGarbage, 0, 0) { | 
|  | isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging, | 
|  | /*compact=*/true); | 
|  | return Object::null(); | 
|  | } | 
|  |  | 
|  | DEFINE_NATIVE_ENTRY(Internal_deoptimizeFunctionsOnStack, 0, 0) { | 
|  | DeoptimizeFunctionsOnStack(); | 
|  | return Object::null(); | 
|  | } | 
|  |  | 
|  | DEFINE_NATIVE_ENTRY(Internal_allocateObjectInstructionsStart, 0, 0) { | 
|  | auto& stub = Code::Handle( | 
|  | zone, isolate->group()->object_store()->allocate_object_stub()); | 
|  | ASSERT(!stub.IsUnknownDartCode()); | 
|  | // We return the start offset in the isolate instructions instead of the | 
|  | // full address because that fits into small Smis on 32-bit architectures | 
|  | // or compressed pointer builds. | 
|  | const uword instructions_start = | 
|  | reinterpret_cast<uword>(isolate->source()->snapshot_instructions); | 
|  | return Smi::New(stub.PayloadStart() - instructions_start); | 
|  | } | 
|  |  | 
|  | DEFINE_NATIVE_ENTRY(Internal_allocateObjectInstructionsEnd, 0, 0) { | 
|  | auto& stub = Code::Handle( | 
|  | zone, isolate->group()->object_store()->allocate_object_stub()); | 
|  | ASSERT(!stub.IsUnknownDartCode()); | 
|  | // We return the end offset in the isolate instructions instead of the | 
|  | // full address because that fits into small Smis on 32-bit architectures | 
|  | // or compressed pointer builds. | 
|  | const uword instructions_start = | 
|  | reinterpret_cast<uword>(isolate->source()->snapshot_instructions); | 
|  | return Smi::New((stub.PayloadStart() - instructions_start) + stub.Size()); | 
|  | } | 
|  |  | 
|  | static bool ExtractInterfaceTypeArgs(Zone* zone, | 
|  | const Class& instance_cls, | 
|  | const TypeArguments& instance_type_args, | 
|  | const Class& interface_cls, | 
|  | TypeArguments* interface_type_args) { | 
|  | Thread* thread = Thread::Current(); | 
|  | Class& cur_cls = Class::Handle(zone, instance_cls.ptr()); | 
|  | // The following code is a specialization of Class::IsSubtypeOf(). | 
|  | Array& interfaces = Array::Handle(zone); | 
|  | Type& interface = Type::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.GetInstanceTypeArguments(thread, /*canonicalize=*/false); | 
|  | 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() && | 
|  | (Type::Cast(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);  // 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, | 
|  | type_args_to_check.Prepend( | 
|  | zone, TypeArguments::Handle(zone, closure.function_type_arguments()), | 
|  | target.NumParentTypeArguments(), target.NumTypeArguments())); | 
|  |  | 
|  | 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 != nullptr); | 
|  | 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(Internal_loadDynamicModule, 0, 1) { | 
|  | #if defined(DART_DYNAMIC_MODULES) | 
|  | GET_NON_NULL_NATIVE_ARGUMENT(TypedData, module_bytes, | 
|  | arguments->NativeArgAt(0)); | 
|  |  | 
|  | const intptr_t length = module_bytes.LengthInBytes(); | 
|  | uint8_t* data = reinterpret_cast<uint8_t*>(::malloc(length)); | 
|  | if (data == nullptr) { | 
|  | const auto& exception = Instance::Handle( | 
|  | zone, thread->isolate_group()->object_store()->out_of_memory()); | 
|  | Exceptions::Throw(thread, exception); | 
|  | } | 
|  | { | 
|  | NoSafepointScope no_safepoint; | 
|  | // The memory does not overlap. | 
|  | memcpy(data, module_bytes.DataAddr(0), length);  // NOLINT | 
|  | } | 
|  | const ExternalTypedData& typed_data = ExternalTypedData::Handle( | 
|  | zone, | 
|  | ExternalTypedData::New(kExternalTypedDataUint8ArrayCid, data, length)); | 
|  | auto& function = Function::Handle(); | 
|  | { | 
|  | SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock()); | 
|  | bytecode::BytecodeLoader loader(thread, typed_data); | 
|  | function = loader.LoadBytecode(); | 
|  | } | 
|  |  | 
|  | if (function.IsNull()) { | 
|  | return Object::null(); | 
|  | } | 
|  | ASSERT(function.is_static()); | 
|  | ASSERT(function.is_declared_in_bytecode()); | 
|  | auto& result = Object::Handle(zone); | 
|  |  | 
|  | intptr_t num_arguments; | 
|  | for (num_arguments = 2; num_arguments >= 0; --num_arguments) { | 
|  | if (function.AreValidArgumentCounts( | 
|  | /*num_type_arguments=*/0, num_arguments, | 
|  | /*num_named_arguments=*/0, /*error_message=*/nullptr)) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (num_arguments < 0) { | 
|  | Exceptions::ThrowUnsupportedError( | 
|  | "Unsupported number of arguments of dynamic module entry point."); | 
|  | } | 
|  | const auto& args = Array::Handle(zone, Array::New(num_arguments)); | 
|  | if (num_arguments > 0) { | 
|  | // <String>[] | 
|  | const auto& arg0 = Array::Handle( | 
|  | zone, Array::New(0, Type::Handle(zone, Type::StringType()))); | 
|  | args.SetAt(0, arg0); | 
|  | } | 
|  | result = DartEntry::InvokeFunction(function, args); | 
|  | if (result.IsError()) { | 
|  | Exceptions::PropagateError(Error::Cast(result)); | 
|  | } | 
|  | return result.ptr(); | 
|  | #else | 
|  | Exceptions::ThrowUnsupportedError( | 
|  | "Loading of dynamic modules is not supported."); | 
|  | return Object::null(); | 
|  | #endif  // defined(DART_DYNAMIC_MODULES) | 
|  | } | 
|  |  | 
|  | 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 (level == InvocationMirror::Level::kTopLevel) { | 
|  | if (receiver.IsString()) return receiver.ptr(); | 
|  | ASSERT(receiver.IsNull()); | 
|  | return String::null(); | 
|  | } | 
|  | 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 |