| // 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)); |
| return instance.GetType(Heap::kNew, TypeVisibility::kUserVisibleType); |
| } |
| |
| 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(TypedDataBase, 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 |