| // 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(ClassPtr, class_class) \ |
| V(ClassPtr, dynamic_class) \ |
| V(ClassPtr, void_class) \ |
| V(ClassPtr, type_parameters_class) \ |
| V(ClassPtr, type_arguments_class) \ |
| V(ClassPtr, patch_class_class) \ |
| V(ClassPtr, function_class) \ |
| V(ClassPtr, closure_data_class) \ |
| V(ClassPtr, ffi_trampoline_data_class) \ |
| V(ClassPtr, field_class) \ |
| V(ClassPtr, script_class) \ |
| V(ClassPtr, library_class) \ |
| V(ClassPtr, namespace_class) \ |
| V(ClassPtr, kernel_program_info_class) \ |
| V(ClassPtr, code_class) \ |
| V(ClassPtr, instructions_class) \ |
| V(ClassPtr, instructions_section_class) \ |
| V(ClassPtr, instructions_table_class) \ |
| V(ClassPtr, object_pool_class) \ |
| V(ClassPtr, pc_descriptors_class) \ |
| V(ClassPtr, code_source_map_class) \ |
| V(ClassPtr, compressed_stackmaps_class) \ |
| V(ClassPtr, var_descriptors_class) \ |
| V(ClassPtr, exception_handlers_class) \ |
| V(ClassPtr, context_class) \ |
| V(ClassPtr, context_scope_class) \ |
| V(ClassPtr, bytecode_class) \ |
| V(ClassPtr, sentinel_class) \ |
| V(ClassPtr, singletargetcache_class) \ |
| V(ClassPtr, unlinkedcall_class) \ |
| V(ClassPtr, monomorphicsmiablecall_class) \ |
| V(ClassPtr, icdata_class) \ |
| V(ClassPtr, megamorphic_cache_class) \ |
| V(ClassPtr, subtypetestcache_class) \ |
| V(ClassPtr, loadingunit_class) \ |
| V(ClassPtr, api_error_class) \ |
| V(ClassPtr, language_error_class) \ |
| V(ClassPtr, unhandled_exception_class) \ |
| V(ClassPtr, unwind_error_class) \ |
| V(ClassPtr, weak_serialization_reference_class) \ |
| V(ClassPtr, weak_array_class) |
| |
| #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_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(Array, vm_isolate_snapshot_object_table) \ |
| V(Type, dynamic_type) \ |
| V(Type, void_type) \ |
| V(AbstractType, null_abstract_type) \ |
| V(TypedData, uninitialized_index) \ |
| V(Array, uninitialized_data) |
| |
| #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 { |
| 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, |
| }; |
| |
| public: |
| #define DECL(type, name) \ |
| static type name() { return roots_.raw_.name##_; } \ |
| static void set_##name(type v) { roots_.raw_.name##_ = v; } |
| RAW_ROOTS_LIST(DECL) |
| #undef DECL |
| |
| static ArrayPtr cached_args_descriptor(intptr_t i) { |
| return roots_.raw_.cached_args_descriptors_[i]; |
| } |
| static void set_cached_args_descriptor(intptr_t i, ArrayPtr v) { |
| roots_.raw_.cached_args_descriptors_[i] = v; |
| } |
| static ArrayPtr cached_icdata_array(intptr_t i) { |
| return roots_.raw_.cached_icdata_arrays_[i]; |
| } |
| static void set_cached_icdata_array(intptr_t i, ArrayPtr v) { |
| roots_.raw_.cached_icdata_arrays_[i] = v; |
| } |
| static StringPtr one_char_symbol(intptr_t i) { |
| return roots_.raw_.one_char_symbols_[i]; |
| } |
| static void set_one_char_symbol(intptr_t i, StringPtr v) { |
| roots_.raw_.one_char_symbols_[i] = v; |
| } |
| static StringPtr* one_char_symbols() { |
| return &roots_.raw_.one_char_symbols_[0]; |
| } |
| |
| #define DECL(type, name) \ |
| static const type& name() { \ |
| return *reinterpret_cast<type*>(&roots_.internal_.name##_); \ |
| } |
| HANDLE_ROOTS_LIST(DECL) |
| #undef DECL |
| static const String& symbol_handle(intptr_t i) { |
| return *reinterpret_cast<const String*>( |
| &roots_.internal_.symbol_handles_[i]); |
| } |
| static const Code& stub_handle(intptr_t i) { |
| return *reinterpret_cast<const Code*>(&roots_.internal_.stub_handles_[i]); |
| } |
| |
| #define DECL(name) \ |
| static LocalHandle* name() { \ |
| return reinterpret_cast<LocalHandle*>(&roots_.api_.name##_); \ |
| } |
| API_HANDLE_ROOTS_LIST(DECL) |
| #undef DECL |
| |
| void Reset() { |
| #define DECL(type, name) \ |
| raw_.name##_ = type{static_cast<uword>(kHeapObjectTag)}; |
| RAW_ROOTS_LIST(DECL) |
| #undef DECL |
| for (size_t i = 0; i < ARRAY_SIZE(raw_.cached_args_descriptors_); i++) { |
| raw_.cached_args_descriptors_[i] = |
| ArrayPtr{static_cast<uword>(kHeapObjectTag)}; |
| } |
| for (size_t i = 0; i < ARRAY_SIZE(raw_.cached_icdata_arrays_); i++) { |
| raw_.cached_icdata_arrays_[i] = |
| ArrayPtr{static_cast<uword>(kHeapObjectTag)}; |
| } |
| for (size_t i = 0; i < ARRAY_SIZE(raw_.one_char_symbols_); i++) { |
| raw_.one_char_symbols_[i] = StringPtr{static_cast<uword>(kHeapObjectTag)}; |
| } |
| } |
| |
| static Roots& Current() { return roots_; } |
| |
| static bool IsReadOnlyHandle(uword handle) { |
| return handle - reinterpret_cast<uword>(&roots_.internal_) < |
| sizeof(Internal); |
| } |
| static bool IsReadOnlyApiHandle(uword handle) { |
| return handle - reinterpret_cast<uword>(&roots_.api_) < sizeof(Api); |
| } |
| |
| void VisitObjectPointers(ObjectPointerVisitor* visitor); |
| |
| private: |
| Roots() {} |
| |
| 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_; |
| |
| struct ApiHandle { |
| uword ptr; |
| }; |
| struct Api { |
| // COMPILE_ASSERT(sizeof(ApiHandle) == sizeof(LocalHandle)) |
| #define DECL(name) ApiHandle name##_ = {}; |
| API_HANDLE_ROOTS_LIST(DECL) |
| #undef DECL |
| }; |
| Api api_; |
| |
| struct VMHandle { |
| cpp_vtable vtable; |
| ObjectPtr ptr; |
| #if defined(DEBUG) |
| uword is_zone_handle = false; |
| #endif |
| }; |
| // COMPILE_ASSERT(sizeof(Handle) == kVMHandleSizeInWords * kWordSize) |
| 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_; |
| |
| static Roots roots_; |
| static inline thread_local Roots* current_ = nullptr; |
| |
| DISALLOW_COPY_AND_ASSIGN(Roots); |
| }; |
| |
| } // namespace dart |
| |
| #endif // RUNTIME_VM_ROOTS_H_ |