| // 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_ |
| |
| #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/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; |
| #if !defined(DART_PRECOMPILED_RUNTIME) |
| class Interpreter; |
| #endif |
| 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 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 { |
| public: |
| PendingLazyDeopt(uword fp, uword pc) : fp_(fp), pc_(pc) {} |
| uword fp() { return fp_; } |
| uword pc() { return pc_; } |
| void set_pc(uword pc) { pc_ = pc; } |
| |
| private: |
| uword fp_; |
| uword pc_; |
| }; |
| |
| class IsolateVisitor { |
| public: |
| IsolateVisitor() {} |
| virtual ~IsolateVisitor() {} |
| |
| virtual void VisitIsolate(Isolate* isolate) = 0; |
| |
| protected: |
| // Returns true if |isolate| is the VM or service isolate. |
| bool IsVMInternalIsolate(Isolate* isolate) const; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(IsolateVisitor); |
| }; |
| |
| // Disallow OOB message handling within this scope. |
| class NoOOBMessageScope : public StackResource { |
| public: |
| explicit NoOOBMessageScope(Thread* thread); |
| ~NoOOBMessageScope(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(NoOOBMessageScope); |
| }; |
| |
| // Disallow isolate reload. |
| class NoReloadScope : public StackResource { |
| public: |
| NoReloadScope(Isolate* isolate, Thread* thread); |
| ~NoReloadScope(); |
| |
| private: |
| Isolate* isolate_; |
| DISALLOW_COPY_AND_ASSIGN(NoReloadScope); |
| }; |
| |
| // 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, Dart_IsolateFlags-member-name, command-line-flag-name) |
| // |
| #define ISOLATE_FLAG_LIST(V) \ |
| 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, \ |
| FLAG_experimental_unsafe_mode_use_at_your_own_risk) |
| |
| 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. |
| kLowMemoryMsg = 12, // Run compactor, etc. |
| }; |
| // 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); |
| #if defined(DEBUG) |
| void ValidateClassTable(); |
| #endif |
| |
| void RehashConstants(); |
| #if defined(DEBUG) |
| void ValidateConstants(); |
| #endif |
| |
| // Visits weak object pointers. |
| void VisitWeakPersistentHandles(HandleVisitor* visitor); |
| |
| // Prepares all threads in an isolate for Garbage Collection. |
| void ReleaseStoreBuffers(); |
| void EnableIncrementalBarrier(MarkingStack* marking_stack); |
| void DisableIncrementalBarrier(); |
| |
| StoreBuffer* store_buffer() const { return store_buffer_; } |
| MarkingStack* marking_stack() const { return 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; |
| |
| // Mutator thread is not scheduled if NULL or no heap is attached |
| // to it. The latter only occurs when the mutator thread object |
| // is unscheduled by the isolate (or never scheduled). |
| bool IsMutatorThreadScheduled() { return scheduled_mutator_thread_ != NULL; } |
| |
| 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()) { |
| set_last_resume_timestamp(); |
| } |
| #endif |
| } |
| |
| 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_; |
| } |
| #endif |
| |
| 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_); |
| } |
| |
| #if !defined(PRODUCT) |
| 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_); |
| 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 = ResumeRequestBit::decode(isolate_flags_); |
| isolate_flags_ = ResumeRequestBit::update(false, isolate_flags_); |
| return resume_request; |
| } |
| #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 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_ = |
| 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) |
| |
| 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); |
| #endif |
| |
| #if !defined(PRODUCT) |
| VMTagCounters* vm_tag_counters() { return &vm_tag_counters_; } |
| |
| #if !defined(DART_PRECOMPILED_RUNTIME) |
| 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_; } |
| #else |
| 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##_; } |
| ISOLATE_METRIC_LIST(ISOLATE_METRIC_ACCESSOR); |
| #undef ISOLATE_METRIC_ACCESSOR |
| #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_; } |
| void clear_sticky_error(); |
| |
| 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); |
| #endif |
| |
| static void VisitIsolates(IsolateVisitor* visitor); |
| |
| #if !defined(PRODUCT) |
| // Handle service messages until we are told to resume execution. |
| void PauseEventHandler(); |
| #endif |
| |
| 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_; } |
| |
| // 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 { \ |
| const bool false_by_default = false; \ |
| USE(false_by_default); \ |
| return FLAG_FOR_##when(bitname##Bit::decode(isolate_flags_), flag_name); \ |
| } |
| ISOLATE_FLAG_LIST(DECLARE_GETTER) |
| #undef FLAG_FOR_NONPRODUCT |
| #undef FLAG_FOR_PRECOMPILER |
| #undef FLAG_FOR_PRODUCT |
| #undef DECLARE_GETTER |
| |
| #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(); |
| |
| private: |
| 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 dart.cc. |
| 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_; |
| Heap* heap_; |
| |
| #define ISOLATE_FLAG_BITS(V) \ |
| 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) \ |
| V(UnsafeTrustStrongModeTypes) |
| |
| // Isolate specific flags. |
| enum FlagBits { |
| #define DECLARE_BIT(Name) k##Name##Bit, |
| ISOLATE_FLAG_BITS(DECLARE_BIT) |
| #undef DECLARE_BIT |
| }; |
| |
| #define DECLARE_BITFIELD(Name) \ |
| class Name##Bit : public BitField<uint32_t, bool, k##Name##Bit, 1> {}; |
| ISOLATE_FLAG_BITS(DECLARE_BITFIELD) |
| #undef DECLARE_BITFIELD |
| |
| 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, |
| 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_; |
| |
| // 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 |
| |
| 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(dartbug.com/33973): 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_; |
| |
| static Dart_IsolateCreateCallback create_callback_; |
| static Dart_IsolateShutdownCallback shutdown_callback_; |
| static Dart_IsolateCleanupCallback cleanup_callback_; |
| |
| #if !defined(PRODUCT) |
| static void WakePauseEventHandler(Dart_Isolate isolate); |
| #endif |
| |
| // 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 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 |
| |
| 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) { |
| ASSERT(Isolate::Current() == NULL); |
| // Do nothing. |
| return; |
| } |
| if (saved_isolate_ != new_isolate_) { |
| ASSERT(Isolate::Current() == NULL); |
| Thread::EnterIsolate(new_isolate_); |
| // 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. |
| return; |
| } |
| 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); |
| Thread::ExitIsolate(); |
| } |
| } |
| |
| private: |
| Isolate* new_isolate_; |
| Isolate* saved_isolate_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StartIsolateScope); |
| }; |
| |
| class IsolateSpawnState { |
| public: |
| 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); |
| ~IsolateSpawnState(); |
| |
| 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(); |
| |
| private: |
| 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 |
| |
| #endif // RUNTIME_VM_ISOLATE_H_ |