// 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. #ifndef RUNTIME_VM_ISOLATE_H_ #define RUNTIME_VM_ISOLATE_H_ #if defined(SHOULD_NOT_INCLUDE_RUNTIME) #error "Should not include runtime" #endif #include #include #include #include "include/dart_api.h" #include "platform/assert.h" #include "platform/atomic.h" #include "platform/growable_array.h" #include "platform/thread_sanitizer.h" #include "vm/class_table.h" #include "vm/dispatch_table.h" #include "vm/exceptions.h" #include "vm/ffi_callback_metadata.h" #include "vm/field_table.h" #include "vm/fixed_cache.h" #include "vm/handles.h" #include "vm/hash_map.h" #include "vm/heap/verifier.h" #include "vm/intrusive_dlist.h" #include "vm/megamorphic_cache_table.h" #include "vm/metrics.h" #include "vm/os_thread.h" #include "vm/port.h" #include "vm/random.h" #include "vm/roots.h" #include "vm/service.h" #include "vm/tags.h" #include "vm/thread.h" #include "vm/thread_pool.h" #include "vm/thread_stack_resource.h" #include "vm/token_position.h" namespace dart { // Forward declarations. class ApiState; class BackgroundCompiler; class Become; class Capability; class CodeIndexTable; class Debugger; class ExternalTypedData; class GroupDebugger; class HandleScope; class HandleVisitor; class Heap; class ICData; class IsolateGroupReloadContext; class IsolateMessageHandler; class IsolateObjectStore; class IsolateProfilerData; class Log; class Message; class MessageHandler; class Mutex; class Object; class ObjectIdRing; class ObjectPointerVisitor; class ObjectStore; class PersistentHandle; class ProgramReloadContext; class RwLock; class SafepointHandler; class SafepointRwLock; class SampleBlock; class SampleBlockBuffer; class SampleBuffer; class SendPort; class SerializedObjectBuffer; class ServiceIdZone; class Simulator; class StackResource; class StackZone; class StoreBuffer; class StubCode; class ThreadRegistry; class UserTag; class IsolateVisitor { public: IsolateVisitor() {} virtual ~IsolateVisitor() {} virtual void VisitIsolate(Isolate* isolate) = 0; protected: // Returns true if |isolate| is the VM or service isolate. bool IsSystemIsolate(Isolate* isolate) const; private: DISALLOW_COPY_AND_ASSIGN(IsolateVisitor); }; class Callable : public ValueObject { public: Callable() {} virtual ~Callable() {} virtual void Call() = 0; private: DISALLOW_COPY_AND_ASSIGN(Callable); }; template class LambdaCallable : public Callable { public: explicit LambdaCallable(T& lambda) : lambda_(lambda) {} void Call() { lambda_(); } private: T& lambda_; DISALLOW_COPY_AND_ASSIGN(LambdaCallable); }; // Fixed cache for exception handler lookup. typedef FixedCache HandlerInfoCache; // Fixed cache for catch entry state lookup. typedef FixedCache CatchEntryMovesCache; // List of Isolate group flags. // // V(when, name, bit-name, Dart_IsolateFlags-name, command-line-flag-name) // #define BOOL_ISOLATE_GROUP_FLAG_LIST(V) \ V(PRECOMPILER, obfuscate, Obfuscate, obfuscate, false) \ V(NONPRODUCT, asserts, EnableAsserts, enable_asserts, FLAG_enable_asserts) \ V(PRODUCT, use_field_guards, UseFieldGuards, use_field_guards, \ FLAG_use_field_guards) \ V(PRODUCT, should_load_vmservice_library, ShouldLoadVmService, \ load_vmservice_library, false) \ V(PRODUCT, use_osr, UseOsr, use_osr, FLAG_use_osr) \ V(NONPRODUCT, snapshot_is_dontneed_safe, SnapshotIsDontNeedSafe, \ snapshot_is_dontneed_safe, false) \ V(NONPRODUCT, branch_coverage, BranchCoverage, branch_coverage, \ FLAG_branch_coverage) \ V(NONPRODUCT, coverage, Coverage, coverage, FLAG_coverage) \ V(PRODUCT, dwarf_stack_traces, DwarfStackTraces, dwarf_stack_traces, \ FLAG_dwarf_stack_traces_mode) \ V(PRODUCT, code_comments, CodeComments, code_comments, FLAG_code_comments) // List of Isolate flags with corresponding members of Dart_IsolateFlags and // corresponding global command line flags. #define BOOL_ISOLATE_FLAG_LIST(V) \ V(NONPRODUCT, is_system_isolate, IsSystemIsolate, is_system_isolate, false) \ V(NONPRODUCT, is_service_isolate, IsServiceIsolate, is_service_isolate, \ false) \ V(NONPRODUCT, is_kernel_isolate, IsKernelIsolate, is_kernel_isolate, false) // Represents the information used for spawning the first isolate within an // isolate group. All isolates within a group will refer to this // [IsolateGroupSource]. class IsolateGroupSource { public: IsolateGroupSource(const char* script_uri, const char* name, const uint8_t* snapshot_data, const uint8_t* snapshot_text, const uint8_t* kernel_buffer, intptr_t kernel_buffer_size, Dart_IsolateFlags flags) : script_uri(script_uri == nullptr ? nullptr : Utils::StrDup(script_uri)), name(Utils::StrDup(name)), snapshot_data(snapshot_data), snapshot_text(snapshot_text), kernel_buffer(kernel_buffer), kernel_buffer_size(kernel_buffer_size), flags(flags), script_kernel_buffer(nullptr), script_kernel_size(-1), loaded_blobs_(nullptr), num_blob_loads_(0) {} ~IsolateGroupSource() { free(script_uri); free(name); } void add_loaded_blob(Zone* zone_, const ExternalTypedData& external_typed_data); // The arguments used for spawning in // `Dart_CreateIsolateGroupFromKernel` / `Dart_CreateIsolate`. char* script_uri; char* name; const uint8_t* snapshot_data; const uint8_t* snapshot_text; const uint8_t* kernel_buffer; const intptr_t kernel_buffer_size; Dart_IsolateFlags flags; // The kernel buffer used in `Dart_LoadScriptFromKernel`. const uint8_t* script_kernel_buffer; intptr_t script_kernel_size; // List of weak pointers to external typed data for loaded blobs. ArrayPtr loaded_blobs_; intptr_t num_blob_loads_; }; // Tracks idle time and notifies heap when idle time expired. class IdleTimeHandler : public ValueObject { public: IdleTimeHandler() {} // Initializes the idle time handler with the given [heap], to which // idle notifications will be sent. void InitializeWithHeap(Heap* heap); // Declares that the idle time should be reset to now. void UpdateStartIdleTime(); // Returns whether idle time expired and [NotifyIdle] should be called. bool ShouldNotifyIdle(int64_t* expiry); // Notifies the heap that now is a good time to do compactions and indicates // we have time for the GC until [deadline]. void NotifyIdle(int64_t deadline); // Calls [NotifyIdle] with the default deadline. void NotifyIdleUsingDefaultDeadline(); private: friend class DisableIdleTimerScope; Mutex mutex_; Heap* heap_ = nullptr; intptr_t disabled_counter_ = 0; int64_t idle_start_time_ = 0; }; // Disables firing of the idle timer while this object is alive. class DisableIdleTimerScope : public ValueObject { public: explicit DisableIdleTimerScope(IdleTimeHandler* handler); ~DisableIdleTimerScope(); private: IdleTimeHandler* handler_; }; class MutatorThreadPool : public ThreadPool { public: MutatorThreadPool(IsolateGroup* isolate_group, intptr_t max_pool_size) : ThreadPool(max_pool_size), isolate_group_(isolate_group) {} virtual ~MutatorThreadPool() {} protected: virtual void OnEnterIdleLocked(MutexLocker* ml, ThreadPool::Worker* worker); private: void NotifyIdle(); IsolateGroup* isolate_group_ = nullptr; }; enum RootSlice : intptr_t { kClassTable, kApiState, kObjectStore, kInitialFieldTable, kSentinelFieldTable, kSharedInitialFieldTable, kSharedFieldTable, kBackgroundCompiler, kDebugger, kReloadContext, kLoadedBlobs, kBecome, kObjectIdZones, kNumRootSlices, }; inline const char* RootSliceToCString(intptr_t slice) { switch (slice) { case kClassTable: return "class table"; case kApiState: return "api state"; case kObjectStore: return "group object store"; case kInitialFieldTable: return "initial field table"; case kSentinelFieldTable: return "sentinel field table"; case kSharedInitialFieldTable: return "shared initial field table"; case kSharedFieldTable: return "shared field table"; case kBackgroundCompiler: return "background compiler"; case kDebugger: return "debugger"; case kReloadContext: return "reload context"; case kLoadedBlobs: return "loaded blobs"; case kBecome: return "become"; case kObjectIdZones: return "object id zones"; default: return "?"; } } // Represents an isolate group and is shared among all isolates within a group. class IsolateGroup : public IntrusiveDListEntry { public: IsolateGroup(std::shared_ptr source, void* embedder_data, ObjectStore* object_store, Dart_IsolateFlags api_flags); IsolateGroup(std::shared_ptr source, void* embedder_data, Dart_IsolateFlags api_flags); ~IsolateGroup(); void RehashConstants(Become* become); #if defined(DEBUG) void ValidateClassTable(); #endif IsolateGroupSource* source() const { return source_.get(); } std::shared_ptr shareable_source() const { return source_; } void* embedder_data() const { return embedder_data_; } bool initial_spawn_successful() { return initial_spawn_successful_; } void set_initial_spawn_successful() { initial_spawn_successful_ = true; } Heap* heap() const { return heap_.get(); } Roots* roots() const { return roots_.get(); } FfiCallbackMetadata* callback_metadata() const { return callback_metadata_.get(); } BackgroundCompiler* background_compiler() const { #if defined(DART_PRECOMPILED_RUNTIME) return nullptr; #else return background_compiler_.get(); #endif } #if !defined(DART_PRECOMPILED_RUNTIME) intptr_t optimization_counter_threshold() const { if (IsSystemIsolateGroup(this)) { return kDefaultOptimizationCounterThreshold; } return FLAG_optimization_counter_threshold; } #endif #if !defined(PRODUCT) GroupDebugger* debugger() const { return debugger_; } #endif IdleTimeHandler* idle_time_handler() { return &idle_time_handler_; } void RegisterIsolate(Isolate* isolate); void UnregisterIsolate(Isolate* isolate); // Returns `true` if this was the last isolate and the caller is responsible // for deleting the isolate group. bool UnregisterIsolateDecrementCount(); void IncrementIsolateGroupMutatorCount(); void DecrementIsolateGroupMutatorCount(); bool ContainsOnlyOneIsolate(); void RegisterIsolateGroupMutator(Thread* mutator); void UnregisterIsolateGroupMutator(Thread* mutator); Dart_Port interrupt_port() { return interrupt_port_; } ThreadRegistry* thread_registry() const { return thread_registry_.get(); } SafepointHandler* safepoint_handler() { return safepoint_handler_.get(); } void CreateHeap(bool is_service_or_kernel_isolate); void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable); void Shutdown(); #define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit) \ type* Get##variable##Metric() { return &metric_##variable##_; } ISOLATE_GROUP_METRIC_LIST(ISOLATE_METRIC_ACCESSOR); #undef ISOLATE_METRIC_ACCESSOR #if !defined(PRODUCT) void UpdateLastAllocationProfileAccumulatorResetTimestamp() { last_allocationprofile_accumulator_reset_timestamp_ = OS::GetCurrentTimeMillis(); } int64_t last_allocationprofile_accumulator_reset_timestamp() const { return last_allocationprofile_accumulator_reset_timestamp_; } void UpdateLastAllocationProfileGCTimestamp() { last_allocationprofile_gc_timestamp_ = OS::GetCurrentTimeMillis(); } int64_t last_allocationprofile_gc_timestamp() const { return last_allocationprofile_gc_timestamp_; } #endif // !defined(PRODUCT) DispatchTable* dispatch_table() const { return dispatch_table_.get(); } void set_dispatch_table(DispatchTable* table) { dispatch_table_.reset(table); } const uint8_t* dispatch_table_snapshot() const { return dispatch_table_snapshot_; } void set_dispatch_table_snapshot(const uint8_t* snapshot) { dispatch_table_snapshot_ = snapshot; } intptr_t dispatch_table_snapshot_size() const { return dispatch_table_snapshot_size_; } void set_dispatch_table_snapshot_size(intptr_t size) { dispatch_table_snapshot_size_ = size; } ClassTableAllocator* class_table_allocator() { return &class_table_allocator_; } static intptr_t class_table_offset() { COMPILE_ASSERT(sizeof(IsolateGroup::class_table_) == kWordSize); return OFFSET_OF(IsolateGroup, class_table_); } ClassPtr* cached_class_table_table() { return cached_class_table_table_.load(); } void set_cached_class_table_table(ClassPtr* cached_class_table_table) { cached_class_table_table_.store(cached_class_table_table); } static intptr_t cached_class_table_table_offset() { COMPILE_ASSERT(sizeof(IsolateGroup::cached_class_table_table_) == kWordSize); return OFFSET_OF(IsolateGroup, cached_class_table_table_); } void set_object_store(ObjectStore* object_store); static intptr_t object_store_offset() { COMPILE_ASSERT(sizeof(IsolateGroup::object_store_) == kWordSize); return OFFSET_OF(IsolateGroup, object_store_); } void set_obfuscation_map(const char** map) { obfuscation_map_ = map; } const char** obfuscation_map() const { return obfuscation_map_; } bool is_system_isolate_group() const { return is_system_isolate_group_; } bool is_bootstrapping() const { return bootstrapping_; } void set_bootstrapping(bool v) { bootstrapping_ = v; } // IsolateGroup-specific flag handling. static void FlagsInitialize(Dart_IsolateFlags* api_flags); void FlagsCopyTo(Dart_IsolateFlags* api_flags); void FlagsCopyFrom(const Dart_IsolateFlags& api_flags); #if defined(DART_PRECOMPILER) #define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field) #else #define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag) #endif #if !defined(PRODUCT) #define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field) #else #define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag) #endif #define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field) #define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name) \ bool name() const { \ return FLAG_FOR_##when(bitname##Bit::decode(isolate_group_flags_), \ flag_name); \ } BOOL_ISOLATE_GROUP_FLAG_LIST(DECLARE_GETTER) #undef FLAG_FOR_NONPRODUCT #undef FLAG_FOR_PRECOMPILER #undef FLAG_FOR_PRODUCT #undef DECLARE_GETTER bool should_load_vmservice() const { return isolate_group_flags_.Read(); } void set_should_load_vmservice(bool value) { isolate_group_flags_.UpdateBool(value); } void set_asserts(bool value) { isolate_group_flags_.UpdateBool(value); } void set_branch_coverage(bool value) { isolate_group_flags_.UpdateBool(value); } void set_coverage(bool value) { isolate_group_flags_.UpdateBool(value); } void set_use_field_guards(bool value) { isolate_group_flags_.UpdateBool(value); } void set_use_osr(bool value) { isolate_group_flags_.UpdateBool(value); } void set_code_comments(bool value) { isolate_group_flags_.UpdateBool(value); } void set_dwarf_stack_traces(bool value) { isolate_group_flags_.UpdateBool(value); } #if defined(DART_SUPPORT_RELOAD) bool HasAttemptedReload() const { return isolate_group_flags_.Read(); } void SetHasAttemptedReload(bool value) { isolate_group_flags_.UpdateBool(value); } void MaybeIncreaseReloadEveryNStackOverflowChecks(); intptr_t reload_every_n_stack_overflow_checks() const { return reload_every_n_stack_overflow_checks_; } #else bool HasAttemptedReload() const { return false; } #endif // defined(DART_SUPPORT_RELOAD) bool has_seen_oom() const { return isolate_group_flags_.Read(); } void set_has_seen_oom(bool value) { isolate_group_flags_.UpdateBool(value); } // Class table for the program loaded into this isolate group. // // This table is modified by kernel loading. ClassTable* class_table() const { return class_table_; } // Class table used for heap walks by GC visitors. Usually it // is the same table as one in |class_table_|, except when in the // middle of the reload. // // See comment for |ClassTable| class for more details. ClassTable* heap_walk_class_table() const { return heap_walk_class_table_; } void CloneClassTableForReload(); void RestoreOriginalClassTable(); void DropOriginalClassTable(); StoreBuffer* store_buffer() const { return store_buffer_.get(); } ObjectStore* object_store() const { return object_store_.get(); } Mutex* symbols_mutex() { return &symbols_mutex_; } Mutex* type_canonicalization_mutex() { return &type_canonicalization_mutex_; } Mutex* type_arguments_canonicalization_mutex() { return &type_arguments_canonicalization_mutex_; } Mutex* subtype_test_cache_mutex() { return &subtype_test_cache_mutex_; } Mutex* megamorphic_table_mutex() { return &megamorphic_table_mutex_; } Mutex* type_feedback_mutex() { return &type_feedback_mutex_; } Mutex* patchable_call_mutex() { return &patchable_call_mutex_; } Mutex* constant_canonicalization_mutex() { return &constant_canonicalization_mutex_; } Mutex* kernel_data_lib_cache_mutex() { return &kernel_data_lib_cache_mutex_; } Mutex* kernel_data_class_cache_mutex() { return &kernel_data_class_cache_mutex_; } Mutex* kernel_constants_mutex() { return &kernel_constants_mutex_; } #if defined(DART_PRECOMPILED_RUNTIME) Mutex* unlinked_call_map_mutex() { return &unlinked_call_map_mutex_; } #endif #if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER) Mutex* initializer_functions_mutex() { return &initializer_functions_mutex_; } #endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER) SafepointRwLock* shared_field_initializer_rwlock() { return &shared_field_initializer_rwlock_; } SafepointRwLock* program_lock() { return program_lock_.get(); } static inline IsolateGroup* Current() { Thread* thread = Thread::Current(); return thread == nullptr ? nullptr : thread->isolate_group(); } void IncreaseMutatorCount(Thread* thread, bool is_nested_reenter, bool was_stolen); void DecreaseMutatorCount(bool is_nested_exit); NO_SANITIZE_THREAD intptr_t MutatorCount() const { return active_mutators_; } bool HasTagHandler() const { return library_tag_handler() != nullptr; } ObjectPtr CallTagHandler(Dart_LibraryTag tag, const Object& arg1, const Object& arg2); Dart_LibraryTagHandler library_tag_handler() const { return library_tag_handler_; } void set_library_tag_handler(Dart_LibraryTagHandler handler) { library_tag_handler_ = handler; } Dart_DeferredLoadHandler deferred_load_handler() const { return deferred_load_handler_; } void set_deferred_load_handler(Dart_DeferredLoadHandler handler) { deferred_load_handler_ = handler; } // Prepares all threads in an isolate for Garbage Collection. void ReleaseStoreBuffers(); void FlushMarkingStacks(); void EnableIncrementalBarrier(MarkingStack* old_marking_stack, MarkingStack* new_marking_stack, MarkingStack* deferred_marking_stack); void DisableIncrementalBarrier(); MarkingStack* old_marking_stack() const { return old_marking_stack_; } MarkingStack* new_marking_stack() const { return new_marking_stack_; } MarkingStack* deferred_marking_stack() const { return deferred_marking_stack_; } // Runs the given [function] on every isolate in the isolate group. // // During the duration of this function, no new isolates can be added or // removed. // // If [at_safepoint] is `true`, then the entire isolate group must be in a // safepoint. There is therefore no reason to guard against other threads // adding/removing isolates, so no locks will be held. void ForEachIsolate(std::function function, bool at_safepoint = false); void ForEachMutatorAtASafepoint(std::function function); // Ensures mutators are stopped during execution of the provided function. // // If the current thread is the only mutator in the isolate group, // [callable] will be called directly. Otherwise [callable] will be // called inside a [SafepointOperationsScope]. // // During the duration of this function, no new isolates can be added to the // isolate group. void RunWithStoppedMutatorsCallable(Callable* callable); template void RunWithStoppedMutators(T function) { LambdaCallable callable(function); RunWithStoppedMutatorsCallable(&callable); } #ifndef PRODUCT void PrintJSON(JSONStream* stream, bool ref = true); void PrintToJSONObject(JSONObject* jsobj, bool ref); // Creates an object with the total heap memory usage statistics for this // isolate group. void PrintMemoryUsageJSON(JSONStream* stream); #endif #if defined(DART_SUPPORT_RELOAD) // By default the reload context is deleted. This parameter allows // the caller to delete is separately if it is still needed. bool ReloadSources(JSONStream* js, bool force_reload, const char* root_script_url = nullptr, const char* packages_url = nullptr, bool dont_delete_reload_context = false); // If provided, the VM takes ownership of kernel_buffer. bool ReloadKernel(JSONStream* js, bool force_reload, const uint8_t* kernel_buffer = nullptr, intptr_t kernel_buffer_size = 0, bool dont_delete_reload_context = false); void set_last_reload_timestamp(int64_t value) { last_reload_timestamp_ = value; } int64_t last_reload_timestamp() const { return last_reload_timestamp_; } IsolateGroupReloadContext* reload_context() { return group_reload_context_.get(); } ProgramReloadContext* program_reload_context() { return program_reload_context_; } void DeleteReloadContext(); bool CanReload(); #else bool CanReload() { return false; } #endif // defined(DART_SUPPORT_RELOAD) bool IsReloading() const { #if defined(DART_SUPPORT_RELOAD) return group_reload_context_ != nullptr; #else return false; #endif } Become* become() const { return become_; } void set_become(Become* become) { become_ = become; } Dart_Port id() const { return id_; } static void Init(); static void Cleanup(); static void ForEach(std::function action); static void RunWithIsolateGroup(Dart_Port id, std::function action, std::function not_found); // Manage list of existing isolate groups. static void RegisterIsolateGroup(IsolateGroup* isolate_group); static void UnregisterIsolateGroup(IsolateGroup* isolate_group); static bool HasIsolateGroups(); static bool HasApplicationIsolateGroups(); static bool IsSystemIsolateGroup(const IsolateGroup* group); int64_t UptimeMicros() const; ApiState* api_state() const { return api_state_.get(); } // Visit all object pointers. Caller must ensure concurrent sweeper is not // running, and the visitor must not allocate. void VisitObjectPointers(ObjectPointerVisitor* visitor, ValidationPolicy validate_frames); void VisitSharedPointers(ObjectPointerVisitor* visitor); void VisitSharedPointers(ObjectPointerVisitor* visitor, intptr_t slice); void VisitStackPointers(ObjectPointerVisitor* visitor, ValidationPolicy validate_frames); void VisitWeakPersistentHandles(HandleVisitor* visitor); // In precompilation we finalize all regular classes before compiling. bool all_classes_finalized() const { return isolate_group_flags_.Read(); } void set_all_classes_finalized(bool value) { isolate_group_flags_.UpdateBool(value); } bool has_dynamically_extendable_classes() const { return isolate_group_flags_.Read(); } void set_has_dynamically_extendable_classes(bool value) { isolate_group_flags_.UpdateBool(value); } bool remapping_cids() const { return isolate_group_flags_.Read(); } void set_remapping_cids(bool value) { isolate_group_flags_.UpdateBool(value); } void RememberLiveTemporaries(); void DeferredMarkLiveTemporaries(); FieldTable* initial_field_table() const { return initial_field_table_.get(); } std::shared_ptr initial_field_table_shareable() { return initial_field_table_; } void set_initial_field_table(std::shared_ptr field_table) { initial_field_table_ = field_table; } FieldTable* sentinel_field_table() const { return sentinel_field_table_.get(); } std::shared_ptr sentinel_field_table_shareable() { return sentinel_field_table_; } void set_sentinel_field_table(std::shared_ptr field_table) { sentinel_field_table_ = field_table; } FieldTable* shared_initial_field_table() const { return shared_initial_field_table_.get(); } std::shared_ptr shared_initial_field_table_shareable() { return shared_initial_field_table_; } void set_shared_initial_field_table(std::shared_ptr field_table) { shared_initial_field_table_ = field_table; } FieldTable* shared_field_table() const { return shared_field_table_.get(); } std::shared_ptr shared_field_table_shareable() { return shared_field_table_; } void set_shared_field_table(Thread* T, FieldTable* shared_field_table) { shared_field_table_.reset(shared_field_table); T->shared_field_table_values_ = shared_field_table->table(); } MutatorThreadPool* thread_pool() { return thread_pool_.get(); } void RegisterClass(const Class& cls); void RegisterSharedStaticField(const Field& field, const Object& initial_value); void RegisterStaticField(const Field& field, const Object& initial_value); void FreeStaticField(const Field& field); Isolate* EnterTemporaryIsolate(); static void ExitTemporaryIsolate(); Mutex* cache_mutex() { return &cache_mutex_; } void RunWithCachedCatchEntryMoves( const Code& code, intptr_t pc, std::function action); void ClearCatchEntryMovesCacheLocked(); HandlerInfoCache* handler_info_cache() { return &handler_info_cache_; } void SetNativeAssetsCallbacks(NativeAssetsApi* native_assets_api) { native_assets_api_ = *native_assets_api; } NativeAssetsApi* native_assets_api() { return &native_assets_api_; } bool has_attempted_stepping() const { return has_attempted_stepping_.load(std::memory_order_relaxed); } void set_has_attempted_stepping(bool value) { has_attempted_stepping_.store(value, std::memory_order_relaxed); } SafepointRwLock* tag_table_lock() { return &tag_table_lock_; } intptr_t thread_locals_count() { return thread_locals_count_; } intptr_t increment_thread_locals_count() { return thread_locals_count_.fetch_add(1u, std::memory_order_relaxed); } FfiCallbackMetadata::Trampoline CreateIsolateGroupBoundFfiCallback( Zone* zone, const Function& trampoline, const Closure& target); void DeleteFfiCallback(FfiCallbackMetadata::Trampoline callback); private: friend class Dart; // For `object_store_ = ` in Dart::Init friend class Heap; friend class StackFrame; // For `[isolates_].First()`. // For `object_store_shared_untag()`, `class_table_shared_untag()` friend class Isolate; #define ISOLATE_GROUP_FLAG_BITS(V) \ V(AllClassesFinalized) \ V(EnableAsserts) \ V(HasAttemptedReload) \ V(HasSeenOOM) \ V(RemappingCids) \ V(ShouldLoadVmService) \ V(Obfuscate) \ V(UseFieldGuards) \ V(UseOsr) \ V(SnapshotIsDontNeedSafe) \ V(BranchCoverage) \ V(Coverage) \ V(HasDynamicallyExtendableClasses) \ V(DwarfStackTraces) \ V(CodeComments) // Isolate group specific flags. enum FlagBits { #define DECLARE_BIT(Name) k##Name##Bit, ISOLATE_GROUP_FLAG_BITS(DECLARE_BIT) #undef DECLARE_BIT }; #define DECLARE_BITFIELD(Name) \ using Name##Bit = BitField; ISOLATE_GROUP_FLAG_BITS(DECLARE_BITFIELD) #undef DECLARE_BITFIELD void set_heap(std::unique_ptr value); // Accessed from generated code. ClassTable* class_table_; AcqRelAtomic cached_class_table_table_; std::unique_ptr object_store_; // End accessed from generated code. ClassTableAllocator class_table_allocator_; ClassTable* heap_walk_class_table_; const char** obfuscation_map_ = nullptr; void* embedder_data_ = nullptr; IdleTimeHandler idle_time_handler_; std::unique_ptr thread_pool_; std::unique_ptr isolates_lock_; IntrusiveDList isolates_; RelaxedAtomic interrupt_port_ = ILLEGAL_PORT; intptr_t isolate_count_ = 0; IntrusiveDList mutators_; intptr_t group_mutator_count_ = 0; bool initial_spawn_successful_ = false; Dart_LibraryTagHandler library_tag_handler_ = nullptr; Dart_DeferredLoadHandler deferred_load_handler_ = nullptr; int64_t start_time_micros_; bool is_system_isolate_group_; bool bootstrapping_ = true; #if defined(DART_SUPPORT_RELOAD) int64_t last_reload_timestamp_; std::shared_ptr group_reload_context_; // Per-isolate-group copy of FLAG_reload_every. RelaxedAtomic reload_every_n_stack_overflow_checks_; ProgramReloadContext* program_reload_context_ = nullptr; #endif Become* become_ = nullptr; #define ISOLATE_METRIC_VARIABLE(type, variable, name, unit) \ type metric_##variable##_; ISOLATE_GROUP_METRIC_LIST(ISOLATE_METRIC_VARIABLE); #undef ISOLATE_METRIC_VARIABLE #if !defined(PRODUCT) // Timestamps of last operation via service. int64_t last_allocationprofile_accumulator_reset_timestamp_ = 0; int64_t last_allocationprofile_gc_timestamp_ = 0; #endif // !defined(PRODUCT) MarkingStack* old_marking_stack_ = nullptr; MarkingStack* new_marking_stack_ = nullptr; MarkingStack* deferred_marking_stack_ = nullptr; std::shared_ptr source_; std::unique_ptr api_state_; std::unique_ptr thread_registry_; std::unique_ptr safepoint_handler_; static RwLock* isolate_groups_rwlock_; static IntrusiveDList* isolate_groups_; static Random* isolate_group_random_; Dart_Port id_ = 0; std::unique_ptr store_buffer_; std::unique_ptr heap_; std::unique_ptr dispatch_table_; const uint8_t* dispatch_table_snapshot_ = nullptr; intptr_t dispatch_table_snapshot_size_ = 0; std::shared_ptr initial_field_table_; std::shared_ptr sentinel_field_table_; std::shared_ptr shared_initial_field_table_; std::shared_ptr shared_field_table_; AtomicBitFieldContainer isolate_group_flags_; NOT_IN_PRECOMPILED(std::unique_ptr background_compiler_); std::unique_ptr callback_metadata_; Mutex symbols_mutex_; Mutex type_canonicalization_mutex_; Mutex type_arguments_canonicalization_mutex_; Mutex subtype_test_cache_mutex_; Mutex megamorphic_table_mutex_; Mutex type_feedback_mutex_; Mutex patchable_call_mutex_; Mutex constant_canonicalization_mutex_; Mutex kernel_data_lib_cache_mutex_; Mutex kernel_data_class_cache_mutex_; Mutex kernel_constants_mutex_; #if defined(DART_PRECOMPILED_RUNTIME) Mutex unlinked_call_map_mutex_; #endif #if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER) Mutex initializer_functions_mutex_; #endif // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_BYTECODE_INTERPRETER) // Ensure exclusive execution of shared field initializers. SafepointRwLock shared_field_initializer_rwlock_; // Ensures synchronized access to classes functions, fields and other // program structure elements to accommodate concurrent modification done // by multiple isolates and background compiler. std::unique_ptr program_lock_; // Allow us to ensure the number of active mutators is limited by a maximum. std::unique_ptr active_mutators_monitor_; intptr_t active_mutators_ = 0; intptr_t waiting_mutators_ = 0; intptr_t max_active_mutators_ = 0; bool has_timeout_waiter_ = false; NOT_IN_PRODUCT(GroupDebugger* debugger_ = nullptr); NativeAssetsApi native_assets_api_; Mutex cache_mutex_; HandlerInfoCache handler_info_cache_; CatchEntryMovesCache catch_entry_moves_cache_; std::atomic has_attempted_stepping_; SafepointRwLock tag_table_lock_; std::atomic thread_locals_count_ = 0; std::unique_ptr roots_; FfiCallbackMetadata::MetadataEntry* ffi_callback_list_head_ = nullptr; }; // When an isolate sends-and-exits this class represent things that it passed // to the beneficiary. class Bequest { public: Bequest(PersistentHandle* handle, Dart_Port beneficiary) : handle_(handle), beneficiary_(beneficiary) {} ~Bequest(); PersistentHandle* handle() { return handle_; } PersistentHandle* TakeHandle() { auto handle = handle_; handle_ = nullptr; return handle; } Dart_Port beneficiary() { return beneficiary_; } private: PersistentHandle* handle_; Dart_Port beneficiary_; }; class Isolate : public IntrusiveDListEntry { public: // Keep both these enums in sync with isolate_patch.dart. // The different Isolate API message types. enum LibMsgId { kPauseMsg = 1, kResumeMsg = 2, kPingMsg = 3, kKillMsg = 4, kAddExitMsg = 5, kDelExitMsg = 6, kAddErrorMsg = 7, kDelErrorMsg = 8, kErrorFatalMsg = 9, // Internal message ids. kInterruptMsg = 10, // Break in the debugger. kInternalKillMsg = 11, // Like kill, but does not run exit listeners, etc. kDrainServiceExtensionsMsg = 12, // Invoke pending service extensions kCheckForReload = 13, // Participate in other isolate group reload. }; // The different Isolate API message priorities for ping and kill messages. enum LibMsgPriority { kImmediateAction = 0, kBeforeNextEventAction = 1, kAsEventAction = 2 }; ~Isolate(); static inline Isolate* Current() { Thread* thread = Thread::Current(); return thread == nullptr ? nullptr : thread->isolate(); } bool IsScheduled() { return scheduled_mutator_thread() != nullptr; } Thread* scheduled_mutator_thread() const { return scheduled_mutator_thread_; } ThreadRegistry* thread_registry() const { return group()->thread_registry(); } SafepointHandler* safepoint_handler() const { return group()->safepoint_handler(); } FieldTable* field_table() const { return field_table_; } void set_field_table(Thread* T, FieldTable* field_table) { delete field_table_; field_table_ = field_table; T->field_table_values_ = field_table->table(); } IsolateObjectStore* isolate_object_store() const { return isolate_object_store_.get(); } Dart_MessageNotifyCallback message_notify_callback() const { return message_notify_callback_.load(std::memory_order_relaxed); } void set_message_notify_callback(Dart_MessageNotifyCallback value) { message_notify_callback_.store(value, std::memory_order_release); is_acquirable_ = false; } void set_on_shutdown_callback(Dart_IsolateShutdownCallback value) { on_shutdown_callback_ = value; } Dart_IsolateShutdownCallback on_shutdown_callback() { return on_shutdown_callback_; } void set_on_cleanup_callback(Dart_IsolateCleanupCallback value) { on_cleanup_callback_ = value; } Dart_IsolateCleanupCallback on_cleanup_callback() { return on_cleanup_callback_; } void bequeath(std::unique_ptr bequest) { bequest_ = std::move(bequest); } IsolateGroupSource* source() const { return isolate_group_->source(); } IsolateGroup* group() const { return isolate_group_; } bool HasPendingMessages(); Thread* mutator_thread() const { return mutator_thread_; } NO_SANITIZE_THREAD Thread* mutator_thread_ignore_race() const { return mutator_thread_; } const char* name() const { return name_; } void set_name(const char* name); int64_t UptimeMicros() const; Dart_Port main_port() const { return main_port_; } void set_main_port(Dart_Port port) { ASSERT(main_port_ == 0); // Only set main port once. main_port_ = port; } void set_pause_capability(uint64_t value) { pause_capability_ = value; } uint64_t pause_capability() const { return pause_capability_; } void set_terminate_capability(uint64_t value) { terminate_capability_ = value; } uint64_t terminate_capability() const { return terminate_capability_; } void SendInternalLibMessage(LibMsgId msg_id, uint64_t capability); static bool SendInternalLibMessage(Dart_Port main_port, LibMsgId msg_id, uint64_t capability); void set_init_callback_data(void* value) { init_callback_data_ = value; } void* init_callback_data() const { return init_callback_data_; } void set_finalizers(const GrowableObjectArray& value); static intptr_t finalizers_offset() { return OFFSET_OF(Isolate, finalizers_); } Dart_EnvironmentCallback environment_callback() const { return environment_callback_; } void set_environment_callback(Dart_EnvironmentCallback value) { environment_callback_ = value; } bool HasDeferredLoadHandler() const { return group()->deferred_load_handler() != nullptr; } ObjectPtr CallDeferredLoadHandler(intptr_t id); void ScheduleInterrupts(uword interrupt_bits); const char* MakeRunnable(); void MakeRunnableLocked(); void Run(); MessageHandler* message_handler() const; bool is_runnable() const { return isolate_flags_.Read(); } void set_is_runnable(bool value) { isolate_flags_.UpdateBool(value); #if !defined(PRODUCT) if (is_runnable()) { set_last_resume_timestamp(); } #endif } #if !defined(PRODUCT) Debugger* debugger() const { return debugger_; } void set_has_resumption_breakpoints(bool value) { has_resumption_breakpoints_ = value; } bool has_resumption_breakpoints() const { return has_resumption_breakpoints_; } static intptr_t has_resumption_breakpoints_offset() { return OFFSET_OF(Isolate, has_resumption_breakpoints_); } bool ResumeRequest() const { return isolate_flags_.Read(); } // Lets the embedder know that a service message resulted in a resume request. void SetResumeRequest() { isolate_flags_.UpdateBool(true); set_last_resume_timestamp(); } void set_last_resume_timestamp() { last_resume_timestamp_ = OS::GetCurrentTimeMillis(); } int64_t last_resume_timestamp() const { return last_resume_timestamp_; } // Returns whether the vm service has requested that the debugger // resume execution. bool GetAndClearResumeRequest() { return isolate_flags_.TryClear(); } #endif #if defined(DART_INCLUDE_PROFILER) // Returns the current SampleBlock used to track CPU profiling samples. SampleBlock* current_sample_block() const { return current_sample_block_; } void set_current_sample_block(SampleBlock* block) { current_sample_block_ = block; } SampleBlock* exchange_current_sample_block(SampleBlock* block) { return current_sample_block_.exchange(block, std::memory_order_acq_rel); } void ProcessFreeSampleBlocks(Thread* thread); // Returns the current SampleBlock used to track Dart allocation samples. SampleBlock* current_allocation_sample_block() const { return current_allocation_sample_block_; } void set_current_allocation_sample_block(SampleBlock* block) { current_allocation_sample_block_ = block; } SampleBlock* exchange_current_allocation_sample_block(SampleBlock* block) { return current_allocation_sample_block_.exchange(block, std::memory_order_acq_rel); } bool TakeHasCompletedBlocks() { return has_completed_blocks_.exchange(0) != 0; } bool TrySetHasCompletedBlocks() { return has_completed_blocks_.exchange(1) == 0; } #endif // Verify that the sender has the capability to pause or terminate the // isolate. bool VerifyPauseCapability(const Object& capability) const; bool VerifyTerminateCapability(const Object& capability) const; // Returns true if the capability was added or removed from this isolate's // list of pause events. bool AddResumeCapability(const Capability& capability); bool RemoveResumeCapability(const Capability& capability); void AddExitListener(const SendPort& listener, const Instance& response); void RemoveExitListener(const SendPort& listener); void NotifyExitListeners(); void AddErrorListener(const SendPort& listener); void RemoveErrorListener(const SendPort& listener); bool NotifyErrorListeners(const char* msg, const char* stacktrace); bool ErrorsFatal() const { return isolate_flags_.Read(); } void SetErrorsFatal(bool value) { isolate_flags_.UpdateBool(value); } Simulator* simulator() const { return simulator_; } void set_simulator(Simulator* value) { simulator_ = value; } void IncrementSpawnCount(); void DecrementSpawnCount(); void WaitForOutstandingSpawns(); bool TryAcquireOwnership(); void ReleaseOwnership(); bool is_permanently_pinned() { return is_permanently_pinned_; } void set_is_permanently_pinned() { is_permanently_pinned_ = true; } void clear_is_permanently_pinned_for_testing_only() { is_permanently_pinned_ = false; } bool is_acquirable() { return is_acquirable_; } void set_is_not_acquirable() { is_acquirable_ = false; } static void SetCreateGroupCallback(Dart_IsolateGroupCreateCallback cb) { create_group_callback_ = cb; } static Dart_IsolateGroupCreateCallback CreateGroupCallback() { return create_group_callback_; } static void SetInitializeCallback_(Dart_InitializeIsolateCallback cb) { initialize_callback_ = cb; } static Dart_InitializeIsolateCallback InitializeCallback() { return initialize_callback_; } static void SetShutdownCallback(Dart_IsolateShutdownCallback cb) { shutdown_callback_ = cb; } static Dart_IsolateShutdownCallback ShutdownCallback() { return shutdown_callback_; } static void SetCleanupCallback(Dart_IsolateCleanupCallback cb) { cleanup_callback_ = cb; } static Dart_IsolateCleanupCallback CleanupCallback() { return cleanup_callback_; } static void SetGroupCleanupCallback(Dart_IsolateGroupCleanupCallback cb) { cleanup_group_callback_ = cb; } static Dart_IsolateGroupCleanupCallback GroupCleanupCallback() { return cleanup_group_callback_; } #if !defined(PRODUCT) // This method first ensures that the default Service ID zone for this isolate // exists, by creating it if necessary, and then adds a new Service ID zone to // `serivce_id_zones_` and returns a reference to that new zone. RingServiceIdZone& AddServiceIdZone( ObjectIdRing::BackingBufferKind backing_buffer_kind, ObjectIdRing::IdPolicy id_assignment_policy, int32_t capacity); void DeleteServiceIdZone(int32_t id); // The default Service ID zone is created lazily; this method returns the // default Service ID zone, creating it if necessary. RingServiceIdZone& EnsureDefaultServiceIdZone(); RingServiceIdZone* GetServiceIdZone(intptr_t zone_id) const; template void ForEachServiceIdZone(F callback) const { if (service_id_zones_ == nullptr) return; auto it = service_id_zones_->GetIterator(); while (auto* pair = it.Next()) { callback(pair->value); } } #endif // !defined(PRODUCT) FfiCallbackMetadata::Trampoline CreateAsyncFfiCallback( Zone* zone, const Function& send_function, Dart_Port send_port); FfiCallbackMetadata::Trampoline CreateIsolateLocalFfiCallback( Zone* zone, const Function& trampoline, const Closure& target, bool keep_isolate_alive); void DeleteFfiCallback(FfiCallbackMetadata::Trampoline callback); void UpdateNativeCallableKeepIsolateAliveCounter(intptr_t delta); bool HasOpenNativeCallables(); bool HasLivePorts(); ReceivePortPtr CreateReceivePort(const String& debug_name); void SetReceivePortKeepAliveState(const ReceivePort& receive_port, bool keep_isolate_alive); void CloseReceivePort(const ReceivePort& receive_port); // Visible for testing. FfiCallbackMetadata::MetadataEntry* ffi_callback_list_head() { return ffi_callback_list_head_; } intptr_t BlockClassFinalization() { ASSERT(defer_finalization_count_ >= 0); return defer_finalization_count_++; } intptr_t UnblockClassFinalization() { ASSERT(defer_finalization_count_ > 0); return defer_finalization_count_--; } bool AllowClassFinalization() { ASSERT(defer_finalization_count_ >= 0); return defer_finalization_count_ == 0; } #ifndef PRODUCT void PrintJSON(JSONStream* stream, bool ref = true); // Creates an object with the total heap memory usage statistics for this // isolate. void PrintMemoryUsageJSON(JSONStream* stream); void PrintPauseEventJSON(JSONStream* stream); #endif #if !defined(PRODUCT) VMTagCounters* vm_tag_counters() { return &vm_tag_counters_; } #endif // !defined(PRODUCT) bool IsPaused() const; #if !defined(PRODUCT) bool should_pause_post_service_request() const { return isolate_flags_.Read(); } void set_should_pause_post_service_request(bool value) { isolate_flags_.UpdateBool(value); } #endif // !defined(PRODUCT) ErrorPtr PausePostRequest(); #if !defined(PRODUCT) #define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit) \ type* Get##variable##Metric() { return &metric_##variable##_; } ISOLATE_METRIC_LIST(ISOLATE_METRIC_ACCESSOR); #undef ISOLATE_METRIC_ACCESSOR #endif // !defined(PRODUCT) static intptr_t IsolateListLength(); // Also sends a paused at exit event over the service protocol. void SetStickyError(ErrorPtr sticky_error); ErrorPtr sticky_error() const { return sticky_error_; } DART_WARN_UNUSED_RESULT ErrorPtr StealStickyError(); #ifndef PRODUCT ErrorPtr InvokePendingServiceExtensionCalls(); void AppendServiceExtensionCall(const Instance& closure, const String& method_name, const Array& parameter_keys, const Array& parameter_values, const Instance& reply_port, const Instance& id); void RegisterServiceExtensionHandler(const String& name, const Instance& closure); InstancePtr LookupServiceExtensionHandler(const String& name); #endif static void VisitIsolates(IsolateVisitor* visitor); #if !defined(PRODUCT) // Handle service messages until we are told to resume execution. void PauseEventHandler(); #endif bool is_service_registered() const { return isolate_flags_.Read(); } void set_is_service_registered(bool value) { isolate_flags_.UpdateBool(value); } // Isolate-specific flag handling. static void FlagsInitialize(Dart_IsolateFlags* api_flags); void FlagsCopyTo(Dart_IsolateFlags* api_flags) const; void FlagsCopyFrom(const Dart_IsolateFlags& api_flags); #if defined(DART_PRECOMPILER) #define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field) #else #define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag) #endif #if !defined(PRODUCT) #define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field) #else #define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag) #endif #define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field) #define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name) \ bool name() const { \ return FLAG_FOR_##when(isolate_flags_.Read(), flag_name); \ } BOOL_ISOLATE_FLAG_LIST(DECLARE_GETTER) #undef FLAG_FOR_NONPRODUCT #undef FLAG_FOR_PRECOMPILER #undef FLAG_FOR_PRODUCT #undef DECLARE_GETTER // Kills all non-system isolates. static void KillAllIsolates(LibMsgId msg_id); // Kills all system isolates, excluding the kernel service and VM service. static void KillAllSystemIsolates(LibMsgId msg_id); static void KillIfExists(Isolate* isolate, LibMsgId msg_id); // Lookup an isolate by its main port and return a copy of its name. Returns // nullptr if not matching isolate is found. static std::unique_ptr LookupIsolateNameByPort(Dart_Port port); static void DisableIsolateCreation(); static void EnableIsolateCreation(); static bool IsolateCreationEnabled(); static bool IsSystemIsolate(const Isolate* isolate) { return IsolateGroup::IsSystemIsolateGroup(isolate->group()); } static bool IsVMInternalIsolate(const Isolate* isolate); void RememberLiveTemporaries(); void DeferredMarkLiveTemporaries(); void init_loaded_prefixes_set_storage(); bool IsPrefixLoaded(const LibraryPrefix& prefix) const; void SetPrefixIsLoaded(const LibraryPrefix& prefix); bool SetOwnerThread(ThreadId expected_old_owner, ThreadId new_owner); // Must be invoked with a valid PortMap::Locker, or while this isolate is the // current isolate (in which case the locker may be null). ThreadId GetOwnerThread(PortMap::Locker* locker); private: friend class Dart; // Init, InitOnce, Shutdown. friend class IsolateKillerVisitor; // Kill(). friend Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* g, const char* n, char** e); Isolate(IsolateGroup* group, const Dart_IsolateFlags& api_flags); static void InitVM(); static Isolate* InitIsolate(const char* name_prefix, IsolateGroup* isolate_group, const Dart_IsolateFlags& api_flags); void FixInitiallyNullFields(); // The isolate_creation_monitor_ should be held when calling Kill(). void KillLocked(LibMsgId msg_id); void Shutdown(); void RunAndCleanupFinalizersOnShutdown(); void LowLevelShutdown(); // Unregister the [isolate] from the thread, remove it from the isolate group, // invoke the cleanup function (if any), delete the isolate and possibly // delete the isolate group (if it's the last isolate in the group). static void LowLevelCleanup(Isolate* isolate); void BuildName(const char* name_prefix); void ProfileIdle(); // Visit all object pointers. Caller must ensure concurrent sweeper is not // running, and the visitor must not allocate. void VisitObjectPointers(ObjectPointerVisitor* visitor, ValidationPolicy validate_frames); void VisitStackPointers(ObjectPointerVisitor* visitor, ValidationPolicy validate_frames); void set_is_system_isolate(bool is_system_isolate) { is_system_isolate_ = is_system_isolate; } #if !defined(PRODUCT) GrowableObjectArrayPtr GetAndClearPendingServiceExtensionCalls(); GrowableObjectArrayPtr pending_service_extension_calls() const { return pending_service_extension_calls_; } void set_pending_service_extension_calls(const GrowableObjectArray& value); GrowableObjectArrayPtr registered_service_extension_handlers() const { return registered_service_extension_handlers_; } void set_registered_service_extension_handlers( const GrowableObjectArray& value); #endif // !defined(PRODUCT) // Accessed from generated code. // ** This block of fields must come first! ** // For AOT cross-compilation, we rely on these members having the same offsets // in SIMARM(IA32) and ARM, and the same offsets in SIMARM64(X64) and ARM64. // We use only word-sized fields to avoid differences in struct packing on the // different architectures. See also CheckOffsets in dart.cc. FieldTable* field_table_ = nullptr; // Used to clear out `UntaggedFinalizerBase::isolate_` pointers on isolate // shutdown to prevent usage of dangling pointers. GrowableObjectArrayPtr finalizers_; bool has_resumption_breakpoints_ = false; // End accessed from generated code. Thread* scheduled_mutator_thread_ = nullptr; // Stores the saved [Thread] object of a mutator. Mutators may retain their // thread even when being descheduled (e.g. due to having an active stack). Thread* mutator_thread_ = nullptr; IsolateGroup* const isolate_group_; std::unique_ptr isolate_object_store_; #define ISOLATE_FLAG_BITS(V) \ V(ErrorsFatal) \ V(IsRunnable) \ V(IsVMIsolate) \ V(IsServiceIsolate) \ V(IsKernelIsolate) \ V(ResumeRequest) \ V(HasAttemptedStepping) \ V(ShouldPausePostServiceRequest) \ V(IsSystemIsolate) \ V(IsServiceRegistered) // Isolate specific flags. enum FlagBits { #define DECLARE_BIT(Name) k##Name##Bit, ISOLATE_FLAG_BITS(DECLARE_BIT) #undef DECLARE_BIT }; #define DECLARE_BITFIELD(Name) \ using Name##Bit = BitField; ISOLATE_FLAG_BITS(DECLARE_BITFIELD) #undef DECLARE_BITFIELD AtomicBitFieldContainer isolate_flags_; // Fields that aren't needed in a product build go here with boolean flags at // the top. #if !defined(PRODUCT) Debugger* debugger_ = nullptr; int64_t last_resume_timestamp_; VMTagCounters vm_tag_counters_; // We use 6 list entries for each pending service extension calls. enum { kPendingHandlerIndex = 0, kPendingMethodNameIndex, kPendingKeysIndex, kPendingValuesIndex, kPendingReplyPortIndex, kPendingIdIndex, kPendingEntrySize }; GrowableObjectArrayPtr pending_service_extension_calls_; // We use 2 list entries for each registered extension handler. enum { kRegisteredNameIndex = 0, kRegisteredHandlerIndex, kRegisteredEntrySize }; GrowableObjectArrayPtr registered_service_extension_handlers_; // Used to wake the isolate when it is in the pause event loop. Monitor* pause_loop_monitor_ = nullptr; // The map of Service ID zones is created lazily. MallocDirectChainedHashMap>* service_id_zones_; // Monotonically increasing counter used to assign unique IDs to non-default // Service ID zones. intptr_t next_service_id_zone_id_; #define ISOLATE_METRIC_VARIABLE(type, variable, name, unit) \ type metric_##variable##_; ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE); #undef ISOLATE_METRIC_VARIABLE #endif // !defined(PRODUCT) #if defined(DART_INCLUDE_PROFILER) // SampleBlock containing CPU profiling samples. RelaxedAtomic current_sample_block_ = nullptr; // SampleBlock containing Dart allocation profiling samples. RelaxedAtomic current_allocation_sample_block_ = nullptr; RelaxedAtomic has_completed_blocks_ = {0}; #endif // All other fields go here. int64_t start_time_micros_; std::atomic message_notify_callback_; Dart_IsolateShutdownCallback on_shutdown_callback_ = nullptr; Dart_IsolateCleanupCallback on_cleanup_callback_ = nullptr; char* name_ = nullptr; Dart_Port main_port_ = 0; uint64_t pause_capability_ = 0; uint64_t terminate_capability_ = 0; void* init_callback_data_ = nullptr; Dart_EnvironmentCallback environment_callback_ = nullptr; Simulator* simulator_ = nullptr; Mutex mutex_; // Protects compiler stats. IsolateMessageHandler* message_handler_ = nullptr; intptr_t defer_finalization_count_ = 0; FfiCallbackMetadata::MetadataEntry* ffi_callback_list_head_ = nullptr; intptr_t ffi_callback_keep_alive_counter_ = 0; RelaxedAtomic owner_thread_ = OSThread::kInvalidThreadId; bool is_permanently_pinned_ = false; bool is_acquirable_ = true; ErrorPtr sticky_error_; std::unique_ptr bequest_; Dart_Port beneficiary_ = 0; // This guards spawn_count_. An isolate cannot complete shutdown and be // destroyed while there are child isolates in the midst of a spawn. Monitor spawn_count_monitor_; intptr_t spawn_count_ = 0; // Signals whether the isolate can receive messages (e.g. KillAllIsolates can // send a kill message). // This is protected by [isolate_creation_monitor_]. bool accepts_messages_ = false; intptr_t wake_pause_event_handler_count_; // The number of open [ReceivePort]s the isolate owns. intptr_t open_ports_ = 0; // The number of open [ReceivePort]s that keep the isolate alive. intptr_t open_ports_keepalive_ = 0; static Dart_IsolateGroupCreateCallback create_group_callback_; static Dart_InitializeIsolateCallback initialize_callback_; static Dart_IsolateShutdownCallback shutdown_callback_; static Dart_IsolateCleanupCallback cleanup_callback_; static Dart_IsolateGroupCleanupCallback cleanup_group_callback_; #if !defined(PRODUCT) static void WakePauseEventHandler(Dart_Isolate isolate); #endif // Manage list of existing isolates. static bool TryMarkIsolateReady(Isolate* isolate); static void UnMarkIsolateReady(Isolate* isolate); static void MaybeNotifyVMShutdown(); bool AcceptsMessagesLocked() { ASSERT(isolate_creation_monitor_->IsOwnedByCurrentThread()); return accepts_messages_; } // This monitor protects [creation_enabled_] and [pending_shutdowns_]. static Monitor* isolate_creation_monitor_; static bool creation_enabled_; static intptr_t pending_shutdowns_; ArrayPtr loaded_prefixes_set_storage_; bool is_system_isolate_ = false; #define REUSABLE_FRIEND_DECLARATION(name) \ friend class Reusable##name##HandleScope; REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION) #undef REUSABLE_FRIEND_DECLARATION friend class Become; // VisitObjectPointers friend class GCCompactor; // VisitObjectPointers friend class GCMarker; // VisitObjectPointers friend class SafepointHandler; friend class ObjectGraph; // VisitObjectPointers friend class HeapSnapshotWriter; // VisitObjectPointers friend class Scavenger; // VisitObjectPointers friend class HeapIterationScope; // VisitObjectPointers friend class ServiceIsolate; friend class Thread; friend class Timeline; friend class IsolateGroup; // reload_context_ DISALLOW_COPY_AND_ASSIGN(Isolate); }; // When we need to execute code in an isolate, we use the // StartIsolateScope. class StartIsolateScope { public: explicit StartIsolateScope(Isolate* new_isolate) : new_isolate_(new_isolate), saved_isolate_(Isolate::Current()) { if (new_isolate_ == nullptr) { ASSERT(Isolate::Current() == nullptr); // Do nothing. return; } if (saved_isolate_ != new_isolate_) { ASSERT(Isolate::Current() == nullptr); Thread::EnterIsolate(new_isolate_); // Ensure this is not a nested 'isolate enter' with prior state. ASSERT(Thread::Current()->top_exit_frame_info() == 0); } } ~StartIsolateScope() { if (new_isolate_ == nullptr) { ASSERT(Isolate::Current() == nullptr); // Do nothing. return; } if (saved_isolate_ != new_isolate_) { ASSERT(saved_isolate_ == nullptr); // ASSERT that we have bottomed out of all Dart invocations. ASSERT(Thread::Current()->top_exit_frame_info() == 0); Thread::ExitIsolate(); } } private: Isolate* new_isolate_; Isolate* saved_isolate_; DISALLOW_COPY_AND_ASSIGN(StartIsolateScope); }; class EnterIsolateGroupScope { public: explicit EnterIsolateGroupScope(IsolateGroup* isolate_group) : isolate_group_(isolate_group) { ASSERT(IsolateGroup::Current() == nullptr); Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask, /*bypass_safepoint=*/false); } ~EnterIsolateGroupScope() { Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false); } private: IsolateGroup* isolate_group_; DISALLOW_COPY_AND_ASSIGN(EnterIsolateGroupScope); }; // Ensure that isolate is not available for the duration of this scope. // // This can be used in code (e.g. GC, Kernel Loader, Compiler) that should not // operate on an individual isolate. class NoActiveIsolateScope : public StackResource { public: explicit NoActiveIsolateScope(bool allow_no_thread = false) : NoActiveIsolateScope(Thread::Current(), allow_no_thread) {} explicit NoActiveIsolateScope(Thread* thread, bool allow_no_thread = false) : StackResource(thread), thread_(thread) { ASSERT(allow_no_thread || thread_ != nullptr); if (thread_ != nullptr) { outer_ = thread_->no_active_isolate_scope_; saved_isolate_ = thread_->isolate_; thread_->no_active_isolate_scope_ = this; thread_->isolate_ = nullptr; } } ~NoActiveIsolateScope() { ASSERT(thread_ == nullptr || thread_->isolate_ == nullptr); ASSERT(thread_ != nullptr || saved_isolate_ == nullptr); if (thread_ != nullptr) { thread_->isolate_ = saved_isolate_; thread_->no_active_isolate_scope_ = outer_; } } private: friend class ActiveIsolateScope; Thread* thread_ = nullptr; Isolate* saved_isolate_ = nullptr; NoActiveIsolateScope* outer_ = nullptr; }; class ActiveIsolateScope : public StackResource { public: explicit ActiveIsolateScope(Thread* thread) : ActiveIsolateScope(thread, thread->no_active_isolate_scope_->saved_isolate_) {} ActiveIsolateScope(Thread* thread, Isolate* isolate) : StackResource(thread), thread_(thread) { RELEASE_ASSERT(thread->isolate() == nullptr); thread_->isolate_ = isolate; } ~ActiveIsolateScope() { ASSERT(thread_->isolate_ != nullptr); thread_->isolate_ = nullptr; } private: Thread* thread_; }; } // namespace dart #endif // RUNTIME_VM_ISOLATE_H_