// 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 "platform/growable_array.h"
#include "platform/thread_sanitizer.h"
#include "vm/class_table.h"
#include "vm/dispatch_table.h"
#include "vm/exceptions.h"
#include "vm/ffi_callback_metadata.h"
#include "vm/field_table.h"
#include "vm/fixed_cache.h"
#include "vm/handles.h"
#include "vm/hash_map.h"
#include "vm/heap/verifier.h"
#include "vm/intrusive_dlist.h"
#include "vm/megamorphic_cache_table.h"
#include "vm/metrics.h"
#include "vm/os_thread.h"
#include "vm/port.h"
#include "vm/random.h"
#include "vm/roots.h"
#include "vm/service.h"
#include "vm/tags.h"
#include "vm/thread.h"
#include "vm/thread_pool.h"
#include "vm/thread_stack_resource.h"
#include "vm/token_position.h"

namespace dart {

// Forward declarations.
class ApiState;
class BackgroundCompiler;
class Become;
class Capability;
class CodeIndexTable;
class Debugger;
class ExternalTypedData;
class GroupDebugger;
class HandleScope;
class HandleVisitor;
class Heap;
class ICData;
class IsolateGroupReloadContext;
class IsolateMessageHandler;
class IsolateObjectStore;
class IsolateProfilerData;
class Log;
class Message;
class MessageHandler;
class Mutex;
class Object;
class ObjectIdRing;
class ObjectPointerVisitor;
class ObjectStore;
class PersistentHandle;
class ProgramReloadContext;
class RwLock;
class SafepointHandler;
class SafepointRwLock;
class SampleBlock;
class SampleBlockBuffer;
class SampleBuffer;
class SendPort;
class SerializedObjectBuffer;
class ServiceIdZone;
class Simulator;
class StackResource;
class StackZone;
class StoreBuffer;
class StubCode;
class ThreadRegistry;
class UserTag;

class IsolateVisitor {
 public:
  IsolateVisitor() {}
  virtual ~IsolateVisitor() {}

  virtual void VisitIsolate(Isolate* isolate) = 0;

 protected:
  // Returns true if |isolate| is the VM or service isolate.
  bool IsSystemIsolate(Isolate* isolate) const;

 private:
  DISALLOW_COPY_AND_ASSIGN(IsolateVisitor);
};

class Callable : public ValueObject {
 public:
  Callable() {}
  virtual ~Callable() {}

  virtual void Call() = 0;

 private:
  DISALLOW_COPY_AND_ASSIGN(Callable);
};

template <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 group flags.
//
//     V(when, name, bit-name, Dart_IsolateFlags-name, command-line-flag-name)
//
#define BOOL_ISOLATE_GROUP_FLAG_LIST(V)                                        \
  V(PRECOMPILER, obfuscate, Obfuscate, obfuscate, false)                       \
  V(NONPRODUCT, asserts, EnableAsserts, enable_asserts, FLAG_enable_asserts)   \
  V(PRODUCT, use_field_guards, UseFieldGuards, use_field_guards,               \
    FLAG_use_field_guards)                                                     \
  V(PRODUCT, should_load_vmservice_library, ShouldLoadVmService,               \
    load_vmservice_library, false)                                             \
  V(PRODUCT, use_osr, UseOsr, use_osr, FLAG_use_osr)                           \
  V(NONPRODUCT, snapshot_is_dontneed_safe, SnapshotIsDontNeedSafe,             \
    snapshot_is_dontneed_safe, false)                                          \
  V(NONPRODUCT, branch_coverage, BranchCoverage, branch_coverage,              \
    FLAG_branch_coverage)                                                      \
  V(NONPRODUCT, coverage, Coverage, coverage, FLAG_coverage)                   \
  V(PRODUCT, dwarf_stack_traces, DwarfStackTraces, dwarf_stack_traces,         \
    FLAG_dwarf_stack_traces_mode)                                              \
  V(PRODUCT, code_comments, CodeComments, code_comments, FLAG_code_comments)

// List of Isolate flags with corresponding members of Dart_IsolateFlags and
// corresponding global command line flags.
#define BOOL_ISOLATE_FLAG_LIST(V)                                              \
  V(NONPRODUCT, is_system_isolate, IsSystemIsolate, is_system_isolate, false)  \
  V(NONPRODUCT, is_service_isolate, IsServiceIsolate, is_service_isolate,      \
    false)                                                                     \
  V(NONPRODUCT, is_kernel_isolate, IsKernelIsolate, is_kernel_isolate, false)

// Represents the information used for spawning the first isolate within an
// isolate group. All isolates within a group will refer to this
// [IsolateGroupSource].
class IsolateGroupSource {
 public:
  IsolateGroupSource(const char* script_uri,
                     const char* name,
                     const uint8_t* snapshot_data,
                     const uint8_t* snapshot_text,
                     const uint8_t* kernel_buffer,
                     intptr_t kernel_buffer_size,
                     Dart_IsolateFlags flags)
      : script_uri(script_uri == nullptr ? nullptr : Utils::StrDup(script_uri)),
        name(Utils::StrDup(name)),
        snapshot_data(snapshot_data),
        snapshot_text(snapshot_text),
        kernel_buffer(kernel_buffer),
        kernel_buffer_size(kernel_buffer_size),
        flags(flags),
        script_kernel_buffer(nullptr),
        script_kernel_size(-1),
        loaded_blobs_(nullptr),
        num_blob_loads_(0) {}
  ~IsolateGroupSource() {
    free(script_uri);
    free(name);
  }

  void add_loaded_blob(Zone* zone_,
                       const ExternalTypedData& external_typed_data);

  // The arguments used for spawning in
  // `Dart_CreateIsolateGroupFromKernel` / `Dart_CreateIsolate`.
  char* script_uri;
  char* name;
  const uint8_t* snapshot_data;
  const uint8_t* snapshot_text;
  const uint8_t* kernel_buffer;
  const intptr_t kernel_buffer_size;
  Dart_IsolateFlags flags;

  // The kernel buffer used in `Dart_LoadScriptFromKernel`.
  const uint8_t* script_kernel_buffer;
  intptr_t script_kernel_size;

  // List of weak pointers to external typed data for loaded blobs.
  ArrayPtr loaded_blobs_;
  intptr_t num_blob_loads_;
};

// Tracks idle time and notifies heap when idle time expired.
class IdleTimeHandler : public ValueObject {
 public:
  IdleTimeHandler() {}

  // Initializes the idle time handler with the given [heap], to which
  // idle notifications will be sent.
  void InitializeWithHeap(Heap* heap);

  // Declares that the idle time should be reset to now.
  void UpdateStartIdleTime();

  // Returns whether idle time expired and [NotifyIdle] should be called.
  bool ShouldNotifyIdle(int64_t* expiry);

  // Notifies the heap that now is a good time to do compactions and indicates
  // we have time for the GC until [deadline].
  void NotifyIdle(int64_t deadline);

  // Calls [NotifyIdle] with the default deadline.
  void NotifyIdleUsingDefaultDeadline();

 private:
  friend class DisableIdleTimerScope;

  Mutex mutex_;
  Heap* heap_ = nullptr;
  intptr_t disabled_counter_ = 0;
  int64_t idle_start_time_ = 0;
};

// Disables firing of the idle timer while this object is alive.
class DisableIdleTimerScope : public ValueObject {
 public:
  explicit DisableIdleTimerScope(IdleTimeHandler* handler);
  ~DisableIdleTimerScope();

