| // 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 VM_ISOLATE_H_ |
| #define VM_ISOLATE_H_ |
| |
| #include "include/dart_api.h" |
| #include "platform/assert.h" |
| #include "vm/atomic.h" |
| #include "vm/base_isolate.h" |
| #include "vm/class_table.h" |
| #include "vm/handles.h" |
| #include "vm/megamorphic_cache_table.h" |
| #include "vm/metrics.h" |
| #include "vm/random.h" |
| #include "vm/tags.h" |
| #include "vm/thread.h" |
| #include "vm/os_thread.h" |
| #include "vm/timeline.h" |
| #include "vm/timer.h" |
| #include "vm/trace_buffer.h" |
| |
| namespace dart { |
| |
| // Forward declarations. |
| class ApiState; |
| class BackgroundCompiler; |
| class Capability; |
| class CodeIndexTable; |
| class CompilerStats; |
| class Debugger; |
| class DeoptContext; |
| class HandleScope; |
| class HandleVisitor; |
| class Heap; |
| class ICData; |
| class IsolateProfilerData; |
| class IsolateSpawnState; |
| class Log; |
| class MessageHandler; |
| class Mutex; |
| class Object; |
| class ObjectIdRing; |
| class ObjectPointerVisitor; |
| class ObjectStore; |
| class RawInstance; |
| class RawArray; |
| class RawContext; |
| class RawDouble; |
| class RawGrowableObjectArray; |
| class RawMint; |
| class RawObject; |
| class RawInteger; |
| class RawError; |
| class RawFloat32x4; |
| class RawInt32x4; |
| class RawUserTag; |
| class SampleBuffer; |
| class SendPort; |
| 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; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(IsolateVisitor); |
| }; |
| |
| |
| class Isolate : public BaseIsolate { |
| 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. |
| kVMRestartMsg = 12, // Sent to isolates when vm is restarting. |
| }; |
| // 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 == NULL ? NULL : thread->isolate(); |
| } |
| |
| // Register a newly introduced class. |
| void RegisterClass(const Class& cls); |
| void RegisterClassAt(intptr_t index, const Class& cls); |
| void ValidateClassTable(); |
| |
| // Visit all object pointers. |
| void IterateObjectPointers(ObjectPointerVisitor* visitor, |
| bool visit_prologue_weak_persistent_handles, |
| bool validate_frames); |
| |
| // Visits weak object pointers. |
| void VisitWeakPersistentHandles(HandleVisitor* visitor, |
| bool visit_prologue_weak_persistent_handles); |
| void VisitPrologueWeakPersistentHandles(HandleVisitor* visitor); |
| |
| StoreBuffer* store_buffer() { return store_buffer_; } |
| |
| ThreadRegistry* thread_registry() { return thread_registry_; } |
| |
| ClassTable* class_table() { return &class_table_; } |
| static intptr_t class_table_offset() { |
| return OFFSET_OF(Isolate, class_table_); |
| } |
| |
| Dart_MessageNotifyCallback message_notify_callback() const { |
| return message_notify_callback_; |
| } |
| void set_message_notify_callback(Dart_MessageNotifyCallback value) { |
| message_notify_callback_ = value; |
| } |
| |
| // Limited public access to BaseIsolate::mutator_thread_ for code that |
| // must treat the mutator as the default or a special case. Prefer code |
| // that works uniformly across all threads. |
| bool HasMutatorThread() { |
| return mutator_thread_ != NULL; |
| } |
| bool MutatorThreadIsCurrentThread() { |
| return mutator_thread_ == Thread::Current(); |
| } |
| |
| const char* name() const { return name_; } |
| const char* debugger_name() const { return debugger_name_; } |
| void set_debugger_name(const char* name); |
| |
| int64_t start_time() const { return start_time_; } |
| |
| 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; } |
| static intptr_t heap_offset() { return OFFSET_OF(Isolate, heap_); } |
| |
| ObjectStore* object_store() const { return object_store_; } |
| void set_object_store(ObjectStore* value) { object_store_ = value; } |
| |
| // DEPRECATED: Use Thread's methods instead. During migration, these default |
| // to using the mutator thread (which must also be the current thread). |
| StackResource* top_resource() const { |
| ASSERT(Thread::Current() == mutator_thread_); |
| return mutator_thread_->top_resource(); |
| } |
| void set_top_resource(StackResource* value) { |
| ASSERT(Thread::Current() == mutator_thread_); |
| mutator_thread_->set_top_resource(value); |
| } |
| // DEPRECATED: Use Thread's methods instead. During migration, these default |
| // to using the mutator thread. |
| // NOTE: These are also used by the profiler. |
| uword top_exit_frame_info() const { |
| return mutator_thread_->top_exit_frame_info(); |
| } |
| void set_top_exit_frame_info(uword value) { |
| mutator_thread_->set_top_exit_frame_info(value); |
| } |
| |
| 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; |
| } |
| |
| Dart_LibraryTagHandler library_tag_handler() const { |
| return library_tag_handler_; |
| } |
| void set_library_tag_handler(Dart_LibraryTagHandler value) { |
| library_tag_handler_ = value; |
| } |
| |
| void InitializeStackLimit(); |
| void SetStackLimit(uword value); |
| void SetStackLimitFromStackBase(uword stack_base); |
| void ClearStackLimit(); |
| |
| // Returns the current C++ stack pointer. Equivalent taking the address of a |
| // stack allocated local, but plays well with AddressSanitizer. |
| // TODO(koda): Move to Thread. |
| static uword GetCurrentStackPointer(); |
| |
| void SetupInstructionsSnapshotPage( |
| const uint8_t* instructions_snapshot_buffer); |
| |
| // Returns true if any of the interrupts specified by 'interrupt_bits' are |
| // currently scheduled for this isolate, but leaves them unchanged. |
| // |
| // NOTE: The read uses relaxed memory ordering, i.e., it is atomic and |
| // an interrupt is guaranteed to be observed eventually, but any further |
| // order guarantees must be ensured by other synchronization. See the |
| // tests in isolate_test.cc for example usage. |
| bool HasInterruptsScheduled(uword interrupt_bits) { |
| ASSERT(interrupt_bits == (interrupt_bits & kInterruptsMask)); |
| uword limit = AtomicOperations::LoadRelaxed(&stack_limit_); |
| return (limit != saved_stack_limit_) && |
| (((limit & kInterruptsMask) & interrupt_bits) != 0); |
| } |
| |
| // Access to the current stack limit for generated code. This may be |
| // overwritten with a special value to trigger interrupts. |
| uword stack_limit_address() const { |
| return reinterpret_cast<uword>(&stack_limit_); |
| } |
| static intptr_t stack_limit_offset() { |
| return OFFSET_OF(Isolate, stack_limit_); |
| } |
| |
| // The true stack limit for this isolate. |
| uword saved_stack_limit() const { return saved_stack_limit_; } |
| |
| uword stack_base() const { return stack_base_; } |
| |
| // Stack overflow flags |
| enum { |
| kOsrRequest = 0x1, // Current stack overflow caused by OSR request. |
| }; |
| |
| uword stack_overflow_flags_address() const { |
| return reinterpret_cast<uword>(&stack_overflow_flags_); |
| } |
| |
| int32_t IncrementAndGetStackOverflowCount() { |
| return ++stack_overflow_count_; |
| } |
| |
| // Retrieves and clears the stack overflow flags. These are set by |
| // the generated code before the slow path runtime routine for a |
| // stack overflow is called. |
| uword GetAndClearStackOverflowFlags(); |
| |
| // Retrieve the stack address bounds for profiler. |
| bool GetProfilerStackBounds(uword* lower, uword* upper) const; |
| |
| static uword GetSpecifiedStackSize(); |
| |
| static const intptr_t kStackSizeBuffer = (4 * KB * kWordSize); |
| |
| // Interrupt bits. |
| enum { |
| kVMInterrupt = 0x1, // Internal VM checks: safepoints, store buffers, etc. |
| kMessageInterrupt = 0x2, // An interrupt to process an out of band message. |
| |
| kInterruptsMask = (kVMInterrupt | kMessageInterrupt), |
| }; |
| |
| void ScheduleInterrupts(uword interrupt_bits); |
| RawError* HandleInterrupts(); |
| uword GetAndClearInterrupts(); |
| |
| // Marks all libraries as loaded. |
| void DoneLoading(); |
| |
| bool MakeRunnable(); |
| void Run(); |
| |
| MessageHandler* message_handler() const { return message_handler_; } |
| void set_message_handler(MessageHandler* value) { message_handler_ = value; } |
| |
| bool is_runnable() const { return is_runnable_; } |
| void set_is_runnable(bool value) { is_runnable_ = value; } |
| |
| IsolateSpawnState* spawn_state() const { return spawn_state_; } |
| void set_spawn_state(IsolateSpawnState* value) { spawn_state_ = value; } |
| |
| Mutex* mutex() const { return mutex_; } |
| |
| 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_); |
| } |
| |
| void set_has_compiled_code(bool value) { has_compiled_code_ = value; } |
| bool has_compiled_code() const { return has_compiled_code_; } |
| |
| // TODO(iposva): Evaluate whether two different isolate flag structures are |
| // needed. Currently it serves as a separation between publicly visible flags |
| // and VM internal flags. |
| class Flags : public ValueObject { |
| public: |
| // Construct default flags as specified by the options. |
| Flags(); |
| |
| bool type_checks() const { return type_checks_; } |
| bool asserts() const { return asserts_; } |
| bool error_on_bad_type() const { return error_on_bad_type_; } |
| bool error_on_bad_override() const { return error_on_bad_override_; } |
| |
| void set_checked(bool val) { |
| type_checks_ = val; |
| asserts_ = val; |
| } |
| |
| void CopyFrom(const Flags& orig); |
| void CopyFrom(const Dart_IsolateFlags& api_flags); |
| void CopyTo(Dart_IsolateFlags* api_flags) const; |
| |
| private: |
| bool type_checks_; |
| bool asserts_; |
| bool error_on_bad_type_; |
| bool error_on_bad_override_; |
| |
| friend class Isolate; |
| |
| DISALLOW_ALLOCATION(); |
| DISALLOW_COPY_AND_ASSIGN(Flags); |
| }; |
| |
| const Flags& flags() const { return flags_; } |
| |
| // Set the checks in the compiler to the highest level. Statically and when |
| // executing generated code. Needs to be called before any code has been |
| // compiled. |
| void set_strict_compilation() { |
| ASSERT(!has_compiled_code()); |
| flags_.type_checks_ = true; |
| flags_.asserts_ = true; |
| flags_.error_on_bad_type_ = true; |
| flags_.error_on_bad_override_ = true; |
| } |
| |
| // Requests that the debugger resume execution. |
| void Resume() { |
| resume_request_ = 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() { |
| bool resume_request = resume_request_; |
| resume_request_ = false; |
| 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 errors_fatal_; } |
| void SetErrorsFatal(bool val) { errors_fatal_ = val; } |
| |
| Random* random() { return &random_; } |
| |
| Simulator* simulator() const { return simulator_; } |
| void set_simulator(Simulator* value) { simulator_ = value; } |
| |
| Dart_GcPrologueCallback gc_prologue_callback() const { |
| return gc_prologue_callback_; |
| } |
| |
| void set_gc_prologue_callback(Dart_GcPrologueCallback callback) { |
| gc_prologue_callback_ = callback; |
| } |
| |
| Dart_GcEpilogueCallback gc_epilogue_callback() const { |
| return gc_epilogue_callback_; |
| } |
| |
| void set_gc_epilogue_callback(Dart_GcEpilogueCallback callback) { |
| gc_epilogue_callback_ = callback; |
| } |
| |
| static void SetCreateCallback(Dart_IsolateCreateCallback cb) { |
| create_callback_ = cb; |
| } |
| static Dart_IsolateCreateCallback CreateCallback() { |
| return create_callback_; |
| } |
| |
| static void SetInterruptCallback(Dart_IsolateInterruptCallback cb) { |
| interrupt_callback_ = cb; |
| } |
| static Dart_IsolateInterruptCallback InterruptCallback() { |
| return interrupt_callback_; |
| } |
| |
| static void SetUnhandledExceptionCallback( |
| Dart_IsolateUnhandledExceptionCallback cb) { |
| unhandled_exception_callback_ = cb; |
| } |
| static Dart_IsolateUnhandledExceptionCallback UnhandledExceptionCallback() { |
| return unhandled_exception_callback_; |
| } |
| |
| static void SetShutdownCallback(Dart_IsolateShutdownCallback cb) { |
| shutdown_callback_ = cb; |
| } |
| static Dart_IsolateShutdownCallback ShutdownCallback() { |
| return shutdown_callback_; |
| } |
| |
| static void SetFileCallbacks(Dart_FileOpenCallback file_open, |
| Dart_FileReadCallback file_read, |
| Dart_FileWriteCallback file_write, |
| Dart_FileCloseCallback file_close) { |
| file_open_callback_ = file_open; |
| file_read_callback_ = file_read; |
| file_write_callback_ = file_write; |
| file_close_callback_ = file_close; |
| } |
| |
| static Dart_FileOpenCallback file_open_callback() { |
| return file_open_callback_; |
| } |
| static Dart_FileReadCallback file_read_callback() { |
| return file_read_callback_; |
| } |
| static Dart_FileWriteCallback file_write_callback() { |
| return file_write_callback_; |
| } |
| static Dart_FileCloseCallback file_close_callback() { |
| return file_close_callback_; |
| } |
| |
| static void SetEntropySourceCallback(Dart_EntropySource entropy_source) { |
| entropy_source_callback_ = entropy_source; |
| } |
| static Dart_EntropySource entropy_source_callback() { |
| return entropy_source_callback_; |
| } |
| |
| void set_object_id_ring(ObjectIdRing* ring) { |
| object_id_ring_ = ring; |
| } |
| ObjectIdRing* object_id_ring() { |
| return object_id_ring_; |
| } |
| |
| void set_trace_buffer(TraceBuffer* buffer) { |
| trace_buffer_ = buffer; |
| } |
| TraceBuffer* trace_buffer() { |
| return trace_buffer_; |
| } |
| |
| 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_; |
| } |
| void set_background_compiler(BackgroundCompiler* value) { |
| background_compiler_ = value; |
| } |
| |
| 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_; |
| } |
| |
| 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; |
| } |
| |
| Mutex* profiler_data_mutex() { |
| return &profiler_data_mutex_; |
| } |
| |
| void set_profiler_data(IsolateProfilerData* profiler_data) { |
| profiler_data_ = profiler_data; |
| } |
| |
| IsolateProfilerData* profiler_data() const { |
| return profiler_data_; |
| } |
| |
| void PrintJSON(JSONStream* stream, bool ref = true); |
| |
| CompilerStats* compiler_stats() { |
| return compiler_stats_; |
| } |
| |
| // Returns the number of sampled threads. |
| intptr_t ProfileInterrupt(); |
| |
| VMTagCounters* vm_tag_counters() { |
| return &vm_tag_counters_; |
| } |
| |
| 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_); |
| } |
| |
| #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 |
| |
| #define ISOLATE_TIMELINE_STREAM_ACCESSOR(name, not_used) \ |
| TimelineStream* Get##name##Stream() { return &stream_##name##_; } |
| ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_ACCESSOR) |
| #undef ISOLATE_TIMELINE_STREAM_ACCESSOR |
| |
| 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); |
| |
| RawGrowableObjectArray* collected_closures() const { |
| return collected_closures_; |
| } |
| void set_collected_closures(const GrowableObjectArray& value); |
| |
| RawGrowableObjectArray* background_compilation_queue() const { |
| return background_compilation_queue_; |
| } |
| void set_background_compilation_queue(const GrowableObjectArray& value); |
| |
| Metric* metrics_list_head() { |
| return metrics_list_head_; |
| } |
| |
| void set_metrics_list_head(Metric* metric) { |
| metrics_list_head_ = metric; |
| } |
| |
| RawGrowableObjectArray* deoptimized_code_array() const { |
| return deoptimized_code_array_; |
| } |
| void set_deoptimized_code_array(const GrowableObjectArray& value); |
| void TrackDeoptimizedCode(const Code& code); |
| |
| bool compilation_allowed() const { return compilation_allowed_; } |
| void set_compilation_allowed(bool allowed) { |
| compilation_allowed_ = allowed; |
| } |
| |
| 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); |
| |
| // Handle service messages until we are told to resume execution. |
| void PauseEventHandler(); |
| |
| // 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(); |
| } |
| void set_current_zone(Zone* zone) { |
| ASSERT(Thread::Current() == mutator_thread_); |
| mutator_thread_->set_zone(zone); |
| } |
| |
| bool is_service_isolate() const { return is_service_isolate_; } |
| |
| static void KillAllIsolates(LibMsgId msg_id); |
| static void KillIfExists(Isolate* isolate, LibMsgId msg_id); |
| |
| static void DisableIsolateCreation(); |
| static void EnableIsolateCreation(); |
| |
| private: |
| friend class Dart; // Init, InitOnce, Shutdown. |
| friend class IsolateKillerVisitor; // Kill(). |
| |
| explicit Isolate(const Dart_IsolateFlags& api_flags); |
| |
| static void InitOnce(); |
| static Isolate* Init(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 ReclaimTimelineBlocks(); |
| |
| void BuildName(const char* name_prefix); |
| void PrintInvokedFunctions(); |
| |
| void ProfileIdle(); |
| |
| // Visit all object pointers. Caller must ensure concurrent sweeper is not |
| // running, and the visitor must not allocate. |
| void VisitObjectPointers(ObjectPointerVisitor* visitor, |
| bool visit_prologue_weak_persistent_handles, |
| bool validate_frames); |
| |
| void set_user_tag(uword tag) { |
| user_tag_ = tag; |
| } |
| |
| 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); |
| |
| void ClearMutatorThread() { |
| mutator_thread_ = NULL; |
| } |
| void MakeCurrentThreadMutator(Thread* thread) { |
| ASSERT(thread == Thread::Current()); |
| DEBUG_ASSERT(IsIsolateOf(thread)); |
| mutator_thread_ = thread; |
| } |
| #if defined(DEBUG) |
| bool IsIsolateOf(Thread* thread); |
| #endif // DEBUG |
| |
| // Accessed from generated code: |
| uword stack_limit_; |
| StoreBuffer* store_buffer_; |
| Heap* heap_; |
| uword vm_tag_; |
| uword user_tag_; |
| RawUserTag* current_tag_; |
| RawUserTag* default_tag_; |
| ClassTable class_table_; |
| bool single_step_; |
| |
| ThreadRegistry* thread_registry_; |
| Dart_MessageNotifyCallback message_notify_callback_; |
| char* name_; |
| char* debugger_name_; |
| int64_t start_time_; |
| Dart_Port main_port_; |
| Dart_Port origin_id_; // Isolates created by spawnFunc have some origin id. |
| uint64_t pause_capability_; |
| uint64_t terminate_capability_; |
| bool errors_fatal_; |
| ObjectStore* object_store_; |
| uword top_exit_frame_info_; |
| void* init_callback_data_; |
| Dart_EnvironmentCallback environment_callback_; |
| Dart_LibraryTagHandler library_tag_handler_; |
| ApiState* api_state_; |
| Debugger* debugger_; |
| bool resume_request_; |
| int64_t last_resume_timestamp_; |
| bool has_compiled_code_; // Can check that no compilation occured. |
| Flags flags_; |
| Random random_; |
| Simulator* simulator_; |
| Mutex* mutex_; // protects stack_limit_ and saved_stack_limit_. |
| uword saved_stack_limit_; |
| uword stack_base_; |
| uword stack_overflow_flags_; |
| int32_t stack_overflow_count_; |
| MessageHandler* message_handler_; |
| IsolateSpawnState* spawn_state_; |
| bool is_runnable_; |
| Dart_GcPrologueCallback gc_prologue_callback_; |
| Dart_GcEpilogueCallback gc_epilogue_callback_; |
| intptr_t defer_finalization_count_; |
| DeoptContext* deopt_context_; |
| BackgroundCompiler* background_compiler_; |
| |
| CompilerStats* compiler_stats_; |
| |
| bool is_service_isolate_; |
| |
| // Status support. |
| char* stacktrace_; |
| intptr_t stack_frame_index_; |
| |
| // Timestamps of last operation via service. |
| int64_t last_allocationprofile_accumulator_reset_timestamp_; |
| int64_t last_allocationprofile_gc_timestamp_; |
| |
| // Ring buffer of objects assigned an id. |
| ObjectIdRing* object_id_ring_; |
| |
| // Trace buffer support. |
| TraceBuffer* trace_buffer_; |
| |
| IsolateProfilerData* profiler_data_; |
| Mutex profiler_data_mutex_; |
| |
| VMTagCounters vm_tag_counters_; |
| RawGrowableObjectArray* tag_table_; |
| |
| |
| RawGrowableObjectArray* collected_closures_; |
| RawGrowableObjectArray* deoptimized_code_array_; |
| RawGrowableObjectArray* background_compilation_queue_; |
| |
| // We use 6 list entries for each pending service extension calls. |
| enum { |
| kPendingHandlerIndex = 0, |
| kPendingMethodNameIndex, |
| kPendingKeysIndex, |
| kPendingValuesIndex, |
| kPendingReplyPortIndex, |
| kPendingIdIndex, |
| kPendingEntrySize |
| }; |
| RawGrowableObjectArray* pending_service_extension_calls_; |
| |
| // We use 2 list entries for each registered extension handler. |
| enum { |
| kRegisteredNameIndex = 0, |
| kRegisteredHandlerIndex, |
| kRegisteredEntrySize |
| }; |
| RawGrowableObjectArray* registered_service_extension_handlers_; |
| |
| Metric* metrics_list_head_; |
| |
| bool compilation_allowed_; |
| |
| // Isolate list next pointer. |
| Isolate* next_; |
| |
| // 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##_; |
| ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE); |
| #undef ISOLATE_METRIC_VARIABLE |
| |
| #define ISOLATE_TIMELINE_STREAM_VARIABLE(name, not_used) \ |
| TimelineStream stream_##name##_; |
| ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_VARIABLE) |
| #undef ISOLATE_TIMELINE_STREAM_VARIABLE |
| |
| static Dart_IsolateCreateCallback create_callback_; |
| static Dart_IsolateInterruptCallback interrupt_callback_; |
| static Dart_IsolateUnhandledExceptionCallback unhandled_exception_callback_; |
| static Dart_IsolateShutdownCallback shutdown_callback_; |
| static Dart_FileOpenCallback file_open_callback_; |
| static Dart_FileReadCallback file_read_callback_; |
| static Dart_FileWriteCallback file_write_callback_; |
| static Dart_FileCloseCallback file_close_callback_; |
| static Dart_EntropySource entropy_source_callback_; |
| static Dart_IsolateInterruptCallback vmstats_callback_; |
| |
| 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_; |
| |
| #define REUSABLE_FRIEND_DECLARATION(name) \ |
| friend class Reusable##name##HandleScope; |
| REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION) |
| #undef REUSABLE_FRIEND_DECLARATION |
| |
| friend class GCMarker; // VisitObjectPointers |
| friend class Scavenger; // VisitObjectPointers |
| friend class ServiceIsolate; |
| friend class Thread; |
| friend class Timeline; |
| |
| 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()) { |
| // TODO(koda): Audit users; passing NULL goes against naming of this class. |
| if (new_isolate_ == NULL) { |
| // Do nothing. |
| return; |
| } |
| if (saved_isolate_ != new_isolate_) { |
| ASSERT(Isolate::Current() == NULL); |
| Thread::EnterIsolate(new_isolate_); |
| new_isolate_->SetStackLimitFromStackBase( |
| Isolate::GetCurrentStackPointer()); |
| } |
| } |
| |
| ~StartIsolateScope() { |
| if (new_isolate_ == NULL) { |
| // Do nothing. |
| return; |
| } |
| if (saved_isolate_ != new_isolate_) { |
| new_isolate_->ClearStackLimit(); |
| Thread::ExitIsolate(); |
| if (saved_isolate_ != NULL) { |
| Thread::EnterIsolate(saved_isolate_); |
| } |
| } |
| } |
| |
| private: |
| Isolate* new_isolate_; |
| Isolate* saved_isolate_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StartIsolateScope); |
| }; |
| |
| // When we need to temporarily become another isolate, we use the |
| // SwitchIsolateScope. It is not permitted to run dart code while in |
| // a SwitchIsolateScope. |
| class SwitchIsolateScope { |
| public: |
| explicit SwitchIsolateScope(Isolate* new_isolate) |
| : new_isolate_(new_isolate), |
| saved_isolate_(Isolate::Current()), |
| saved_stack_limit_(saved_isolate_ |
| ? saved_isolate_->saved_stack_limit() : 0) { |
| // TODO(koda): Audit users; why would these two ever be equal? |
| if (saved_isolate_ != new_isolate_) { |
| if (new_isolate_ == NULL) { |
| Thread::ExitIsolate(); |
| } else { |
| Thread::EnterIsolate(new_isolate_); |
| // Don't allow dart code to execute. |
| new_isolate_->SetStackLimit(~static_cast<uword>(0)); |
| } |
| } |
| } |
| |
| ~SwitchIsolateScope() { |
| if (saved_isolate_ != new_isolate_) { |
| if (new_isolate_ != NULL) { |
| Thread::ExitIsolate(); |
| } |
| if (saved_isolate_ != NULL) { |
| Thread::EnterIsolate(saved_isolate_); |
| saved_isolate_->SetStackLimit(saved_stack_limit_); |
| } |
| } |
| } |
| |
| private: |
| Isolate* new_isolate_; |
| Isolate* saved_isolate_; |
| uword saved_stack_limit_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SwitchIsolateScope); |
| }; |
| |
| |
| class IsolateSpawnState { |
| public: |
| IsolateSpawnState(Dart_Port parent_port, |
| const Function& func, |
| const Instance& message, |
| bool paused, |
| bool errorsAreFatal, |
| Dart_Port onExit, |
| Dart_Port onError); |
| IsolateSpawnState(Dart_Port parent_port, |
| const char* script_url, |
| const char* package_root, |
| const char** package_map, |
| const Instance& args, |
| const Instance& message, |
| bool paused, |
| bool errorsAreFatal, |
| Dart_Port onExit, |
| Dart_Port onError); |
| ~IsolateSpawnState(); |
| |
| Isolate* isolate() const { return isolate_; } |
| void set_isolate(Isolate* value) { isolate_ = value; } |
| |
| Dart_Port parent_port() const { return parent_port_; } |
| 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_map() const { return package_map_; } |
| 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_; } |
| Isolate::Flags* isolate_flags() { return &isolate_flags_; } |
| |
| RawObject* ResolveFunction(); |
| RawInstance* BuildArgs(Thread* thread); |
| RawInstance* BuildMessage(Thread* thread); |
| void Cleanup(); |
| |
| private: |
| Isolate* isolate_; |
| Dart_Port parent_port_; |
| Dart_Port on_exit_port_; |
| Dart_Port on_error_port_; |
| const char* script_url_; |
| const char* package_root_; |
| const char** package_map_; |
| const char* library_url_; |
| const char* class_name_; |
| const char* function_name_; |
| uint8_t* serialized_args_; |
| intptr_t serialized_args_len_; |
| uint8_t* serialized_message_; |
| intptr_t serialized_message_len_; |
| Isolate::Flags isolate_flags_; |
| bool paused_; |
| bool errors_are_fatal_; |
| }; |
| |
| } // namespace dart |
| |
| #endif // VM_ISOLATE_H_ |