1 /* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_GC_ROOT_H 17 #define ECMASCRIPT_GC_ROOT_H 18 19 #include "ecmascript/js_tagged_value.h" 20 #include "ecmascript/mem/barriers.h" 21 #include "ecmascript/mem/slots.h" 22 23 namespace panda::ecmascript { 24 25 /** 26 * When CMCGC is enabled, this class ensures that root references can be safely 27 * accessed during concurrent GC phases by: 28 * - Adding write barriers on creation if needed 29 * - Requiring read barriers when accessing values to handle object forwarding 30 * 31 */ 32 class GCRoot { 33 public: 34 /** 35 * When CMCGC is enabled and needWriteBarrier is true, notifies the GC 36 * that a new root reference has been created. 37 * This is especially usefull when store GCRoot in a data structure 38 * and act as a write-barrier for the root container. 39 */ 40 template <typename T, bool needWriteBarrier = true> GCRoot(T value)41 explicit GCRoot(T value) : objPtr_(value) 42 { 43 if constexpr (needWriteBarrier) { 44 if (g_isEnableCMCGC) { 45 common::BaseRuntime::WriteRoot(reinterpret_cast<void *>(objPtr_.GetRawData())); 46 } 47 } 48 } 49 50 /** Creates a GCRoot pointing to a hole value (empty/uninitialized) */ GCRoot()51 explicit GCRoot() : objPtr_(JSTaggedValue::Hole()) {} 52 53 // Copying is forbidden to prevent accidental root duplication 54 GCRoot(const GCRoot &) = delete; 55 GCRoot &operator=(const GCRoot &) = delete; 56 57 // Move semantics are allowed for container storage GCRoot(GCRoot && other)58 GCRoot(GCRoot &&other) noexcept : objPtr_(other.objPtr_) {} 59 GCRoot &operator=(GCRoot &&other) noexcept 60 { 61 objPtr_ = other.objPtr_; 62 return *this; 63 } 64 65 ~GCRoot() = default; 66 67 /** 68 * Safely reads the wrapped value with GC synchronization. 69 * 70 * When CMCGC is enabled, applies a read barrier to handle 71 * object forwarding if the object was moved during GC 72 */ Read()73 JSTaggedValue Read() 74 { 75 if (g_isEnableCMCGC) { 76 return JSTaggedValue( 77 reinterpret_cast<JSTaggedType>(common::BaseRuntime::ReadBarrier(reinterpret_cast<void *>(&objPtr_)))); 78 } else { 79 return objPtr_; 80 } 81 } 82 83 /** 84 * Allows GC to visit this root during root scanning phases. 85 * Such as enumeration phase and fowarding phase 86 */ 87 template <typename Func> VisitRoot(Func && fn)88 void VisitRoot(Func &&fn) const 89 { 90 ObjectSlot slot(reinterpret_cast<uintptr_t>(&objPtr_)); 91 fn(slot); 92 } 93 94 /** 95 * Hash functor for using GCRoot as hash table keys. 96 * 97 * WARNING: Only safe to use if the referenced objects are non-movable! 98 * 99 * For movable objects, the hash will become invalid after GC copy phases, 100 * breaking hash table invariants. Safe alternatives: 101 * 1. Only use with non-movable objects (e.g., HClass) 102 * 2. Rehash/rebuild the table after each GC cycle 103 * 3. Use object content hash instead of address-based hash 104 */ 105 class GCRootHash { 106 public: operator()107 size_t operator()(const GCRoot &root) const 108 { 109 return std::hash<JSTaggedType>()(root.objPtr_.GetRawData()); 110 } 111 112 template <typename T> operator()113 size_t operator()(const T &key) const 114 { 115 return std::hash<JSTaggedType>()(key); 116 } 117 }; 118 119 private: 120 JSTaggedValue objPtr_; 121 }; 122 123 } // namespace panda::ecmascript 124 #endif 125