 private:
  IdleTimeHandler* handler_;
};

class MutatorThreadPool : public ThreadPool {
 public:
  MutatorThreadPool(IsolateGroup* isolate_group, intptr_t max_pool_size)
      : ThreadPool(max_pool_size), isolate_group_(isolate_group) {}
  virtual ~MutatorThreadPool() {}

 protected:
  virtual void OnEnterIdleLocked(MutexLocker* ml, ThreadPool::Worker* worker);

 private:
  void NotifyIdle();

  IsolateGroup* isolate_group_ = nullptr;
};

enum RootSlice : intptr_t {
  kClassTable,
  kApiState,
  kObjectStore,
  kInitialFieldTable,
  kSentinelFieldTable,
  kSharedInitialFieldTable,
  kSharedFieldTable,
  kBackgroundCompiler,
  kDebugger,
  kReloadContext,
  kLoadedBlobs,
  kBecome,
  kObjectIdZones,

  kNumRootSlices,
};

inline const char* RootSliceToCString(intptr_t slice) {
  switch (slice) {
    case kClassTable:
      return "class table";
    case kApiState:
      return "api state";
    case kObjectStore:
      return "group object store";
    case kInitialFieldTable:
      return "initial field table";
    case kSentinelFieldTable:
      return "sentinel field table";
    case kSharedInitialFieldTable:
      return "shared initial field table";
    case kSharedFieldTable:
      return "shared field table";
    case kBackgroundCompiler:
      return "background compiler";
    case kDebugger:
      return "debugger";
    case kReloadContext:
      return "reload context";
    case kLoadedBlobs:
      return "loaded blobs";
    case kBecome:
      return "become";
    case kObjectIdZones:
      return "object id zones";
    default:
      return "?";
  }
}

// Represents an isolate group and is shared among all isolates within a group.
class IsolateGroup : public IntrusiveDListEntry<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(Become* become);
#if defined(DEBUG)
  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(); }
  Roots* roots() const { return roots_.get(); }
  FfiCallbackMetadata* callback_metadata() const {
    return callback_metadata_.get();
  }

  BackgroundCompiler* background_compiler() const {
#if defined(DART_PRECOMPILED_RUNTIME)
    return nullptr;
#else
    return background_compiler_.get();
#endif
  }
#if !defined(DART_PRECOMPILED_RUNTIME)
  intptr_t optimization_counter_threshold() const {
    if (IsSystemIsolateGroup(this)) {
      return kDefaultOptimizationCounterThreshold;
    }
    return FLAG_optimization_counter_threshold;
  }
#endif

#if !defined(PRODUCT)
  GroupDebugger* debugger() const { return debugger_; }
#endif

  IdleTimeHandler* idle_time_handler() { return &idle_time_handler_; }

  void RegisterIsolate(Isolate* isolate);
  void UnregisterIsolate(Isolate* isolate);
  // Returns `true` if this was the last isolate and the caller is responsible
  // for deleting the isolate group.
  bool UnregisterIsolateDecrementCount();
  void IncrementIsolateGroupMutatorCount();
  void DecrementIsolateGroupMutatorCount();
  bool ContainsOnlyOneIsolate();
  void RegisterIsolateGroupMutator(Thread* mutator);
  void UnregisterIsolateGroupMutator(Thread* mutator);

  Dart_Port interrupt_port() { return interrupt_port_; }

  ThreadRegistry* thread_registry() const { return thread_registry_.get(); }
  SafepointHandler* safepoint_handler() { return safepoint_handler_.get(); }

  void CreateHeap(bool is_service_or_kernel_isolate);
  void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable);
  void Shutdown();

#define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit)                    \
  type* Get##variable##Metric() { return &metric_##variable##_; }
  ISOLATE_GROUP_METRIC_LIST(ISOLATE_METRIC_ACCESSOR);
#undef ISOLATE_METRIC_ACCESSOR

#if !defined(PRODUCT)
  void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
    last_allocationprofile_accumulator_reset_timestamp_ =
        OS::GetCurrentTimeMillis();
  }

  int64_t last_allocationprofile_accumulator_reset_timestamp() const {
    return last_allocationprofile_accumulator_reset_timestamp_;
  }

  void UpdateLastAllocationProfileGCTimestamp() {
    last_allocationprofile_gc_timestamp_ = OS::GetCurrentTimeMillis();
  }

  int64_t last_allocationprofile_gc_timestamp() const {
    return last_allocationprofile_gc_timestamp_;
  }
#endif  // !defined(PRODUCT)

  DispatchTable* dispatch_table() const { return dispatch_table_.get(); }
  void set_dispatch_table(DispatchTable* table) {
    dispatch_table_.reset(table);
  }
  const uint8_t* dispatch_table_snapshot() const {
    return dispatch_table_snapshot_;
  }
  void set_dispatch_table_snapshot(const uint8_t* snapshot) {
    dispatch_table_snapshot_ = snapshot;
  }
  intptr_t dispatch_table_snapshot_size() const {
    return dispatch_table_snapshot_size_;
  }
  void set_dispatch_table_snapshot_size(intptr_t size) {
    dispatch_table_snapshot_size_ = size;
  }

  ClassTableAllocator* class_table_allocator() {
    return &class_table_allocator_;
  }

  static intptr_t class_table_offset() {
    COMPILE_ASSERT(sizeof(IsolateGroup::class_table_) == kWordSize);
    return OFFSET_OF(IsolateGroup, class_table_);
  }

  ClassPtr* cached_class_table_table() {
    return cached_class_table_table_.load();
  }
  void set_cached_class_table_table(ClassPtr* cached_class_table_table) {
    cached_class_table_table_.store(cached_class_table_table);
  }
  static intptr_t cached_class_table_table_offset() {
    COMPILE_ASSERT(sizeof(IsolateGroup::cached_class_table_table_) ==
                   kWordSize);
    return OFFSET_OF(IsolateGroup, cached_class_table_table_);
  }

  void set_object_store(ObjectStore* object_store);
  static intptr_t object_store_offset() {
    COMPILE_ASSERT(sizeof(IsolateGroup::object_store_) == kWordSize);
    return OFFSET_OF(IsolateGroup, object_store_);
  }

  void set_obfuscation_map(const char** map) { obfuscation_map_ = map; }
  const char** obfuscation_map() const { return obfuscation_map_; }

  bool is_system_isolate_group() const { return is_system_isolate_group_; }
  bool is_bootstrapping() const { return bootstrapping_; }
  void set_bootstrapping(bool v) { bootstrapping_ = v; }

  // IsolateGroup-specific flag handling.
  static void FlagsInitialize(Dart_IsolateFlags* api_flags);
  void FlagsCopyTo(Dart_IsolateFlags* api_flags);
  void FlagsCopyFrom(const Dart_IsolateFlags& api_flags);

#if defined(DART_PRECOMPILER)
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag)
#endif

#if !defined(PRODUCT)
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag)
#endif

#define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field)

#define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name)      \
  bool name() const {                                                          \
    return FLAG_FOR_##when(bitname##Bit::decode(isolate_group_flags_),         \
                           flag_name);                                         \
  }
  BOOL_ISOLATE_GROUP_FLAG_LIST(DECLARE_GETTER)
