// 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 #include #include "vm/dart.h" #include "platform/unwinding_records.h" #include "vm/app_snapshot.h" #include "vm/code_observers.h" #include "vm/compiler/runtime_offsets_extracted.h" #include "vm/compiler/runtime_offsets_list.h" #include "vm/cpu.h" #include "vm/dart_api_state.h" #include "vm/dart_entry.h" #include "vm/debugger.h" #if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_TARGET_OS_LINUX) #include "vm/elf.h" #endif #include "vm/ffi_callback_metadata.h" #include "vm/flags.h" #include "vm/handles.h" #include "vm/heap/become.h" #include "vm/heap/freelist.h" #include "vm/heap/heap.h" #include "vm/heap/pointer_block.h" #include "vm/isolate.h" #include "vm/isolate_reload.h" #include "vm/kernel_isolate.h" #include "vm/message_handler.h" #include "vm/metrics.h" #include "vm/microtask_mirror_queues.h" #include "vm/native_entry.h" #include "vm/native_message_handler.h" #include "vm/object.h" #include "vm/object_id_ring.h" #include "vm/object_store.h" #include "vm/port.h" #include "vm/profiler.h" #include "vm/raw_object_fields.h" #include "vm/reverse_pc_lookup_cache.h" #include "vm/service_isolate.h" #include "vm/simulator.h" #include "vm/snapshot.h" #include "vm/stack_frame.h" #include "vm/stub_code.h" #include "vm/symbols.h" #include "vm/tags.h" #include "vm/thread_interrupter.h" #include "vm/thread_pool.h" #include "vm/timeline.h" #include "vm/unwinding_records.h" #include "vm/virtual_memory.h" #include "vm/zone.h" namespace dart { DECLARE_FLAG(bool, print_class_table); DEFINE_FLAG(bool, trace_shutdown, false, "Trace VM shutdown on stderr"); DEFINE_FLAG(bool, check_core_snapshot_match, false, "Also check core snapshot matches on OS and arch"); int64_t Dart::start_time_micros_ = 0; ThreadPool* Dart::thread_pool_ = nullptr; Dart_ThreadStartCallback Dart::thread_start_callback_ = nullptr; Dart_ThreadExitCallback Dart::thread_exit_callback_ = nullptr; Dart_FileOpenCallback Dart::file_open_callback_ = nullptr; Dart_FileReadCallback Dart::file_read_callback_ = nullptr; Dart_FileWriteCallback Dart::file_write_callback_ = nullptr; Dart_FileCloseCallback Dart::file_close_callback_ = nullptr; Dart_EntropySource Dart::entropy_source_callback_ = nullptr; Dart_DwarfStackTraceFootnoteCallback Dart::dwarf_stacktrace_footnote_callback_ = nullptr; class DartInitializationState : public AllStatic { public: static bool StartInit() { uword expected = PhaseField::encode(kUnInitialized) | CountField::encode(0); uword desired = PhaseField::encode(kInitializing) | CountField::encode(0); return state_.compare_exchange_strong(expected, desired, std::memory_order_acquire); } static void AbandonInit() { uword expected = PhaseField::encode(kInitializing) | CountField::encode(0); uword desired = PhaseField::encode(kUnInitialized) | CountField::encode(0); bool result = state_.compare_exchange_strong(expected, desired, std::memory_order_release); ASSERT(result); } static void FinishInit() { uword expected = PhaseField::encode(kInitializing) | CountField::encode(0); uword desired = PhaseField::encode(kInitialized) | CountField::encode(0); bool result = state_.compare_exchange_strong(expected, desired, std::memory_order_release); ASSERT(result); } static bool IsInitialized() { return PhaseField::decode(state_.load()) == kInitialized; } static bool IsShuttingDown() { return PhaseField::decode(state_.load()) == kCleaningup; } static bool StartCleanup() { uword expected = state_.load(std::memory_order_acquire); uword desired; do { if (PhaseField::decode(expected) != kInitialized) { return false; } desired = PhaseField::update(kCleaningup, expected); } while (!state_.compare_exchange_weak(expected, desired, std::memory_order_relaxed)); while (CountField::decode(expected) != 0) { OS::Sleep(1); expected = state_.load(std::memory_order_acquire); } return true; } static void FinishCleanup() { uword expected = PhaseField::encode(kCleaningup) | CountField::encode(0); uword desired = PhaseField::encode(kUnInitialized) | CountField::encode(0); bool result = state_.compare_exchange_strong(expected, desired, std::memory_order_release); ASSERT(result); } static bool SetInUse() { uword expected = state_.load(std::memory_order_relaxed); uword desired; do { if (PhaseField::decode(expected) != kInitialized) { return false; } desired = PhaseField::encode(kInitialized) | CountField::encode(CountField::decode(expected) + 1); } while (!state_.compare_exchange_weak(expected, desired, std::memory_order_relaxed)); return true; } static void ResetInUse() { uword expected = state_.load(std::memory_order_relaxed); uword desired; do { ASSERT(PhaseField::decode(expected) == kInitialized || PhaseField::decode(expected) == kCleaningup); desired = CountField::update(CountField::decode(expected) - 1, expected); } while (!state_.compare_exchange_weak(expected, desired, std::memory_order_release)); } private: static constexpr uword kUnInitialized = 0; static constexpr uword kInitializing = 1; static constexpr uword kInitialized = 2; static constexpr uword kCleaningup = 3; using PhaseField = BitField; using CountField = BitField; static std::atomic state_; }; std::atomic DartInitializationState::state_ = { PhaseField::encode(kUnInitialized) | CountField::encode(0)}; #if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME) static void CheckOffsets() { #if !defined(IS_SIMARM_HOST64) // These offsets are embedded in precompiled instructions. We need the // compiler and the runtime to agree. bool ok = true; #define CHECK_OFFSET(expr, offset) \ if ((expr) != (offset)) { \ OS::PrintErr("%s got %" Pd ", %s expected %" Pd "\n", #expr, \ static_cast(expr), #offset, \ static_cast(offset)); \ ok = false; \ } // No consistency checks needed for these constructs. #define CHECK_ARRAY_SIZEOF(Class, Name, ElementOffset) #define CHECK_PAYLOAD_SIZEOF(Class, Name, HeaderSize) #define CHECK_ENUM(Name, Elements) #if defined(DART_PRECOMPILED_RUNTIME) #define CHECK_FIELD(Class, Name) \ CHECK_OFFSET(Class::Name(), AOT_##Class##_##Name); #define CHECK_ARRAY(Class, Name) \ CHECK_OFFSET(Class::ArrayTraits::elements_start_offset(), \ AOT_##Class##_elements_start_offset); \ CHECK_OFFSET(Class::ArrayTraits::kElementSize, AOT_##Class##_element_size) #define CHECK_SIZEOF(Class, Name, What) \ CHECK_OFFSET(sizeof(What), AOT_##Class##_##Name); #define CHECK_RANGE(Class, Getter, Type, First, Last, Filter) \ for (intptr_t i = static_cast(First); \ i <= static_cast(Last); i++) { \ if (Filter(static_cast(i))) { \ CHECK_OFFSET(Class::Getter(static_cast(i)), \ AOT_##Class##_##Getter[i - static_cast(First)]); \ } \ } #define CHECK_CONSTANT(Class, Name) \ CHECK_OFFSET(Class::Name, AOT_##Class##_##Name); #else #define CHECK_FIELD(Class, Name) CHECK_OFFSET(Class::Name(), Class##_##Name); #define CHECK_ARRAY(Class, Name) \ CHECK_OFFSET(Class::ArrayTraits::elements_start_offset(), \ Class##_elements_start_offset); \ CHECK_OFFSET(Class::ArrayTraits::kElementSize, Class##_element_size); #if defined(DART_PRECOMPILER) // Objects in precompiler may have extra fields only used during // precompilation (such as Class::target_instance_size_in_words_), // so size of objects in precompiler doesn't necessarily match // size of objects at run time. #define CHECK_SIZEOF(Class, Name, What) #else #define CHECK_SIZEOF(Class, Name, What) \ CHECK_OFFSET(sizeof(What), Class##_##Name); #endif // defined(DART_PRECOMPILER) #define CHECK_RANGE(Class, Getter, Type, First, Last, Filter) \ for (intptr_t i = static_cast(First); \ i <= static_cast(Last); i++) { \ if (Filter(static_cast(i))) { \ CHECK_OFFSET(Class::Getter(static_cast(i)), \ Class##_##Getter[i - static_cast(First)]); \ } \ } #define CHECK_CONSTANT(Class, Name) CHECK_OFFSET(Class::Name, Class##_##Name); #endif // defined(DART_PRECOMPILED_RUNTIME) COMMON_OFFSETS_LIST(CHECK_FIELD, CHECK_ARRAY, CHECK_SIZEOF, CHECK_ARRAY_SIZEOF, CHECK_PAYLOAD_SIZEOF, CHECK_RANGE, CHECK_CONSTANT, CHECK_ENUM) NOT_IN_PRECOMPILED_RUNTIME(JIT_OFFSETS_LIST( CHECK_FIELD, CHECK_ARRAY, CHECK_SIZEOF, CHECK_ARRAY_SIZEOF, CHECK_PAYLOAD_SIZEOF, CHECK_RANGE, CHECK_CONSTANT, CHECK_ENUM)) ONLY_IN_PRECOMPILED(AOT_OFFSETS_LIST(CHECK_FIELD, CHECK_ARRAY, CHECK_SIZEOF, CHECK_ARRAY_SIZEOF, CHECK_PAYLOAD_SIZEOF, CHECK_RANGE, CHECK_CONSTANT, CHECK_ENUM)) if (!ok) { FATAL( "CheckOffsets failed. Try updating offsets by running " "./tools/run_offsets_extractor.dart"); } #undef CHECK_FIELD #undef CHECK_ARRAY #undef CHECK_ARRAY_STRUCTFIELD #undef CHECK_SIZEOF #undef CHECK_RANGE #undef CHECK_CONSTANT #undef CHECK_OFFSET #undef CHECK_PAYLOAD_SIZEOF #undef CHECK_ENUM #endif // !defined(IS_SIMARM_HOST64) } #endif // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME) char* Dart::DartInit(const Dart_InitializeParams* params) { #if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME) CheckOffsets(); #elif defined(ARCH_IS_64_BIT) != defined(TARGET_ARCH_IS_64_BIT) return Utils::StrDup( "JIT cannot simulate target architecture with different word size than " "host"); #endif #if defined(DART_HOST_OS_MACOS) && !defined(DART_HOST_OS_IOS) char* error = CheckIsAtLeastMinRequiredMacOSXVersion(); if (error != nullptr) { return error; } #endif if (!Flags::Initialized()) { return Utils::StrDup("VM initialization failed-VM Flags not initialized."); } if (((FLAG_target_address_sanitizer ? 1 : 0) + (FLAG_target_memory_sanitizer ? 1 : 0) + (FLAG_target_thread_sanitizer ? 1 : 0)) > 1) { return Utils::StrDup("Can only target one sanitizer at a time"); } FrameLayout::Init(); set_thread_start_callback(params->thread_start); set_thread_exit_callback(params->thread_exit); SetFileCallbacks(params->file_open, params->file_read, params->file_write, params->file_close); set_entropy_source_callback(params->entropy_source); OS::Init(); NOT_IN_PRODUCT(CodeObservers::Init()); if (params->code_observer != nullptr) { NOT_IN_PRODUCT(CodeObservers::RegisterExternal(*params->code_observer)); } start_time_micros_ = OS::GetCurrentMonotonicMicros(); VirtualMemory::Init(); #if defined(DART_PRECOMPILED_RUNTIME) && defined(DART_TARGET_OS_LINUX) if (VirtualMemory::PageSize() > kElfPageSize) { return Utils::SCreate( "Incompatible page size for AOT compiled ELF: expected at most %" Pd ", got %" Pd "", kElfPageSize, VirtualMemory::PageSize()); } #endif OSThread::Init(); Zone::Init(); #if defined(SUPPORT_TIMELINE) Timeline::Init(); TimelineBeginEndScope tbes(Timeline::GetVMStream(), "Dart::Init"); #endif IsolateGroup::Init(); Isolate::InitVM(); PortMap::Init(); NativeMessageHandler::Init(); Service::Init(); FreeListElement::Init(); ForwardingCorpse::Init(); NativeSymbolResolver::Init(); Page::Init(); StoreBuffer::Init(); MarkingStack::Init(); TargetCPUFeatures::Init(); #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) // Dart VM requires at least SSE2. if (!TargetCPUFeatures::sse2_supported()) { return Utils::StrDup("SSE2 is required."); } #endif #if defined(DART_INCLUDE_SIMULATOR) Simulator::Init(); #endif Object::InitVtables(); OffsetsTable::Init(); ASSERT(thread_pool_ == nullptr); thread_pool_ = new ThreadPool(); #if defined(DART_INCLUDE_PROFILER) Profiler::Init(); #endif Isolate::SetCreateGroupCallback(params->create_group); Isolate::SetInitializeCallback_(params->initialize_isolate); Isolate::SetShutdownCallback(params->shutdown_isolate); Isolate::SetCleanupCallback(params->cleanup_isolate); Isolate::SetGroupCleanupCallback(params->cleanup_group); return nullptr; } char* Dart::Init(const Dart_InitializeParams* params) { if (!DartInitializationState::StartInit()) { return Utils::StrDup( "Bad VM initialization state, " "already initialized or " "multiple threads initializing the VM."); } char* retval = DartInit(params); if (retval != nullptr) { DartInitializationState::AbandonInit(); return retval; } DartInitializationState::FinishInit(); // The service and kernel isolates require the VM state to be initialized. // The embedder, not the VM, should trigger creation of the service and kernel // isolates. https://github.com/dart-lang/sdk/issues/33433 #if !defined(PRODUCT) ServiceIsolate::Run(); #endif #if !defined(DART_PRECOMPILED_RUNTIME) if (params->start_kernel_isolate) { KernelIsolate::InitializeState(); } #endif return nullptr; } static void DumpAliveIsolates(intptr_t num_attempts, bool only_application_isolates) { IsolateGroup::ForEach([&](IsolateGroup* group) { group->ForEachIsolate([&](Isolate* isolate) { if (!only_application_isolates || !Isolate::IsSystemIsolate(isolate)) { OS::PrintErr("Attempt:%" Pd " waiting for isolate %s to check in\n", num_attempts, isolate->name()); } }); }); } // This waits until only the VM, service and kernel isolates are in the list. void Dart::WaitForApplicationIsolateShutdown() { ASSERT(!Isolate::creation_enabled_); MonitorLocker ml(Isolate::isolate_creation_monitor_); intptr_t num_attempts = 0; while (IsolateGroup::HasApplicationIsolateGroups()) { Monitor::WaitResult retval = ml.Wait(1000); if (retval == Monitor::kTimedOut) { num_attempts += 1; if (num_attempts > 10) { DumpAliveIsolates(num_attempts, /*only_application_isolates=*/true); } } } } // This waits until only the VM isolate remains in the list. void Dart::WaitForIsolateShutdown() { int64_t start_time = 0; if (FLAG_trace_shutdown) { start_time = UptimeMillis(); OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Waiting for service " "and kernel isolates to shutdown\n", start_time); } ASSERT(!Isolate::creation_enabled_); MonitorLocker ml(Isolate::isolate_creation_monitor_); intptr_t num_attempts = 0; while (IsolateGroup::HasIsolateGroups() || (Isolate::pending_shutdowns_ != 0)) { Monitor::WaitResult retval = ml.Wait(1000); if (retval == Monitor::kTimedOut) { num_attempts += 1; if (num_attempts > 10) { DumpAliveIsolates(num_attempts, /*only_application_isolates=*/false); } if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: %" Pd " time out waiting for " "service and kernel isolates to shutdown\n", UptimeMillis(), num_attempts); } } } if (FLAG_trace_shutdown) { int64_t stop_time = UptimeMillis(); OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done waiting for service " "and kernel isolates to shutdown\n", stop_time); if ((stop_time - start_time) > 500) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: waited too long for service " "and kernel isolates to shutdown\n", (stop_time - start_time)); } } ASSERT(!IsolateGroup::HasIsolateGroups()); } char* Dart::Cleanup() { ASSERT(Isolate::Current() == nullptr); if (!DartInitializationState::StartCleanup()) { return Utils::StrDup("VM already terminated."); } if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Starting shutdown\n", UptimeMillis()); } #if defined(DART_INCLUDE_PROFILER) if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Stopping profiling\n", UptimeMillis()); } Profiler::SetConfig({.enabled = false}); #endif // defined(DART_INCLUDE_PROFILER) #if defined(SUPPORT_TIMELINE) if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Stopping timeline streaming\n", UptimeMillis()); } Timeline::StopStreaming(/*reinitialize=*/false); #endif NativeSymbolResolver::Cleanup(); // Disable the creation of new isolates. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling isolate creation\n", UptimeMillis()); } Isolate::DisableIsolateCreation(); // Send the OOB Kill message to all remaining application isolates. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Killing all app isolates\n", UptimeMillis()); } Isolate::KillAllIsolates(Isolate::kInternalKillMsg); // Wait for all isolates, but the service and the kernel isolate to shut down. // Only do that if there is a service isolate running. if (ServiceIsolate::IsRunning() || KernelIsolate::IsRunning()) { if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down app isolates\n", UptimeMillis()); } WaitForApplicationIsolateShutdown(); if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done shutting down app isolates\n", UptimeMillis()); } } Isolate::KillAllSystemIsolates(Isolate::kInternalKillMsg); // Shutdown the kernel isolate. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down kernel isolate\n", UptimeMillis()); } KernelIsolate::Shutdown(); // Shutdown the service isolate. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down service isolate\n", UptimeMillis()); } ServiceIsolate::Shutdown(); // Wait for the remaining isolate (service/kernel isolate) to shutdown // before shutting down the thread pool. WaitForIsolateShutdown(); // Shutdown the thread pool. On return, all thread pool threads have exited. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting thread pool\n", UptimeMillis()); } NativeMessageHandler::Cleanup(); PortMap::Shutdown(); thread_pool_->Shutdown(); delete thread_pool_; thread_pool_ = nullptr; if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done deleting thread pool\n", UptimeMillis()); } #if defined(DART_INCLUDE_PROFILER) // Destroy profiler state. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Destroying profiler state\n", UptimeMillis()); } Profiler::Cleanup(); #endif // defined(DART_INCLUDE_PROFILER) // Disable creation of any new OSThread structures which means no more new // threads can do an EnterIsolate. This must come after isolate shutdown // because new threads may need to be spawned to shutdown the isolates. // This must come after deletion of the thread pool to avoid a race in which // a thread spawned by the thread pool does not exit through the thread // pool, messing up its bookkeeping. if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling OS Thread creation\n", UptimeMillis()); } OSThread::DisableOSThreadCreation(); ASSERT(Isolate::IsolateListLength() == 0); Service::Cleanup(); PortMap::Cleanup(); IsolateGroup::Cleanup(); OffsetsTable::Cleanup(); TargetCPUFeatures::Cleanup(); MarkingStack::Cleanup(); StoreBuffer::Cleanup(); Page::Cleanup(); #if defined(SUPPORT_TIMELINE) if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down timeline\n", UptimeMillis()); } Timeline::Cleanup(); #endif NOT_IN_PRODUCT(MicrotaskMirrorQueues::CleanUp()); Zone::Cleanup(); // Delete the current thread's TLS and set it's TLS to null. // If it is the last thread then the destructor would call // OSThread::Cleanup. OSThread* os_thread = OSThread::Current(); OSThread::SetCurrent(nullptr); delete os_thread; if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleted os_thread\n", UptimeMillis()); } if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting code observers\n", UptimeMillis()); } NOT_IN_PRODUCT(CodeObservers::Cleanup()); OS::Cleanup(); if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done\n", UptimeMillis()); } Flags::Cleanup(); #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) IsolateGroupReloadContext::SetFileModifiedCallback(nullptr); Service::SetEmbedderStreamCallbacks(nullptr, nullptr); #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) VirtualMemory::Cleanup(); DartInitializationState::FinishCleanup(); return nullptr; } bool Dart::IsInitialized() { return DartInitializationState::IsInitialized(); } bool Dart::IsShuttingDown() { return DartInitializationState::IsShuttingDown(); } bool Dart::SetActiveApiCall() { return DartInitializationState::SetInUse(); } void Dart::ResetActiveApiCall() { DartInitializationState::ResetInUse(); } Isolate* Dart::CreateIsolate(const char* name_prefix, const Dart_IsolateFlags& api_flags, IsolateGroup* isolate_group) { // Create a new isolate. Isolate* isolate = Isolate::InitIsolate(name_prefix, isolate_group, api_flags); return isolate; } char* Dart::InitIsolateGroupFromSnapshot(Thread* T, const uint8_t* snapshot_data, const uint8_t* snapshot_text, const uint8_t* kernel_buffer, intptr_t kernel_buffer_size) { auto IG = T->isolate_group(); Error& error = Error::Handle(T->zone()); error = Object::Init(IG, kernel_buffer, kernel_buffer_size); if (!error.IsNull()) { return Utils::StrDup(error.ToCString()); } if (snapshot_data != nullptr && kernel_buffer == nullptr) { // Read the snapshot and setup the initial state. #if defined(SUPPORT_TIMELINE) TimelineBeginEndScope tbes(T, Timeline::GetIsolateStream(), "ReadProgramSnapshot"); #endif // defined(SUPPORT_TIMELINE) const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_data); if (snapshot == nullptr) { return Utils::StrDup("Invalid snapshot"); } #if defined(DART_PRECOMPILED_RUNTIME) if (snapshot->kind() != Snapshot::kFullAOT) { return Utils::StrDup("AOT runtime cannot run a JIT snapshot"); } #else if (snapshot->kind() == Snapshot::kFullAOT) { return Utils::StrDup("JIT runtime cannot run an AOT snapshot"); } #endif if (FLAG_trace_isolates) { OS::PrintErr("Size of isolate snapshot = %" Pd "\n", snapshot->length()); } FullSnapshotReader reader(snapshot, snapshot_text, T); char* error = reader.ReadProgramSnapshot(); if (error != nullptr) { return error; } { // Initialize sentinel field table, which should have sentinel values for // all fields. auto len = IG->initial_field_table()->Capacity(); IG->sentinel_field_table()->AllocateIndex(len); for (intptr_t i = 0; i < len; i++) { IG->sentinel_field_table()->SetAt(i, Object::sentinel().ptr()); } } T->SetupDartMutatorStateDependingOnSnapshot(IG); #if defined(SUPPORT_TIMELINE) if (tbes.enabled()) { tbes.SetNumArguments(2); tbes.FormatArgument(0, "snapshotSize", "%" Pd, snapshot->length()); tbes.FormatArgument(1, "heapSize", "%" Pd, IG->heap()->UsedInWords(Heap::kOld) * kWordSize); } #endif // defined(SUPPORT_TIMELINE) if (FLAG_trace_isolates) { IG->heap()->PrintSizes(); MegamorphicCacheTable::PrintSizes(T); } } else { if (kernel_buffer == nullptr) { return Utils::StrDup("Missing isolate snapshot"); } } #if !defined(PRODUCT) || defined(FORCE_INCLUDE_SAMPLING_HEAP_PROFILER) IG->class_table()->PopulateUserVisibleNames(); #endif return nullptr; } #if !defined(DART_PRECOMPILED_RUNTIME) // The runtime assumes it can create certain kinds of objects at-will without // a check whether their class need to be finalized first. // // Some of those objects can end up flowing to user code (i.e. their class is a // subclass of [Instance]). // // We therefore ensure that classes are finalized before objects of them are // created or at least before such objects can reach user code. static void FinalizeBuiltinClasses(Thread* thread) { auto class_table = thread->isolate_group()->class_table(); Class& cls = Class::Handle(thread->zone()); for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) { if (class_table->HasValidClassAt(cid)) { cls = class_table->At(cid); RELEASE_ASSERT(cls.EnsureIsFinalized(thread) == Object::null()); } } } #endif // !defined(DART_PRECOMPILED_RUNTIME) char* Dart::InitializeIsolateGroup(Thread* T, const uint8_t* snapshot_data, const uint8_t* snapshot_text, const uint8_t* kernel_buffer, intptr_t kernel_buffer_size) { // TODO(bootstrap-only-in-gen-snapshot) bool skip_bootstrap = false; if (snapshot_data != nullptr && kernel_buffer == nullptr) { const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_data); skip_bootstrap = snapshot->kind() == Snapshot::kFullAOT || snapshot->kind() == Snapshot::kFullJIT; char* error = SnapshotHeaderReader::InitializeIsolateGroupFlagsFromSnapshot(snapshot); if (error != nullptr) { return error; } } { StackZone zone(T); IsolateGroup* IG = T->isolate_group(); Object::InitNullAndBool(IG); // Fix fields that were initialized with Object::null() before it pointed to // the null objects and so currently have Smi 0. T->isolate()->FixInitiallyNullFields(); T->FixInitiallyNullFields(); IG->set_object_store(new ObjectStore()); if (!skip_bootstrap) { #if defined(DART_PRECOMPILED_RUNTIME) UNREACHABLE(); #else Object::Init(IG); ArgumentsDescriptor::Init(); ICData::Init(); StubCode::Init(); T->InitVMConstants(); Symbols::Init(IG); Object::FinishInit(IG); Api::InitHandles(); #endif } } char* error = InitIsolateGroupFromSnapshot(T, snapshot_data, snapshot_text, kernel_buffer, kernel_buffer_size); if (error != nullptr) { return error; } T->isolate_group()->set_bootstrapping(false); Object::VerifyBuiltinVtables(); auto IG = T->isolate_group(); { SafepointReadRwLocker reader(T, IG->program_lock()); IG->set_shared_field_table(T, IG->shared_initial_field_table()->Clone( /*for_isolate=*/nullptr, /*for_isolate_group=*/IG)); } DEBUG_ONLY(IG->heap()->Verify("InitializeIsolate", kForbidMarked)); #if !defined(DART_PRECOMPILED_RUNTIME) FinalizeBuiltinClasses(T); #endif if (snapshot_data == nullptr || kernel_buffer != nullptr) { auto object_store = IG->object_store(); const Error& error = Error::Handle(object_store->PreallocateObjects()); if (!error.IsNull()) { return Utils::StrDup(error.ToErrorCString()); } } if (FLAG_print_class_table) { IG->class_table()->Print(); } IG->object_store()->set_tag_table( GrowableObjectArray::Handle(GrowableObjectArray::New())); return nullptr; } ErrorPtr Dart::InitializeIsolate(Thread* T, bool is_first_isolate_in_group, void* isolate_data) { auto I = T->isolate(); auto IG = T->isolate_group(); auto Z = T->zone(); // If a static field gets registered in [IsolateGroup::RegisterStaticField]: // // * before this block it will ignore this isolate. The [Clone] of the // initial field table will pick up the new value. // * after this block it will add the new static field to this isolate. { SafepointReadRwLocker reader(T, IG->program_lock()); I->set_field_table(T, IG->initial_field_table()->Clone(I)); I->field_table()->MarkReadyToUse(); } T->set_thread_locals(Object::empty_array()); const auto& error = Error::Handle(Z, I->isolate_object_store()->PreallocateObjects()); if (!error.IsNull()) { return error.ptr(); } I->set_init_callback_data(isolate_data); #if !defined(PRODUCT) if (Isolate::IsSystemIsolate(I)) { ServiceIsolate::MaybeMakeServiceIsolate(I); } else { I->message_handler()->set_should_pause_on_start( FLAG_pause_isolates_on_start); I->message_handler()->set_should_pause_on_exit(FLAG_pause_isolates_on_exit); } #endif // !defined(PRODUCT) ServiceIsolate::SendIsolateStartupMessage(); #if !defined(PRODUCT) I->debugger()->NotifyIsolateCreated(); #endif if (is_first_isolate_in_group) { // IsolateGroup tag_table was not available when isolate was first // created, but now it is. ASSERT(T->current_tag() == UserTag::null()); const UserTag& default_tag = UserTag::Handle(UserTag::DefaultTag(T)); T->set_current_tag(default_tag); } I->init_loaded_prefixes_set_storage(); return Error::null(); } char* Dart::FeaturesString(IsolateGroup* isolate_group, Snapshot::Kind kind) { TextBuffer buffer(64); // Different fields are included for DEBUG/RELEASE/PRODUCT. #if defined(DEBUG) buffer.AddString("debug"); #elif defined(PRODUCT) buffer.AddString("product"); #else buffer.AddString("release"); #endif #define ADD_FLAG(name, value) \ do { \ buffer.AddString(value ? (" " #name) : (" no-" #name)); \ } while (0); #define ADD_P(name, T, DV, C) ADD_FLAG(name, FLAG_##name) #define ADD_R(name, PV, T, DV, C) ADD_FLAG(name, FLAG_##name) #define ADD_C(name, PCV, PV, T, DV, C) ADD_FLAG(name, FLAG_##name) #define ADD_D(name, T, DV, C) ADD_FLAG(name, FLAG_##name) #define ADD_ISOLATE_GROUP_FLAG(name, isolate_flag, flag) \ do { \ const bool value = \ isolate_group != nullptr ? isolate_group->name() : flag; \ ADD_FLAG(name, value); \ } while (0); if (Snapshot::IncludesCode(kind)) { ADD_FLAG(asan, FLAG_target_address_sanitizer) ADD_FLAG(msan, FLAG_target_memory_sanitizer) ADD_FLAG(tsan, FLAG_target_thread_sanitizer) ADD_FLAG(shared_data, FLAG_experimental_shared_data) if (kind == Snapshot::kFullJIT) { // Enabling assertions affects deopt ids. // // This flag is only used at compile time for AOT, so it's only relevant // when running JIT snapshots. We can omit this flag for AOT snapshots so // feature verification won't fail if --enable-snapshots isn't provided // at runtime. ADD_ISOLATE_GROUP_FLAG(asserts, enable_asserts, FLAG_enable_asserts); ADD_ISOLATE_GROUP_FLAG(use_field_guards, use_field_guards, FLAG_use_field_guards); ADD_ISOLATE_GROUP_FLAG(use_osr, use_osr, FLAG_use_osr); ADD_ISOLATE_GROUP_FLAG(branch_coverage, branch_coverage, FLAG_branch_coverage); ADD_ISOLATE_GROUP_FLAG(coverage, coverage, FLAG_coverage); } ADD_ISOLATE_GROUP_FLAG(code_comments, code_comments, FLAG_code_comments); ADD_ISOLATE_GROUP_FLAG(dwarf_stack_traces, dwarf_stack_traces, FLAG_dwarf_stack_traces_mode); } if (Snapshot::IncludesCode(kind) || FLAG_check_core_snapshot_match) { // Generated code must match the host architecture and ABI. We check the // strong condition of matching on operating system so that // Platform.isAndroid etc can be compile-time constants. #if defined(TARGET_ARCH_IA32) buffer.AddString(" ia32"); #elif defined(TARGET_ARCH_X64) buffer.AddString(" x64"); #elif defined(TARGET_ARCH_ARM) buffer.AddString(" arm"); #elif defined(TARGET_ARCH_ARM64) buffer.AddString(" arm64"); #elif defined(TARGET_ARCH_RISCV32) buffer.AddString(" riscv32"); #elif defined(TARGET_ARCH_RISCV64) buffer.AddString(" riscv64"); #else #error What architecture? #endif #if defined(DART_TARGET_OS_ANDROID) buffer.AddString(" android"); #elif defined(DART_TARGET_OS_FUCHSIA) buffer.AddString(" fuchsia"); #elif defined(DART_TARGET_OS_MACOS) #if defined(DART_TARGET_OS_MACOS_IOS) buffer.AddString(" ios"); #else buffer.AddString(" macos"); #endif #elif defined(DART_TARGET_OS_LINUX) buffer.AddString(" linux"); #elif defined(DART_TARGET_OS_WINDOWS) buffer.AddString(" windows"); #else #error What operating system? #endif #if defined(DART_COMPRESSED_POINTERS) buffer.AddString(" compressed-pointers"); #else buffer.AddString(" no-compressed-pointers"); #endif } #undef ADD_ISOLATE_FLAG #undef ADD_D #undef ADD_C #undef ADD_R #undef ADD_P #undef ADD_FLAG return buffer.Steal(); } void Dart::RunShutdownCallback() { Thread* thread = Thread::Current(); ASSERT(thread->execution_state() == Thread::kThreadInVM); Isolate* isolate = thread->isolate(); void* isolate_group_data = isolate->group()->embedder_data(); void* isolate_data = isolate->init_callback_data(); Dart_IsolateShutdownCallback callback = isolate->on_shutdown_callback(); if (callback != nullptr) { TransitionVMToNative transition(thread); (callback)(isolate_group_data, isolate_data); } } void Dart::ShutdownIsolate(Thread* T) { T->isolate()->Shutdown(); } int64_t Dart::UptimeMicros() { return OS::GetCurrentMonotonicMicros() - Dart::start_time_micros_; } } // namespace dart