• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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