#undef FLAG_FOR_NONPRODUCT
#undef FLAG_FOR_PRECOMPILER
#undef FLAG_FOR_PRODUCT
#undef DECLARE_GETTER

  bool should_load_vmservice() const {
    return isolate_group_flags_.Read<ShouldLoadVmServiceBit>();
  }
  void set_should_load_vmservice(bool value) {
    isolate_group_flags_.UpdateBool<ShouldLoadVmServiceBit>(value);
  }

  void set_asserts(bool value) {
    isolate_group_flags_.UpdateBool<EnableAssertsBit>(value);
  }
  void set_branch_coverage(bool value) {
    isolate_group_flags_.UpdateBool<BranchCoverageBit>(value);
  }
  void set_coverage(bool value) {
    isolate_group_flags_.UpdateBool<CoverageBit>(value);
  }
  void set_use_field_guards(bool value) {
    isolate_group_flags_.UpdateBool<UseFieldGuardsBit>(value);
  }
  void set_use_osr(bool value) {
    isolate_group_flags_.UpdateBool<UseOsrBit>(value);
  }
  void set_code_comments(bool value) {
    isolate_group_flags_.UpdateBool<CodeCommentsBit>(value);
  }
  void set_dwarf_stack_traces(bool value) {
    isolate_group_flags_.UpdateBool<DwarfStackTracesBit>(value);
  }

#if !defined(PRODUCT)
#if !defined(DART_PRECOMPILED_RUNTIME)
  bool HasAttemptedReload() const {
    return isolate_group_flags_.Read<HasAttemptedReloadBit>();
  }
  void SetHasAttemptedReload(bool value) {
    isolate_group_flags_.UpdateBool<HasAttemptedReloadBit>(value);
  }
  void MaybeIncreaseReloadEveryNStackOverflowChecks();
  intptr_t reload_every_n_stack_overflow_checks() const {
    return reload_every_n_stack_overflow_checks_;
  }
#else
  bool HasAttemptedReload() const { return false; }
#endif  // !defined(DART_PRECOMPILED_RUNTIME)
#endif  // !defined(PRODUCT)

  bool has_seen_oom() const {
    return isolate_group_flags_.Read<HasSeenOOMBit>();
  }
  void set_has_seen_oom(bool value) {
    isolate_group_flags_.UpdateBool<HasSeenOOMBit>(value);
  }

  // Class table for the program loaded into this isolate group.
  //
  // This table is modified by kernel loading.
  ClassTable* class_table() const { return class_table_; }

  // Class table used for heap walks by GC visitors. Usually it
  // is the same table as one in |class_table_|, except when in the
  // middle of the reload.
  //
  // See comment for |ClassTable| class for more details.
  ClassTable* heap_walk_class_table() const { return heap_walk_class_table_; }

  void CloneClassTableForReload();
  void RestoreOriginalClassTable();
  void DropOriginalClassTable();

  StoreBuffer* store_buffer() const { return store_buffer_.get(); }
  ObjectStore* object_store() const { return object_store_.get(); }
  Mutex* symbols_mutex() { return &symbols_mutex_; }
  Mutex* type_canonicalization_mutex() { return &type_canonicalization_mutex_; }
  Mutex* type_arguments_canonicalization_mutex() {
    return &type_arguments_canonicalization_mutex_;
  }
  Mutex* subtype_test_cache_mutex() { return &subtype_test_cache_mutex_; }
  Mutex* megamorphic_table_mutex() { return &megamorphic_table_mutex_; }
  Mutex* type_feedback_mutex() { return &type_feedback_mutex_; }
  Mutex* patchable_call_mutex() { return &patchable_call_mutex_; }
  Mutex* constant_canonicalization_mutex() {
    return &constant_canonicalization_mutex_;
  }
  Mutex* kernel_data_lib_cache_mutex() { return &kernel_data_lib_cache_mutex_; }
  Mutex* kernel_data_class_cache_mutex() {
    return &kernel_data_class_cache_mutex_;
  }
  Mutex* kernel_constants_mutex() { return &kernel_constants_mutex_; }

#if defined(DART_PRECOMPILED_RUNTIME)
  Mutex* unlinked_call_map_mutex() { return &unlinked_call_map_mutex_; }
#endif

#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
  Mutex* initializer_functions_mutex() { return &initializer_functions_mutex_; }
#endif  // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)

  SafepointRwLock* shared_field_initializer_rwlock() {
    return &shared_field_initializer_rwlock_;
  }

  SafepointRwLock* program_lock() { return program_lock_.get(); }

  static inline IsolateGroup* Current() {
    Thread* thread = Thread::Current();
    return thread == nullptr ? nullptr : thread->isolate_group();
  }

  void IncreaseMutatorCount(Thread* thread,
                            bool is_nested_reenter,
                            bool was_stolen);
  void DecreaseMutatorCount(bool is_nested_exit);
  NO_SANITIZE_THREAD
  intptr_t MutatorCount() const { return active_mutators_; }

  bool HasTagHandler() const { return library_tag_handler() != nullptr; }
  ObjectPtr CallTagHandler(Dart_LibraryTag tag,
                           const Object& arg1,
                           const Object& arg2);
  Dart_LibraryTagHandler library_tag_handler() const {
    return library_tag_handler_;
  }
  void set_library_tag_handler(Dart_LibraryTagHandler handler) {
    library_tag_handler_ = handler;
  }
  Dart_DeferredLoadHandler deferred_load_handler() const {
    return deferred_load_handler_;
  }
  void set_deferred_load_handler(Dart_DeferredLoadHandler handler) {
    deferred_load_handler_ = handler;
  }

  // Prepares all threads in an isolate for Garbage Collection.
  void ReleaseStoreBuffers();
  void FlushMarkingStacks();
  void EnableIncrementalBarrier(MarkingStack* old_marking_stack,
                                MarkingStack* new_marking_stack,
                                MarkingStack* deferred_marking_stack);
  void DisableIncrementalBarrier();

  MarkingStack* old_marking_stack() const { return old_marking_stack_; }
  MarkingStack* new_marking_stack() const { return new_marking_stack_; }
  MarkingStack* deferred_marking_stack() const {
    return deferred_marking_stack_;
  }

  // Runs the given [function] on every isolate in the isolate group.
  //
  // During the duration of this function, no new isolates can be added or
  // removed.
  //
  // If [at_safepoint] is `true`, then the entire isolate group must be in a
  // safepoint. There is therefore no reason to guard against other threads
  // adding/removing isolates, so no locks will be held.
  void ForEachIsolate(std::function<void(Isolate* isolate)> function,
                      bool at_safepoint = false);

  void ForEachMutatorAtASafepoint(std::function<void(Thread* thread)> function);

  // Ensures mutators are stopped during execution of the provided function.
  //
  // If the current thread is the only mutator in the isolate group,
  // [callable] will be called directly. Otherwise [callable] will be
  // called inside a [SafepointOperationsScope].
  //
  // During the duration of this function, no new isolates can be added to the
  // isolate group.
  void RunWithStoppedMutatorsCallable(Callable* callable);

  template <typename T>
  void RunWithStoppedMutators(T function) {
    LambdaCallable<T> callable(function);
    RunWithStoppedMutatorsCallable(&callable);
  }

#ifndef PRODUCT
  void PrintJSON(JSONStream* stream, bool ref = true);
  void PrintToJSONObject(JSONObject* jsobj, bool ref);

  // Creates an object with the total heap memory usage statistics for this
  // isolate group.
  void PrintMemoryUsageJSON(JSONStream* stream);
#endif

