| // 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(Bytecode, null_bytecode) \ | |
| 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_ |