7cd8fda37e
Also load/store canonical hashes in the heap for non-empty TypedData instances in the same manner as canonical hashes for Arrays. TEST=ci (refactoring only) Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try Change-Id: I54274b558fa9f0c8e304198b18cb3f0e9c3e0dfb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/504600 Commit-Queue: Tess Strickland <sstrickl@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
274 lines
12 KiB
C++
274 lines
12 KiB
C++
// Copyright (c) 2026, 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_ROOTS_H_
|
|
#define RUNTIME_VM_ROOTS_H_
|
|
|
|
#include "vm/stub_code_list.h"
|
|
#include "vm/symbol_list.h"
|
|
#include "vm/tagged_pointer.h"
|
|
|
|
namespace dart {
|
|
|
|
#define RAW_ROOTS_LIST(V) \
|
|
V(ObjectPtr, null_obj) \
|
|
V(BoolPtr, true_obj) \
|
|
V(BoolPtr, false_obj) \
|
|
V(SentinelPtr, sentinel_obj) \
|
|
V(SentinelPtr, unknown_constant_obj) \
|
|
V(SentinelPtr, non_constant_obj) \
|
|
V(SentinelPtr, optimized_out_obj)
|
|
|
|
#define HANDLE_ROOTS_LIST(V) \
|
|
V(Object, null_object) \
|
|
V(Class, null_class) \
|
|
V(Array, null_array) \
|
|
V(String, null_string) \
|
|
V(Instance, null_instance) \
|
|
V(Function, null_function) \
|
|
V(FunctionType, null_function_type) \
|
|
V(RecordType, null_record_type) \
|
|
V(TypeArguments, null_type_arguments) \
|
|
V(CompressedStackMaps, null_compressed_stackmaps) \
|
|
V(Closure, null_closure) \
|
|
V(TypeArguments, empty_type_arguments) \
|
|
V(Array, empty_array) \
|
|
V(Array, empty_instantiations_cache_array) \
|
|
V(Array, empty_subtype_test_cache_array) \
|
|
V(Array, mutable_empty_array) \
|
|
V(ContextScope, empty_context_scope) \
|
|
V(ObjectPool, empty_object_pool) \
|
|
V(CompressedStackMaps, empty_compressed_stackmaps) \
|
|
V(PcDescriptors, empty_descriptors) \
|
|
V(LocalVarDescriptors, empty_var_descriptors) \
|
|
V(ExceptionHandlers, empty_exception_handlers) \
|
|
V(ExceptionHandlers, empty_async_exception_handlers) \
|
|
V(Array, synthetic_getter_parameter_types) \
|
|
V(Array, synthetic_getter_parameter_names) \
|
|
V(Bytecode, implicit_getter_bytecode) \
|
|
V(Bytecode, implicit_setter_bytecode) \
|
|
V(Bytecode, implicit_static_getter_bytecode) \
|
|
V(Bytecode, implicit_shared_static_getter_bytecode) \
|
|
V(Bytecode, implicit_static_setter_bytecode) \
|
|
V(Bytecode, implicit_shared_static_setter_bytecode) \
|
|
V(Bytecode, method_extractor_with_ita_bytecode) \
|
|
V(Bytecode, method_extractor_without_ita_bytecode) \
|
|
V(Bytecode, invoke_closure_bytecode) \
|
|
V(Bytecode, invoke_field_bytecode) \
|
|
V(Bytecode, nsm_dispatcher_bytecode) \
|
|
V(Bytecode, dynamic_invocation_forwarder_bytecode) \
|
|
V(Bytecode, implicit_static_closure_bytecode) \
|
|
V(Bytecode, implicit_instance_closure_bytecode) \
|
|
V(Bytecode, implicit_constructor_closure_bytecode) \
|
|
V(Sentinel, sentinel) \
|
|
V(Sentinel, unknown_constant) \
|
|
V(Sentinel, non_constant) \
|
|
V(Sentinel, optimized_out) \
|
|
V(Bool, bool_true) \
|
|
V(Bool, bool_false) \
|
|
V(Smi, smi_illegal_cid) \
|
|
V(Smi, smi_zero) \
|
|
V(ApiError, no_callbacks_error) \
|
|
V(UnwindError, unwind_error) \
|
|
V(UnwindError, unwind_in_progress_error) \
|
|
V(LanguageError, snapshot_writer_error) \
|
|
V(LanguageError, branch_offset_error) \
|
|
V(LanguageError, background_compilation_error) \
|
|
V(LanguageError, no_debuggable_code_error) \
|
|
V(LanguageError, out_of_memory_error) \
|
|
V(UnhandledException, unhandled_oom_exception) \
|
|
V(Type, dynamic_type) \
|
|
V(Type, void_type) \
|
|
V(AbstractType, null_abstract_type) \
|
|
V(TypedData, uninitialized_index) \
|
|
V(Array, uninitialized_data) \
|
|
V(TypedData, empty_coverage_array)
|
|
|
|
#define API_HANDLE_ROOTS_LIST(V) \
|
|
V(true_api_handle) \
|
|
V(false_api_handle) \
|
|
V(null_api_handle) \
|
|
V(empty_string_api_handle) \
|
|
V(no_callbacks_error_api_handle) \
|
|
V(unwind_in_progress_error_api_handle)
|
|
|
|
class AbstractType;
|
|
class ApiError;
|
|
class Array;
|
|
class Bool;
|
|
class Bytecode;
|
|
class Class;
|
|
class Closure;
|
|
class Code;
|
|
class CompressedStackMaps;
|
|
class ContextScope;
|
|
class ExceptionHandlers;
|
|
class Function;
|
|
class FunctionType;
|
|
class Instance;
|
|
class LanguageError;
|
|
class LocalVarDescriptors;
|
|
class Object;
|
|
class ObjectPool;
|
|
class PcDescriptors;
|
|
class RecordType;
|
|
class Sentinel;
|
|
class Smi;
|
|
class String;
|
|
class Type;
|
|
class TypeArguments;
|
|
class TypedData;
|
|
class UnhandledException;
|
|
class UnwindError;
|
|
|
|
class LocalHandle;
|
|
class ObjectPointerVisitor;
|
|
|
|
class Roots {
|
|
public:
|
|
Roots() {}
|
|
~Roots() {}
|
|
|
|
#define DECL(type, name) \
|
|
static type name() { return current_->raw_.name##_; } \
|
|
static void set_##name(type v) { current_->raw_.name##_ = v; }
|
|
RAW_ROOTS_LIST(DECL)
|
|
#undef DECL
|
|
|
|
static ArrayPtr cached_args_descriptor(intptr_t i) {
|
|
return current_->raw_.cached_args_descriptors_[i];
|
|
}
|
|
static void set_cached_args_descriptor(intptr_t i, ArrayPtr v) {
|
|
current_->raw_.cached_args_descriptors_[i] = v;
|
|
}
|
|
static ArrayPtr cached_icdata_array(intptr_t i) {
|
|
return current_->raw_.cached_icdata_arrays_[i];
|
|
}
|
|
static void set_cached_icdata_array(intptr_t i, ArrayPtr v) {
|
|
current_->raw_.cached_icdata_arrays_[i] = v;
|
|
}
|
|
static StringPtr one_char_symbol(intptr_t i) {
|
|
return current_->raw_.one_char_symbols_[i];
|
|
}
|
|
static void set_one_char_symbol(intptr_t i, StringPtr v) {
|
|
current_->raw_.one_char_symbols_[i] = v;
|
|
}
|
|
static StringPtr* one_char_symbols() {
|
|
return ¤t_->raw_.one_char_symbols_[0];
|
|
}
|
|
|
|
#define DECL(type, name) \
|
|
static const type& name() { \
|
|
return *reinterpret_cast<type*>(¤t_->internal_.name##_); \
|
|
}
|
|
HANDLE_ROOTS_LIST(DECL)
|
|
#undef DECL
|
|
static const String& symbol_handle(intptr_t i) {
|
|
return *reinterpret_cast<const String*>(
|
|
¤t_->internal_.symbol_handles_[i]);
|
|
}
|
|
static const Code& stub_handle(intptr_t i) {
|
|
return *reinterpret_cast<const Code*>(
|
|
¤t_->internal_.stub_handles_[i]);
|
|
}
|
|
const Code& x_stub_handle(intptr_t i) {
|
|
return *reinterpret_cast<const Code*>(&internal_.stub_handles_[i]);
|
|
}
|
|
|
|
#define DECL(name) \
|
|
static LocalHandle* name() { \
|
|
return reinterpret_cast<LocalHandle*>(¤t_->api_.name##_); \
|
|
}
|
|
API_HANDLE_ROOTS_LIST(DECL)
|
|
#undef DECL
|
|
|
|
static bool IsReadOnlyHandle(uword handle) {
|
|
return handle - reinterpret_cast<uword>(¤t_->internal_) <
|
|
sizeof(Internal);
|
|
}
|
|
static bool IsReadOnlyApiHandle(uword handle) {
|
|
return handle - reinterpret_cast<uword>(¤t_->api_) < sizeof(Api);
|
|
}
|
|
|
|
void VisitObjectPointers(ObjectPointerVisitor* visitor);
|
|
|
|
static Roots* Current() { return current_; }
|
|
static void SetCurrent(Roots* roots) { current_ = roots; }
|
|
static void ClearCurrent() { current_ = nullptr; }
|
|
|
|
void InitVTables();
|
|
|
|
private:
|
|
enum {
|
|
#define DEFINE_SYMBOL_INDEX(symbol, literal) k##symbol##Id,
|
|
PREDEFINED_SYMBOLS_LIST(DEFINE_SYMBOL_INDEX)
|
|
#undef DEFINE_SYMBOL_INDEX
|
|
kNumPredefinedSymbols,
|
|
};
|
|
enum {
|
|
#define STUB_CODE_ENTRY(name) k##name##Index,
|
|
VM_STUB_CODE_LIST(STUB_CODE_ENTRY)
|
|
#undef STUB_CODE_ENTRY
|
|
kNumStubEntries,
|
|
};
|
|
|
|
struct Raw {
|
|
#define DECL(type, name) \
|
|
type name##_ = type{static_cast<uword>(kHeapObjectTag)};
|
|
RAW_ROOTS_LIST(DECL)
|
|
#undef DECL
|
|
ArrayPtr cached_args_descriptors_[35];
|
|
ArrayPtr cached_icdata_arrays_[4];
|
|
StringPtr one_char_symbols_[256];
|
|
};
|
|
Raw raw_;
|
|
|
|
// Must have the same layout as LocalHandle. Not using LocalHandle itself to
|
|
// break include cycle.
|
|
struct ApiHandle {
|
|
uword ptr;
|
|
};
|
|
struct Api {
|
|
#define DECL(name) ApiHandle name##_ = {};
|
|
API_HANDLE_ROOTS_LIST(DECL)
|
|
#undef DECL
|
|
};
|
|
Api api_;
|
|
|
|
// Must have the same layout as created by VMHandles. Not using VMHandles
|
|
// itself to break include cycle.
|
|
struct VMHandle {
|
|
cpp_vtable vtable;
|
|
ObjectPtr ptr = {nullptr};
|
|
#if defined(DEBUG)
|
|
uword is_zone_handle = 0;
|
|
#endif
|
|
};
|
|
struct Internal {
|
|
#define DECL(type, name) VMHandle name##_ = {};
|
|
HANDLE_ROOTS_LIST(DECL)
|
|
#undef DECL
|
|
VMHandle symbol_handles_[kNumPredefinedSymbols + 256] = {};
|
|
VMHandle stub_handles_[kNumStubEntries] = {};
|
|
};
|
|
Internal internal_ = {};
|
|
|
|
ObjectPtr* from() { return reinterpret_cast<ObjectPtr*>(&raw_); }
|
|
ObjectPtr* to() { return from() + sizeof(Raw) / sizeof(ObjectPtr) - 1; }
|
|
VMHandle* fromh() { return reinterpret_cast<VMHandle*>(&internal_); }
|
|
VMHandle* toh() { return fromh() + sizeof(Internal) / sizeof(VMHandle) - 1; }
|
|
ObjectPtr* fromah() { return reinterpret_cast<ObjectPtr*>(&api_); }
|
|
ObjectPtr* toah() { return fromah() + sizeof(Api) / sizeof(ObjectPtr) - 1; }
|
|
|
|
static inline thread_local Roots* current_ = nullptr;
|
|
|
|
friend class ProgramSerializationRoots;
|
|
friend class ProgramDeserializationRoots;
|
|
DISALLOW_COPY_AND_ASSIGN(Roots);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_ROOTS_H_
|