#if !defined(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; }

  Dart_Port id() const { return id_; }

  static void Init();
  static void Cleanup();

  static void ForEach(std::function<void(IsolateGroup*)> action);
  static void RunWithIsolateGroup(Dart_Port 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 HasIsolateGroups();
  static bool HasApplicationIsolateGroups();
  static bool IsSystemIsolateGroup(const IsolateGroup* group);

  int64_t UptimeMicros() const;

  ApiState* api_state() const { return api_state_.get(); }

  // Visit all object pointers. Caller must ensure concurrent sweeper is not
  // running, and the visitor must not allocate.
  void VisitObjectPointers(ObjectPointerVisitor* visitor,
                           ValidationPolicy validate_frames);
  void VisitSharedPointers(ObjectPointerVisitor* visitor);
  void VisitSharedPointers(ObjectPointerVisitor* visitor, intptr_t slice);
  void VisitStackPointers(ObjectPointerVisitor* visitor,
                          ValidationPolicy validate_frames);
  void VisitWeakPersistentHandles(HandleVisitor* visitor);

  // In precompilation we finalize all regular classes before compiling.
  bool all_classes_finalized() const {
    return isolate_group_flags_.Read<AllClassesFinalizedBit>();
  }
  void set_all_classes_finalized(bool value) {
    isolate_group_flags_.UpdateBool<AllClassesFinalizedBit>(value);
  }
  bool has_dynamically_extendable_classes() const {
    return isolate_group_flags_.Read<HasDynamicallyExtendableClassesBit>();
  }
  void set_has_dynamically_extendable_classes(bool value) {
    isolate_group_flags_.UpdateBool<HasDynamicallyExtendableClassesBit>(value);
  }

  bool remapping_cids() const {
    return isolate_group_flags_.Read<RemappingCidsBit>();
  }
  void set_remapping_cids(bool value) {
    isolate_group_flags_.UpdateBool<RemappingCidsBit>(value);
  }

  void RememberLiveTemporaries();
  void DeferredMarkLiveTemporaries();

  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;
  }

  FieldTable* sentinel_field_table() const {
    return sentinel_field_table_.get();
  }
  std::shared_ptr<FieldTable> sentinel_field_table_shareable() {
    return sentinel_field_table_;
  }
  void set_sentinel_field_table(std::shared_ptr<FieldTable> field_table) {
    sentinel_field_table_ = field_table;
  }

  FieldTable* shared_initial_field_table() const {
    return shared_initial_field_table_.get();
  }
  std::shared_ptr<FieldTable> shared_initial_field_table_shareable() {
    return shared_initial_field_table_;
  }
  void set_shared_initial_field_table(std::shared_ptr<FieldTable> field_table) {
    shared_initial_field_table_ = field_table;
  }

  FieldTable* shared_field_table() const { return shared_field_table_.get(); }
  std::shared_ptr<FieldTable> shared_field_table_shareable() {
    return shared_field_table_;
  }
  void set_shared_field_table(Thread* T, FieldTable* shared_field_table) {
    shared_field_table_.reset(shared_field_table);
    T->shared_field_table_values_ = shared_field_table->table();
  }

  MutatorThreadPool* thread_pool() { return thread_pool_.get(); }

  void RegisterClass(const Class& cls);
  void RegisterSharedStaticField(const Field& field,
                                 const Object& initial_value);
  void RegisterStaticField(const Field& field, const Object& initial_value);
  void FreeStaticField(const Field& field);

  Isolate* EnterTemporaryIsolate();
  static void ExitTemporaryIsolate();

  Mutex* cache_mutex() { return &cache_mutex_; }
  void RunWithCachedCatchEntryMoves(
      const Code& code,
      intptr_t pc,
      std::function<void(const CatchEntryMoves&)> action);
  void ClearCatchEntryMovesCacheLocked();
  HandlerInfoCache* handler_info_cache() { return &handler_info_cache_; }

  void SetNativeAssetsCallbacks(NativeAssetsApi* native_assets_api) {
    native_assets_api_ = *native_assets_api;
  }
  NativeAssetsApi* native_assets_api() { return &native_assets_api_; }

  bool has_attempted_stepping() const {
    return has_attempted_stepping_.load(std::memory_order_relaxed);
  }
  void set_has_attempted_stepping(bool value) {
    has_attempted_stepping_.store(value, std::memory_order_relaxed);
  }

  SafepointRwLock* tag_table_lock() { return &tag_table_lock_; }

  intptr_t thread_locals_count() { return thread_locals_count_; }
  intptr_t increment_thread_locals_count() {
    return thread_locals_count_.fetch_add(1u, std::memory_order_relaxed);
  }

  FfiCallbackMetadata::Trampoline CreateIsolateGroupBoundFfiCallback(
      Zone* zone,
      const Function& trampoline,
      const Closure& target);
  void DeleteFfiCallback(FfiCallbackMetadata::Trampoline callback);

 private:
  friend class Dart;  // For `object_store_ = ` in Dart::Init
  friend class Heap;
  friend class StackFrame;  // For `[isolates_].First()`.
  // For `object_store_shared_untag()`, `class_table_shared_untag()`
  friend class Isolate;

#define ISOLATE_GROUP_FLAG_BITS(V)                                             \
  V(AllClassesFinalized)                                                       \
  V(EnableAsserts)                                                             \
  V(HasAttemptedReload)                                                        \
  V(HasSeenOOM)                                                                \
  V(RemappingCids)                                                             \
  V(ShouldLoadVmService)                                                       \
  V(Obfuscate)                                                                 \
  V(UseFieldGuards)                                                            \
  V(UseOsr)                                                                    \
  V(SnapshotIsDontNeedSafe)                                                    \
  V(BranchCoverage)                                                            \
  V(Coverage)                                                                  \
  V(HasDynamicallyExtendableClasses)                                           \
  V(DwarfStackTraces)                                                          \
  V(CodeComments)

  // Isolate group specific flags.
  enum FlagBits {
#define DECLARE_BIT(Name) k##Name##Bit,
    ISOLATE_GROUP_FLAG_BITS(DECLARE_BIT)
#undef DECLARE_BIT
  };

#define DECLARE_BITFIELD(Name)                                                 \
  using Name##Bit = BitField<uint32_t, bool, k##Name##Bit>;
  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;

  void* embedder_data_ = nullptr;

  IdleTimeHandler idle_time_handler_;
  std::unique_ptr<MutatorThreadPool> thread_pool_;
  std::unique_ptr<SafepointRwLock> isolates_lock_;
  IntrusiveDList<Isolate> isolates_;
  RelaxedAtomic<Dart_Port> interrupt_port_ = ILLEGAL_PORT;
  intptr_t isolate_count_ = 0;
  IntrusiveDList<Thread> mutators_;
  intptr_t group_mutator_count_ = 0;
  bool initial_spawn_successful_ = false;
  Dart_LibraryTagHandler library_tag_handler_ = nullptr;
  Dart_DeferredLoadHandler deferred_load_handler_ = nullptr;
  int64_t start_time_micros_;
  bool is_system_isolate_group_;
  bool bootstrapping_ = true;

#if !defined(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* old_marking_stack_ = nullptr;
  MarkingStack* new_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_;

  static RwLock* isolate_groups_rwlock_;
  static IntrusiveDList<IsolateGroup>* isolate_groups_;
  static Random* isolate_group_random_;

  Dart_Port 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;
  std::shared_ptr<FieldTable> initial_field_table_;
  std::shared_ptr<FieldTable> sentinel_field_table_;
  std::shared_ptr<FieldTable> shared_initial_field_table_;
  std::shared_ptr<FieldTable> shared_field_table_;
  AtomicBitFieldContainer<uint32_t> isolate_group_flags_;

  NOT_IN_PRECOMPILED(std::unique_ptr<BackgroundCompiler> background_compiler_);

  std::unique_ptr<FfiCallbackMetadata> callback_metadata_;

  Mutex symbols_mutex_;
  Mutex type_canonicalization_mutex_;
  Mutex type_arguments_canonicalization_mutex_;
  Mutex subtype_test_cache_mutex_;
  Mutex megamorphic_table_mutex_;
  Mutex type_feedback_mutex_;
  Mutex patchable_call_mutex_;
  Mutex constant_canonicalization_mutex_;
  Mutex kernel_data_lib_cache_mutex_;
  Mutex kernel_data_class_cache_mutex_;
  Mutex kernel_constants_mutex_;

