a44a524bb0
This adds the `Native.addressOf` function, which takes a constant tear- off of a method annotated with `@Native` as a parameter and returns a pointer to the underlying C function. The CFE will resolve these calls in two steps: First, the existing transformer for `@Native` methods adds a pragma describing the fully- resolved native annotation (with the asset id inferred from the library if not given explicitly). Then, the FFI use sites transformer rewrites calls to `Native.addressOf` by searching for this pragma on the passed function and passing the `Native` constants to `Native._addressOf`. The latter method is implemented in the VM, which can re-use existing parts already used for `@Native` calls. An alternative implementation strategy would have been to forward `addressOf` calls to `Native.ffi_resolver_function` directly without any special consideration in the VM. However, the chosen approach makes it easier to support static linking in the future, as this requires unresolved symbols in the generated assembly. Closes https://github.com/dart-lang/sdk/issues/50552 TEST=pkg/vm/testcases/transformations/ffi/ffinative.dart TEST=tests/ffi/native_assets/asset_*_test.dart TEST=tests/ffi/vmspecific_static_checks_ffinative_test.dart TEST=pkg/analyzer/test/src/diagnostics/ffi_native_test.dart Cq-Include-Trybots: luci.dart.try:vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-kernel-precomp-linux-release-x64-try CoreLibraryReviewExempt: VM & dart2wasm only feature Change-Id: Ic8e3a390146dffd44c95578f975a4472db79a0ee Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333920 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
632 lines
22 KiB
C++
632 lines
22 KiB
C++
// Copyright (c) 2013, 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/object_store.h"
|
|
|
|
#include "vm/dart_entry.h"
|
|
#include "vm/exceptions.h"
|
|
#include "vm/isolate.h"
|
|
#include "vm/object.h"
|
|
#include "vm/raw_object.h"
|
|
#include "vm/resolver.h"
|
|
#include "vm/stub_code.h"
|
|
#include "vm/symbols.h"
|
|
#include "vm/visitor.h"
|
|
|
|
namespace dart {
|
|
|
|
void IsolateObjectStore::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
|
ASSERT(visitor != nullptr);
|
|
visitor->set_gc_root_type("isolate_object store");
|
|
visitor->VisitPointers(from(), to());
|
|
visitor->clear_gc_root_type();
|
|
}
|
|
|
|
void IsolateObjectStore::Init() {
|
|
for (ObjectPtr* current = from(); current <= to(); current++) {
|
|
*current = Object::null();
|
|
}
|
|
}
|
|
|
|
#ifndef PRODUCT
|
|
void IsolateObjectStore::PrintToJSONObject(JSONObject* jsobj) {
|
|
jsobj->AddProperty("type", "_IsolateObjectStore");
|
|
|
|
{
|
|
JSONObject fields(jsobj, "fields");
|
|
Object& value = Object::Handle();
|
|
|
|
static const char* const names[] = {
|
|
#define EMIT_FIELD_NAME(type, name) #name "_",
|
|
ISOLATE_OBJECT_STORE_FIELD_LIST(EMIT_FIELD_NAME, EMIT_FIELD_NAME)
|
|
#undef EMIT_FIELD_NAME
|
|
};
|
|
ObjectPtr* current = from();
|
|
intptr_t i = 0;
|
|
while (current <= to()) {
|
|
value = *current;
|
|
fields.AddProperty(names[i], value);
|
|
current++;
|
|
i++;
|
|
}
|
|
ASSERT(i == ARRAY_SIZE(names));
|
|
}
|
|
}
|
|
#endif // !PRODUCT
|
|
|
|
static StackTracePtr CreatePreallocatedStackTrace(Zone* zone) {
|
|
const Array& code_array = Array::Handle(
|
|
zone, Array::New(StackTrace::kPreallocatedStackdepth, Heap::kOld));
|
|
const TypedData& pc_offset_array = TypedData::Handle(
|
|
zone, TypedData::New(kUintPtrCid, StackTrace::kPreallocatedStackdepth,
|
|
Heap::kOld));
|
|
const StackTrace& stack_trace =
|
|
StackTrace::Handle(zone, StackTrace::New(code_array, pc_offset_array));
|
|
// Expansion of inlined functions requires additional memory at run time,
|
|
// avoid it.
|
|
stack_trace.set_expand_inlined(false);
|
|
return stack_trace.ptr();
|
|
}
|
|
|
|
ErrorPtr IsolateObjectStore::PreallocateObjects(const Object& out_of_memory) {
|
|
Thread* thread = Thread::Current();
|
|
Isolate* isolate = thread->isolate();
|
|
Zone* zone = thread->zone();
|
|
ASSERT(isolate != nullptr && isolate->isolate_object_store() == this);
|
|
ASSERT(preallocated_stack_trace() == StackTrace::null());
|
|
resume_capabilities_ = GrowableObjectArray::New();
|
|
exit_listeners_ = GrowableObjectArray::New();
|
|
error_listeners_ = GrowableObjectArray::New();
|
|
dart_args_1_ = Array::New(1);
|
|
dart_args_2_ = Array::New(2);
|
|
|
|
// Allocate pre-allocated unhandled exception object initialized with the
|
|
// pre-allocated OutOfMemoryError.
|
|
const StackTrace& preallocated_stack_trace =
|
|
StackTrace::Handle(zone, CreatePreallocatedStackTrace(zone));
|
|
set_preallocated_stack_trace(preallocated_stack_trace);
|
|
set_preallocated_unhandled_exception(UnhandledException::Handle(
|
|
zone, UnhandledException::New(Instance::Cast(out_of_memory),
|
|
preallocated_stack_trace)));
|
|
const UnwindError& preallocated_unwind_error =
|
|
UnwindError::Handle(zone, UnwindError::New(String::Handle(
|
|
zone, String::New("isolate is exiting"))));
|
|
set_preallocated_unwind_error(preallocated_unwind_error);
|
|
|
|
return Error::null();
|
|
}
|
|
|
|
ObjectStore::ObjectStore()
|
|
:
|
|
#define EMIT_FIELD_INIT(type, name) name##_(nullptr),
|
|
OBJECT_STORE_FIELD_LIST(EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT,
|
|
EMIT_FIELD_INIT)
|
|
#undef EMIT_FIELD_INIT
|
|
// Just to prevent a trailing comma.
|
|
unused_field_(0) {
|
|
for (ObjectPtr* current = from(); current <= to(); current++) {
|
|
*current = Object::null();
|
|
}
|
|
}
|
|
|
|
ObjectStore::~ObjectStore() {}
|
|
|
|
void ObjectStore::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
|
ASSERT(visitor != nullptr);
|
|
visitor->set_gc_root_type("object store");
|
|
visitor->VisitPointers(from(), to());
|
|
visitor->clear_gc_root_type();
|
|
}
|
|
|
|
void ObjectStore::InitStubs() {
|
|
#define DO(member, name) set_##member(StubCode::name());
|
|
OBJECT_STORE_STUB_CODE_LIST(DO)
|
|
#undef DO
|
|
}
|
|
|
|
#ifndef PRODUCT
|
|
void ObjectStore::PrintToJSONObject(JSONObject* jsobj) {
|
|
jsobj->AddProperty("type", "_ObjectStore");
|
|
|
|
{
|
|
JSONObject fields(jsobj, "fields");
|
|
Object& value = Object::Handle();
|
|
static const char* const names[] = {
|
|
#define EMIT_FIELD_NAME(type, name) #name "_",
|
|
OBJECT_STORE_FIELD_LIST(
|
|
EMIT_FIELD_NAME, EMIT_FIELD_NAME, EMIT_FIELD_NAME, EMIT_FIELD_NAME,
|
|
EMIT_FIELD_NAME, EMIT_FIELD_NAME, EMIT_FIELD_NAME, EMIT_FIELD_NAME,
|
|
EMIT_FIELD_NAME)
|
|
#undef EMIT_FIELD_NAME
|
|
};
|
|
ObjectPtr* current = from();
|
|
intptr_t i = 0;
|
|
while (current <= to()) {
|
|
value = *current;
|
|
fields.AddProperty(names[i], value);
|
|
current++;
|
|
i++;
|
|
}
|
|
ASSERT(i == ARRAY_SIZE(names));
|
|
}
|
|
}
|
|
#endif // !PRODUCT
|
|
|
|
static InstancePtr AllocateObjectByClassName(const Library& library,
|
|
const String& class_name) {
|
|
const Class& cls = Class::Handle(library.LookupClassAllowPrivate(class_name));
|
|
ASSERT(!cls.IsNull());
|
|
return Instance::New(cls);
|
|
}
|
|
|
|
ErrorPtr ObjectStore::PreallocateObjects() {
|
|
Thread* thread = Thread::Current();
|
|
IsolateGroup* isolate_group = thread->isolate_group();
|
|
// Either we are the object store on isolate group, or isolate group has no
|
|
// object store and we are the object store on the isolate.
|
|
ASSERT(isolate_group != nullptr && isolate_group->object_store() == this);
|
|
|
|
if (this->stack_overflow() != Instance::null()) {
|
|
ASSERT(this->out_of_memory() != Instance::null());
|
|
return Error::null();
|
|
}
|
|
ASSERT(this->stack_overflow() == Instance::null());
|
|
ASSERT(this->out_of_memory() == Instance::null());
|
|
|
|
this->closure_functions_ = GrowableObjectArray::New();
|
|
|
|
Object& result = Object::Handle();
|
|
const Library& library = Library::Handle(Library::CoreLibrary());
|
|
|
|
result = AllocateObjectByClassName(library, Symbols::StackOverflowError());
|
|
if (result.IsError()) {
|
|
return Error::Cast(result).ptr();
|
|
}
|
|
set_stack_overflow(Instance::Cast(result));
|
|
|
|
result = AllocateObjectByClassName(library, Symbols::OutOfMemoryError());
|
|
if (result.IsError()) {
|
|
return Error::Cast(result).ptr();
|
|
}
|
|
set_out_of_memory(Instance::Cast(result));
|
|
|
|
return Error::null();
|
|
}
|
|
|
|
FunctionPtr ObjectStore::PrivateObjectLookup(const String& name) {
|
|
const Library& core_lib = Library::Handle(core_library());
|
|
const String& mangled = String::ZoneHandle(core_lib.PrivateName(name));
|
|
const Class& cls = Class::Handle(object_class());
|
|
Thread* thread = Thread::Current();
|
|
const auto& error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error == Error::null());
|
|
const Function& result = Function::Handle(
|
|
Resolver::ResolveDynamicFunction(thread->zone(), cls, mangled));
|
|
ASSERT(!result.IsNull());
|
|
return result.ptr();
|
|
}
|
|
|
|
void ObjectStore::InitKnownObjects() {
|
|
Thread* thread = Thread::Current();
|
|
Zone* zone = thread->zone();
|
|
Class& cls = Class::Handle(zone);
|
|
const Library& collection_lib = Library::Handle(zone, collection_library());
|
|
cls = collection_lib.LookupClassAllowPrivate(Symbols::_Set());
|
|
ASSERT(!cls.IsNull());
|
|
set_set_impl_class(cls);
|
|
|
|
#ifdef DART_PRECOMPILED_RUNTIME
|
|
// The rest of these objects are only needed for code generation.
|
|
return;
|
|
#else
|
|
auto isolate_group = thread->isolate_group();
|
|
ASSERT(isolate_group != nullptr && isolate_group->object_store() == this);
|
|
|
|
const Library& async_lib = Library::Handle(zone, async_library());
|
|
ASSERT(!async_lib.IsNull());
|
|
cls = async_lib.LookupClass(Symbols::Future());
|
|
ASSERT(!cls.IsNull());
|
|
set_future_class(cls);
|
|
|
|
String& function_name = String::Handle(zone);
|
|
Function& function = Function::Handle(zone);
|
|
Field& field = Field::Handle(zone);
|
|
|
|
cls =
|
|
async_lib.LookupClassAllowPrivate(Symbols::_AsyncStarStreamController());
|
|
ASSERT(!cls.IsNull());
|
|
RELEASE_ASSERT(cls.EnsureIsFinalized(thread) == Error::null());
|
|
set_async_star_stream_controller(cls);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::add());
|
|
ASSERT(!function.IsNull());
|
|
set_async_star_stream_controller_add(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::addStream());
|
|
ASSERT(!function.IsNull());
|
|
set_async_star_stream_controller_add_stream(function);
|
|
|
|
field = cls.LookupFieldAllowPrivate(Symbols::asyncStarBody());
|
|
ASSERT(!field.IsNull());
|
|
set_async_star_stream_controller_async_star_body(field);
|
|
|
|
#if !defined(PRODUCT)
|
|
// Disable debugging and inlining of all functions on the
|
|
// _AsyncStarStreamController class.
|
|
const Array& functions = Array::Handle(zone, cls.current_functions());
|
|
for (intptr_t i = 0; i < functions.Length(); i++) {
|
|
function ^= functions.At(i);
|
|
if (function.IsNull()) {
|
|
break;
|
|
}
|
|
function.set_is_debuggable(false);
|
|
function.set_is_inlinable(false);
|
|
}
|
|
#endif
|
|
|
|
cls = async_lib.LookupClassAllowPrivate(Symbols::Stream());
|
|
ASSERT(!cls.IsNull());
|
|
set_stream_class(cls);
|
|
|
|
cls = async_lib.LookupClassAllowPrivate(Symbols::_SuspendState());
|
|
ASSERT(!cls.IsNull());
|
|
const auto& error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error == Error::null());
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_initAsync());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_init_async(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_await());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_await(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_awaitWithTypeCheck());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_await_with_type_check(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_returnAsync());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_return_async(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_returnAsyncNotFuture());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_return_async_not_future(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_initAsyncStar());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_init_async_star(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_yieldAsyncStar());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_yield_async_star(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_returnAsyncStar());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_return_async_star(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_initSyncStar());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_init_sync_star(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_suspendSyncStarAtStart());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_suspend_sync_star_at_start(function);
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_handleException());
|
|
ASSERT(!function.IsNull());
|
|
set_suspend_state_handle_exception(function);
|
|
|
|
cls = async_lib.LookupClassAllowPrivate(Symbols::_SyncStarIterator());
|
|
ASSERT(!cls.IsNull());
|
|
RELEASE_ASSERT(cls.EnsureIsFinalized(thread) == Error::null());
|
|
set_sync_star_iterator_class(cls);
|
|
|
|
field = cls.LookupFieldAllowPrivate(Symbols::_current());
|
|
ASSERT(!field.IsNull());
|
|
set_sync_star_iterator_current(field);
|
|
|
|
field = cls.LookupFieldAllowPrivate(Symbols::_state());
|
|
ASSERT(!field.IsNull());
|
|
set_sync_star_iterator_state(field);
|
|
|
|
field = cls.LookupFieldAllowPrivate(Symbols::_yieldStarIterable());
|
|
ASSERT(!field.IsNull());
|
|
set_sync_star_iterator_yield_star_iterable(field);
|
|
|
|
const Library& core_lib = Library::Handle(zone, core_library());
|
|
cls = core_lib.LookupClassAllowPrivate(Symbols::_CompileTimeError());
|
|
ASSERT(!cls.IsNull());
|
|
set_compiletime_error_class(cls);
|
|
|
|
cls = core_lib.LookupClassAllowPrivate(Symbols::Pragma());
|
|
ASSERT(!cls.IsNull());
|
|
set_pragma_class(cls);
|
|
RELEASE_ASSERT(cls.EnsureIsFinalized(thread) == Error::null());
|
|
set_pragma_name(Field::Handle(zone, cls.LookupField(Symbols::name())));
|
|
set_pragma_options(Field::Handle(zone, cls.LookupField(Symbols::options())));
|
|
|
|
cls = core_lib.LookupClassAllowPrivate(Symbols::_GrowableList());
|
|
ASSERT(!cls.IsNull());
|
|
RELEASE_ASSERT(cls.EnsureIsFinalized(thread) == Error::null());
|
|
growable_list_factory_ =
|
|
cls.LookupFactoryAllowPrivate(Symbols::_GrowableListFactory());
|
|
ASSERT(growable_list_factory_ != Function::null());
|
|
|
|
cls = core_lib.LookupClassAllowPrivate(Symbols::Error());
|
|
ASSERT(!cls.IsNull());
|
|
set_error_class(cls);
|
|
|
|
cls = core_lib.LookupClassAllowPrivate(Symbols::Expando());
|
|
ASSERT(!cls.IsNull());
|
|
set_expando_class(cls);
|
|
|
|
cls = core_lib.LookupClassAllowPrivate(Symbols::Iterable());
|
|
ASSERT(!cls.IsNull());
|
|
set_iterable_class(cls);
|
|
|
|
// Cache the core private functions used for fast instance of checks.
|
|
simple_instance_of_function_ =
|
|
PrivateObjectLookup(Symbols::_simpleInstanceOf());
|
|
simple_instance_of_true_function_ =
|
|
PrivateObjectLookup(Symbols::_simpleInstanceOfTrue());
|
|
simple_instance_of_false_function_ =
|
|
PrivateObjectLookup(Symbols::_simpleInstanceOfFalse());
|
|
|
|
// Ensure AddSmiSmiCheckForFastSmiStubs run by the background compiler
|
|
// will not create new functions.
|
|
const Class& smi_class = Class::Handle(zone, this->smi_class());
|
|
RELEASE_ASSERT(smi_class.EnsureIsFinalized(thread) == Error::null());
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::Plus());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::Minus());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::Equals());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::LAngleBracket());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::RAngleBracket());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::BitAnd());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::BitOr());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
function_name =
|
|
Function::CreateDynamicInvocationForwarderName(Symbols::Star());
|
|
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name);
|
|
#endif
|
|
}
|
|
|
|
void ObjectStore::LazyInitCoreMembers() {
|
|
auto* const thread = Thread::Current();
|
|
SafepointWriteRwLocker locker(thread,
|
|
thread->isolate_group()->program_lock());
|
|
if (list_class_.load() == Type::null()) {
|
|
ASSERT(non_nullable_list_rare_type_.load() == Type::null());
|
|
ASSERT(non_nullable_map_rare_type_.load() == Type::null());
|
|
ASSERT(enum_index_field_.load() == Field::null());
|
|
ASSERT(enum_name_field_.load() == Field::null());
|
|
ASSERT(_object_equals_function_.load() == Function::null());
|
|
ASSERT(_object_hash_code_function_.load() == Function::null());
|
|
ASSERT(_object_to_string_function_.load() == Function::null());
|
|
|
|
auto* const zone = thread->zone();
|
|
const auto& core_lib = Library::Handle(zone, Library::CoreLibrary());
|
|
auto& cls = Class::Handle(zone);
|
|
|
|
cls = core_lib.LookupClass(Symbols::List());
|
|
ASSERT(!cls.IsNull());
|
|
list_class_.store(cls.ptr());
|
|
|
|
auto& type = Type::Handle(zone);
|
|
type = cls.RareType();
|
|
non_nullable_list_rare_type_.store(type.ptr());
|
|
|
|
cls = core_lib.LookupClass(Symbols::Map());
|
|
ASSERT(!cls.IsNull());
|
|
map_class_.store(cls.ptr());
|
|
|
|
type = cls.RareType();
|
|
non_nullable_map_rare_type_.store(type.ptr());
|
|
|
|
cls = core_lib.LookupClass(Symbols::Set());
|
|
ASSERT(!cls.IsNull());
|
|
set_class_.store(cls.ptr());
|
|
|
|
auto& field = Field::Handle(zone);
|
|
|
|
cls = core_lib.LookupClassAllowPrivate(Symbols::_Enum());
|
|
ASSERT(!cls.IsNull());
|
|
const auto& error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error == Error::null());
|
|
|
|
field = cls.LookupInstanceField(Symbols::Index());
|
|
ASSERT(!field.IsNull());
|
|
enum_index_field_.store(field.ptr());
|
|
|
|
field = cls.LookupInstanceFieldAllowPrivate(Symbols::_name());
|
|
ASSERT(!field.IsNull());
|
|
enum_name_field_.store(field.ptr());
|
|
|
|
auto& function = Function::Handle(zone);
|
|
|
|
function = core_lib.LookupFunctionAllowPrivate(Symbols::_objectHashCode());
|
|
ASSERT(!function.IsNull());
|
|
_object_hash_code_function_.store(function.ptr());
|
|
|
|
function = core_lib.LookupFunctionAllowPrivate(Symbols::_objectEquals());
|
|
ASSERT(!function.IsNull());
|
|
_object_equals_function_.store(function.ptr());
|
|
|
|
function = core_lib.LookupFunctionAllowPrivate(Symbols::_objectToString());
|
|
ASSERT(!function.IsNull());
|
|
_object_to_string_function_.store(function.ptr());
|
|
}
|
|
}
|
|
|
|
void ObjectStore::LazyInitAsyncMembers() {
|
|
auto* const thread = Thread::Current();
|
|
SafepointWriteRwLocker locker(thread,
|
|
thread->isolate_group()->program_lock());
|
|
if (nullable_future_null_type_.load() == Type::null()) {
|
|
ASSERT(non_nullable_future_never_type_.load() == Type::null());
|
|
|
|
auto* const zone = thread->zone();
|
|
const auto& cls = Class::Handle(zone, future_class());
|
|
ASSERT(!cls.IsNull());
|
|
|
|
auto& type_args = TypeArguments::Handle(zone);
|
|
auto& type = Type::Handle(zone);
|
|
type = never_type();
|
|
ASSERT(!type.IsNull());
|
|
type_args = TypeArguments::New(1);
|
|
type_args.SetTypeAt(0, type);
|
|
type = Type::New(cls, type_args, Nullability::kNonNullable);
|
|
type.SetIsFinalized();
|
|
type ^= type.Canonicalize(thread);
|
|
non_nullable_future_never_type_.store(type.ptr());
|
|
|
|
type = null_type();
|
|
ASSERT(!type.IsNull());
|
|
type_args = TypeArguments::New(1);
|
|
type_args.SetTypeAt(0, type);
|
|
type = Type::New(cls, type_args, Nullability::kNullable);
|
|
type.SetIsFinalized();
|
|
type ^= type.Canonicalize(thread);
|
|
nullable_future_null_type_.store(type.ptr());
|
|
}
|
|
}
|
|
|
|
void ObjectStore::LazyInitFfiMembers() {
|
|
auto* const thread = Thread::Current();
|
|
SafepointWriteRwLocker locker(thread,
|
|
thread->isolate_group()->program_lock());
|
|
if (handle_finalizer_message_function_.load() == Function::null()) {
|
|
auto* const zone = thread->zone();
|
|
auto& cls = Class::Handle(zone);
|
|
auto& function = Function::Handle(zone);
|
|
auto& error = Error::Handle(zone);
|
|
|
|
const auto& ffi_lib = Library::Handle(zone, Library::FfiLibrary());
|
|
ASSERT(!ffi_lib.IsNull());
|
|
|
|
cls = finalizer_class();
|
|
ASSERT(!cls.IsNull());
|
|
error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error.IsNull());
|
|
function =
|
|
cls.LookupFunctionAllowPrivate(Symbols::_handleFinalizerMessage());
|
|
ASSERT(!function.IsNull());
|
|
handle_finalizer_message_function_.store(function.ptr());
|
|
|
|
cls = native_finalizer_class();
|
|
ASSERT(!cls.IsNull());
|
|
error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error.IsNull());
|
|
function = cls.LookupFunctionAllowPrivate(
|
|
Symbols::_handleNativeFinalizerMessage());
|
|
ASSERT(!function.IsNull());
|
|
handle_native_finalizer_message_function_.store(function.ptr());
|
|
|
|
cls = ffi_lib.LookupClass(Symbols::FfiNative());
|
|
ASSERT(!cls.IsNull());
|
|
error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error.IsNull());
|
|
function =
|
|
cls.LookupStaticFunctionAllowPrivate(Symbols::_ffi_resolver_function());
|
|
ASSERT(!function.IsNull());
|
|
ffi_resolver_function_.store(function.ptr());
|
|
|
|
cls = ffi_lib.LookupClass(Symbols::VarArgs());
|
|
ASSERT(!cls.IsNull());
|
|
varargs_class_.store(cls.ptr());
|
|
}
|
|
}
|
|
|
|
void ObjectStore::LazyInitIsolateMembers() {
|
|
auto* const thread = Thread::Current();
|
|
SafepointWriteRwLocker locker(thread,
|
|
thread->isolate_group()->program_lock());
|
|
if (lookup_port_handler_.load() == Type::null()) {
|
|
ASSERT(lookup_open_ports_.load() == Type::null());
|
|
ASSERT(handle_message_function_.load() == Type::null());
|
|
|
|
auto* const zone = thread->zone();
|
|
const auto& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
|
|
auto& cls = Class::Handle(zone);
|
|
auto& function = Function::Handle(zone);
|
|
|
|
cls = isolate_lib.LookupClass(Symbols::Capability());
|
|
ASSERT(!cls.IsNull());
|
|
capability_class_.store(cls.ptr());
|
|
|
|
cls = isolate_lib.LookupClass(Symbols::SendPort());
|
|
ASSERT(!cls.IsNull());
|
|
send_port_class_.store(cls.ptr());
|
|
|
|
cls = isolate_lib.LookupClass(Symbols::TransferableTypedData());
|
|
ASSERT(!cls.IsNull());
|
|
transferable_class_.store(cls.ptr());
|
|
|
|
cls = isolate_lib.LookupClassAllowPrivate(Symbols::_RawReceivePort());
|
|
ASSERT(!cls.IsNull());
|
|
const auto& error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error == Error::null());
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_lookupHandler());
|
|
ASSERT(!function.IsNull());
|
|
lookup_port_handler_.store(function.ptr());
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_lookupOpenPorts());
|
|
ASSERT(!function.IsNull());
|
|
lookup_open_ports_.store(function.ptr());
|
|
|
|
function = cls.LookupFunctionAllowPrivate(Symbols::_handleMessage());
|
|
ASSERT(!function.IsNull());
|
|
handle_message_function_.store(function.ptr());
|
|
}
|
|
}
|
|
|
|
void ObjectStore::LazyInitInternalMembers() {
|
|
auto* const thread = Thread::Current();
|
|
SafepointWriteRwLocker locker(thread,
|
|
thread->isolate_group()->program_lock());
|
|
if (symbol_class_.load() == Type::null()) {
|
|
ASSERT(symbol_name_field_.load() == Field::null());
|
|
|
|
auto* const zone = thread->zone();
|
|
auto& cls = Class::Handle(zone);
|
|
auto& field = Field::Handle(zone);
|
|
auto& error = Error::Handle(zone);
|
|
|
|
const auto& internal_lib =
|
|
Library::Handle(zone, Library::InternalLibrary());
|
|
cls = internal_lib.LookupClass(Symbols::Symbol());
|
|
ASSERT(!cls.IsNull());
|
|
error = cls.EnsureIsFinalized(thread);
|
|
ASSERT(error.IsNull());
|
|
symbol_class_.store(cls.ptr());
|
|
|
|
field = cls.LookupInstanceFieldAllowPrivate(Symbols::_name());
|
|
ASSERT(!field.IsNull());
|
|
symbol_name_field_.store(field.ptr());
|
|
}
|
|
}
|
|
|
|
} // namespace dart
|