blob: 40f0c6f0ffa4902df2aa18643ca14fa933fb4404 [file] [log] [blame]
// 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.
#error "Should not include runtime"
#include "include/dart_api.h"
#include "platform/assert.h"
#include "platform/atomic.h"
#include "vm/base_isolate.h"
#include "vm/class_table.h"
#include "vm/exceptions.h"
#include "vm/fixed_cache.h"
#include "vm/growable_array.h"
#include "vm/handles.h"
#include "vm/heap/verifier.h"
#include "vm/megamorphic_cache_table.h"
#include "vm/metrics.h"
#include "vm/os_thread.h"
#include "vm/random.h"
#include "vm/tags.h"
#include "vm/thread.h"
#include "vm/thread_stack_resource.h"
#include "vm/token_position.h"
namespace dart {
// Forward declarations.
class ApiState;
class BackgroundCompiler;
class Capability;
class CodeIndexTable;
class Debugger;
class DeoptContext;
class ExternalTypedData;
class HandleScope;
class HandleVisitor;
class Heap;
class ICData;
class Interpreter;
class IsolateProfilerData;
class IsolateReloadContext;
class IsolateSpawnState;
class Log;
class Message;
class MessageHandler;
class Mutex;
class Object;
class ObjectIdRing;
class ObjectPointerVisitor;
class ObjectStore;
class RawInstance;
class RawArray;
class RawContext;
class RawDouble;
class RawError;
class RawField;
class RawGrowableObjectArray;
class RawMint;
class RawObject;
class RawInteger;
class RawFloat32x4;
class RawInt32x4;
class RawUserTag;
class ReversePcLookupCache;
class SafepointHandler;
class SampleBuffer;
class SendPort;
class SerializedObjectBuffer;
class ServiceIdZone;
class Simulator;
class StackResource;
class StackZone;
class StoreBuffer;
class StubCode;
class ThreadRegistry;
class UserTag;
class PendingLazyDeopt {
PendingLazyDeopt(uword fp, uword pc) : fp_(fp), pc_(pc) {}
uword fp() { return fp_; }
uword pc() { return pc_; }
void set_pc(uword pc) { pc_ = pc; }
uword fp_;
uword pc_;
class IsolateVisitor {
IsolateVisitor() {}
virtual ~IsolateVisitor() {}
virtual void VisitIsolate(Isolate* isolate) = 0;
// Returns true if |isolate| is the VM or service isolate.
bool IsVMInternalIsolate(Isolate* isolate) const;
// Disallow OOB message handling within this scope.
class NoOOBMessageScope : public ThreadStackResource {
explicit NoOOBMessageScope(Thread* thread);
// Disallow isolate reload.
class NoReloadScope : public ThreadStackResource {
NoReloadScope(Isolate* isolate, Thread* thread);
Isolate* isolate_;
// Fixed cache for exception handler lookup.
typedef FixedCache<intptr_t, ExceptionHandlerInfo, 16> HandlerInfoCache;
// Fixed cache for catch entry state lookup.
typedef FixedCache<intptr_t, CatchEntryMovesRefPtr, 16> CatchEntryMovesCache;
// List of Isolate flags with corresponding members of Dart_IsolateFlags and
// corresponding global command line flags.
// V(when, name, bit-name, Dart_IsolateFlags-name, command-line-flag-name)
V(NONPRODUCT, asserts, EnableAsserts, enable_asserts, FLAG_enable_asserts) \
V(NONPRODUCT, use_field_guards, UseFieldGuards, use_field_guards, \
FLAG_use_field_guards) \
V(NONPRODUCT, use_osr, UseOsr, use_osr, FLAG_use_osr) \
V(PRECOMPILER, obfuscate, Obfuscate, obfuscate, false_by_default) \
V(PRODUCT, unsafe_trust_strong_mode_types, UnsafeTrustStrongModeTypes, \
unsafe_trust_strong_mode_types, \
class Isolate : public BaseIsolate {
// 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.
kLowMemoryMsg = 12, // Run compactor, etc.
// The different Isolate API message priorities for ping and kill messages.
enum LibMsgPriority {
kImmediateAction = 0,
kBeforeNextEventAction = 1,
kAsEventAction = 2
static inline Isolate* Current() {
Thread* thread = Thread::Current();
return thread == NULL ? NULL : thread->isolate();
// Register a newly introduced class.
void RegisterClass(const Class& cls);
#if defined(DEBUG)
void ValidateClassTable();
void RehashConstants();
#if defined(DEBUG)
void ValidateConstants();
// Visits weak object pointers.
void VisitWeakPersistentHandles(HandleVisitor* visitor);
// Prepares all threads in an isolate for Garbage Collection.
void ReleaseStoreBuffers();
void EnableIncrementalBarrier(MarkingStack* marking_stack,
MarkingStack* deferred_marking_stack);
void DisableIncrementalBarrier();
StoreBuffer* store_buffer() const { return store_buffer_; }
MarkingStack* marking_stack() const { return marking_stack_; }
MarkingStack* deferred_marking_stack() const {
return deferred_marking_stack_;
ThreadRegistry* thread_registry() const { return thread_registry_; }
SafepointHandler* safepoint_handler() const { return safepoint_handler_; }
ClassTable* class_table() { return &class_table_; }
static intptr_t class_table_offset() {
return OFFSET_OF(Isolate, class_table_);
// Prefers old classes when we are in the middle of a reload.
RawClass* GetClassForHeapWalkAt(intptr_t cid);
intptr_t GetClassSizeForHeapWalkAt(intptr_t cid);
static intptr_t ic_miss_code_offset() {
return OFFSET_OF(Isolate, ic_miss_code_);
Dart_MessageNotifyCallback message_notify_callback() const {
return message_notify_callback_;
void set_message_notify_callback(Dart_MessageNotifyCallback value) {
message_notify_callback_ = value;
bool HasPendingMessages();
Thread* mutator_thread() const;
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;
Dart_Port origin_id() const { return origin_id_; }
void set_origin_id(Dart_Port id) {
ASSERT((id == main_port_ && origin_id_ == 0) || (origin_id_ == main_port_));
origin_id_ = id;
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);
Heap* heap() const { return heap_; }
void set_heap(Heap* value) { heap_ = value; }
ObjectStore* object_store() const { return object_store_; }
void set_object_store(ObjectStore* value) { object_store_ = value; }
static intptr_t object_store_offset() {
return OFFSET_OF(Isolate, object_store_);
ApiState* api_state() const { return api_state_; }
void set_api_state(ApiState* value) { api_state_ = value; }
void set_init_callback_data(void* value) { init_callback_data_ = value; }
void* init_callback_data() const { return init_callback_data_; }
Dart_EnvironmentCallback environment_callback() const {
return environment_callback_;
void set_environment_callback(Dart_EnvironmentCallback value) {
environment_callback_ = value;
bool HasTagHandler() const { return library_tag_handler_ != nullptr; }
RawObject* CallTagHandler(Dart_LibraryTag tag,
const Object& arg1,
const Object& arg2);
void set_library_tag_handler(Dart_LibraryTagHandler value) {
library_tag_handler_ = value;
void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable);
void ScheduleInterrupts(uword interrupt_bits);
// Marks all libraries as loaded.
void DoneLoading();
void DoneFinalizing();
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
// 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 = NULL,
const char* packages_url = NULL,
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 = NULL,
intptr_t kernel_buffer_size = 0,
bool dont_delete_reload_context = false);
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
const char* MakeRunnable();
void Run();
MessageHandler* message_handler() const { return message_handler_; }
void set_message_handler(MessageHandler* value) { message_handler_ = value; }
bool is_runnable() const { return IsRunnableBit::decode(isolate_flags_); }
void set_is_runnable(bool value) {
isolate_flags_ = IsRunnableBit::update(value, isolate_flags_);
#if !defined(PRODUCT)
if (is_runnable()) {
void NotifyIdle(int64_t deadline);
bool compaction_in_progress() const {
return CompactionInProgressBit::decode(isolate_flags_);
void set_compaction_in_progress(bool value) {
isolate_flags_ = CompactionInProgressBit::update(value, isolate_flags_);
IsolateSpawnState* spawn_state() const { return spawn_state_; }
void set_spawn_state(IsolateSpawnState* value) { spawn_state_ = value; }
Mutex* mutex() const { return mutex_; }
Mutex* symbols_mutex() const { return symbols_mutex_; }
Mutex* type_canonicalization_mutex() const {
return type_canonicalization_mutex_;
Mutex* constant_canonicalization_mutex() const {
return constant_canonicalization_mutex_;
Mutex* megamorphic_lookup_mutex() const { return megamorphic_lookup_mutex_; }
Mutex* kernel_data_lib_cache_mutex() const {
return kernel_data_lib_cache_mutex_;
Mutex* kernel_data_class_cache_mutex() const {
return kernel_data_class_cache_mutex_;
// Any access to constants arrays must be locked since mutator and
// background compiler can access the arrays at the same time.
Mutex* kernel_constants_mutex() const { return kernel_constants_mutex_; }
#if !defined(PRODUCT)
Debugger* debugger() const {
ASSERT(debugger_ != NULL);
return debugger_;
void set_single_step(bool value) { single_step_ = value; }
bool single_step() const { return single_step_; }
static intptr_t single_step_offset() {
return OFFSET_OF(Isolate, single_step_);
bool ResumeRequest() const {
return ResumeRequestBit::decode(isolate_flags_);
// Lets the embedder know that a service message resulted in a resume request.
void SetResumeRequest() {
isolate_flags_ = ResumeRequestBit::update(true, isolate_flags_);
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() {
bool resume_request = ResumeRequestBit::decode(isolate_flags_);
isolate_flags_ = ResumeRequestBit::update(false, isolate_flags_);
return resume_request;
// 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 String& msg, const String& stacktrace);
bool ErrorsFatal() const { return ErrorsFatalBit::decode(isolate_flags_); }
void SetErrorsFatal(bool val) {
isolate_flags_ = ErrorsFatalBit::update(val, isolate_flags_);
Random* random() { return &random_; }
Simulator* simulator() const { return simulator_; }
void set_simulator(Simulator* value) { simulator_ = value; }
Monitor* spawn_count_monitor() const { return spawn_count_monitor_; }
intptr_t* spawn_count() { return &spawn_count_; }
void IncrementSpawnCount();
void WaitForOutstandingSpawns();
static void SetCreateCallback(Dart_IsolateCreateCallback cb) {
create_callback_ = cb;
static Dart_IsolateCreateCallback CreateCallback() {
return create_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_;
#if !defined(PRODUCT)
void set_object_id_ring(ObjectIdRing* ring) { object_id_ring_ = ring; }
ObjectIdRing* object_id_ring() { return object_id_ring_; }
#endif // !defined(PRODUCT)
void AddPendingDeopt(uword fp, uword pc);
uword FindPendingDeopt(uword fp) const;
void ClearPendingDeoptsAtOrBelow(uword fp) const;
MallocGrowableArray<PendingLazyDeopt>* pending_deopts() const {
return pending_deopts_;
bool IsDeoptimizing() const { return deopt_context_ != NULL; }
DeoptContext* deopt_context() const { return deopt_context_; }
void set_deopt_context(DeoptContext* value) {
ASSERT(value == NULL || deopt_context_ == NULL);
deopt_context_ = value;
BackgroundCompiler* background_compiler() const {
return background_compiler_;
#if !defined(PRODUCT)
void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
last_allocationprofile_accumulator_reset_timestamp_ =
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)
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);
#if !defined(PRODUCT)
VMTagCounters* vm_tag_counters() { return &vm_tag_counters_; }
bool IsReloading() const { return reload_context_ != NULL; }
IsolateReloadContext* reload_context() { return reload_context_; }
void DeleteReloadContext();
bool HasAttemptedReload() const {
return HasAttemptedReloadBit::decode(isolate_flags_);
void SetHasAttemptedReload(bool value) {
isolate_flags_ = HasAttemptedReloadBit::update(value, isolate_flags_);
bool CanReload() const;
void set_last_reload_timestamp(int64_t value) {
last_reload_timestamp_ = value;
int64_t last_reload_timestamp() const { return last_reload_timestamp_; }
bool IsReloading() const { return false; }
bool HasAttemptedReload() const { return false; }
bool CanReload() const { return false; }
#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // !defined(PRODUCT)
bool IsPaused() const;
#if !defined(PRODUCT)
bool should_pause_post_service_request() const {
return ShouldPausePostServiceRequestBit::decode(isolate_flags_);
void set_should_pause_post_service_request(bool value) {
isolate_flags_ =
ShouldPausePostServiceRequestBit::update(value, isolate_flags_);
#endif // !defined(PRODUCT)
RawError* PausePostRequest();
uword user_tag() const { return user_tag_; }
static intptr_t user_tag_offset() { return OFFSET_OF(Isolate, user_tag_); }
static intptr_t current_tag_offset() {
return OFFSET_OF(Isolate, current_tag_);
static intptr_t default_tag_offset() {
return OFFSET_OF(Isolate, default_tag_);
#if !defined(PRODUCT)
#define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit) \
type* Get##variable##Metric() { return &metric_##variable##_; }
#endif // !defined(PRODUCT)
static intptr_t IsolateListLength();
RawGrowableObjectArray* tag_table() const { return tag_table_; }
void set_tag_table(const GrowableObjectArray& value);
RawUserTag* current_tag() const { return current_tag_; }
void set_current_tag(const UserTag& tag);
RawUserTag* default_tag() const { return default_tag_; }
void set_default_tag(const UserTag& tag);
void set_ic_miss_code(const Code& code);
#if !defined(PRODUCT)
Metric* metrics_list_head() { return metrics_list_head_; }
void set_metrics_list_head(Metric* metric) { metrics_list_head_ = metric; }
#endif // !defined(PRODUCT)
RawGrowableObjectArray* deoptimized_code_array() const {
return deoptimized_code_array_;
void set_deoptimized_code_array(const GrowableObjectArray& value);
void TrackDeoptimizedCode(const Code& code);
// Also sends a paused at exit event over the service protocol.
void SetStickyError(RawError* sticky_error);
RawError* sticky_error() const { return sticky_error_; }
DART_WARN_UNUSED_RESULT RawError* StealStickyError();
void RetainKernelBlob(const ExternalTypedData& kernel_blob);
bool compilation_allowed() const {
return CompilationAllowedBit::decode(isolate_flags_);
void set_compilation_allowed(bool allowed) {
isolate_flags_ = CompilationAllowedBit::update(allowed, isolate_flags_);
// In precompilation we finalize all regular classes before compiling.
bool all_classes_finalized() const {
return AllClassesFinalizedBit::decode(isolate_flags_);
void set_all_classes_finalized(bool value) {
isolate_flags_ = AllClassesFinalizedBit::update(value, isolate_flags_);
bool remapping_cids() const {
return RemappingCidsBit::decode(isolate_flags_);
void set_remapping_cids(bool value) {
isolate_flags_ = RemappingCidsBit::update(value, isolate_flags_);
static const intptr_t kInvalidGen = 0;
void IncrLoadingInvalidationGen() {
AtomicOperations::IncrementBy(&loading_invalidation_gen_, 1);
if (loading_invalidation_gen_ == kInvalidGen) {
AtomicOperations::IncrementBy(&loading_invalidation_gen_, 1);
intptr_t loading_invalidation_gen() {
return AtomicOperations::LoadRelaxed(&loading_invalidation_gen_);
// Used by background compiler which field became boxed and must trigger
// deoptimization in the mutator thread.
void AddDeoptimizingBoxedField(const Field& field);
// Returns Field::null() if none available in the list.
RawField* GetDeoptimizingBoxedField();
#ifndef PRODUCT
RawObject* 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);
RawInstance* LookupServiceExtensionHandler(const String& name);
static void VisitIsolates(IsolateVisitor* visitor);
#if !defined(PRODUCT)
// Handle service messages until we are told to resume execution.
void PauseEventHandler();
void AddClosureFunction(const Function& function) const;
RawFunction* LookupClosureFunction(const Function& parent,
TokenPosition token_pos) const;
intptr_t FindClosureIndex(const Function& needle) const;
RawFunction* ClosureFunctionFromIndex(intptr_t idx) const;
bool is_service_isolate() const {
return IsServiceIsolateBit::decode(isolate_flags_);
void set_is_service_isolate(bool value) {
isolate_flags_ = IsServiceIsolateBit::update(value, isolate_flags_);
bool is_kernel_isolate() const {
return IsKernelIsolateBit::decode(isolate_flags_);
void set_is_kernel_isolate(bool value) {
isolate_flags_ = IsKernelIsolateBit::update(value, isolate_flags_);
bool can_use_strong_mode_types() const {
return FLAG_use_strong_mode_types && !unsafe_trust_strong_mode_types();
bool should_load_vmservice() const {
return ShouldLoadVmServiceBit::decode(isolate_flags_);
void set_should_load_vmservice(bool value) {
isolate_flags_ = ShouldLoadVmServiceBit::update(value, isolate_flags_);
Dart_QualifiedFunctionName* embedder_entry_points() const {
return embedder_entry_points_;
void set_obfuscation_map(const char** map) { obfuscation_map_ = map; }
const char** obfuscation_map() const { return obfuscation_map_; }
// Returns the pc -> code lookup cache object for this isolate.
ReversePcLookupCache* reverse_pc_lookup_cache() const {
return reverse_pc_lookup_cache_;
// Sets the pc -> code lookup cache object for this isolate.
void set_reverse_pc_lookup_cache(ReversePcLookupCache* table) {
ASSERT(reverse_pc_lookup_cache_ == nullptr);
reverse_pc_lookup_cache_ = table;
// 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);
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field)
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag)
#if !defined(PRODUCT)
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field)
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag)
#define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field)
#define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name) \
bool name() const { \
const bool false_by_default = false; \
USE(false_by_default); \
return FLAG_FOR_##when(bitname##Bit::decode(isolate_flags_), flag_name); \
#if defined(PRODUCT)
void set_use_osr(bool use_osr) { ASSERT(!use_osr); }
#else // defined(PRODUCT)
void set_use_osr(bool use_osr) {
isolate_flags_ = UseOsrBit::update(use_osr, isolate_flags_);
#endif // defined(PRODUCT)
// Convenience flag tester indicating whether incoming function arguments
// should be type checked.
bool argument_type_checks() const { return should_emit_strong_mode_checks(); }
bool should_emit_strong_mode_checks() const {
return !unsafe_trust_strong_mode_types();
static void KillAllIsolates(LibMsgId msg_id);
static void KillIfExists(Isolate* isolate, LibMsgId msg_id);
static void DisableIsolateCreation();
static void EnableIsolateCreation();
static bool IsolateCreationEnabled();
static bool IsVMInternalIsolate(const Isolate* isolate);
#if !defined(PRODUCT)
intptr_t reload_every_n_stack_overflow_checks() const {
return reload_every_n_stack_overflow_checks_;
#endif // !defined(PRODUCT)
HandlerInfoCache* handler_info_cache() { return &handler_info_cache_; }
CatchEntryMovesCache* catch_entry_moves_cache() {
return &catch_entry_moves_cache_;
void MaybeIncreaseReloadEveryNStackOverflowChecks();
static void NotifyLowMemory();
friend class Dart; // Init, InitOnce, Shutdown.
friend class IsolateKillerVisitor; // Kill().
explicit Isolate(const Dart_IsolateFlags& api_flags);
static void InitVM();
static Isolate* InitIsolate(const char* name_prefix,
const Dart_IsolateFlags& api_flags,
bool is_vm_isolate = false);
// The isolates_list_monitor_ should be held when calling Kill().
void KillLocked(LibMsgId msg_id);
void LowLevelShutdown();
void Shutdown();
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_user_tag(uword tag) { user_tag_ = tag; }
#if !defined(PRODUCT)
RawGrowableObjectArray* GetAndClearPendingServiceExtensionCalls();
RawGrowableObjectArray* pending_service_extension_calls() const {
return pending_service_extension_calls_;
void set_pending_service_extension_calls(const GrowableObjectArray& value);
RawGrowableObjectArray* registered_service_extension_handlers() const {
return registered_service_extension_handlers_;
void set_registered_service_extension_handlers(
const GrowableObjectArray& value);
#endif // !defined(PRODUCT)
Monitor* threads_lock() const;
Thread* ScheduleThread(bool is_mutator, bool bypass_safepoint = false);
void UnscheduleThread(Thread* thread,
bool is_mutator,
bool bypass_safepoint = false);
// DEPRECATED: Use Thread's methods instead. During migration, these default
// to using the mutator thread (which must also be the current thread).
Zone* current_zone() const {
ASSERT(Thread::Current() == mutator_thread());
return mutator_thread()->zone();
// 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
uword user_tag_;
RawUserTag* current_tag_;
RawUserTag* default_tag_;
RawCode* ic_miss_code_;
ObjectStore* object_store_;
ClassTable class_table_;
bool single_step_;
// End accessed from generated code.
StoreBuffer* store_buffer_;
MarkingStack* marking_stack_;
MarkingStack* deferred_marking_stack_;
Heap* heap_;
V(ErrorsFatal) \
V(IsRunnable) \
V(IsServiceIsolate) \
V(IsKernelIsolate) \
V(CompilationAllowed) \
V(AllClassesFinalized) \
V(RemappingCids) \
V(ResumeRequest) \
V(HasAttemptedReload) \
V(ShouldPausePostServiceRequest) \
V(EnableTypeChecks) \
V(EnableAsserts) \
V(ErrorOnBadType) \
V(ErrorOnBadOverride) \
V(UseFieldGuards) \
V(UseOsr) \
V(Obfuscate) \
V(CompactionInProgress) \
V(ShouldLoadVmService) \
// Isolate specific flags.
enum FlagBits {
#define DECLARE_BIT(Name) k##Name##Bit,
#define DECLARE_BITFIELD(Name) \
class Name##Bit : public BitField<uint32_t, bool, k##Name##Bit, 1> {};
uint32_t isolate_flags_;
// Background compilation.
BackgroundCompiler* background_compiler_;
// Fields that aren't needed in a product build go here with boolean flags at
// the top.
#if !defined(PRODUCT)
Debugger* debugger_;
int64_t last_resume_timestamp_;
// Timestamps of last operation via service.
int64_t last_allocationprofile_accumulator_reset_timestamp_;
int64_t last_allocationprofile_gc_timestamp_;
VMTagCounters vm_tag_counters_;
// We use 6 list entries for each pending service extension calls.
enum {
kPendingHandlerIndex = 0,
RawGrowableObjectArray* pending_service_extension_calls_;
// We use 2 list entries for each registered extension handler.
enum {
kRegisteredNameIndex = 0,
RawGrowableObjectArray* registered_service_extension_handlers_;
Metric* metrics_list_head_;
// Used to wake the isolate when it is in the pause event loop.
Monitor* pause_loop_monitor_;
#define ISOLATE_METRIC_VARIABLE(type, variable, name, unit) \
type metric_##variable##_;
intptr_t no_reload_scope_depth_; // we can only reload when this is 0.
// Per-isolate copy of FLAG_reload_every.
intptr_t reload_every_n_stack_overflow_checks_;
IsolateReloadContext* reload_context_;
int64_t last_reload_timestamp_;
// Ring buffer of objects assigned an id.
ObjectIdRing* object_id_ring_;
#endif // !defined(PRODUCT)
// All other fields go here.
int64_t start_time_micros_;
ThreadRegistry* thread_registry_;
SafepointHandler* safepoint_handler_;
Dart_MessageNotifyCallback message_notify_callback_;
char* name_;
Dart_Port main_port_;
Dart_Port origin_id_; // Isolates created by spawnFunc have some origin id.
uint64_t pause_capability_;
uint64_t terminate_capability_;
void* init_callback_data_;
Dart_EnvironmentCallback environment_callback_;
Dart_LibraryTagHandler library_tag_handler_;
ApiState* api_state_;
Random random_;
Simulator* simulator_;
Mutex* mutex_; // Protects compiler stats.
Mutex* symbols_mutex_; // Protects concurrent access to the symbol table.
Mutex* type_canonicalization_mutex_; // Protects type canonicalization.
Mutex* constant_canonicalization_mutex_; // Protects const canonicalization.
Mutex* megamorphic_lookup_mutex_; // Protects megamorphic table lookup.
Mutex* kernel_data_lib_cache_mutex_;
Mutex* kernel_data_class_cache_mutex_;
Mutex* kernel_constants_mutex_;
MessageHandler* message_handler_;
IsolateSpawnState* spawn_state_;
intptr_t defer_finalization_count_;
MallocGrowableArray<PendingLazyDeopt>* pending_deopts_;
DeoptContext* deopt_context_;
RawGrowableObjectArray* tag_table_;
RawGrowableObjectArray* deoptimized_code_array_;
RawError* sticky_error_;
// Issue( We keep a reference to [ExternalTypedData]s with
// finalizers to ensure we keep the hot-reloaded kernel blobs alive.
// -> We should get rid of this field once Issue 33973 is fixed.
RawGrowableObjectArray* reloaded_kernel_blobs_;
// Isolate list next pointer.
Isolate* next_;
// Invalidation generations; used to track events occurring in parallel
// to background compilation. The counters may overflow, which is OK
// since we check for equality to detect if an event occured.
intptr_t loading_invalidation_gen_;
// Protect access to boxed_field_list_.
Mutex* field_list_mutex_;
// List of fields that became boxed and that trigger deoptimization.
RawGrowableObjectArray* boxed_field_list_;
// 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_;
HandlerInfoCache handler_info_cache_;
CatchEntryMovesCache catch_entry_moves_cache_;
Dart_QualifiedFunctionName* embedder_entry_points_;
const char** obfuscation_map_;
ReversePcLookupCache* reverse_pc_lookup_cache_;
static Dart_IsolateCreateCallback create_callback_;
static Dart_IsolateShutdownCallback shutdown_callback_;
static Dart_IsolateCleanupCallback cleanup_callback_;
#if !defined(PRODUCT)
static void WakePauseEventHandler(Dart_Isolate isolate);
// Manage list of existing isolates.
static bool AddIsolateToList(Isolate* isolate);
static void RemoveIsolateFromList(Isolate* isolate);
// This monitor protects isolates_list_head_, and creation_enabled_.
static Monitor* isolates_list_monitor_;
static Isolate* isolates_list_head_;
static bool creation_enabled_;
friend class Reusable##name##HandleScope;
friend class Become; // VisitObjectPointers
friend class GCCompactor; // VisitObjectPointers
friend class GCMarker; // VisitObjectPointers
friend class SafepointHandler;
friend class ObjectGraph; // VisitObjectPointers
friend class Scavenger; // VisitObjectPointers
friend class HeapIterationScope; // VisitObjectPointers
friend class ServiceIsolate;
friend class Thread;
friend class Timeline;
friend class NoReloadScope; // reload_block
// When we need to execute code in an isolate, we use the
// StartIsolateScope.
class StartIsolateScope {
explicit StartIsolateScope(Isolate* new_isolate)
: new_isolate_(new_isolate), saved_isolate_(Isolate::Current()) {
// TODO(koda): Audit users; passing NULL goes against naming of this class.
if (new_isolate_ == NULL) {
ASSERT(Isolate::Current() == NULL);
// Do nothing.
if (saved_isolate_ != new_isolate_) {
ASSERT(Isolate::Current() == NULL);
// Ensure this is not a nested 'isolate enter' with prior state.
ASSERT(Thread::Current()->saved_stack_limit() == 0);
~StartIsolateScope() {
if (new_isolate_ == NULL) {
ASSERT(Isolate::Current() == NULL);
// Do nothing.
if (saved_isolate_ != new_isolate_) {
ASSERT(saved_isolate_ == NULL);
// ASSERT that we have bottomed out of all Dart invocations.
ASSERT(Thread::Current()->saved_stack_limit() == 0);
Isolate* new_isolate_;
Isolate* saved_isolate_;
class IsolateSpawnState {
IsolateSpawnState(Dart_Port parent_port,
Dart_Port origin_id,
void* init_data,
const char* script_url,
const Function& func,
SerializedObjectBuffer* message_buffer,
Monitor* spawn_count_monitor,
intptr_t* spawn_count,
const char* package_root,
const char* package_config,
bool paused,
bool errorsAreFatal,
Dart_Port onExit,
Dart_Port onError);
IsolateSpawnState(Dart_Port parent_port,
void* init_data,
const char* script_url,
const char* package_root,
const char* package_config,
SerializedObjectBuffer* args_buffer,
SerializedObjectBuffer* message_buffer,
Monitor* spawn_count_monitor,
intptr_t* spawn_count,
bool paused,
bool errorsAreFatal,
Dart_Port onExit,
Dart_Port onError);
Isolate* isolate() const { return isolate_; }
void set_isolate(Isolate* value) { isolate_ = value; }
Dart_Port parent_port() const { return parent_port_; }
Dart_Port origin_id() const { return origin_id_; }
void* init_data() const { return init_data_; }
Dart_Port on_exit_port() const { return on_exit_port_; }
Dart_Port on_error_port() const { return on_error_port_; }
const char* script_url() const { return script_url_; }
const char* package_root() const { return package_root_; }
const char* package_config() const { return package_config_; }
const char* library_url() const { return library_url_; }
const char* class_name() const { return class_name_; }
const char* function_name() const { return function_name_; }
bool is_spawn_uri() const { return library_url_ == NULL; }
bool paused() const { return paused_; }
bool errors_are_fatal() const { return errors_are_fatal_; }
Dart_IsolateFlags* isolate_flags() { return &isolate_flags_; }
RawObject* ResolveFunction();
RawInstance* BuildArgs(Thread* thread);
RawInstance* BuildMessage(Thread* thread);
void DecrementSpawnCount();
Isolate* isolate_;
Dart_Port parent_port_;
Dart_Port origin_id_;
void* init_data_;
Dart_Port on_exit_port_;
Dart_Port on_error_port_;
const char* script_url_;
const char* package_root_;
const char* package_config_;
const char* library_url_;
const char* class_name_;
const char* function_name_;
Message* serialized_args_;
Message* serialized_message_;
// This counter tracks the number of outstanding calls to spawn by the parent
// isolate.
Monitor* spawn_count_monitor_;
intptr_t* spawn_count_;
Dart_IsolateFlags isolate_flags_;
bool paused_;
bool errors_are_fatal_;
} // namespace dart