#if defined(DART_PRECOMPILED_RUNTIME)
  Mutex unlinked_call_map_mutex_;
#endif

#if !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)
  Mutex initializer_functions_mutex_;
#endif  // !defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DYNAMIC_MODULES)

  // Ensure exclusive execution of shared field initializers.
  SafepointRwLock shared_field_initializer_rwlock_;

  // Ensures synchronized access to classes functions, fields and other
  // program structure elements to accommodate concurrent modification done
  // by multiple isolates and background compiler.
  std::unique_ptr<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;
  bool has_timeout_waiter_ = false;

  NOT_IN_PRODUCT(GroupDebugger* debugger_ = nullptr);

  NativeAssetsApi native_assets_api_;

  Mutex cache_mutex_;
  HandlerInfoCache handler_info_cache_;
  CatchEntryMovesCache catch_entry_moves_cache_;

  std::atomic<bool> has_attempted_stepping_;

  SafepointRwLock tag_table_lock_;

  std::atomic<intptr_t> thread_locals_count_ = 0;

  std::unique_ptr<Roots> roots_;

  FfiCallbackMetadata::MetadataEntry* ffi_callback_list_head_ = nullptr;
};

// When an isolate sends-and-exits this class represent things that it passed
// to the beneficiary.
class Bequest {
 public:
  Bequest(PersistentHandle* handle, Dart_Port beneficiary)
      : handle_(handle), beneficiary_(beneficiary) {}
  ~Bequest();

  PersistentHandle* handle() { return handle_; }
  PersistentHandle* TakeHandle() {
    auto handle = handle_;
    handle_ = nullptr;
    return handle;
  }
  Dart_Port beneficiary() { return beneficiary_; }

 private:
  PersistentHandle* handle_;
  Dart_Port beneficiary_;
};

class Isolate : public IntrusiveDListEntry<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();
  }

  Dart_MessageNotifyCallback message_notify_callback() const {
    return message_notify_callback_.load(std::memory_order_relaxed);
  }

  void set_message_notify_callback(Dart_MessageNotifyCallback value) {
    message_notify_callback_.store(value, std::memory_order_release);
    is_acquirable_ = false;
  }

  void set_on_shutdown_callback(Dart_IsolateShutdownCallback value) {
    on_shutdown_callback_ = value;
  }
  Dart_IsolateShutdownCallback on_shutdown_callback() {
    return on_shutdown_callback_;
  }
  void set_on_cleanup_callback(Dart_IsolateCleanupCallback value) {
    on_cleanup_callback_ = value;
  }
  Dart_IsolateCleanupCallback on_cleanup_callback() {
    return on_cleanup_callback_;
  }

  void bequeath(std::unique_ptr<Bequest> bequest) {
    bequest_ = std::move(bequest);
  }

  IsolateGroupSource* source() const { return isolate_group_->source(); }
  IsolateGroup* group() const { return isolate_group_; }

  bool HasPendingMessages();

  Thread* mutator_thread() const { return mutator_thread_; }
  NO_SANITIZE_THREAD
  Thread* mutator_thread_ignore_race() const { return mutator_thread_; }

  const char* name() const { return name_; }
  void set_name(const char* name);

  int64_t UptimeMicros() const;

  Dart_Port main_port() const { return main_port_; }
  void set_main_port(Dart_Port port) {
    ASSERT(main_port_ == 0);  // Only set main port once.
    main_port_ = port;
  }
  void set_pause_capability(uint64_t value) { pause_capability_ = value; }
  uint64_t pause_capability() const { return pause_capability_; }
  void set_terminate_capability(uint64_t value) {
    terminate_capability_ = value;
  }
  uint64_t terminate_capability() const { return terminate_capability_; }

  void SendInternalLibMessage(LibMsgId msg_id, uint64_t capability);
  static bool SendInternalLibMessage(Dart_Port main_port,
                                     LibMsgId msg_id,
                                     uint64_t capability);

  void set_init_callback_data(void* value) { init_callback_data_ = value; }
  void* init_callback_data() const { return init_callback_data_; }

  void set_finalizers(const GrowableObjectArray& value);
  static intptr_t finalizers_offset() {
    return OFFSET_OF(Isolate, finalizers_);
  }

  Dart_EnvironmentCallback environment_callback() const {
    return environment_callback_;
  }
  void set_environment_callback(Dart_EnvironmentCallback value) {
    environment_callback_ = value;
  }

  bool HasDeferredLoadHandler() const {
    return group()->deferred_load_handler() != nullptr;
  }
  ObjectPtr CallDeferredLoadHandler(intptr_t id);

  void ScheduleInterrupts(uword interrupt_bits);

  const char* MakeRunnable();
  void MakeRunnableLocked();
  void Run();

  MessageHandler* message_handler() const;

  bool is_runnable() const { return isolate_flags_.Read<IsRunnableBit>(); }
  void set_is_runnable(bool value) {
    isolate_flags_.UpdateBool<IsRunnableBit>(value);
#if !defined(PRODUCT)
    if (is_runnable()) {
      set_last_resume_timestamp();
    }
#endif
  }

#if !defined(PRODUCT)
  Debugger* debugger() const { return debugger_; }

  void set_has_resumption_breakpoints(bool value) {
    has_resumption_breakpoints_ = value;
  }
  bool has_resumption_breakpoints() const {
    return has_resumption_breakpoints_;
  }
  static intptr_t has_resumption_breakpoints_offset() {
    return OFFSET_OF(Isolate, has_resumption_breakpoints_);
  }

  bool ResumeRequest() const { return isolate_flags_.Read<ResumeRequestBit>(); }
  // Lets the embedder know that a service message resulted in a resume request.
  void SetResumeRequest() {
    isolate_flags_.UpdateBool<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 isolate_flags_.TryClear<ResumeRequestBit>();
  }
#endif

#if defined(DART_INCLUDE_PROFILER)
  // Returns the current SampleBlock used to track CPU profiling samples.
  SampleBlock* current_sample_block() const { return current_sample_block_; }
  void set_current_sample_block(SampleBlock* block) {
    current_sample_block_ = block;
  }
  SampleBlock* exchange_current_sample_block(SampleBlock* block) {
    return current_sample_block_.exchange(block, std::memory_order_acq_rel);
  }
  void ProcessFreeSampleBlocks(Thread* thread);

  // Returns the current SampleBlock used to track Dart allocation samples.
  SampleBlock* current_allocation_sample_block() const {
    return current_allocation_sample_block_;
  }
  void set_current_allocation_sample_block(SampleBlock* block) {
    current_allocation_sample_block_ = block;
  }
  SampleBlock* exchange_current_allocation_sample_block(SampleBlock* block) {
    return current_allocation_sample_block_.exchange(block,
                                                     std::memory_order_acq_rel);
  }

  bool TakeHasCompletedBlocks() {
    return has_completed_blocks_.exchange(0) != 0;
  }
  bool TrySetHasCompletedBlocks() {
    return has_completed_blocks_.exchange(1) == 0;
  }
