dart-sdk/runtime/vm/isolate.h
Martin Kustermann ef8a308669 [gardening] Make --optimization-counter-threshold= not affect system isolates
We have many tests that explicitly use --optimization-counter-threshold=
flag. We also have a CI builder that uses this flag for all tests.

This is an issue for cases where `kernel-isolate` is not AppJIT'ed,
which is the case for simulators and ia32. Especially in debug builds
this causes a very-very slow time-to main due to JIT'ing the CFE code in
`kernel-isolate` and running flow graph checker etc (in debug mode).

This causes various tests to sporadically hit the timeout limit, become
flaky and require gardening attention.

As workarounds: the actual threshold was modified in tests, status files
were updated to mark tests as Pass,Slow etc.

=> This Cl will make `kernel-isolate` no longer be affected by the
   `--optimization-counter-threshold`
=> This should make the cycle times faster on those modes and avoid
   flaky timeouts that gardeners constantly have to pay attention to.

TEST=ci

Change-Id: Ia58e807b22f69f924315a43c6764427afe398ee6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/266683
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2022-10-31 14:38:44 +00:00

1876 lines
63 KiB
C++

// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_ISOLATE_H_
#define RUNTIME_VM_ISOLATE_H_
#if defined(SHOULD_NOT_INCLUDE_RUNTIME)
#error "Should not include runtime"
#endif
#include <functional>
#include <memory>
#include <utility>
#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/dispatch_table.h"
#include "vm/exceptions.h"
#include "vm/field_table.h"
#include "vm/fixed_cache.h"
#include "vm/growable_array.h"
#include "vm/handles.h"
#include "vm/heap/verifier.h"
#include "vm/intrusive_dlist.h"
#include "vm/megamorphic_cache_table.h"
#include "vm/metrics.h"
#include "vm/os_thread.h"
#include "vm/random.h"
#include "vm/tags.h"
#include "vm/thread.h"
#include "vm/thread_pool.h"
#include "vm/thread_stack_resource.h"
#include "vm/token_position.h"
#include "vm/virtual_memory.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/ffi_callback_trampolines.h"
#endif // !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
// Forward declarations.
class ApiState;
class BackgroundCompiler;
class Become;
class Capability;
class CodeIndexTable;
class Debugger;
class DeoptContext;
class ExternalTypedData;
class GroupDebugger;
class HandleScope;
class HandleVisitor;
class Heap;
class ICData;
class IsolateGroupReloadContext;
class IsolateObjectStore;
class IsolateProfilerData;
class ProgramReloadContext;
class ReloadHandler;
class Log;
class Message;
class MessageHandler;
class MonitorLocker;
class Mutex;
class Object;
class ObjectIdRing;
class ObjectPointerVisitor;
class ObjectStore;
class PersistentHandle;
class RwLock;
class SafepointRwLock;
class SafepointHandler;
class SampleBuffer;
class SampleBlock;
class SampleBlockBuffer;
class SendPort;
class SerializedObjectBuffer;
class ServiceIdZone;
class Simulator;
class StackResource;
class StackZone;
class StoreBuffer;
class StubCode;
class ThreadRegistry;
class UserTag;
class WeakTable;
/*
* Possible values of null safety flag
0 - not specified
1 - weak mode
2 - strong mode)
*/
constexpr int kNullSafetyOptionUnspecified = 0;
constexpr int kNullSafetyOptionWeak = 1;
constexpr int kNullSafetyOptionStrong = 2;
extern int FLAG_sound_null_safety;
class IsolateVisitor {
public:
IsolateVisitor() {}
virtual ~IsolateVisitor() {}
virtual void VisitIsolate(Isolate* isolate) = 0;
protected:
// Returns true if |isolate| is the VM or service isolate.
bool IsSystemIsolate(Isolate* isolate) const;
private:
DISALLOW_COPY_AND_ASSIGN(IsolateVisitor);
};
class Callable : public ValueObject {
public:
Callable() {}
virtual ~Callable() {}
virtual void Call() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Callable);
};
template <typename T>
class LambdaCallable : public Callable {
public:
explicit LambdaCallable(T& lambda) : lambda_(lambda) {}
void Call() { lambda_(); }
private:
T& lambda_;
DISALLOW_COPY_AND_ASSIGN(LambdaCallable);
};
// Fixed cache for exception handler lookup.
typedef FixedCache<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.
#define BOOL_ISOLATE_FLAG_LIST(V) BOOL_ISOLATE_FLAG_LIST_DEFAULT_GETTER(V)
#define BOOL_ISOLATE_GROUP_FLAG_LIST(V) \
BOOL_ISOLATE_GROUP_FLAG_LIST_DEFAULT_GETTER(V) \
BOOL_ISOLATE_GROUP_FLAG_LIST_CUSTOM_GETTER(V)
// List of Isolate flags with default getters.
//
// V(when, name, bit-name, Dart_IsolateFlags-name, command-line-flag-name)
//
#define BOOL_ISOLATE_GROUP_FLAG_LIST_DEFAULT_GETTER(V) \
V(PRECOMPILER, obfuscate, Obfuscate, obfuscate, false) \
V(NONPRODUCT, asserts, EnableAsserts, enable_asserts, FLAG_enable_asserts) \
V(NONPRODUCT, use_field_guards, UseFieldGuards, use_field_guards, \
FLAG_use_field_guards) \
V(PRODUCT, should_load_vmservice_library, ShouldLoadVmService, \
load_vmservice_library, false) \
V(NONPRODUCT, use_osr, UseOsr, use_osr, FLAG_use_osr) \
V(NONPRODUCT, snapshot_is_dontneed_safe, SnapshotIsDontNeedSafe, \
snapshot_is_dontneed_safe, false) \
V(NONPRODUCT, branch_coverage, BranchCoverage, branch_coverage, \
FLAG_branch_coverage)
#define BOOL_ISOLATE_FLAG_LIST_DEFAULT_GETTER(V) \
V(PRODUCT, copy_parent_code, CopyParentCode, copy_parent_code, false) \
V(PRODUCT, is_system_isolate, IsSystemIsolate, is_system_isolate, false)
// List of Isolate flags with custom getters named #name().
//
// V(when, name, bit-name, Dart_IsolateFlags-name, default_value)
//
#define BOOL_ISOLATE_GROUP_FLAG_LIST_CUSTOM_GETTER(V) \
V(PRODUCT, null_safety, NullSafety, null_safety, false)
// Represents the information used for spawning the first isolate within an
// isolate group. All isolates within a group will refer to this
// [IsolateGroupSource].
class IsolateGroupSource {
public:
IsolateGroupSource(const char* script_uri,
const char* name,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size,
Dart_IsolateFlags flags)
: script_uri(script_uri == nullptr ? nullptr : Utils::StrDup(script_uri)),
name(Utils::StrDup(name)),
snapshot_data(snapshot_data),
snapshot_instructions(snapshot_instructions),
kernel_buffer(kernel_buffer),
kernel_buffer_size(kernel_buffer_size),
flags(flags),
script_kernel_buffer(nullptr),
script_kernel_size(-1),
loaded_blobs_(nullptr),
num_blob_loads_(0) {}
~IsolateGroupSource() {
free(script_uri);
free(name);
}
void add_loaded_blob(Zone* zone_,
const ExternalTypedData& external_typed_data);
// The arguments used for spawning in
// `Dart_CreateIsolateGroupFromKernel` / `Dart_CreateIsolate`.
char* script_uri;
char* name;
const uint8_t* snapshot_data;
const uint8_t* snapshot_instructions;
const uint8_t* kernel_buffer;
const intptr_t kernel_buffer_size;
Dart_IsolateFlags flags;
// The kernel buffer used in `Dart_LoadScriptFromKernel`.
const uint8_t* script_kernel_buffer;
intptr_t script_kernel_size;
// List of weak pointers to external typed data for loaded blobs.
ArrayPtr loaded_blobs_;
intptr_t num_blob_loads_;
};
// Tracks idle time and notifies heap when idle time expired.
class IdleTimeHandler : public ValueObject {
public:
IdleTimeHandler() {}
// Initializes the idle time handler with the given [heap], to which
// idle notifications will be sent.
void InitializeWithHeap(Heap* heap);
// Returns whether the caller should check for idle timeouts.
bool ShouldCheckForIdle();
// Declares that the idle time should be reset to now.
void UpdateStartIdleTime();
// Returns whether idle time expired and [NotifyIdle] should be called.
bool ShouldNotifyIdle(int64_t* expiry);
// Notifies the heap that now is a good time to do compactions and indicates
// we have time for the GC until [deadline].
void NotifyIdle(int64_t deadline);
// Calls [NotifyIdle] with the default deadline.
void NotifyIdleUsingDefaultDeadline();
private:
friend class DisableIdleTimerScope;
Mutex mutex_;
Heap* heap_ = nullptr;
intptr_t disabled_counter_ = 0;
int64_t idle_start_time_ = 0;
};
// Disables firing of the idle timer while this object is alive.
class DisableIdleTimerScope : public ValueObject {
public:
explicit DisableIdleTimerScope(IdleTimeHandler* handler);
~DisableIdleTimerScope();
private:
IdleTimeHandler* handler_;
};
class MutatorThreadPool : public ThreadPool {
public:
MutatorThreadPool(IsolateGroup* isolate_group, intptr_t max_pool_size)
: ThreadPool(max_pool_size), isolate_group_(isolate_group) {}
virtual ~MutatorThreadPool() {}
protected:
virtual void OnEnterIdleLocked(MonitorLocker* ml);
private:
void NotifyIdle();
IsolateGroup* isolate_group_ = nullptr;
};
// Represents an isolate group and is shared among all isolates within a group.
class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
public:
IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
void* embedder_data,
ObjectStore* object_store,
Dart_IsolateFlags api_flags);
IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
void* embedder_data,
Dart_IsolateFlags api_flags);
~IsolateGroup();
void RehashConstants();
#if defined(DEBUG)
void ValidateConstants();
void ValidateClassTable();
#endif
IsolateGroupSource* source() const { return source_.get(); }
std::shared_ptr<IsolateGroupSource> shareable_source() const {
return source_;
}
void* embedder_data() const { return embedder_data_; }
bool initial_spawn_successful() { return initial_spawn_successful_; }
void set_initial_spawn_successful() { initial_spawn_successful_ = true; }
Heap* heap() const { return heap_.get(); }
BackgroundCompiler* background_compiler() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return nullptr;
#else
return background_compiler_.get();
#endif
}
#if !defined(DART_PRECOMPILED_RUNTIME)
intptr_t optimization_counter_threshold() const {
if (IsSystemIsolateGroup(this)) {
return kDefaultOptimizationCounterThreshold;
}
return FLAG_optimization_counter_threshold;
}
#endif
#if !defined(PRODUCT)
GroupDebugger* debugger() const { return debugger_; }
#endif
IdleTimeHandler* idle_time_handler() { return &idle_time_handler_; }
// Returns true if this is the first isolate registered.
void RegisterIsolate(Isolate* isolate);
void UnregisterIsolate(Isolate* isolate);
// Returns `true` if this was the last isolate and the caller is responsible
// for deleting the isolate group.
bool UnregisterIsolateDecrementCount();
bool ContainsOnlyOneIsolate();
void RunWithLockedGroup(std::function<void()> fun);
Monitor* threads_lock() const;
ThreadRegistry* thread_registry() const { return thread_registry_.get(); }
SafepointHandler* safepoint_handler() { return safepoint_handler_.get(); }
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
ReloadHandler* reload_handler() { return reload_handler_.get(); }
#endif
void CreateHeap(bool is_vm_isolate, bool is_service_or_kernel_isolate);
void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable);
void Shutdown();
#define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit) \
type* Get##variable##Metric() { return &metric_##variable##_; }
ISOLATE_GROUP_METRIC_LIST(ISOLATE_METRIC_ACCESSOR);
#undef ISOLATE_METRIC_ACCESSOR
#if !defined(PRODUCT)
void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
last_allocationprofile_accumulator_reset_timestamp_ =
OS::GetCurrentTimeMillis();
}
int64_t last_allocationprofile_accumulator_reset_timestamp() const {
return last_allocationprofile_accumulator_reset_timestamp_;
}
void UpdateLastAllocationProfileGCTimestamp() {
last_allocationprofile_gc_timestamp_ = OS::GetCurrentTimeMillis();
}
int64_t last_allocationprofile_gc_timestamp() const {
return last_allocationprofile_gc_timestamp_;
}
#endif // !defined(PRODUCT)
DispatchTable* dispatch_table() const { return dispatch_table_.get(); }
void set_dispatch_table(DispatchTable* table) {
dispatch_table_.reset(table);
}
const uint8_t* dispatch_table_snapshot() const {
return dispatch_table_snapshot_;
}
void set_dispatch_table_snapshot(const uint8_t* snapshot) {
dispatch_table_snapshot_ = snapshot;
}
intptr_t dispatch_table_snapshot_size() const {
return dispatch_table_snapshot_size_;
}
void set_dispatch_table_snapshot_size(intptr_t size) {
dispatch_table_snapshot_size_ = size;
}
ClassTableAllocator* class_table_allocator() {
return &class_table_allocator_;
}
static intptr_t class_table_offset() {
COMPILE_ASSERT(sizeof(IsolateGroup::class_table_) == kWordSize);
return OFFSET_OF(IsolateGroup, class_table_);
}
ClassPtr* cached_class_table_table() {
return cached_class_table_table_.load();
}
void set_cached_class_table_table(ClassPtr* cached_class_table_table) {
cached_class_table_table_.store(cached_class_table_table);
}
static intptr_t cached_class_table_table_offset() {
COMPILE_ASSERT(sizeof(IsolateGroup::cached_class_table_table_) ==
kWordSize);
return OFFSET_OF(IsolateGroup, cached_class_table_table_);
}
void set_object_store(ObjectStore* object_store);
static intptr_t object_store_offset() {
COMPILE_ASSERT(sizeof(IsolateGroup::object_store_) == kWordSize);
return OFFSET_OF(IsolateGroup, object_store_);
}
void set_obfuscation_map(const char** map) { obfuscation_map_ = map; }
const char** obfuscation_map() const { return obfuscation_map_; }
Random* random() { return &random_; }
bool is_system_isolate_group() const { return is_system_isolate_group_; }
// IsolateGroup-specific flag handling.
static void FlagsInitialize(Dart_IsolateFlags* api_flags);
void FlagsCopyTo(Dart_IsolateFlags* api_flags);
void FlagsCopyFrom(const Dart_IsolateFlags& api_flags);
#if defined(DART_PRECOMPILER)
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag)
#endif
#if !defined(PRODUCT)
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag)
#endif
#define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field)
#define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name) \
bool name() const { \
return FLAG_FOR_##when(bitname##Bit::decode(isolate_group_flags_), \
flag_name); \
}
BOOL_ISOLATE_GROUP_FLAG_LIST_DEFAULT_GETTER(DECLARE_GETTER)
#undef FLAG_FOR_NONPRODUCT
#undef FLAG_FOR_PRECOMPILER
#undef FLAG_FOR_PRODUCT
#undef DECLARE_GETTER
bool null_safety_not_set() const {
return !NullSafetySetBit::decode(isolate_group_flags_);
}
bool null_safety() const {
ASSERT(!null_safety_not_set());
return NullSafetyBit::decode(isolate_group_flags_);
}
void set_null_safety(bool null_safety) {
isolate_group_flags_ = NullSafetySetBit::update(true, isolate_group_flags_);
isolate_group_flags_ =
NullSafetyBit::update(null_safety, isolate_group_flags_);
}
bool use_strict_null_safety_checks() const {
return null_safety() || FLAG_strict_null_safety_checks;
}
bool should_load_vmservice() const {
return ShouldLoadVmServiceBit::decode(isolate_group_flags_);
}
void set_should_load_vmservice(bool value) {
isolate_group_flags_ =
ShouldLoadVmServiceBit::update(value, isolate_group_flags_);
}
void set_asserts(bool value) {
isolate_group_flags_ =
EnableAssertsBit::update(value, isolate_group_flags_);
}
void set_branch_coverage(bool value) {
isolate_group_flags_ =
BranchCoverageBit::update(value, isolate_group_flags_);
}
#if !defined(PRODUCT)
#if !defined(DART_PRECOMPILED_RUNTIME)
bool HasAttemptedReload() const {
return HasAttemptedReloadBit::decode(isolate_group_flags_);
}
void SetHasAttemptedReload(bool value) {
isolate_group_flags_ =
HasAttemptedReloadBit::update(value, isolate_group_flags_);
}
void MaybeIncreaseReloadEveryNStackOverflowChecks();
intptr_t reload_every_n_stack_overflow_checks() const {
return reload_every_n_stack_overflow_checks_;
}
#else
bool HasAttemptedReload() const { return false; }
#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // !defined(PRODUCT)
#if defined(PRODUCT)
void set_use_osr(bool use_osr) { ASSERT(!use_osr); }
#else // defined(PRODUCT)
void set_use_osr(bool use_osr) {
isolate_group_flags_ = UseOsrBit::update(use_osr, isolate_group_flags_);
}
#endif // defined(PRODUCT)
// Class table for the program loaded into this isolate group.
//
// This table is modified by kernel loading.
ClassTable* class_table() const {
return class_table_;
}
// Class table used for heap walks by GC visitors. Usually it
// is the same table as one in |class_table_|, except when in the
// middle of the reload.
//
// See comment for |ClassTable| class for more details.
ClassTable* heap_walk_class_table() const {
return heap_walk_class_table_;
}
void CloneClassTableForReload();
void RestoreOriginalClassTable();
void DropOriginalClassTable();
StoreBuffer* store_buffer() const { return store_buffer_.get(); }
ObjectStore* object_store() const { return object_store_.get(); }
Mutex* symbols_mutex() { return &symbols_mutex_; }
Mutex* type_canonicalization_mutex() { return &type_canonicalization_mutex_; }
Mutex* type_arguments_canonicalization_mutex() {
return &type_arguments_canonicalization_mutex_;
}
Mutex* subtype_test_cache_mutex() { return &subtype_test_cache_mutex_; }
Mutex* megamorphic_table_mutex() { return &megamorphic_table_mutex_; }
Mutex* type_feedback_mutex() { return &type_feedback_mutex_; }
Mutex* patchable_call_mutex() { return &patchable_call_mutex_; }
Mutex* constant_canonicalization_mutex() {
return &constant_canonicalization_mutex_;
}
Mutex* kernel_data_lib_cache_mutex() { return &kernel_data_lib_cache_mutex_; }
Mutex* kernel_data_class_cache_mutex() {
return &kernel_data_class_cache_mutex_;
}
Mutex* kernel_constants_mutex() { return &kernel_constants_mutex_; }
#if defined(DART_PRECOMPILED_RUNTIME)
Mutex* unlinked_call_map_mutex() { return &unlinked_call_map_mutex_; }
#endif
#if !defined(DART_PRECOMPILED_RUNTIME)
Mutex* initializer_functions_mutex() { return &initializer_functions_mutex_; }
#endif // !defined(DART_PRECOMPILED_RUNTIME)
SafepointRwLock* program_lock() { return program_lock_.get(); }
static inline IsolateGroup* Current() {
Thread* thread = Thread::Current();
return thread == nullptr ? nullptr : thread->isolate_group();
}
Thread* ScheduleThreadLocked(MonitorLocker* ml,
Thread* existing_mutator_thread,
bool is_vm_isolate,
bool is_mutator,
bool bypass_safepoint = false);
void UnscheduleThreadLocked(MonitorLocker* ml,
Thread* thread,
bool is_mutator,
bool bypass_safepoint = false);
Thread* ScheduleThread(bool bypass_safepoint = false);
void UnscheduleThread(Thread* thread,
bool is_mutator,
bool bypass_safepoint = false);
void IncreaseMutatorCount(Isolate* mutator, bool is_nested_reenter);
void DecreaseMutatorCount(Isolate* mutator, bool is_nested_exit);
intptr_t MutatorCount() const {
MonitorLocker ml(active_mutators_monitor_.get());
return active_mutators_;
}
bool HasTagHandler() const { return library_tag_handler() != nullptr; }
ObjectPtr CallTagHandler(Dart_LibraryTag tag,
const Object& arg1,
const Object& arg2);
Dart_LibraryTagHandler library_tag_handler() const {
return library_tag_handler_;
}
void set_library_tag_handler(Dart_LibraryTagHandler handler) {
library_tag_handler_ = handler;
}
Dart_DeferredLoadHandler deferred_load_handler() const {
return deferred_load_handler_;
}
void set_deferred_load_handler(Dart_DeferredLoadHandler handler) {
deferred_load_handler_ = handler;
}
// Prepares all threads in an isolate for Garbage Collection.
void ReleaseStoreBuffers();
void EnableIncrementalBarrier(MarkingStack* marking_stack,
MarkingStack* deferred_marking_stack);
void DisableIncrementalBarrier();
MarkingStack* marking_stack() const { return marking_stack_; }
MarkingStack* deferred_marking_stack() const {
return deferred_marking_stack_;
}
// Runs the given [function] on every isolate in the isolate group.
//
// During the duration of this function, no new isolates can be added or
// removed.
//
// If [at_safepoint] is `true`, then the entire isolate group must be in a
// safepoint. There is therefore no reason to guard against other threads
// adding/removing isolates, so no locks will be held.
void ForEachIsolate(std::function<void(Isolate* isolate)> function,
bool at_safepoint = false);
Isolate* FirstIsolate() const;
Isolate* FirstIsolateLocked() const;
// Ensures mutators are stopped during execution of the provided function.
//
// If the current thread is the only mutator in the isolate group,
// [single_current_mutator] will be called. Otherwise [otherwise] will be
// called inside a [SafepointOperationsScope] (or
// [ForceGrowthSafepointOperationScope] if [use_force_growth_in_otherwise]
// is set).
//
// During the duration of this function, no new isolates can be added to the
// isolate group.
void RunWithStoppedMutatorsCallable(
Callable* single_current_mutator,
Callable* otherwise,
bool use_force_growth_in_otherwise = false);
template <typename T, typename S>
void RunWithStoppedMutators(T single_current_mutator,
S otherwise,
bool use_force_growth_in_otherwise = false) {
LambdaCallable<T> single_callable(single_current_mutator);
LambdaCallable<S> otherwise_callable(otherwise);
RunWithStoppedMutatorsCallable(&single_callable, &otherwise_callable,
use_force_growth_in_otherwise);
}
template <typename T>
void RunWithStoppedMutators(T function, bool use_force_growth = false) {
LambdaCallable<T> callable(function);
RunWithStoppedMutatorsCallable(&callable, &callable, use_force_growth);
}
#ifndef PRODUCT
void PrintJSON(JSONStream* stream, bool ref = true);
void PrintToJSONObject(JSONObject* jsobj, bool ref);
// Creates an object with the total heap memory usage statistics for this
// isolate group.
void PrintMemoryUsageJSON(JSONStream* stream);
#endif
#if !defined(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 = nullptr,
const char* packages_url = nullptr,
bool dont_delete_reload_context = false);
// If provided, the VM takes ownership of kernel_buffer.
bool ReloadKernel(JSONStream* js,
bool force_reload,
const uint8_t* kernel_buffer = nullptr,
intptr_t kernel_buffer_size = 0,
bool dont_delete_reload_context = false);
void set_last_reload_timestamp(int64_t value) {
last_reload_timestamp_ = value;
}
int64_t last_reload_timestamp() const { return last_reload_timestamp_; }
IsolateGroupReloadContext* reload_context() {
return group_reload_context_.get();
}
ProgramReloadContext* program_reload_context() {
return program_reload_context_;
}
void DeleteReloadContext();
bool CanReload();
#else
bool CanReload() { return false; }
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
bool IsReloading() const {
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
return group_reload_context_ != nullptr;
#else
return false;
#endif
}
Become* become() const { return become_; }
void set_become(Become* become) { become_ = become; }
uint64_t id() const { return id_; }
static void Init();
static void Cleanup();
static void ForEach(std::function<void(IsolateGroup*)> action);
static void RunWithIsolateGroup(uint64_t id,
std::function<void(IsolateGroup*)> action,
std::function<void()> not_found);
// Manage list of existing isolate groups.
static void RegisterIsolateGroup(IsolateGroup* isolate_group);
static void UnregisterIsolateGroup(IsolateGroup* isolate_group);
static bool HasApplicationIsolateGroups();
static bool HasOnlyVMIsolateGroup();
static bool IsSystemIsolateGroup(const IsolateGroup* group);
int64_t UptimeMicros() const;
ApiState* api_state() const { return api_state_.get(); }
// Visit all object pointers. Caller must ensure concurrent sweeper is not
// running, and the visitor must not allocate.
void VisitObjectPointers(ObjectPointerVisitor* visitor,
ValidationPolicy validate_frames);
void VisitSharedPointers(ObjectPointerVisitor* visitor);
void VisitStackPointers(ObjectPointerVisitor* visitor,
ValidationPolicy validate_frames);
void VisitObjectIdRingPointers(ObjectPointerVisitor* visitor);
void VisitWeakPersistentHandles(HandleVisitor* visitor);
bool compaction_in_progress() const {
return CompactionInProgressBit::decode(isolate_group_flags_);
}
void set_compaction_in_progress(bool value) {
isolate_group_flags_ =
CompactionInProgressBit::update(value, isolate_group_flags_);
}
// In precompilation we finalize all regular classes before compiling.
bool all_classes_finalized() const {
return AllClassesFinalizedBit::decode(isolate_group_flags_);
}
void set_all_classes_finalized(bool value) {
isolate_group_flags_ =
AllClassesFinalizedBit::update(value, isolate_group_flags_);
}
bool remapping_cids() const {
return RemappingCidsBit::decode(isolate_group_flags_);
}
void set_remapping_cids(bool value) {
isolate_group_flags_ =
RemappingCidsBit::update(value, isolate_group_flags_);
}
void RememberLiveTemporaries();
void DeferredMarkLiveTemporaries();
ArrayPtr saved_unlinked_calls() const { return saved_unlinked_calls_; }
void set_saved_unlinked_calls(const Array& saved_unlinked_calls);
FieldTable* initial_field_table() const { return initial_field_table_.get(); }
std::shared_ptr<FieldTable> initial_field_table_shareable() {
return initial_field_table_;
}
void set_initial_field_table(std::shared_ptr<FieldTable> field_table) {
initial_field_table_ = field_table;
}
MutatorThreadPool* thread_pool() { return thread_pool_.get(); }
void RegisterClass(const Class& cls);
void RegisterStaticField(const Field& field, const Object& initial_value);
void FreeStaticField(const Field& field);
private:
friend class Dart; // For `object_store_ = ` in Dart::Init
friend class Heap;
friend class StackFrame; // For `[isolates_].First()`.
// For `object_store_shared_untag()`, `class_table_shared_untag()`
friend class Isolate;
#define ISOLATE_GROUP_FLAG_BITS(V) \
V(AllClassesFinalized) \
V(CompactionInProgress) \
V(EnableAsserts) \
V(HasAttemptedReload) \
V(NullSafety) \
V(RemappingCids) \
V(ShouldLoadVmService) \
V(NullSafetySet) \
V(Obfuscate) \
V(UseFieldGuards) \
V(UseOsr) \
V(SnapshotIsDontNeedSafe) \
V(BranchCoverage)
// Isolate group specific flags.
enum FlagBits {
#define DECLARE_BIT(Name) k##Name##Bit,
ISOLATE_GROUP_FLAG_BITS(DECLARE_BIT)
#undef DECLARE_BIT
};
#define DECLARE_BITFIELD(Name) \
class Name##Bit : public BitField<uint32_t, bool, k##Name##Bit, 1> {};
ISOLATE_GROUP_FLAG_BITS(DECLARE_BITFIELD)
#undef DECLARE_BITFIELD
void set_heap(std::unique_ptr<Heap> value);
// Accessed from generated code.
ClassTable* class_table_;
AcqRelAtomic<ClassPtr*> cached_class_table_table_;
std::unique_ptr<ObjectStore> object_store_;
// End accessed from generated code.
ClassTableAllocator class_table_allocator_;
ClassTable* heap_walk_class_table_;
const char** obfuscation_map_ = nullptr;
bool is_vm_isolate_heap_ = false;
void* embedder_data_ = nullptr;
IdleTimeHandler idle_time_handler_;
std::unique_ptr<MutatorThreadPool> thread_pool_;
std::unique_ptr<SafepointRwLock> isolates_lock_;
IntrusiveDList<Isolate> isolates_;
intptr_t isolate_count_ = 0;
bool initial_spawn_successful_ = false;
Dart_LibraryTagHandler library_tag_handler_ = nullptr;
Dart_DeferredLoadHandler deferred_load_handler_ = nullptr;
int64_t start_time_micros_;
bool is_system_isolate_group_;
Random random_;
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
int64_t last_reload_timestamp_;
std::shared_ptr<IsolateGroupReloadContext> group_reload_context_;
// Per-isolate-group copy of FLAG_reload_every.
RelaxedAtomic<intptr_t> reload_every_n_stack_overflow_checks_;
ProgramReloadContext* program_reload_context_ = nullptr;
#endif
Become* become_ = nullptr;
#define ISOLATE_METRIC_VARIABLE(type, variable, name, unit) \
type metric_##variable##_;
ISOLATE_GROUP_METRIC_LIST(ISOLATE_METRIC_VARIABLE);
#undef ISOLATE_METRIC_VARIABLE
#if !defined(PRODUCT)
// Timestamps of last operation via service.
int64_t last_allocationprofile_accumulator_reset_timestamp_ = 0;
int64_t last_allocationprofile_gc_timestamp_ = 0;
#endif // !defined(PRODUCT)
MarkingStack* marking_stack_ = nullptr;
MarkingStack* deferred_marking_stack_ = nullptr;
std::shared_ptr<IsolateGroupSource> source_;
std::unique_ptr<ApiState> api_state_;
std::unique_ptr<ThreadRegistry> thread_registry_;
std::unique_ptr<SafepointHandler> safepoint_handler_;
NOT_IN_PRODUCT(
NOT_IN_PRECOMPILED(std::unique_ptr<ReloadHandler> reload_handler_));
static RwLock* isolate_groups_rwlock_;
static IntrusiveDList<IsolateGroup>* isolate_groups_;
static Random* isolate_group_random_;
uint64_t id_ = 0;
std::unique_ptr<StoreBuffer> store_buffer_;
std::unique_ptr<Heap> heap_;
std::unique_ptr<DispatchTable> dispatch_table_;
const uint8_t* dispatch_table_snapshot_ = nullptr;
intptr_t dispatch_table_snapshot_size_ = 0;
ArrayPtr saved_unlinked_calls_;
std::shared_ptr<FieldTable> initial_field_table_;
uint32_t isolate_group_flags_ = 0;
NOT_IN_PRECOMPILED(std::unique_ptr<BackgroundCompiler> background_compiler_);
Mutex symbols_mutex_;
Mutex type_canonicalization_mutex_;
Mutex type_arguments_canonicalization_mutex_;
Mutex subtype_test_cache_mutex_;
Mutex megamorphic_table_mutex_;
Mutex type_feedback_mutex_;
Mutex patchable_call_mutex_;
Mutex constant_canonicalization_mutex_;
Mutex kernel_data_lib_cache_mutex_;
Mutex kernel_data_class_cache_mutex_;
Mutex kernel_constants_mutex_;
#if defined(DART_PRECOMPILED_RUNTIME)
Mutex unlinked_call_map_mutex_;
#endif
#if !defined(DART_PRECOMPILED_RUNTIME)
Mutex initializer_functions_mutex_;
#endif // !defined(DART_PRECOMPILED_RUNTIME)
// Protect access to boxed_field_list_.
Mutex field_list_mutex_;
// List of fields that became boxed and that trigger deoptimization.
GrowableObjectArrayPtr boxed_field_list_;
// Ensures synchronized access to classes functions, fields and other
// program structure elements to accommodate concurrent modification done
// by multiple isolates and background compiler.
std::unique_ptr<SafepointRwLock> program_lock_;
// Allow us to ensure the number of active mutators is limited by a maximum.
std::unique_ptr<Monitor> active_mutators_monitor_;
intptr_t active_mutators_ = 0;
intptr_t waiting_mutators_ = 0;
intptr_t max_active_mutators_ = 0;
NOT_IN_PRODUCT(GroupDebugger* debugger_ = nullptr);
};
// When an isolate sends-and-exits this class represent things that it passed
// to the beneficiary.
class Bequest {
public:
Bequest(PersistentHandle* handle, Dart_Port beneficiary)
: handle_(handle), beneficiary_(beneficiary) {}
~Bequest();
PersistentHandle* handle() { return handle_; }
PersistentHandle* TakeHandle() {
auto handle = handle_;
handle_ = nullptr;
return handle;
}
Dart_Port beneficiary() { return beneficiary_; }
private:
PersistentHandle* handle_;
Dart_Port beneficiary_;
};
class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
public:
// Keep both these enums in sync with isolate_patch.dart.
// The different Isolate API message types.
enum LibMsgId {
kPauseMsg = 1,
kResumeMsg = 2,
kPingMsg = 3,
kKillMsg = 4,
kAddExitMsg = 5,
kDelExitMsg = 6,
kAddErrorMsg = 7,
kDelErrorMsg = 8,
kErrorFatalMsg = 9,
// Internal message ids.
kInterruptMsg = 10, // Break in the debugger.
kInternalKillMsg = 11, // Like kill, but does not run exit listeners, etc.
kDrainServiceExtensionsMsg = 12, // Invoke pending service extensions
kCheckForReload = 13, // Participate in other isolate group reload.
};
// The different Isolate API message priorities for ping and kill messages.
enum LibMsgPriority {
kImmediateAction = 0,
kBeforeNextEventAction = 1,
kAsEventAction = 2
};
~Isolate();
static inline Isolate* Current() {
Thread* thread = Thread::Current();
return thread == nullptr ? nullptr : thread->isolate();
}
bool IsScheduled() { return scheduled_mutator_thread() != nullptr; }
Thread* scheduled_mutator_thread() const { return scheduled_mutator_thread_; }
ThreadRegistry* thread_registry() const { return group()->thread_registry(); }
SafepointHandler* safepoint_handler() const {
return group()->safepoint_handler();
}
FieldTable* field_table() const { return field_table_; }
void set_field_table(Thread* T, FieldTable* field_table) {
delete field_table_;
field_table_ = field_table;
T->field_table_values_ = field_table->table();
}
IsolateObjectStore* isolate_object_store() const {
return isolate_object_store_.get();
}
static intptr_t ic_miss_code_offset() {
return OFFSET_OF(Isolate, ic_miss_code_);
}
Dart_MessageNotifyCallback message_notify_callback() const {
return message_notify_callback_.load(std::memory_order_relaxed);
}
void set_message_notify_callback(Dart_MessageNotifyCallback value) {
message_notify_callback_.store(value, std::memory_order_release);
}
void set_on_shutdown_callback(Dart_IsolateShutdownCallback value) {
on_shutdown_callback_ = value;
}
Dart_IsolateShutdownCallback on_shutdown_callback() {
return on_shutdown_callback_;
}
void set_on_cleanup_callback(Dart_IsolateCleanupCallback value) {
on_cleanup_callback_ = value;
}
Dart_IsolateCleanupCallback on_cleanup_callback() {
return on_cleanup_callback_;
}
void bequeath(std::unique_ptr<Bequest> bequest) {
bequest_ = std::move(bequest);
}
IsolateGroupSource* source() const { return isolate_group_->source(); }
IsolateGroup* group() const { return isolate_group_; }
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();
void set_origin_id(Dart_Port 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);
void set_init_callback_data(void* value) { init_callback_data_ = value; }
void* init_callback_data() const { return init_callback_data_; }
void set_finalizers(const GrowableObjectArray& value);
static intptr_t finalizers_offset() {
return OFFSET_OF(Isolate, finalizers_);
}
#if !defined(DART_PRECOMPILED_RUNTIME)
NativeCallbackTrampolines* native_callback_trampolines() {
return &native_callback_trampolines_;
}
#endif
Dart_EnvironmentCallback environment_callback() const {
return environment_callback_;
}
void set_environment_callback(Dart_EnvironmentCallback value) {
environment_callback_ = value;
}
bool HasDeferredLoadHandler() const {
return group()->deferred_load_handler() != nullptr;
}
ObjectPtr CallDeferredLoadHandler(intptr_t id);
void ScheduleInterrupts(uword interrupt_bits);
const char* MakeRunnable();
void MakeRunnableLocked();
void Run();
MessageHandler* message_handler() const { return message_handler_; }
void set_message_handler(MessageHandler* value) { message_handler_ = value; }
bool is_runnable() const { return LoadIsolateFlagsBit<IsRunnableBit>(); }
void set_is_runnable(bool value) {
UpdateIsolateFlagsBit<IsRunnableBit>(value);
#if !defined(PRODUCT)
if (is_runnable()) {
set_last_resume_timestamp();
}
#endif
}
Mutex* mutex() { return &mutex_; }
#if !defined(PRODUCT)
Debugger* debugger() const { return debugger_; }
// NOTE: this lock should only be acquired within the profiler signal handler.
Mutex* current_sample_block_lock() const {
return const_cast<Mutex*>(&current_sample_block_lock_);
}
// Returns the current SampleBlock used to track CPU profiling samples.
//
// NOTE: current_sample_block_lock() should be held when accessing this
// block.
SampleBlock* current_sample_block() const { return current_sample_block_; }
void set_current_sample_block(SampleBlock* current);
void FreeSampleBlock(SampleBlock* block);
void ProcessFreeSampleBlocks(Thread* thread);
bool should_process_blocks() const {
return free_block_list_.load(std::memory_order_relaxed) != nullptr;
}
std::atomic<SampleBlock*> free_block_list_ = nullptr;
// Returns the current SampleBlock used to track Dart allocation samples.
//
// Allocations should only occur on the mutator thread for an isolate, so we
// don't need to worry about grabbing a lock while accessing this block.
SampleBlock* current_allocation_sample_block() const {
return current_allocation_sample_block_;
}
void set_current_allocation_sample_block(SampleBlock* current);
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_resumption_breakpoints(bool value) {
has_resumption_breakpoints_ = value;
}
bool has_resumption_breakpoints() const {
return has_resumption_breakpoints_;
}
static intptr_t has_resumption_breakpoints_offset() {
return OFFSET_OF(Isolate, has_resumption_breakpoints_);
}
bool ResumeRequest() const { return LoadIsolateFlagsBit<ResumeRequestBit>(); }
// Lets the embedder know that a service message resulted in a resume request.
void SetResumeRequest() {
UpdateIsolateFlagsBit<ResumeRequestBit>(true);
set_last_resume_timestamp();
}
void set_last_resume_timestamp() {
last_resume_timestamp_ = OS::GetCurrentTimeMillis();
}
int64_t last_resume_timestamp() const { return last_resume_timestamp_; }
// Returns whether the vm service has requested that the debugger
// resume execution.
bool GetAndClearResumeRequest() {
return UpdateIsolateFlagsBit<ResumeRequestBit>(false);
}
#endif
// Verify that the sender has the capability to pause or terminate the
// isolate.
bool VerifyPauseCapability(const Object& capability) const;
bool VerifyTerminateCapability(const Object& capability) const;
// Returns true if the capability was added or removed from this isolate's
// list of pause events.
bool AddResumeCapability(const Capability& capability);
bool RemoveResumeCapability(const Capability& capability);
void AddExitListener(const SendPort& listener, const Instance& response);
void RemoveExitListener(const SendPort& listener);
void NotifyExitListeners();
void AddErrorListener(const SendPort& listener);
void RemoveErrorListener(const SendPort& listener);
bool NotifyErrorListeners(const char* msg, const char* stacktrace);
bool ErrorsFatal() const { return LoadIsolateFlagsBit<ErrorsFatalBit>(); }
void SetErrorsFatal(bool value) {
UpdateIsolateFlagsBit<ErrorsFatalBit>(value);
}
Random* random() { return &random_; }
Simulator* simulator() const { return simulator_; }
void set_simulator(Simulator* value) { simulator_ = value; }
void IncrementSpawnCount();
void DecrementSpawnCount();
void WaitForOutstandingSpawns();
static void SetCreateGroupCallback(Dart_IsolateGroupCreateCallback cb) {
create_group_callback_ = cb;
}
static Dart_IsolateGroupCreateCallback CreateGroupCallback() {
return create_group_callback_;
}
static void SetInitializeCallback_(Dart_InitializeIsolateCallback cb) {
initialize_callback_ = cb;
}
static Dart_InitializeIsolateCallback InitializeCallback() {
return initialize_callback_;
}
static void SetShutdownCallback(Dart_IsolateShutdownCallback cb) {
shutdown_callback_ = cb;
}
static Dart_IsolateShutdownCallback ShutdownCallback() {
return shutdown_callback_;
}
static void SetCleanupCallback(Dart_IsolateCleanupCallback cb) {
cleanup_callback_ = cb;
}
static Dart_IsolateCleanupCallback CleanupCallback() {
return cleanup_callback_;
}
static void SetGroupCleanupCallback(Dart_IsolateGroupCleanupCallback cb) {
cleanup_group_callback_ = cb;
}
static Dart_IsolateGroupCleanupCallback GroupCleanupCallback() {
return cleanup_group_callback_;
}
static void SetRegisterKernelBlobCallback(
Dart_RegisterKernelBlobCallback cb) {
register_kernel_blob_callback_ = cb;
}
static Dart_RegisterKernelBlobCallback RegisterKernelBlobCallback() {
return register_kernel_blob_callback_;
}
static void SetUnregisterKernelBlobCallback(
Dart_UnregisterKernelBlobCallback cb) {
unregister_kernel_blob_callback_ = cb;
}
static Dart_UnregisterKernelBlobCallback UnregisterKernelBlobCallback() {
return unregister_kernel_blob_callback_;
}
#if !defined(PRODUCT)
ObjectIdRing* object_id_ring() const { return object_id_ring_; }
ObjectIdRing* EnsureObjectIdRing();
#endif // !defined(PRODUCT)
bool IsDeoptimizing() const { return deopt_context_ != nullptr; }
DeoptContext* deopt_context() const { return deopt_context_; }
void set_deopt_context(DeoptContext* value) {
ASSERT(value == nullptr || deopt_context_ == nullptr);
deopt_context_ = value;
}
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);
#endif
#if !defined(PRODUCT)
VMTagCounters* vm_tag_counters() { return &vm_tag_counters_; }
#endif // !defined(PRODUCT)
bool IsPaused() const;
#if !defined(PRODUCT)
bool should_pause_post_service_request() const {
return LoadIsolateFlagsBit<ShouldPausePostServiceRequestBit>();
}
void set_should_pause_post_service_request(bool value) {
UpdateIsolateFlagsBit<ShouldPausePostServiceRequestBit>(value);
}
#endif // !defined(PRODUCT)
ErrorPtr 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();
GrowableObjectArrayPtr tag_table() const { return tag_table_; }
void set_tag_table(const GrowableObjectArray& value);
UserTagPtr current_tag() const { return current_tag_; }
void set_current_tag(const UserTag& tag);
UserTagPtr default_tag() const { return default_tag_; }
void set_default_tag(const UserTag& tag);
void set_ic_miss_code(const Code& code);
// Also sends a paused at exit event over the service protocol.
void SetStickyError(ErrorPtr sticky_error);
ErrorPtr sticky_error() const { return sticky_error_; }
DART_WARN_UNUSED_RESULT ErrorPtr StealStickyError();
#ifndef PRODUCT
ErrorPtr InvokePendingServiceExtensionCalls();
void AppendServiceExtensionCall(const Instance& closure,
const String& method_name,
const Array& parameter_keys,
const Array& parameter_values,
const Instance& reply_port,
const Instance& id);
void RegisterServiceExtensionHandler(const String& name,
const Instance& closure);
InstancePtr LookupServiceExtensionHandler(const String& name);
#endif
static void VisitIsolates(IsolateVisitor* visitor);
#if !defined(PRODUCT)
// Handle service messages until we are told to resume execution.
void PauseEventHandler();
#endif
bool is_service_isolate() const {
return LoadIsolateFlagsBit<IsServiceIsolateBit>();
}
void set_is_service_isolate(bool value) {
UpdateIsolateFlagsBit<IsServiceIsolateBit>(value);
}
bool is_kernel_isolate() const {
return LoadIsolateFlagsBit<IsKernelIsolateBit>();
}
void set_is_kernel_isolate(bool value) {
UpdateIsolateFlagsBit<IsKernelIsolateBit>(value);
}
bool is_service_registered() const {
return LoadIsolateFlagsBit<IsServiceRegisteredBit>();
}
void set_is_service_registered(bool value) {
UpdateIsolateFlagsBit<IsServiceRegisteredBit>(value);
}
const DispatchTable* dispatch_table() const {
return group()->dispatch_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);
#if defined(DART_PRECOMPILER)
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag)
#endif
#if !defined(PRODUCT)
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag)
#endif
#define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field)
#define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name) \
bool name() const { \
return FLAG_FOR_##when(LoadIsolateFlagsBit<bitname##Bit>(), flag_name); \
}
BOOL_ISOLATE_FLAG_LIST_DEFAULT_GETTER(DECLARE_GETTER)
#undef FLAG_FOR_NONPRODUCT
#undef FLAG_FOR_PRECOMPILER
#undef FLAG_FOR_PRODUCT
#undef DECLARE_GETTER
bool has_attempted_stepping() const {
return LoadIsolateFlagsBit<HasAttemptedSteppingBit>();
}
void set_has_attempted_stepping(bool value) {
UpdateIsolateFlagsBit<HasAttemptedSteppingBit>(value);
}
static void KillAllIsolates(LibMsgId msg_id);
static void KillIfExists(Isolate* isolate, LibMsgId msg_id);
// Lookup an isolate by its main port. Returns nullptr if no matching isolate
// is found.
static Isolate* LookupIsolateByPort(Dart_Port port);
// Lookup an isolate by its main port and return a copy of its name. Returns
// nullptr if not matching isolate is found.
static std::unique_ptr<char[]> LookupIsolateNameByPort(Dart_Port port);
static void DisableIsolateCreation();
static void EnableIsolateCreation();
static bool IsolateCreationEnabled();
static bool IsSystemIsolate(const Isolate* isolate) {
return IsolateGroup::IsSystemIsolateGroup(isolate->group());
}
static bool IsVMInternalIsolate(const Isolate* isolate);
HandlerInfoCache* handler_info_cache() { return &handler_info_cache_; }
CatchEntryMovesCache* catch_entry_moves_cache() {
return &catch_entry_moves_cache_;
}
// The weak table used in the snapshot writer for the purpose of fast message
// sending.
WeakTable* forward_table_new() { return forward_table_new_.get(); }
void set_forward_table_new(WeakTable* table);
WeakTable* forward_table_old() { return forward_table_old_.get(); }
void set_forward_table_old(WeakTable* table);
void RememberLiveTemporaries();
void DeferredMarkLiveTemporaries();
std::unique_ptr<VirtualMemory> TakeRegexpBacktrackStack() {
return std::move(regexp_backtracking_stack_cache_);
}
void CacheRegexpBacktrackStack(std::unique_ptr<VirtualMemory> stack) {
regexp_backtracking_stack_cache_ = std::move(stack);
}
void init_loaded_prefixes_set_storage();
bool IsPrefixLoaded(const LibraryPrefix& prefix) const;
void SetPrefixIsLoaded(const LibraryPrefix& prefix);
MallocGrowableArray<ObjectPtr>* pointers_to_verify_at_exit() {
return &pointers_to_verify_at_exit_;
}
private:
friend class Dart; // Init, InitOnce, Shutdown.
friend class IsolateKillerVisitor; // Kill().
friend Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* g,
const char* n,
char** e);
Isolate(IsolateGroup* group, const Dart_IsolateFlags& api_flags);
static void InitVM();
static Isolate* InitIsolate(const char* name_prefix,
IsolateGroup* isolate_group,
const Dart_IsolateFlags& api_flags,
bool is_vm_isolate = false);
// The isolate_creation_monitor_ should be held when calling Kill().
void KillLocked(LibMsgId msg_id);
void Shutdown();
void RunAndCleanupFinalizersOnShutdown();
void LowLevelShutdown();
// Unregister the [isolate] from the thread, remove it from the isolate group,
// invoke the cleanup function (if any), delete the isolate and possibly
// delete the isolate group (if it's the last isolate in the group).
static void LowLevelCleanup(Isolate* isolate);
void BuildName(const char* name_prefix);
void ProfileIdle();
// Visit all object pointers. Caller must ensure concurrent sweeper is not
// running, and the visitor must not allocate.
void VisitObjectPointers(ObjectPointerVisitor* visitor,
ValidationPolicy validate_frames);
void VisitStackPointers(ObjectPointerVisitor* visitor,
ValidationPolicy validate_frames);
void set_user_tag(uword tag) { user_tag_ = tag; }
void set_is_system_isolate(bool is_system_isolate) {
is_system_isolate_ = is_system_isolate;
}
#if !defined(PRODUCT)
GrowableObjectArrayPtr GetAndClearPendingServiceExtensionCalls();
GrowableObjectArrayPtr pending_service_extension_calls() const {
return pending_service_extension_calls_;
}
void set_pending_service_extension_calls(const GrowableObjectArray& value);
GrowableObjectArrayPtr registered_service_extension_handlers() const {
return registered_service_extension_handlers_;
}
void set_registered_service_extension_handlers(
const GrowableObjectArray& value);
#endif // !defined(PRODUCT)
Thread* ScheduleThread(bool is_mutator,
bool is_nested_reenter,
bool bypass_safepoint);
void UnscheduleThread(Thread* thread,
bool is_mutator,
bool is_nested_exit,
bool bypass_safepoint);
// 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_ = 0;
UserTagPtr current_tag_;
UserTagPtr default_tag_;
CodePtr ic_miss_code_;
FieldTable* field_table_ = nullptr;
// Used to clear out `UntaggedFinalizerBase::isolate_` pointers on isolate
// shutdown to prevent usage of dangling pointers.
GrowableObjectArrayPtr finalizers_;
bool single_step_ = false;
bool has_resumption_breakpoints_ = false;
bool is_system_isolate_ = false;
// End accessed from generated code.
IsolateGroup* isolate_group_;
IdleTimeHandler idle_time_handler_;
std::unique_ptr<IsolateObjectStore> isolate_object_store_;
#if !defined(DART_PRECOMPILED_RUNTIME)
NativeCallbackTrampolines native_callback_trampolines_;
#endif
#define ISOLATE_FLAG_BITS(V) \
V(ErrorsFatal) \
V(IsRunnable) \
V(IsServiceIsolate) \
V(IsKernelIsolate) \
V(ResumeRequest) \
V(HasAttemptedStepping) \
V(ShouldPausePostServiceRequest) \
V(CopyParentCode) \
V(IsSystemIsolate) \
V(IsServiceRegistered)
// Isolate specific flags.
enum FlagBits {
#define DECLARE_BIT(Name) k##Name##Bit,
ISOLATE_FLAG_BITS(DECLARE_BIT)
#undef DECLARE_BIT
};
#define DECLARE_BITFIELD(Name) \
class Name##Bit : public BitField<uint32_t, bool, k##Name##Bit, 1> {};
ISOLATE_FLAG_BITS(DECLARE_BITFIELD)
#undef DECLARE_BITFIELD
template <class T>
bool UpdateIsolateFlagsBit(bool value) {
return T::decode(value ? isolate_flags_.fetch_or(T::encode(true),
std::memory_order_relaxed)
: isolate_flags_.fetch_and(
~T::encode(true), std::memory_order_relaxed));
}
template <class T>
bool LoadIsolateFlagsBit() const {
return T::decode(isolate_flags_.load(std::memory_order_relaxed));
}
std::atomic<uint32_t> isolate_flags_;
// Fields that aren't needed in a product build go here with boolean flags at
// the top.
#if !defined(PRODUCT)
Debugger* debugger_ = nullptr;
// SampleBlock containing CPU profiling samples.
//
// Can be accessed by multiple threads, so current_sample_block_lock_ should
// be acquired before accessing.
SampleBlock* current_sample_block_ = nullptr;
Mutex current_sample_block_lock_;
// SampleBlock containing Dart allocation profiling samples.
//
// Allocations should only occur on the mutator thread for an isolate, so we
// shouldn't need to worry about grabbing a lock for the allocation sample
// block.
SampleBlock* current_allocation_sample_block_ = nullptr;
int64_t last_resume_timestamp_;
VMTagCounters vm_tag_counters_;
// We use 6 list entries for each pending service extension calls.
enum {kPendingHandlerIndex = 0, kPendingMethodNameIndex, kPendingKeysIndex,
kPendingValuesIndex, kPendingReplyPortIndex, kPendingIdIndex,
kPendingEntrySize};
GrowableObjectArrayPtr pending_service_extension_calls_;
// We use 2 list entries for each registered extension handler.
enum {kRegisteredNameIndex = 0, kRegisteredHandlerIndex,
kRegisteredEntrySize};
GrowableObjectArrayPtr registered_service_extension_handlers_;
// Used to wake the isolate when it is in the pause event loop.
Monitor* pause_loop_monitor_ = nullptr;
#define ISOLATE_METRIC_VARIABLE(type, variable, name, unit) \
type metric_##variable##_;
ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE);
#undef ISOLATE_METRIC_VARIABLE
// Ring buffer of objects assigned an id.
ObjectIdRing* object_id_ring_ = nullptr;
#endif // !defined(PRODUCT)
// All other fields go here.
int64_t start_time_micros_;
std::atomic<Dart_MessageNotifyCallback> message_notify_callback_;
Dart_IsolateShutdownCallback on_shutdown_callback_ = nullptr;
Dart_IsolateCleanupCallback on_cleanup_callback_ = nullptr;
char* name_ = nullptr;
Dart_Port main_port_ = 0;
// Isolates created by Isolate.spawn have the same origin id.
Dart_Port origin_id_ = 0;
Mutex origin_id_mutex_;
uint64_t pause_capability_ = 0;
uint64_t terminate_capability_ = 0;
void* init_callback_data_ = nullptr;
Dart_EnvironmentCallback environment_callback_ = nullptr;
Random random_;
Simulator* simulator_ = nullptr;
Mutex mutex_; // Protects compiler stats.
MessageHandler* message_handler_ = nullptr;
intptr_t defer_finalization_count_ = 0;
DeoptContext* deopt_context_ = nullptr;
GrowableObjectArrayPtr tag_table_;
ErrorPtr sticky_error_;
std::unique_ptr<Bequest> bequest_;
Dart_Port beneficiary_ = 0;
// This guards spawn_count_. An isolate cannot complete shutdown and be
// destroyed while there are child isolates in the midst of a spawn.
Monitor spawn_count_monitor_;
intptr_t spawn_count_ = 0;
HandlerInfoCache handler_info_cache_;
CatchEntryMovesCache catch_entry_moves_cache_;
DispatchTable* dispatch_table_ = nullptr;
// Used during message sending of messages between isolates.
std::unique_ptr<WeakTable> forward_table_new_;
std::unique_ptr<WeakTable> forward_table_old_;
// Signals whether the isolate can receive messages (e.g. KillAllIsolates can
// send a kill message).
// This is protected by [isolate_creation_monitor_].
bool accepts_messages_ = false;
std::unique_ptr<VirtualMemory> regexp_backtracking_stack_cache_ = nullptr;
intptr_t wake_pause_event_handler_count_;
static Dart_IsolateGroupCreateCallback create_group_callback_;
static Dart_InitializeIsolateCallback initialize_callback_;
static Dart_IsolateShutdownCallback shutdown_callback_;
static Dart_IsolateCleanupCallback cleanup_callback_;
static Dart_IsolateGroupCleanupCallback cleanup_group_callback_;
static Dart_RegisterKernelBlobCallback register_kernel_blob_callback_;
static Dart_UnregisterKernelBlobCallback unregister_kernel_blob_callback_;
#if !defined(PRODUCT)
static void WakePauseEventHandler(Dart_Isolate isolate);
#endif
// Manage list of existing isolates.
static bool TryMarkIsolateReady(Isolate* isolate);
static void UnMarkIsolateReady(Isolate* isolate);
static void MaybeNotifyVMShutdown();
bool AcceptsMessagesLocked() {
ASSERT(isolate_creation_monitor_->IsOwnedByCurrentThread());
return accepts_messages_;
}
// This monitor protects [creation_enabled_].
static Monitor* isolate_creation_monitor_;
static bool creation_enabled_;
ArrayPtr loaded_prefixes_set_storage_;
MallocGrowableArray<ObjectPtr> pointers_to_verify_at_exit_;
#define REUSABLE_FRIEND_DECLARATION(name) \
friend class Reusable##name##HandleScope;
REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
#undef REUSABLE_FRIEND_DECLARATION
friend class Become; // VisitObjectPointers
friend class GCCompactor; // VisitObjectPointers
friend class GCMarker; // VisitObjectPointers
friend class SafepointHandler;
friend class ObjectGraph; // VisitObjectPointers
friend class HeapSnapshotWriter; // VisitObjectPointers
friend class Scavenger; // VisitObjectPointers
friend class HeapIterationScope; // VisitObjectPointers
friend class ServiceIsolate;
friend class Thread;
friend class Timeline;
friend class IsolateGroup; // reload_context_
DISALLOW_COPY_AND_ASSIGN(Isolate);
};
// When we need to execute code in an isolate, we use the
// StartIsolateScope.
class StartIsolateScope {
public:
explicit StartIsolateScope(Isolate* new_isolate)
: new_isolate_(new_isolate), saved_isolate_(Isolate::Current()) {
if (new_isolate_ == nullptr) {
ASSERT(Isolate::Current() == nullptr);
// Do nothing.
return;
}
if (saved_isolate_ != new_isolate_) {
ASSERT(Isolate::Current() == nullptr);
Thread::EnterIsolate(new_isolate_);
// Ensure this is not a nested 'isolate enter' with prior state.
ASSERT(Thread::Current()->saved_stack_limit() == 0);
}
}
~StartIsolateScope() {
if (new_isolate_ == nullptr) {
ASSERT(Isolate::Current() == nullptr);
// Do nothing.
return;
}
if (saved_isolate_ != new_isolate_) {
ASSERT(saved_isolate_ == nullptr);
// ASSERT that we have bottomed out of all Dart invocations.
ASSERT(Thread::Current()->saved_stack_limit() == 0);
Thread::ExitIsolate();
}
}
private:
Isolate* new_isolate_;
Isolate* saved_isolate_;
DISALLOW_COPY_AND_ASSIGN(StartIsolateScope);
};
class EnterIsolateGroupScope {
public:
explicit EnterIsolateGroupScope(IsolateGroup* isolate_group)
: isolate_group_(isolate_group) {
ASSERT(IsolateGroup::Current() == nullptr);
const bool result = Thread::EnterIsolateGroupAsHelper(
isolate_group_, Thread::kUnknownTask, /*bypass_safepoint=*/false);
ASSERT(result);
}
~EnterIsolateGroupScope() {
Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false);
}
private:
IsolateGroup* isolate_group_;
DISALLOW_COPY_AND_ASSIGN(EnterIsolateGroupScope);
};
// Ensure that isolate is not available for the duration of this scope.
//
// This can be used in code (e.g. GC, Kernel Loader) that should not operate on
// an individual isolate.
class NoActiveIsolateScope : public StackResource {
public:
NoActiveIsolateScope() : NoActiveIsolateScope(Thread::Current()) {}
explicit NoActiveIsolateScope(Thread* thread)
: StackResource(thread), thread_(thread) {
saved_isolate_ = thread_->isolate_;
thread_->isolate_ = nullptr;
}
~NoActiveIsolateScope() {
ASSERT(thread_->isolate_ == nullptr);
thread_->isolate_ = saved_isolate_;
}
private:
Thread* thread_;
Isolate* saved_isolate_;
};
} // namespace dart
#endif // RUNTIME_VM_ISOLATE_H_