Files
sdk/runtime/vm/object_store.cc
T
Vyacheslav Egorov 49ed2007e5 [vm] Fix deadlock in AllocateSuspendState
AllocateSuspendState was calling `Instance::SetField` but did not allow lazy deopt to occur. Possibility of lazy deopt from those
field stores is only theoretical, but it manifested as a
deadlock between background compiler and main thread: if main
thread calls `SetField` which tries to acquire write access to
the program lock, while background compiler has already
acquired write access to the program lock and is trying to
stop all mutators at a GC+Deopt safepoint then we will
deadlock as `AllocateSuspendState` does not allow Deopts
(safepoint level was lowered by 5bc107c29d).

We fix this problem by bypassing field guard and simply
writing affected fields directly in AllocateSuspendState.
We make sure to initialize guarded state for these fields
eagerly, so it never needs to change.

TEST=added assertion which validates that attempting to acquire program lock for write can only occur where GC+Deopt are permitted.

Change-Id: I6ee6b82f3296f49f799c0069e42850711c9320ac
Bug: b/355226004
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381240
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
2024-08-19 14:04:47 +00:00

649 lines
23 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());
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& compact_hash_lib =
Library::Handle(zone, _compact_hash_library());
cls = compact_hash_lib.LookupClassAllowPrivate(Symbols::_Set());
ASSERT(!cls.IsNull());
set_set_impl_class(cls);
#if defined(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());
// Force the state of guarded cid to be nullable closure so that
// AllocateSuspendState could write to the field directly without
// updating the guard state.
field.set_guarded_cid(kClosureCid);
field.set_is_nullable(true);
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());
// Force the state of guarded cid to be nullable SuspendState so that
// AllocateSuspendState could write to the field directly without
// updating the guard state.
field.set_guarded_cid(kSuspendStateCid);
field.set_is_nullable(true);
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,
/*allow_add=*/true);
function_name =
Function::CreateDynamicInvocationForwarderName(Symbols::Minus());
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name,
/*allow_add=*/true);
function_name =
Function::CreateDynamicInvocationForwarderName(Symbols::Equals());
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name,
/*allow_add=*/true);
function_name =
Function::CreateDynamicInvocationForwarderName(Symbols::LAngleBracket());
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name,
/*allow_add=*/true);
function_name =
Function::CreateDynamicInvocationForwarderName(Symbols::RAngleBracket());
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name,
/*allow_add=*/true);
function_name =
Function::CreateDynamicInvocationForwarderName(Symbols::BitAnd());
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name,
/*allow_add=*/true);
function_name =
Function::CreateDynamicInvocationForwarderName(Symbols::BitOr());
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name,
/*allow_add=*/true);
function_name =
Function::CreateDynamicInvocationForwarderName(Symbols::Star());
Resolver::ResolveDynamicAnyArgs(zone, smi_class, function_name,
/*allow_add=*/true);
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
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