#endif

  // Verify that the sender has the capability to pause or terminate the
  // isolate.
  bool VerifyPauseCapability(const Object& capability) const;
  bool VerifyTerminateCapability(const Object& capability) const;

  // Returns true if the capability was added or removed from this isolate's
  // list of pause events.
  bool AddResumeCapability(const Capability& capability);
  bool RemoveResumeCapability(const Capability& capability);

  void AddExitListener(const SendPort& listener, const Instance& response);
  void RemoveExitListener(const SendPort& listener);
  void NotifyExitListeners();

  void AddErrorListener(const SendPort& listener);
  void RemoveErrorListener(const SendPort& listener);
  bool NotifyErrorListeners(const char* msg, const char* stacktrace);

  bool ErrorsFatal() const { return isolate_flags_.Read<ErrorsFatalBit>(); }
  void SetErrorsFatal(bool value) {
    isolate_flags_.UpdateBool<ErrorsFatalBit>(value);
  }

  Simulator* simulator() const { return simulator_; }
  void set_simulator(Simulator* value) { simulator_ = value; }

  void IncrementSpawnCount();
  void DecrementSpawnCount();
  void WaitForOutstandingSpawns();

  bool TryAcquireOwnership();
  void ReleaseOwnership();
  bool is_permanently_pinned() { return is_permanently_pinned_; }
  void set_is_permanently_pinned() { is_permanently_pinned_ = true; }
  void clear_is_permanently_pinned_for_testing_only() {
    is_permanently_pinned_ = false;
  }
  bool is_acquirable() { return is_acquirable_; }
  void set_is_not_acquirable() { is_acquirable_ = false; }

  static void SetCreateGroupCallback(Dart_IsolateGroupCreateCallback cb) {
    create_group_callback_ = cb;
  }
  static Dart_IsolateGroupCreateCallback CreateGroupCallback() {
    return create_group_callback_;
  }

  static void SetInitializeCallback_(Dart_InitializeIsolateCallback cb) {
    initialize_callback_ = cb;
  }
  static Dart_InitializeIsolateCallback InitializeCallback() {
    return initialize_callback_;
  }

  static void SetShutdownCallback(Dart_IsolateShutdownCallback cb) {
    shutdown_callback_ = cb;
  }
  static Dart_IsolateShutdownCallback ShutdownCallback() {
    return shutdown_callback_;
  }

  static void SetCleanupCallback(Dart_IsolateCleanupCallback cb) {
    cleanup_callback_ = cb;
  }
  static Dart_IsolateCleanupCallback CleanupCallback() {
    return cleanup_callback_;
  }

  static void SetGroupCleanupCallback(Dart_IsolateGroupCleanupCallback cb) {
    cleanup_group_callback_ = cb;
  }
  static Dart_IsolateGroupCleanupCallback GroupCleanupCallback() {
    return cleanup_group_callback_;
  }

#if !defined(PRODUCT)
  // This method first ensures that the default Service ID zone for this isolate
  // exists, by creating it if necessary, and then adds a new Service ID zone to
  // `serivce_id_zones_` and returns a reference to that new zone.
  RingServiceIdZone& AddServiceIdZone(
      ObjectIdRing::BackingBufferKind backing_buffer_kind,
      ObjectIdRing::IdPolicy id_assignment_policy,
      int32_t capacity);

  void DeleteServiceIdZone(int32_t id);

  // The default Service ID zone is created lazily; this method returns the
  // default Service ID zone, creating it if necessary.
  RingServiceIdZone& EnsureDefaultServiceIdZone();

  RingServiceIdZone* GetServiceIdZone(intptr_t zone_id) const;

  template <typename F>
  void ForEachServiceIdZone(F callback) const {
    if (service_id_zones_ == nullptr) return;
    auto it = service_id_zones_->GetIterator();
    while (auto* pair = it.Next()) {
      callback(pair->value);
    }
  }
#endif  // !defined(PRODUCT)

  FfiCallbackMetadata::Trampoline CreateAsyncFfiCallback(
      Zone* zone,
      const Function& send_function,
      Dart_Port send_port);
  FfiCallbackMetadata::Trampoline CreateIsolateLocalFfiCallback(
      Zone* zone,
      const Function& trampoline,
      const Closure& target,
      bool keep_isolate_alive);
  void DeleteFfiCallback(FfiCallbackMetadata::Trampoline callback);
  void UpdateNativeCallableKeepIsolateAliveCounter(intptr_t delta);
  bool HasOpenNativeCallables();

  bool HasLivePorts();
  ReceivePortPtr CreateReceivePort(const String& debug_name);
  void SetReceivePortKeepAliveState(const ReceivePort& receive_port,
                                    bool keep_isolate_alive);
  void CloseReceivePort(const ReceivePort& receive_port);

  // Visible for testing.
  FfiCallbackMetadata::MetadataEntry* ffi_callback_list_head() {
    return ffi_callback_list_head_;
  }

  intptr_t BlockClassFinalization() {
    ASSERT(defer_finalization_count_ >= 0);
    return defer_finalization_count_++;
  }

  intptr_t UnblockClassFinalization() {
    ASSERT(defer_finalization_count_ > 0);
    return defer_finalization_count_--;
  }

  bool AllowClassFinalization() {
    ASSERT(defer_finalization_count_ >= 0);
    return defer_finalization_count_ == 0;
  }

#ifndef PRODUCT
  void PrintJSON(JSONStream* stream, bool ref = true);

  // Creates an object with the total heap memory usage statistics for this
  // isolate.
  void PrintMemoryUsageJSON(JSONStream* stream);

  void PrintPauseEventJSON(JSONStream* stream);
#endif

#if !defined(PRODUCT)
  VMTagCounters* vm_tag_counters() { return &vm_tag_counters_; }
#endif  // !defined(PRODUCT)

  bool IsPaused() const;

#if !defined(PRODUCT)
  bool should_pause_post_service_request() const {
    return isolate_flags_.Read<ShouldPausePostServiceRequestBit>();
  }
  void set_should_pause_post_service_request(bool value) {
    isolate_flags_.UpdateBool<ShouldPausePostServiceRequestBit>(value);
  }
#endif  // !defined(PRODUCT)

  ErrorPtr PausePostRequest();

#if !defined(PRODUCT)
#define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit)                    \
  type* Get##variable##Metric() { return &metric_##variable##_; }
  ISOLATE_METRIC_LIST(ISOLATE_METRIC_ACCESSOR);
#undef ISOLATE_METRIC_ACCESSOR
#endif  // !defined(PRODUCT)

  static intptr_t IsolateListLength();

  // Also sends a paused at exit event over the service protocol.
  void SetStickyError(ErrorPtr sticky_error);

  ErrorPtr sticky_error() const { return sticky_error_; }
  DART_WARN_UNUSED_RESULT ErrorPtr StealStickyError();

#ifndef PRODUCT
  ErrorPtr InvokePendingServiceExtensionCalls();
  void AppendServiceExtensionCall(const Instance& closure,
                                  const String& method_name,
                                  const Array& parameter_keys,
                                  const Array& parameter_values,
                                  const Instance& reply_port,
                                  const Instance& id);
  void RegisterServiceExtensionHandler(const String& name,
                                       const Instance& closure);
  InstancePtr LookupServiceExtensionHandler(const String& name);
#endif

  static void VisitIsolates(IsolateVisitor* visitor);

#if !defined(PRODUCT)
  // Handle service messages until we are told to resume execution.
  void PauseEventHandler();
