• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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 PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_H_
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_H_
18 
19 #include "plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.h"
20 #include "plugins/ets/runtime/interop_js/ets_proxy/shared_reference_flags.h"
21 
22 #include <node_api.h>
23 
24 #if defined(PANDA_JS_ETS_HYBRID_MODE)
25 #include "interfaces/inner_api/napi/native_node_hybrid_api.h"
26 #endif
27 
28 namespace ark::ets::interop::js {
29 class InteropCtx;
30 }  // namespace ark::ets::interop::js
31 
32 namespace ark::ets::interop::js::ets_proxy {
33 // Forward declaration
34 class SharedReferenceStorage;
35 namespace testing {
36 class SharedReferenceStorage1GTest;
37 }  // namespace testing
38 
39 class SharedReference {
40 public:
41     static constexpr size_t MAX_MARK_BITS = 27U;
42     static_assert(MAX_MARK_BITS <= EtsMarkWord::INTEROP_INDEX_SIZE);
43 
44     // Actual state of shared object is contained in ETS
45     void InitETSObject(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx);
46 
47     // Actual state of shared object is contained in JS
48     void InitJSObject(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx);
49 
50     // State of object is shared between ETS and JS
51     void InitHybridObject(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx);
52 
53     using InitFn = decltype(&SharedReference::InitHybridObject);
54 
GetEtsObject()55     EtsObject *GetEtsObject() const
56     {
57         ASSERT(etsRef_ != nullptr);
58         return etsRef_;
59     }
60 
GetJsRef()61     napi_ref GetJsRef() const
62     {
63         return jsRef_;
64     }
65 
GetCtx()66     const InteropCtx *GetCtx() const
67     {
68         ASSERT(ctx_ != nullptr);
69         return ctx_;
70     }
71 
HasETSFlag()72     bool HasETSFlag() const
73     {
74         return flags_.HasBit<SharedReferenceFlags::Bit::ETS>();
75     }
76 
HasJSFlag()77     bool HasJSFlag() const
78     {
79         return flags_.HasBit<SharedReferenceFlags::Bit::JS>();
80     }
81 
82     /**
83      * Empty ref means the ref is not allocated or removed from storage and can't be used
84      * @return true if reference is empty, false - otherwise
85      */
IsEmpty()86     bool IsEmpty() const
87     {
88         return flags_.IsEmpty();
89     }
90 
91     /**
92      * Mark the reference as live. It's special method for XGC marking
93      * @return true if the method marked the reference, false if the reference has already been marked
94      */
95     PANDA_PUBLIC_API bool MarkIfNotMarked();
96 
97     /// @return true if the refernce is marked, false - otherwise
IsMarked()98     bool IsMarked() const
99     {
100         return flags_.HasBit<SharedReferenceFlags::Bit::MARK>();
101     }
102 
103     /// @class provides forward iterator for SharedReference with chain of contexts and one EtsObject
104     class Iterator {
105     public:
106         // NOLINTBEGIN(readability-identifier-naming)
107         using iterator_category = std::forward_iterator_tag;
108         using value_type = SharedReference *;
109         using difference_type = std::ptrdiff_t;
110         using pointer = value_type *;
111         using reference = value_type &;
112         // NOLINTEND(readability-identifier-naming)
113 
114         friend class SharedReference;
115 
116         PANDA_PUBLIC_API Iterator &operator++();
117         PANDA_PUBLIC_API Iterator operator++(int);  // NOLINT(cert-dcl21-cpp)
118 
119         bool operator==(const Iterator &other) const
120         {
121             return ref_ == other.ref_;
122         }
123 
124         bool operator!=(const Iterator &other) const
125         {
126             return ref_ != other.ref_;
127         }
128 
129         SharedReference *operator*()
130         {
131             return const_cast<SharedReference *>(ref_);
132         }
133 
134         const SharedReference *operator*() const
135         {
136             return ref_;
137         }
138 
139         SharedReference *operator->()
140         {
141             return const_cast<SharedReference *>(ref_);
142         }
143 
144         const SharedReference *operator->() const
145         {
146             return ref_;
147         }
148 
149         Iterator() = default;
Iterator(const SharedReference * ref)150         explicit Iterator(const SharedReference *ref) : ref_(ref) {}
151         DEFAULT_COPY_SEMANTIC(Iterator);
152         DEFAULT_NOEXCEPT_MOVE_SEMANTIC(Iterator);
153         ~Iterator() = default;
154 
155     private:
156         const SharedReference *ref_ {nullptr};
157     };
158 
GetIterator()159     Iterator GetIterator() const
160     {
161         return Iterator(this);
162     }
163 
164     friend std::ostream &operator<<(std::ostream &out, const SharedReference *ref)
165     {
166         out << static_cast<const void *>(ref);
167         if (LIKELY(ref != nullptr)) {
168             out << ": | ETSObject:" << ref->etsRef_ << " | napi_ref:" << ref->jsRef_ << " | ctx:" << ref->ctx_ << " | "
169                 << ref->flags_ << " |";
170         }
171         return out;
172     }
173 
174 private:
175     friend class SharedReferenceSanity;
176     friend class SharedReferenceStorage;
177     friend class testing::SharedReferenceStorage1GTest;
178 
179     void InitRef(InteropCtx *ctx, EtsObject *etsObject, napi_ref jsRef, uint32_t refIdx);
180 
SetETSObject(EtsObject * obj)181     void SetETSObject(EtsObject *obj)
182     {
183         ASSERT(obj != nullptr);
184         etsRef_ = obj;
185     }
186 
HasReference(EtsObject * etsObject)187     static bool HasReference(EtsObject *etsObject)
188     {
189         return etsObject->HasInteropIndex();
190     }
191 
ExtractMaybeIndex(EtsObject * etsObject)192     static uint32_t ExtractMaybeIndex(EtsObject *etsObject)
193     {
194         ASSERT(HasReference(etsObject));
195         return etsObject->GetInteropIndex();
196     }
197 
198     /// Unset mark flag from the reference
Unmark()199     void Unmark()
200     {
201         flags_.Unmark();
202     }
203 
204     /* Possible values:
205      *                 ets_proxy:  {instance,       proxy}
206      *      extensible ets_proxy:  {proxy-base,     extender-proxy}
207      *                  js_proxy:  {proxy,          instance}
208      *      extensible  js_proxy:  {extender-proxy, proxy-base}
209      */
210     EtsObject *etsRef_ {};
211     napi_ref jsRef_ {};
212     const InteropCtx *ctx_ {};
213 
214     SharedReferenceFlags flags_ {};
215 };
216 
217 }  // namespace ark::ets::interop::js::ets_proxy
218 
219 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_H_
220