76c6282de6
This is a Dart-tailored implementation of the "row-displacement dispatch table" technique for closed-world instance calls: All interface targets in the program are grouped into selectors such that all targets that could potentially be called from the same call site have the same selector (currently just grouped by name). Each selector is assigned a selector offset such that offset + classid is unique for all selector/classid combinations where the class implements the selector. At every instance call site that has an interface target (i.e. where the static type of the receiver is not dynamic), the selector offset + receiver classid is computed and used as index into a global table of entry points. If the receiver can be null (as determined by the front-end TFA and the VM type propagation), a null check is inserted before the call. An arguments descriptor is provided (only) for selectors that need it (those which have type parameters or optional/named parameters). The dispatch table calls don't need the monomorphic entry code, so for functions that are only called via dispatch table calls (i.e. never called dynamically), the monomorphic entry code is left out. Some future improvements to the table dispatch implementation are mentioned in https://github.com/dart-lang/sdk/issues/40188 The table dispatch flag is disabled by default in this commit. A separate commit enables the flag. Change-Id: Ic2911742b4a2c9a8d3bc7df60605454cbe4c0714 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126648 Commit-Queue: Aske Simon Christensen <askesc@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
1462 lines
49 KiB
C++
1462 lines
49 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/constants_kbc.h"
|
|
#include "vm/exceptions.h"
|
|
#include "vm/ffi_callback_trampolines.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_stack_resource.h"
|
|
#include "vm/token_position.h"
|
|
#include "vm/virtual_memory.h"
|
|
|
|
namespace dart {
|
|
|
|
// Forward declarations.
|
|
class ApiState;
|
|
class BackgroundCompiler;
|
|
class Capability;
|
|
class CodeIndexTable;
|
|
class Debugger;
|
|
class DeoptContext;
|
|
class DispatchTable;
|
|
class ExternalTypedData;
|
|
class HandleScope;
|
|
class HandleVisitor;
|
|
class Heap;
|
|
class ICData;
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
class Interpreter;
|
|
#endif
|
|
class IsolateProfilerData;
|
|
class IsolateReloadContext;
|
|
class IsolateSpawnState;
|
|
class Log;
|
|
class Message;
|
|
class MessageHandler;
|
|
class MonitorLocker;
|
|
class Mutex;
|
|
class Object;
|
|
class ObjectIdRing;
|
|
class ObjectPointerVisitor;
|
|
class ObjectStore;
|
|
class RawInstance;
|
|
class RawArray;
|
|
class RawContext;
|
|
class RawDouble;
|
|
class RawError;
|
|
class RawField;
|
|
class RawGrowableObjectArray;
|
|
class RawMint;
|
|
class RawObject;
|
|
class RawInteger;
|
|
class RawFloat32x4;
|
|
class RawInt32x4;
|
|
class RawUserTag;
|
|
class ReversePcLookupCache;
|
|
class RwLock;
|
|
class SafepointHandler;
|
|
class SampleBuffer;
|
|
class SendPort;
|
|
class SerializedObjectBuffer;
|
|
class ServiceIdZone;
|
|
class Simulator;
|
|
class StackResource;
|
|
class StackZone;
|
|
class StoreBuffer;
|
|
class StubCode;
|
|
class ThreadRegistry;
|
|
class UserTag;
|
|
class WeakTable;
|
|
|
|
class PendingLazyDeopt {
|
|
public:
|
|
PendingLazyDeopt(uword fp, uword pc) : fp_(fp), pc_(pc) {}
|
|
uword fp() { return fp_; }
|
|
uword pc() { return pc_; }
|
|
void set_pc(uword pc) { pc_ = pc; }
|
|
|
|
private:
|
|
uword fp_;
|
|
uword pc_;
|
|
};
|
|
|
|
class IsolateVisitor {
|
|
public:
|
|
IsolateVisitor() {}
|
|
virtual ~IsolateVisitor() {}
|
|
|
|
virtual void VisitIsolate(Isolate* isolate) = 0;
|
|
|
|
protected:
|
|
// Returns true if |isolate| is the VM or service isolate.
|
|
bool IsVMInternalIsolate(Isolate* isolate) const;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(IsolateVisitor);
|
|
};
|
|
|
|
// Disallow OOB message handling within this scope.
|
|
class NoOOBMessageScope : public ThreadStackResource {
|
|
public:
|
|
explicit NoOOBMessageScope(Thread* thread);
|
|
~NoOOBMessageScope();
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(NoOOBMessageScope);
|
|
};
|
|
|
|
// Disallow isolate reload.
|
|
class NoReloadScope : public ThreadStackResource {
|
|
public:
|
|
NoReloadScope(Isolate* isolate, Thread* thread);
|
|
~NoReloadScope();
|
|
|
|
private:
|
|
Isolate* isolate_;
|
|
DISALLOW_COPY_AND_ASSIGN(NoReloadScope);
|
|
};
|
|
|
|
// Fixed cache for exception handler lookup.
|
|
typedef FixedCache<intptr_t, ExceptionHandlerInfo, 16> HandlerInfoCache;
|
|
// Fixed cache for catch entry state lookup.
|
|
typedef FixedCache<intptr_t, CatchEntryMovesRefPtr, 16> CatchEntryMovesCache;
|
|
|
|
// List of Isolate flags with corresponding members of Dart_IsolateFlags and
|
|
// corresponding global command line flags.
|
|
//
|
|
// V(when, name, bit-name, Dart_IsolateFlags-name, command-line-flag-name)
|
|
//
|
|
#define ISOLATE_FLAG_LIST(V) \
|
|
V(NONPRODUCT, asserts, EnableAsserts, enable_asserts, FLAG_enable_asserts) \
|
|
V(NONPRODUCT, use_field_guards, UseFieldGuards, use_field_guards, \
|
|
FLAG_use_field_guards) \
|
|
V(NONPRODUCT, use_osr, UseOsr, use_osr, FLAG_use_osr) \
|
|
V(PRECOMPILER, obfuscate, Obfuscate, obfuscate, false_by_default) \
|
|
V(PRODUCT, unsafe_trust_strong_mode_types, UnsafeTrustStrongModeTypes, \
|
|
unsafe_trust_strong_mode_types, \
|
|
FLAG_experimental_unsafe_mode_use_at_your_own_risk)
|
|
|
|
// Represents the information used for spawning the first isolate within an
|
|
// isolate group.
|
|
//
|
|
// Any subsequent isolates created via `Isolate.spawn()` will be created using
|
|
// the same [IsolateGroupSource] (the object itself is shared among all isolates
|
|
// within the same group).
|
|
//
|
|
// Issue(http://dartbug.com/36097): It is still possible to run into issues if
|
|
// an isolate has spawned another one and then loads more code into the first
|
|
// one, which the latter will not get. Though it makes the status quo better
|
|
// than what we had before (where the embedder needed to maintain the
|
|
// same-source guarantee).
|
|
//
|
|
// => This is only the first step towards having multiple isolates share the
|
|
// same heap (and therefore the same program structure).
|
|
//
|
|
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),
|
|
name(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) {}
|
|
~IsolateGroupSource() { free(name); }
|
|
|
|
// The arguments used for spawning in
|
|
// `Dart_CreateIsolateGroupFromKernel` / `Dart_CreateIsolate`.
|
|
const 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;
|
|
};
|
|
|
|
// 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_;
|
|
};
|
|
|
|
// Represents an isolate group and is shared among all isolates within a group.
|
|
class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
|
|
public:
|
|
IsolateGroup(std::unique_ptr<IsolateGroupSource> source, void* embedder_data);
|
|
~IsolateGroup();
|
|
|
|
IsolateGroupSource* source() const { return source_.get(); }
|
|
void* embedder_data() const { return embedder_data_; }
|
|
|
|
void set_initial_spawn_successful() { initial_spawn_successful_ = true; }
|
|
|
|
void RegisterIsolate(Isolate* isolate);
|
|
void UnregisterIsolate(Isolate* isolate);
|
|
|
|
Monitor* threads_lock() const;
|
|
ThreadRegistry* thread_registry() const { return thread_registry_.get(); }
|
|
SafepointHandler* safepoint_handler() { return safepoint_handler_.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);
|
|
|
|
Dart_LibraryTagHandler library_tag_handler() const {
|
|
return library_tag_handler_;
|
|
}
|
|
void set_library_tag_handler(Dart_LibraryTagHandler handler) {
|
|
library_tag_handler_ = handler;
|
|
}
|
|
|
|
// Runs the given [function] on every isolate in the isolate group.
|
|
//
|
|
// During the duration of this function, no new isolates can be added to the
|
|
// isolate group.
|
|
void ForEachIsolate(std::function<void(Isolate* isolate)> function);
|
|
|
|
// 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 RunWithStoppedMutators(std::function<void()> single_current_mutator,
|
|
std::function<void()> otherwise,
|
|
bool use_force_growth_in_otherwise = false);
|
|
|
|
void RunWithStoppedMutators(std::function<void()> function) {
|
|
RunWithStoppedMutators(function, function);
|
|
}
|
|
|
|
#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();
|
|
}
|
|
|
|
void DeleteReloadContext();
|
|
|
|
bool IsReloading() const { return group_reload_context_ != nullptr; }
|
|
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
uint64_t id() { 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);
|
|
|
|
private:
|
|
void* embedder_data_ = nullptr;
|
|
|
|
std::unique_ptr<RwLock> isolates_rwlock_;
|
|
IntrusiveDList<Isolate> isolates_;
|
|
intptr_t isolate_count_ = 0;
|
|
bool initial_spawn_successful_ = false;
|
|
Dart_LibraryTagHandler library_tag_handler_ = nullptr;
|
|
|
|
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
|
int64_t last_reload_timestamp_;
|
|
std::shared_ptr<IsolateGroupReloadContext> group_reload_context_;
|
|
#endif
|
|
|
|
std::unique_ptr<IsolateGroupSource> source_;
|
|
std::unique_ptr<ThreadRegistry> thread_registry_;
|
|
std::unique_ptr<SafepointHandler> safepoint_handler_;
|
|
|
|
static RwLock* isolate_groups_rwlock_;
|
|
static IntrusiveDList<IsolateGroup>* isolate_groups_;
|
|
|
|
Random isolate_group_random_;
|
|
uint64_t id_ = isolate_group_random_.NextUInt64();
|
|
};
|
|
|
|
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.
|
|
kLowMemoryMsg = 12, // Run compactor, etc.
|
|
kDrainServiceExtensionsMsg = 13, // Invoke pending service extensions
|
|
};
|
|
// 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();
|
|
}
|
|
|
|
// Register a newly introduced class.
|
|
void RegisterClass(const Class& cls);
|
|
#if defined(DEBUG)
|
|
void ValidateClassTable();
|
|
#endif
|
|
// Register a newly introduced static field.
|
|
void RegisterStaticField(const Field& field);
|
|
|
|
void RehashConstants();
|
|
#if defined(DEBUG)
|
|
void ValidateConstants();
|
|
#endif
|
|
|
|
// Visits weak object pointers.
|
|
void VisitWeakPersistentHandles(HandleVisitor* visitor);
|
|
|
|
// Prepares all threads in an isolate for Garbage Collection.
|
|
void ReleaseStoreBuffers();
|
|
void EnableIncrementalBarrier(MarkingStack* marking_stack,
|
|
MarkingStack* deferred_marking_stack);
|
|
void DisableIncrementalBarrier();
|
|
|
|
StoreBuffer* store_buffer() const { return store_buffer_; }
|
|
MarkingStack* marking_stack() const { return marking_stack_; }
|
|
MarkingStack* deferred_marking_stack() const {
|
|
return deferred_marking_stack_;
|
|
}
|
|
|
|
ThreadRegistry* thread_registry() const { return group()->thread_registry(); }
|
|
|
|
SafepointHandler* safepoint_handler() const {
|
|
return group()->safepoint_handler();
|
|
}
|
|
|
|
SharedClassTable* shared_class_table() { return shared_class_table_.get(); }
|
|
|
|
ClassTable* class_table() { return &class_table_; }
|
|
static intptr_t class_table_offset() {
|
|
return OFFSET_OF(Isolate, class_table_);
|
|
}
|
|
|
|
FieldTable* field_table() const { return field_table_; }
|
|
|
|
// Prefers old classes when we are in the middle of a reload.
|
|
RawClass* GetClassForHeapWalkAt(intptr_t cid);
|
|
intptr_t GetClassSizeForHeapWalkAt(intptr_t cid);
|
|
|
|
static intptr_t ic_miss_code_offset() {
|
|
return OFFSET_OF(Isolate, ic_miss_code_);
|
|
}
|
|
|
|
Dart_MessageNotifyCallback message_notify_callback() const {
|
|
return message_notify_callback_;
|
|
}
|
|
|
|
void set_message_notify_callback(Dart_MessageNotifyCallback value) {
|
|
message_notify_callback_ = value;
|
|
}
|
|
|
|
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() const { return origin_id_; }
|
|
void set_origin_id(Dart_Port id) {
|
|
ASSERT((id == main_port_ && origin_id_ == 0) || (origin_id_ == main_port_));
|
|
origin_id_ = id;
|
|
}
|
|
void set_pause_capability(uint64_t value) { pause_capability_ = value; }
|
|
uint64_t pause_capability() const { return pause_capability_; }
|
|
void set_terminate_capability(uint64_t value) {
|
|
terminate_capability_ = value;
|
|
}
|
|
uint64_t terminate_capability() const { return terminate_capability_; }
|
|
|
|
void SendInternalLibMessage(LibMsgId msg_id, uint64_t capability);
|
|
|
|
IdleTimeHandler* idle_time_handler() { return &idle_time_handler_; }
|
|
|
|
Heap* heap() const { return heap_; }
|
|
void set_heap(Heap* value) {
|
|
idle_time_handler_.InitializeWithHeap(value);
|
|
heap_ = value;
|
|
}
|
|
|
|
ObjectStore* object_store() const { return object_store_; }
|
|
void set_object_store(ObjectStore* value) { object_store_ = value; }
|
|
static intptr_t object_store_offset() {
|
|
return OFFSET_OF(Isolate, object_store_);
|
|
}
|
|
|
|
ApiState* api_state() const { return api_state_; }
|
|
void set_api_state(ApiState* value) { api_state_ = value; }
|
|
|
|
void set_init_callback_data(void* value) { init_callback_data_ = value; }
|
|
void* init_callback_data() const { return init_callback_data_; }
|
|
|
|
#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 HasTagHandler() const {
|
|
return group()->library_tag_handler() != nullptr;
|
|
}
|
|
RawObject* CallTagHandler(Dart_LibraryTag tag,
|
|
const Object& arg1,
|
|
const Object& arg2);
|
|
|
|
void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable);
|
|
|
|
void ScheduleInterrupts(uword interrupt_bits);
|
|
|
|
const char* MakeRunnable();
|
|
void Run();
|
|
|
|
MessageHandler* message_handler() const { return message_handler_; }
|
|
void set_message_handler(MessageHandler* value) { message_handler_ = value; }
|
|
|
|
bool is_runnable() const { return IsRunnableBit::decode(isolate_flags_); }
|
|
void set_is_runnable(bool value) {
|
|
isolate_flags_ = IsRunnableBit::update(value, isolate_flags_);
|
|
#if !defined(PRODUCT)
|
|
if (is_runnable()) {
|
|
set_last_resume_timestamp();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool compaction_in_progress() const {
|
|
return CompactionInProgressBit::decode(isolate_flags_);
|
|
}
|
|
void set_compaction_in_progress(bool value) {
|
|
isolate_flags_ = CompactionInProgressBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
IsolateSpawnState* spawn_state() const { return spawn_state_.get(); }
|
|
void set_spawn_state(std::unique_ptr<IsolateSpawnState> value) {
|
|
spawn_state_ = std::move(value);
|
|
}
|
|
|
|
Mutex* mutex() { return &mutex_; }
|
|
Mutex* symbols_mutex() { return &symbols_mutex_; }
|
|
Mutex* type_canonicalization_mutex() { return &type_canonicalization_mutex_; }
|
|
Mutex* constant_canonicalization_mutex() {
|
|
return &constant_canonicalization_mutex_;
|
|
}
|
|
Mutex* megamorphic_mutex() { return &megamorphic_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_;
|
|
}
|
|
|
|
// Any access to constants arrays must be locked since mutator and
|
|
// background compiler can access the arrays at the same time.
|
|
Mutex* kernel_constants_mutex() { return &kernel_constants_mutex_; }
|
|
|
|
#if !defined(PRODUCT)
|
|
Debugger* debugger() const {
|
|
ASSERT(debugger_ != nullptr);
|
|
return debugger_;
|
|
}
|
|
|
|
void set_single_step(bool value) { single_step_ = value; }
|
|
bool single_step() const { return single_step_; }
|
|
static intptr_t single_step_offset() {
|
|
return OFFSET_OF(Isolate, single_step_);
|
|
}
|
|
|
|
bool ResumeRequest() const {
|
|
return ResumeRequestBit::decode(isolate_flags_);
|
|
}
|
|
// Lets the embedder know that a service message resulted in a resume request.
|
|
void SetResumeRequest() {
|
|
isolate_flags_ = ResumeRequestBit::update(true, isolate_flags_);
|
|
set_last_resume_timestamp();
|
|
}
|
|
|
|
void set_last_resume_timestamp() {
|
|
last_resume_timestamp_ = OS::GetCurrentTimeMillis();
|
|
}
|
|
|
|
int64_t last_resume_timestamp() const { return last_resume_timestamp_; }
|
|
|
|
// Returns whether the vm service has requested that the debugger
|
|
// resume execution.
|
|
bool GetAndClearResumeRequest() {
|
|
bool resume_request = ResumeRequestBit::decode(isolate_flags_);
|
|
isolate_flags_ = ResumeRequestBit::update(false, isolate_flags_);
|
|
return resume_request;
|
|
}
|
|
#endif
|
|
|
|
// Verify that the sender has the capability to pause or terminate the
|
|
// isolate.
|
|
bool VerifyPauseCapability(const Object& capability) const;
|
|
bool VerifyTerminateCapability(const Object& capability) const;
|
|
|
|
// Returns true if the capability was added or removed from this isolate's
|
|
// list of pause events.
|
|
bool AddResumeCapability(const Capability& capability);
|
|
bool RemoveResumeCapability(const Capability& capability);
|
|
|
|
void AddExitListener(const SendPort& listener, const Instance& response);
|
|
void RemoveExitListener(const SendPort& listener);
|
|
void NotifyExitListeners();
|
|
|
|
void AddErrorListener(const SendPort& listener);
|
|
void RemoveErrorListener(const SendPort& listener);
|
|
bool NotifyErrorListeners(const String& msg, const String& stacktrace);
|
|
|
|
bool ErrorsFatal() const { return ErrorsFatalBit::decode(isolate_flags_); }
|
|
void SetErrorsFatal(bool val) {
|
|
isolate_flags_ = ErrorsFatalBit::update(val, isolate_flags_);
|
|
}
|
|
|
|
Random* random() { return &random_; }
|
|
|
|
Simulator* simulator() const { return simulator_; }
|
|
void set_simulator(Simulator* value) { simulator_ = value; }
|
|
|
|
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_;
|
|
}
|
|
|
|
#if !defined(PRODUCT)
|
|
void set_object_id_ring(ObjectIdRing* ring) { object_id_ring_ = ring; }
|
|
ObjectIdRing* object_id_ring() { return object_id_ring_; }
|
|
#endif // !defined(PRODUCT)
|
|
|
|
void AddPendingDeopt(uword fp, uword pc);
|
|
uword FindPendingDeopt(uword fp) const;
|
|
void ClearPendingDeoptsAtOrBelow(uword fp) const;
|
|
MallocGrowableArray<PendingLazyDeopt>* pending_deopts() const {
|
|
return pending_deopts_;
|
|
}
|
|
bool IsDeoptimizing() const { return deopt_context_ != nullptr; }
|
|
DeoptContext* deopt_context() const { return deopt_context_; }
|
|
void set_deopt_context(DeoptContext* value) {
|
|
ASSERT(value == nullptr || deopt_context_ == nullptr);
|
|
deopt_context_ = value;
|
|
}
|
|
|
|
BackgroundCompiler* background_compiler() const {
|
|
return background_compiler_;
|
|
}
|
|
|
|
BackgroundCompiler* optimizing_background_compiler() const {
|
|
return optimizing_background_compiler_;
|
|
}
|
|
|
|
#if !defined(PRODUCT)
|
|
void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
|
|
last_allocationprofile_accumulator_reset_timestamp_ =
|
|
OS::GetCurrentTimeMillis();
|
|
}
|
|
|
|
int64_t last_allocationprofile_accumulator_reset_timestamp() const {
|
|
return last_allocationprofile_accumulator_reset_timestamp_;
|
|
}
|
|
|
|
void UpdateLastAllocationProfileGCTimestamp() {
|
|
last_allocationprofile_gc_timestamp_ = OS::GetCurrentTimeMillis();
|
|
}
|
|
|
|
int64_t last_allocationprofile_gc_timestamp() const {
|
|
return last_allocationprofile_gc_timestamp_;
|
|
}
|
|
#endif // !defined(PRODUCT)
|
|
|
|
intptr_t BlockClassFinalization() {
|
|
ASSERT(defer_finalization_count_ >= 0);
|
|
return defer_finalization_count_++;
|
|
}
|
|
|
|
intptr_t UnblockClassFinalization() {
|
|
ASSERT(defer_finalization_count_ > 0);
|
|
return defer_finalization_count_--;
|
|
}
|
|
|
|
bool AllowClassFinalization() {
|
|
ASSERT(defer_finalization_count_ >= 0);
|
|
return defer_finalization_count_ == 0;
|
|
}
|
|
|
|
#ifndef PRODUCT
|
|
void PrintJSON(JSONStream* stream, bool ref = true);
|
|
|
|
// 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_; }
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
IsolateReloadContext* reload_context() { return reload_context_; }
|
|
|
|
void DeleteReloadContext();
|
|
|
|
bool HasAttemptedReload() const {
|
|
return HasAttemptedReloadBit::decode(isolate_flags_);
|
|
}
|
|
void SetHasAttemptedReload(bool value) {
|
|
isolate_flags_ = HasAttemptedReloadBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
bool CanReload() const;
|
|
#else
|
|
bool IsReloading() const { return false; }
|
|
bool HasAttemptedReload() const { return false; }
|
|
bool CanReload() const { return false; }
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
#endif // !defined(PRODUCT)
|
|
|
|
bool IsPaused() const;
|
|
|
|
#if !defined(PRODUCT)
|
|
bool should_pause_post_service_request() const {
|
|
return ShouldPausePostServiceRequestBit::decode(isolate_flags_);
|
|
}
|
|
void set_should_pause_post_service_request(bool value) {
|
|
isolate_flags_ =
|
|
ShouldPausePostServiceRequestBit::update(value, isolate_flags_);
|
|
}
|
|
#endif // !defined(PRODUCT)
|
|
|
|
RawError* PausePostRequest();
|
|
|
|
uword user_tag() const { return user_tag_; }
|
|
static intptr_t user_tag_offset() { return OFFSET_OF(Isolate, user_tag_); }
|
|
static intptr_t current_tag_offset() {
|
|
return OFFSET_OF(Isolate, current_tag_);
|
|
}
|
|
static intptr_t default_tag_offset() {
|
|
return OFFSET_OF(Isolate, default_tag_);
|
|
}
|
|
|
|
#if !defined(PRODUCT)
|
|
#define ISOLATE_METRIC_ACCESSOR(type, variable, name, unit) \
|
|
type* Get##variable##Metric() { return &metric_##variable##_; }
|
|
ISOLATE_METRIC_LIST(ISOLATE_METRIC_ACCESSOR);
|
|
#undef ISOLATE_METRIC_ACCESSOR
|
|
#endif // !defined(PRODUCT)
|
|
|
|
static intptr_t IsolateListLength();
|
|
|
|
RawGrowableObjectArray* tag_table() const { return tag_table_; }
|
|
void set_tag_table(const GrowableObjectArray& value);
|
|
|
|
RawUserTag* current_tag() const { return current_tag_; }
|
|
void set_current_tag(const UserTag& tag);
|
|
|
|
RawUserTag* default_tag() const { return default_tag_; }
|
|
void set_default_tag(const UserTag& tag);
|
|
|
|
void set_ic_miss_code(const Code& code);
|
|
|
|
#if !defined(PRODUCT)
|
|
Metric* metrics_list_head() { return metrics_list_head_; }
|
|
void set_metrics_list_head(Metric* metric) { metrics_list_head_ = metric; }
|
|
#endif // !defined(PRODUCT)
|
|
|
|
RawGrowableObjectArray* deoptimized_code_array() const {
|
|
return deoptimized_code_array_;
|
|
}
|
|
void set_deoptimized_code_array(const GrowableObjectArray& value);
|
|
void TrackDeoptimizedCode(const Code& code);
|
|
|
|
// Also sends a paused at exit event over the service protocol.
|
|
void SetStickyError(RawError* sticky_error);
|
|
|
|
RawError* sticky_error() const { return sticky_error_; }
|
|
DART_WARN_UNUSED_RESULT RawError* StealStickyError();
|
|
|
|
bool compilation_allowed() const {
|
|
return CompilationAllowedBit::decode(isolate_flags_);
|
|
}
|
|
void set_compilation_allowed(bool allowed) {
|
|
isolate_flags_ = CompilationAllowedBit::update(allowed, isolate_flags_);
|
|
}
|
|
|
|
// In precompilation we finalize all regular classes before compiling.
|
|
bool all_classes_finalized() const {
|
|
return AllClassesFinalizedBit::decode(isolate_flags_);
|
|
}
|
|
void set_all_classes_finalized(bool value) {
|
|
isolate_flags_ = AllClassesFinalizedBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
bool remapping_cids() const {
|
|
return RemappingCidsBit::decode(isolate_flags_);
|
|
}
|
|
void set_remapping_cids(bool value) {
|
|
isolate_flags_ = RemappingCidsBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
// Used by background compiler which field became boxed and must trigger
|
|
// deoptimization in the mutator thread.
|
|
void AddDeoptimizingBoxedField(const Field& field);
|
|
// Returns Field::null() if none available in the list.
|
|
RawField* GetDeoptimizingBoxedField();
|
|
|
|
#ifndef PRODUCT
|
|
RawError* InvokePendingServiceExtensionCalls();
|
|
void AppendServiceExtensionCall(const Instance& closure,
|
|
const String& method_name,
|
|
const Array& parameter_keys,
|
|
const Array& parameter_values,
|
|
const Instance& reply_port,
|
|
const Instance& id);
|
|
void RegisterServiceExtensionHandler(const String& name,
|
|
const Instance& closure);
|
|
RawInstance* LookupServiceExtensionHandler(const String& name);
|
|
#endif
|
|
|
|
static void VisitIsolates(IsolateVisitor* visitor);
|
|
|
|
#if !defined(PRODUCT)
|
|
// Handle service messages until we are told to resume execution.
|
|
void PauseEventHandler();
|
|
#endif
|
|
|
|
void AddClosureFunction(const Function& function) const;
|
|
RawFunction* LookupClosureFunction(const Function& parent,
|
|
TokenPosition token_pos) const;
|
|
intptr_t FindClosureIndex(const Function& needle) const;
|
|
RawFunction* ClosureFunctionFromIndex(intptr_t idx) const;
|
|
|
|
bool is_service_isolate() const {
|
|
return IsServiceIsolateBit::decode(isolate_flags_);
|
|
}
|
|
void set_is_service_isolate(bool value) {
|
|
isolate_flags_ = IsServiceIsolateBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
bool is_kernel_isolate() const {
|
|
return IsKernelIsolateBit::decode(isolate_flags_);
|
|
}
|
|
void set_is_kernel_isolate(bool value) {
|
|
isolate_flags_ = IsKernelIsolateBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
bool can_use_strong_mode_types() const {
|
|
return FLAG_use_strong_mode_types && !unsafe_trust_strong_mode_types();
|
|
}
|
|
|
|
// Whether it's possible for unoptimized code to optimize immediately on entry
|
|
// (can happen with random or very low optimization counter thresholds)
|
|
bool CanOptimizeImmediately() const {
|
|
return FLAG_optimization_counter_threshold < 2 ||
|
|
FLAG_randomize_optimization_counter;
|
|
}
|
|
|
|
bool should_load_vmservice() const {
|
|
return ShouldLoadVmServiceBit::decode(isolate_flags_);
|
|
}
|
|
void set_should_load_vmservice(bool value) {
|
|
isolate_flags_ = ShouldLoadVmServiceBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
Dart_QualifiedFunctionName* embedder_entry_points() const {
|
|
return embedder_entry_points_;
|
|
}
|
|
|
|
void set_obfuscation_map(const char** map) { obfuscation_map_ = map; }
|
|
const char** obfuscation_map() const { return obfuscation_map_; }
|
|
|
|
const DispatchTable* dispatch_table() const { return dispatch_table_; }
|
|
void set_dispatch_table(DispatchTable* table) { dispatch_table_ = table; }
|
|
|
|
// Returns the pc -> code lookup cache object for this isolate.
|
|
ReversePcLookupCache* reverse_pc_lookup_cache() const {
|
|
return reverse_pc_lookup_cache_;
|
|
}
|
|
|
|
// Sets the pc -> code lookup cache object for this isolate.
|
|
void set_reverse_pc_lookup_cache(ReversePcLookupCache* table) {
|
|
ASSERT(reverse_pc_lookup_cache_ == nullptr);
|
|
reverse_pc_lookup_cache_ = table;
|
|
}
|
|
|
|
// Isolate-specific flag handling.
|
|
static void FlagsInitialize(Dart_IsolateFlags* api_flags);
|
|
void FlagsCopyTo(Dart_IsolateFlags* api_flags) const;
|
|
void FlagsCopyFrom(const Dart_IsolateFlags& api_flags);
|
|
|
|
#if defined(DART_PRECOMPILER)
|
|
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_field)
|
|
#else
|
|
#define FLAG_FOR_PRECOMPILER(from_field, from_flag) (from_flag)
|
|
#endif
|
|
|
|
#if !defined(PRODUCT)
|
|
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_field)
|
|
#else
|
|
#define FLAG_FOR_NONPRODUCT(from_field, from_flag) (from_flag)
|
|
#endif
|
|
|
|
#define FLAG_FOR_PRODUCT(from_field, from_flag) (from_field)
|
|
|
|
#define DECLARE_GETTER(when, name, bitname, isolate_flag_name, flag_name) \
|
|
bool name() const { \
|
|
const bool false_by_default = false; \
|
|
USE(false_by_default); \
|
|
return FLAG_FOR_##when(bitname##Bit::decode(isolate_flags_), flag_name); \
|
|
}
|
|
ISOLATE_FLAG_LIST(DECLARE_GETTER)
|
|
#undef FLAG_FOR_NONPRODUCT
|
|
#undef FLAG_FOR_PRECOMPILER
|
|
#undef FLAG_FOR_PRODUCT
|
|
#undef DECLARE_GETTER
|
|
|
|
#if defined(PRODUCT)
|
|
void set_use_osr(bool use_osr) { ASSERT(!use_osr); }
|
|
#else // defined(PRODUCT)
|
|
void set_use_osr(bool use_osr) {
|
|
isolate_flags_ = UseOsrBit::update(use_osr, isolate_flags_);
|
|
}
|
|
#endif // defined(PRODUCT)
|
|
|
|
// Convenience flag tester indicating whether incoming function arguments
|
|
// should be type checked.
|
|
bool argument_type_checks() const { return should_emit_strong_mode_checks(); }
|
|
|
|
bool should_emit_strong_mode_checks() const {
|
|
return !unsafe_trust_strong_mode_types();
|
|
}
|
|
|
|
bool has_attempted_stepping() const {
|
|
return HasAttemptedSteppingBit::decode(isolate_flags_);
|
|
}
|
|
void set_has_attempted_stepping(bool value) {
|
|
isolate_flags_ = HasAttemptedSteppingBit::update(value, isolate_flags_);
|
|
}
|
|
|
|
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 IsVMInternalIsolate(const Isolate* isolate);
|
|
|
|
#if !defined(PRODUCT)
|
|
intptr_t reload_every_n_stack_overflow_checks() const {
|
|
return reload_every_n_stack_overflow_checks_;
|
|
}
|
|
#endif // !defined(PRODUCT)
|
|
|
|
HandlerInfoCache* handler_info_cache() { return &handler_info_cache_; }
|
|
|
|
CatchEntryMovesCache* catch_entry_moves_cache() {
|
|
return &catch_entry_moves_cache_;
|
|
}
|
|
|
|
void MaybeIncreaseReloadEveryNStackOverflowChecks();
|
|
|
|
// 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);
|
|
|
|
static void NotifyLowMemory();
|
|
|
|
private:
|
|
friend class Dart; // Init, InitOnce, Shutdown.
|
|
friend class IsolateKillerVisitor; // Kill().
|
|
|
|
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 isolates_list_monitor_ should be held when calling Kill().
|
|
void KillLocked(LibMsgId msg_id);
|
|
|
|
void LowLevelShutdown();
|
|
void Shutdown();
|
|
|
|
void BuildName(const char* name_prefix);
|
|
|
|
void ProfileIdle();
|
|
|
|
// Visit all object pointers. Caller must ensure concurrent sweeper is not
|
|
// running, and the visitor must not allocate.
|
|
void VisitObjectPointers(ObjectPointerVisitor* visitor,
|
|
ValidationPolicy validate_frames);
|
|
void VisitStackPointers(ObjectPointerVisitor* visitor,
|
|
ValidationPolicy validate_frames);
|
|
|
|
void set_user_tag(uword tag) { user_tag_ = tag; }
|
|
|
|
#if !defined(PRODUCT)
|
|
RawGrowableObjectArray* GetAndClearPendingServiceExtensionCalls();
|
|
RawGrowableObjectArray* pending_service_extension_calls() const {
|
|
return pending_service_extension_calls_;
|
|
}
|
|
void set_pending_service_extension_calls(const GrowableObjectArray& value);
|
|
RawGrowableObjectArray* registered_service_extension_handlers() const {
|
|
return registered_service_extension_handlers_;
|
|
}
|
|
void set_registered_service_extension_handlers(
|
|
const GrowableObjectArray& value);
|
|
#endif // !defined(PRODUCT)
|
|
|
|
Monitor* threads_lock() { return isolate_group_->threads_lock(); }
|
|
Thread* ScheduleThread(bool is_mutator, bool bypass_safepoint = false);
|
|
void UnscheduleThread(Thread* thread,
|
|
bool is_mutator,
|
|
bool bypass_safepoint = false);
|
|
|
|
// DEPRECATED: Use Thread's methods instead. During migration, these default
|
|
// to using the mutator thread (which must also be the current thread).
|
|
Zone* current_zone() const {
|
|
ASSERT(Thread::Current() == mutator_thread());
|
|
return mutator_thread()->zone();
|
|
}
|
|
|
|
// Accessed from generated code.
|
|
// ** This block of fields must come first! **
|
|
// For AOT cross-compilation, we rely on these members having the same offsets
|
|
// in SIMARM(IA32) and ARM, and the same offsets in SIMARM64(X64) and ARM64.
|
|
// We use only word-sized fields to avoid differences in struct packing on the
|
|
// different architectures. See also CheckOffsets in dart.cc.
|
|
uword user_tag_ = 0;
|
|
RawUserTag* current_tag_;
|
|
RawUserTag* default_tag_;
|
|
RawCode* ic_miss_code_;
|
|
std::unique_ptr<SharedClassTable> shared_class_table_;
|
|
ObjectStore* object_store_ = nullptr;
|
|
ClassTable class_table_;
|
|
FieldTable* field_table_ = nullptr;
|
|
bool single_step_ = false;
|
|
// End accessed from generated code.
|
|
|
|
StoreBuffer* store_buffer_ = nullptr;
|
|
MarkingStack* marking_stack_ = nullptr;
|
|
MarkingStack* deferred_marking_stack_ = nullptr;
|
|
Heap* heap_ = nullptr;
|
|
IsolateGroup* isolate_group_ = nullptr;
|
|
IdleTimeHandler idle_time_handler_;
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
NativeCallbackTrampolines native_callback_trampolines_;
|
|
#endif
|
|
|
|
#define ISOLATE_FLAG_BITS(V) \
|
|
V(ErrorsFatal) \
|
|
V(IsRunnable) \
|
|
V(IsServiceIsolate) \
|
|
V(IsKernelIsolate) \
|
|
V(CompilationAllowed) \
|
|
V(AllClassesFinalized) \
|
|
V(RemappingCids) \
|
|
V(ResumeRequest) \
|
|
V(HasAttemptedReload) \
|
|
V(HasAttemptedStepping) \
|
|
V(ShouldPausePostServiceRequest) \
|
|
V(EnableAsserts) \
|
|
V(UseFieldGuards) \
|
|
V(UseOsr) \
|
|
V(Obfuscate) \
|
|
V(CompactionInProgress) \
|
|
V(ShouldLoadVmService) \
|
|
V(UnsafeTrustStrongModeTypes)
|
|
|
|
// Isolate specific flags.
|
|
enum FlagBits {
|
|
#define DECLARE_BIT(Name) k##Name##Bit,
|
|
ISOLATE_FLAG_BITS(DECLARE_BIT)
|
|
#undef DECLARE_BIT
|
|
};
|
|
|
|
#define DECLARE_BITFIELD(Name) \
|
|
class Name##Bit : public BitField<uint32_t, bool, k##Name##Bit, 1> {};
|
|
ISOLATE_FLAG_BITS(DECLARE_BITFIELD)
|
|
#undef DECLARE_BITFIELD
|
|
|
|
uint32_t isolate_flags_ = 0;
|
|
|
|
// Unoptimized background compilation.
|
|
BackgroundCompiler* background_compiler_ = nullptr;
|
|
|
|
// Optimized background compilation.
|
|
BackgroundCompiler* optimizing_background_compiler_ = nullptr;
|
|
|
|
// 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_;
|
|
|
|
// Timestamps of last operation via service.
|
|
int64_t last_allocationprofile_accumulator_reset_timestamp_ = 0;
|
|
int64_t last_allocationprofile_gc_timestamp_ = 0;
|
|
|
|
VMTagCounters vm_tag_counters_;
|
|
|
|
// We use 6 list entries for each pending service extension calls.
|
|
enum {kPendingHandlerIndex = 0, kPendingMethodNameIndex, kPendingKeysIndex,
|
|
kPendingValuesIndex, kPendingReplyPortIndex, kPendingIdIndex,
|
|
kPendingEntrySize};
|
|
RawGrowableObjectArray* pending_service_extension_calls_;
|
|
|
|
// We use 2 list entries for each registered extension handler.
|
|
enum {kRegisteredNameIndex = 0, kRegisteredHandlerIndex,
|
|
kRegisteredEntrySize};
|
|
RawGrowableObjectArray* registered_service_extension_handlers_;
|
|
|
|
Metric* metrics_list_head_ = nullptr;
|
|
|
|
// 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
|
|
|
|
RelaxedAtomic<intptr_t> no_reload_scope_depth_ =
|
|
0; // we can only reload when this is 0.
|
|
// Per-isolate copy of FLAG_reload_every.
|
|
intptr_t reload_every_n_stack_overflow_checks_;
|
|
IsolateReloadContext* reload_context_ = nullptr;
|
|
// 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_;
|
|
Dart_MessageNotifyCallback message_notify_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;
|
|
uint64_t pause_capability_ = 0;
|
|
uint64_t terminate_capability_ = 0;
|
|
void* init_callback_data_ = nullptr;
|
|
Dart_EnvironmentCallback environment_callback_ = nullptr;
|
|
ApiState* api_state_ = nullptr;
|
|
Random random_;
|
|
Simulator* simulator_ = nullptr;
|
|
Mutex mutex_; // Protects compiler stats.
|
|
Mutex symbols_mutex_; // Protects concurrent access to the symbol table.
|
|
Mutex type_canonicalization_mutex_; // Protects type canonicalization.
|
|
Mutex constant_canonicalization_mutex_; // Protects const canonicalization.
|
|
Mutex megamorphic_mutex_; // Protects the table of megamorphic caches and
|
|
// their entries.
|
|
Mutex kernel_data_lib_cache_mutex_;
|
|
Mutex kernel_data_class_cache_mutex_;
|
|
Mutex kernel_constants_mutex_;
|
|
MessageHandler* message_handler_ = nullptr;
|
|
std::unique_ptr<IsolateSpawnState> spawn_state_;
|
|
intptr_t defer_finalization_count_ = 0;
|
|
MallocGrowableArray<PendingLazyDeopt>* pending_deopts_;
|
|
DeoptContext* deopt_context_ = nullptr;
|
|
|
|
RawGrowableObjectArray* tag_table_;
|
|
|
|
RawGrowableObjectArray* deoptimized_code_array_;
|
|
|
|
RawError* sticky_error_;
|
|
|
|
// Isolate list next pointer.
|
|
Isolate* next_ = nullptr;
|
|
|
|
// Protect access to boxed_field_list_.
|
|
Mutex field_list_mutex_;
|
|
// List of fields that became boxed and that trigger deoptimization.
|
|
RawGrowableObjectArray* boxed_field_list_;
|
|
|
|
// This guards spawn_count_. An isolate cannot complete shutdown and be
|
|
// destroyed while there are child isolates in the midst of a spawn.
|
|
Monitor spawn_count_monitor_;
|
|
intptr_t spawn_count_ = 0;
|
|
|
|
HandlerInfoCache handler_info_cache_;
|
|
CatchEntryMovesCache catch_entry_moves_cache_;
|
|
|
|
Dart_QualifiedFunctionName* embedder_entry_points_ = nullptr;
|
|
const char** obfuscation_map_ = nullptr;
|
|
|
|
DispatchTable* dispatch_table_ = nullptr;
|
|
ReversePcLookupCache* reverse_pc_lookup_cache_ = nullptr;
|
|
|
|
// Used during message sending of messages between isolates.
|
|
std::unique_ptr<WeakTable> forward_table_new_;
|
|
std::unique_ptr<WeakTable> forward_table_old_;
|
|
|
|
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 AddIsolateToList(Isolate* isolate);
|
|
static void RemoveIsolateFromList(Isolate* isolate);
|
|
|
|
// This monitor protects isolates_list_head_, and creation_enabled_.
|
|
static Monitor* isolates_list_monitor_;
|
|
static Isolate* isolates_list_head_;
|
|
static bool creation_enabled_;
|
|
|
|
#define REUSABLE_FRIEND_DECLARATION(name) \
|
|
friend class Reusable##name##HandleScope;
|
|
REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
|
|
#undef REUSABLE_FRIEND_DECLARATION
|
|
|
|
friend class Become; // VisitObjectPointers
|
|
friend class GCCompactor; // VisitObjectPointers
|
|
friend class GCMarker; // VisitObjectPointers
|
|
friend class SafepointHandler;
|
|
friend class ObjectGraph; // VisitObjectPointers
|
|
friend class HeapSnapshotWriter; // VisitObjectPointers
|
|
friend class Scavenger; // VisitObjectPointers
|
|
friend class HeapIterationScope; // VisitObjectPointers
|
|
friend class ServiceIsolate;
|
|
friend class Thread;
|
|
friend class Timeline;
|
|
friend class NoReloadScope; // reload_block
|
|
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 IsolateSpawnState {
|
|
public:
|
|
IsolateSpawnState(Dart_Port parent_port,
|
|
Dart_Port origin_id,
|
|
const char* script_url,
|
|
const Function& func,
|
|
SerializedObjectBuffer* message_buffer,
|
|
const char* package_config,
|
|
bool paused,
|
|
bool errorsAreFatal,
|
|
Dart_Port onExit,
|
|
Dart_Port onError,
|
|
const char* debug_name,
|
|
IsolateGroup* group);
|
|
IsolateSpawnState(Dart_Port parent_port,
|
|
const char* script_url,
|
|
const char* package_config,
|
|
SerializedObjectBuffer* args_buffer,
|
|
SerializedObjectBuffer* message_buffer,
|
|
bool paused,
|
|
bool errorsAreFatal,
|
|
Dart_Port onExit,
|
|
Dart_Port onError,
|
|
const char* debug_name,
|
|
IsolateGroup* group);
|
|
~IsolateSpawnState();
|
|
|
|
Isolate* isolate() const { return isolate_; }
|
|
void set_isolate(Isolate* value) { isolate_ = value; }
|
|
|
|
Dart_Port parent_port() const { return parent_port_; }
|
|
Dart_Port origin_id() const { return origin_id_; }
|
|
Dart_Port on_exit_port() const { return on_exit_port_; }
|
|
Dart_Port on_error_port() const { return on_error_port_; }
|
|
const char* script_url() const { return script_url_; }
|
|
const char* package_config() const { return package_config_; }
|
|
const char* library_url() const { return library_url_; }
|
|
const char* class_name() const { return class_name_; }
|
|
const char* function_name() const { return function_name_; }
|
|
const char* debug_name() const { return debug_name_; }
|
|
bool is_spawn_uri() const { return library_url_ == nullptr; }
|
|
bool paused() const { return paused_; }
|
|
bool errors_are_fatal() const { return errors_are_fatal_; }
|
|
Dart_IsolateFlags* isolate_flags() { return &isolate_flags_; }
|
|
|
|
RawObject* ResolveFunction();
|
|
RawInstance* BuildArgs(Thread* thread);
|
|
RawInstance* BuildMessage(Thread* thread);
|
|
|
|
IsolateGroup* isolate_group() const { return isolate_group_; }
|
|
|
|
private:
|
|
Isolate* isolate_;
|
|
Dart_Port parent_port_;
|
|
Dart_Port origin_id_;
|
|
Dart_Port on_exit_port_;
|
|
Dart_Port on_error_port_;
|
|
const char* script_url_;
|
|
const char* package_config_;
|
|
const char* library_url_;
|
|
const char* class_name_;
|
|
const char* function_name_;
|
|
const char* debug_name_;
|
|
IsolateGroup* isolate_group_;
|
|
std::unique_ptr<Message> serialized_args_;
|
|
std::unique_ptr<Message> serialized_message_;
|
|
|
|
Dart_IsolateFlags isolate_flags_;
|
|
bool paused_;
|
|
bool errors_are_fatal_;
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_ISOLATE_H_
|