#endif

  bool is_service_registered() const {
    return isolate_flags_.Read<IsServiceRegisteredBit>();
  }
  void set_is_service_registered(bool value) {
    isolate_flags_.UpdateBool<IsServiceRegisteredBit>(value);
  }

  // Isolate-specific flag handling.
  static void FlagsInitialize(Dart_IsolateFlags* api_flags);
  void FlagsCopyTo(Dart_IsolateFlags* api_flags) const;
  void FlagsCopyFrom(const Dart_IsolateFlags& api_flags);

#if defined(DART_PRECOMPILER)
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag)
#endif

#if !defined(PRODUCT)
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field)
#else
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag)
#endif

#define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field)

#define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name)      \
  bool name() const {                                                          \
    return FLAG_FOR_##when(isolate_flags_.Read<bitname##Bit>(), flag_name);    \
  }
  BOOL_ISOLATE_FLAG_LIST(DECLARE_GETTER)
#undef FLAG_FOR_NONPRODUCT
#undef FLAG_FOR_PRECOMPILER
#undef FLAG_FOR_PRODUCT
#undef DECLARE_GETTER

  // Kills all non-system isolates.
  static void KillAllIsolates(LibMsgId msg_id);
  // Kills all system isolates, excluding the kernel service and VM service.
  static void KillAllSystemIsolates(LibMsgId msg_id);
  static void KillIfExists(Isolate* isolate, LibMsgId msg_id);

  // Lookup an isolate by its main port and return a copy of its name. Returns
  // nullptr if not matching isolate is found.
  static std::unique_ptr<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);

  void RememberLiveTemporaries();
  void DeferredMarkLiveTemporaries();

  void init_loaded_prefixes_set_storage();
  bool IsPrefixLoaded(const LibraryPrefix& prefix) const;
  void SetPrefixIsLoaded(const LibraryPrefix& prefix);

  bool SetOwnerThread(ThreadId expected_old_owner, ThreadId new_owner);

  // Must be invoked with a valid PortMap::Locker, or while this isolate is the
  // current isolate (in which case the locker may be null).
  ThreadId GetOwnerThread(PortMap::Locker* locker);

 private:
  friend class Dart;                  // Init, InitOnce, Shutdown.
  friend class IsolateKillerVisitor;  // Kill().
  friend Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* g,
                                                   const char* n,
                                                   char** e);

  Isolate(IsolateGroup* group, const Dart_IsolateFlags& api_flags);

  static void InitVM();
  static Isolate* InitIsolate(const char* name_prefix,
                              IsolateGroup* isolate_group,
                              const Dart_IsolateFlags& api_flags);
  void FixInitiallyNullFields();

  // The isolate_creation_monitor_ should be held when calling Kill().
  void KillLocked(LibMsgId msg_id);

  void Shutdown();
  void RunAndCleanupFinalizersOnShutdown();
  void LowLevelShutdown();

  // Unregister the [isolate] from the thread, remove it from the isolate group,
  // invoke the cleanup function (if any), delete the isolate and possibly
  // delete the isolate group (if it's the last isolate in the group).
  static void LowLevelCleanup(Isolate* isolate);

  void BuildName(const char* name_prefix);

  void ProfileIdle();

  // Visit all object pointers. Caller must ensure concurrent sweeper is not
  // running, and the visitor must not allocate.
  void VisitObjectPointers(ObjectPointerVisitor* visitor,
                           ValidationPolicy validate_frames);
  void VisitStackPointers(ObjectPointerVisitor* visitor,
                          ValidationPolicy validate_frames);

  void set_is_system_isolate(bool is_system_isolate) {
    is_system_isolate_ = is_system_isolate;
  }

#if !defined(PRODUCT)
  GrowableObjectArrayPtr GetAndClearPendingServiceExtensionCalls();
  GrowableObjectArrayPtr pending_service_extension_calls() const {
    return pending_service_extension_calls_;
  }
  void set_pending_service_extension_calls(const GrowableObjectArray& value);
  GrowableObjectArrayPtr registered_service_extension_handlers() const {
    return registered_service_extension_handlers_;
  }
  void set_registered_service_extension_handlers(
      const GrowableObjectArray& value);
#endif  // !defined(PRODUCT)

  // Accessed from generated code.
  // ** This block of fields must come first! **
  // For AOT cross-compilation, we rely on these members having the same offsets
  // in SIMARM(IA32) and ARM, and the same offsets in SIMARM64(X64) and ARM64.
  // We use only word-sized fields to avoid differences in struct packing on the
  // different architectures. See also CheckOffsets in dart.cc.
  FieldTable* field_table_ = nullptr;
  // Used to clear out `UntaggedFinalizerBase::isolate_` pointers on isolate
  // shutdown to prevent usage of dangling pointers.
  GrowableObjectArrayPtr finalizers_;
  bool has_resumption_breakpoints_ = false;
  // End accessed from generated code.

  Thread* scheduled_mutator_thread_ = nullptr;
  // Stores the saved [Thread] object of a mutator. Mutators may retain their
  // thread even when being descheduled (e.g. due to having an active stack).
  Thread* mutator_thread_ = nullptr;

  IsolateGroup* const isolate_group_;
  std::unique_ptr<IsolateObjectStore> isolate_object_store_;

#define ISOLATE_FLAG_BITS(V)                                                   \
  V(ErrorsFatal)                                                               \
  V(IsRunnable)                                                                \
  V(IsVMIsolate)                                                               \
  V(IsServiceIsolate)                                                          \
  V(IsKernelIsolate)                                                           \
  V(ResumeRequest)                                                             \
  V(HasAttemptedStepping)                                                      \
  V(ShouldPausePostServiceRequest)                                             \
  V(IsSystemIsolate)                                                           \
  V(IsServiceRegistered)

  // Isolate specific flags.
  enum FlagBits {
#define DECLARE_BIT(Name) k##Name##Bit,
    ISOLATE_FLAG_BITS(DECLARE_BIT)
#undef DECLARE_BIT
  };

#define DECLARE_BITFIELD(Name)                                                 \
  using Name##Bit = BitField<uint32_t, bool, k##Name##Bit>;
  ISOLATE_FLAG_BITS(DECLARE_BITFIELD)
#undef DECLARE_BITFIELD

  AtomicBitFieldContainer<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;

  int64_t last_resume_timestamp_;

  VMTagCounters vm_tag_counters_;

  // We use 6 list entries for each pending service extension calls.
  enum {
    kPendingHandlerIndex = 0,
    kPendingMethodNameIndex,
    kPendingKeysIndex,
    kPendingValuesIndex,
    kPendingReplyPortIndex,
    kPendingIdIndex,
    kPendingEntrySize
  };
  GrowableObjectArrayPtr pending_service_extension_calls_;

  // We use 2 list entries for each registered extension handler.
  enum {
    kRegisteredNameIndex = 0,
    kRegisteredHandlerIndex,
    kRegisteredEntrySize
  };
  GrowableObjectArrayPtr registered_service_extension_handlers_;

  // Used to wake the isolate when it is in the pause event loop.
  Monitor* pause_loop_monitor_ = nullptr;

  // The map of Service ID zones is created lazily.
  MallocDirectChainedHashMap<IntKeyRawPointerValueTrait<RingServiceIdZone*>>*
      service_id_zones_;

  // Monotonically increasing counter used to assign unique IDs to non-default
  // Service ID zones.
  intptr_t next_service_id_zone_id_;

#define ISOLATE_METRIC_VARIABLE(type, variable, name, unit)                    \
  type metric_##variable##_;
  ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE);
#undef ISOLATE_METRIC_VARIABLE
#endif  // !defined(PRODUCT)

#if defined(DART_INCLUDE_PROFILER)
  // SampleBlock containing CPU profiling samples.
  RelaxedAtomic<SampleBlock*> current_sample_block_ = nullptr;

  // SampleBlock containing Dart allocation profiling samples.
  RelaxedAtomic<SampleBlock*> current_allocation_sample_block_ = nullptr;

  RelaxedAtomic<uword> has_completed_blocks_ = {0};
#endif

  // 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;
  uint64_t pause_capability_ = 0;
  uint64_t terminate_capability_ = 0;
  void* init_callback_data_ = nullptr;
  Dart_EnvironmentCallback environment_callback_ = nullptr;
  Simulator* simulator_ = nullptr;
  Mutex mutex_;  // Protects compiler stats.
  IsolateMessageHandler* message_handler_ = nullptr;
  intptr_t defer_finalization_count_ = 0;
  FfiCallbackMetadata::MetadataEntry* ffi_callback_list_head_ = nullptr;
  intptr_t ffi_callback_keep_alive_counter_ = 0;
  RelaxedAtomic<ThreadId> owner_thread_ = OSThread::kInvalidThreadId;
  bool is_permanently_pinned_ = false;
  bool is_acquirable_ = true;

  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;

  // Signals whether the isolate can receive messages (e.g. KillAllIsolates can
  // send a kill message).
  // This is protected by [isolate_creation_monitor_].
  bool accepts_messages_ = false;

  intptr_t wake_pause_event_handler_count_;

  // The number of open [ReceivePort]s the isolate owns.
  intptr_t open_ports_ = 0;

  // The number of open [ReceivePort]s that keep the isolate alive.
  intptr_t open_ports_keepalive_ = 0;

  static Dart_IsolateGroupCreateCallback create_group_callback_;
  static Dart_InitializeIsolateCallback initialize_callback_;
  static Dart_IsolateShutdownCallback shutdown_callback_;
  static Dart_IsolateCleanupCallback cleanup_callback_;
  static Dart_IsolateGroupCleanupCallback cleanup_group_callback_;

#if !defined(PRODUCT)
  static void WakePauseEventHandler(Dart_Isolate isolate);
#endif

  // Manage list of existing isolates.
  static bool TryMarkIsolateReady(Isolate* isolate);
  static void UnMarkIsolateReady(Isolate* isolate);
  static void MaybeNotifyVMShutdown();
  bool AcceptsMessagesLocked() {
    ASSERT(isolate_creation_monitor_->IsOwnedByCurrentThread());
    return accepts_messages_;
  }

  // This monitor protects [creation_enabled_] and [pending_shutdowns_].
  static Monitor* isolate_creation_monitor_;
  static bool creation_enabled_;
  static intptr_t pending_shutdowns_;

  ArrayPtr loaded_prefixes_set_storage_;

  bool is_system_isolate_ = false;

#define REUSABLE_FRIEND_DECLARATION(name)                                      \
  friend class Reusable##name##HandleScope;
  REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
#undef REUSABLE_FRIEND_DECLARATION

  friend class Become;       // VisitObjectPointers
  friend class GCCompactor;  // VisitObjectPointers
  friend class GCMarker;     // VisitObjectPointers
  friend class SafepointHandler;
  friend class ObjectGraph;         // VisitObjectPointers
  friend class HeapSnapshotWriter;  // VisitObjectPointers
  friend class Scavenger;           // VisitObjectPointers
  friend class HeapIterationScope;  // VisitObjectPointers
  friend class ServiceIsolate;
  friend class Thread;
  friend class Timeline;
  friend class IsolateGroup;  // reload_context_

  DISALLOW_COPY_AND_ASSIGN(Isolate);
};

// When we need to execute code in an isolate, we use the
// StartIsolateScope.
class StartIsolateScope {
 public:
  explicit StartIsolateScope(Isolate* new_isolate)
      : new_isolate_(new_isolate), saved_isolate_(Isolate::Current()) {
    if (new_isolate_ == nullptr) {
      ASSERT(Isolate::Current() == nullptr);
      // Do nothing.
      return;
    }
    if (saved_isolate_ != new_isolate_) {
      ASSERT(Isolate::Current() == nullptr);
      Thread::EnterIsolate(new_isolate_);
      // Ensure this is not a nested 'isolate enter' with prior state.
      ASSERT(Thread::Current()->top_exit_frame_info() == 0);
    }
  }

  ~StartIsolateScope() {
    if (new_isolate_ == nullptr) {
      ASSERT(Isolate::Current() == nullptr);
      // Do nothing.
      return;
    }
    if (saved_isolate_ != new_isolate_) {
      ASSERT(saved_isolate_ == nullptr);
      // ASSERT that we have bottomed out of all Dart invocations.
      ASSERT(Thread::Current()->top_exit_frame_info() == 0);
      Thread::ExitIsolate();
    }
  }

 private:
  Isolate* new_isolate_;
  Isolate* saved_isolate_;

  DISALLOW_COPY_AND_ASSIGN(StartIsolateScope);
};

class EnterIsolateGroupScope {
 public:
  explicit EnterIsolateGroupScope(IsolateGroup* isolate_group)
      : isolate_group_(isolate_group) {
    ASSERT(IsolateGroup::Current() == nullptr);
    Thread::EnterIsolateGroupAsHelper(isolate_group_, Thread::kUnknownTask,
                                      /*bypass_safepoint=*/false);
  }

  ~EnterIsolateGroupScope() {
    Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false);
  }

 private:
  IsolateGroup* isolate_group_;

  DISALLOW_COPY_AND_ASSIGN(EnterIsolateGroupScope);
};

// Ensure that isolate is not available for the duration of this scope.
//
// This can be used in code (e.g. GC, Kernel Loader, Compiler) that should not
// operate on an individual isolate.
class NoActiveIsolateScope : public StackResource {
 public:
  explicit NoActiveIsolateScope(bool allow_no_thread = false)
      : NoActiveIsolateScope(Thread::Current(), allow_no_thread) {}
  explicit NoActiveIsolateScope(Thread* thread, bool allow_no_thread = false)
      : StackResource(thread), thread_(thread) {
    ASSERT(allow_no_thread || thread_ != nullptr);
    if (thread_ != nullptr) {
      outer_ = thread_->no_active_isolate_scope_;
      saved_isolate_ = thread_->isolate_;

      thread_->no_active_isolate_scope_ = this;
      thread_->isolate_ = nullptr;
    }
  }
  ~NoActiveIsolateScope() {
    ASSERT(thread_ == nullptr || thread_->isolate_ == nullptr);
    ASSERT(thread_ != nullptr || saved_isolate_ == nullptr);
    if (thread_ != nullptr) {
      thread_->isolate_ = saved_isolate_;
      thread_->no_active_isolate_scope_ = outer_;
    }
  }

 private:
  friend class ActiveIsolateScope;

  Thread* thread_ = nullptr;
  Isolate* saved_isolate_ = nullptr;
  NoActiveIsolateScope* outer_ = nullptr;
};

class ActiveIsolateScope : public StackResource {
 public:
  explicit ActiveIsolateScope(Thread* thread)
      : ActiveIsolateScope(thread,
                           thread->no_active_isolate_scope_->saved_isolate_) {}

  ActiveIsolateScope(Thread* thread, Isolate* isolate)
      : StackResource(thread), thread_(thread) {
    RELEASE_ASSERT(thread->isolate() == nullptr);
    thread_->isolate_ = isolate;
  }
  ~ActiveIsolateScope() {
    ASSERT(thread_->isolate_ != nullptr);
    thread_->isolate_ = nullptr;
  }

 private:
  Thread* thread_;
};

}  // namespace dart

#endif  // RUNTIME_VM_ISOLATE_H_
