• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include <cinttypes>
17 
18 #include "ark_native_reference.h"
19 
20 #include "native_engine/native_api_internal.h"
21 #include "native_engine/native_utils.h"
22 
ArkNativeReference(ArkNativeEngine * engine,napi_value value,uint32_t initialRefcount,bool deleteSelf,NapiNativeFinalize napiCallback,void * data,void * hint,bool isAsyncCall,size_t nativeBindingSize)23 ArkNativeReference::ArkNativeReference(ArkNativeEngine* engine,
24                                        napi_value value,
25                                        uint32_t initialRefcount,
26                                        bool deleteSelf,
27                                        NapiNativeFinalize napiCallback,
28                                        void* data,
29                                        void* hint,
30                                        bool isAsyncCall,
31                                        size_t nativeBindingSize)
32     : engine_(engine),
33       value_(engine->GetEcmaVm(), LocalValueFromJsValue(value)),
34       refCount_(initialRefcount),
35       ownership_(deleteSelf ? ReferenceOwnerShip::RUNTIME : ReferenceOwnerShip::USER),
36       napiCallback_(napiCallback),
37       data_(data),
38       hint_(hint),
39       nativeBindingSize_(nativeBindingSize)
40 {
41     InitProperties(deleteSelf, isAsyncCall);
42     ArkNativeReferenceConstructor();
43 }
44 
ArkNativeReference(ArkNativeEngine * engine,Local<JSValueRef> value,uint32_t initialRefcount,bool deleteSelf,NapiNativeFinalize napiCallback,void * data,void * hint,bool isAsyncCall,size_t nativeBindingSize)45 ArkNativeReference::ArkNativeReference(ArkNativeEngine* engine,
46                                        Local<JSValueRef> value,
47                                        uint32_t initialRefcount,
48                                        bool deleteSelf,
49                                        NapiNativeFinalize napiCallback,
50                                        void* data,
51                                        void* hint,
52                                        bool isAsyncCall,
53                                        size_t nativeBindingSize)
54     : engine_(engine),
55       value_(engine->GetEcmaVm(), value),
56       refCount_(initialRefcount),
57       ownership_(deleteSelf ? ReferenceOwnerShip::RUNTIME : ReferenceOwnerShip::USER),
58       napiCallback_(napiCallback),
59       data_(data),
60       hint_(hint),
61       nativeBindingSize_(nativeBindingSize)
62 {
63     InitProperties(deleteSelf, isAsyncCall);
64     ArkNativeReferenceConstructor();
65 }
66 
ArkNativeReferenceConstructor()67 void ArkNativeReference::ArkNativeReferenceConstructor()
68 {
69     if (napiCallback_ != nullptr) {
70         // Async callback will redirect to root engine, no monitoring needed.
71         if (!IsAsyncCall()) {
72             engine_->IncreaseCallbackbleRefCounter();
73             // Non-callback runtime owned napi_ref will free when env teardown.
74             if (ownership_ == ReferenceOwnerShip::RUNTIME && !engine_->IsMainEnvContext()) {
75                 engine_->IncreaseRuntimeOwnedRefCounter();
76             }
77         }
78     } else {
79         engine_->IncreaseNonCallbackRefCounter();
80     }
81 
82     if (refCount_ == 0) {
83         value_.SetWeakCallback(reinterpret_cast<void*>(this), FreeGlobalCallBack, NativeFinalizeCallBack);
84     }
85 
86     if (ownership_ == ReferenceOwnerShip::RUNTIME) {
87         NativeReferenceManager* referenceManager = engine_->GetReferenceManager();
88         if (referenceManager != nullptr) {
89             referenceManager->CreateHandler(this);
90         }
91     }
92 
93     engineId_ = engine_->GetId();
94 }
95 
InitProperties(bool deleteSelf,bool isAsyncCall)96 inline void ArkNativeReference::InitProperties(bool deleteSelf, bool isAsyncCall)
97 {
98     if (deleteSelf) {
99         SetDeleteSelf();
100     }
101     if (isAsyncCall) {
102         properties_ |= ReferencePropertiesMask::IS_ASYNC_CALL_MASK;
103     }
104 }
105 
106 // Do not use pure virtual function of NativeEngine,
107 // it may cause crash if ArkNativeEngine is deconstructed.
108 // Which would occur when EcmaVM is destroying in CleanEnv.
~ArkNativeReference()109 ArkNativeReference::~ArkNativeReference()
110 {
111     VALID_ENGINE_CHECK(engine_, engine_, engineId_);
112 
113     if (!napiCallback_) {
114         engine_->DecreaseNonCallbackRefCounter();
115     }
116 
117     NativeReferenceManager* refMgr = engine_->GetReferenceManager();
118     if (ownership_ == ReferenceOwnerShip::RUNTIME && refMgr != nullptr) {
119         refMgr->ReleaseHandler(this);
120         prev_ = nullptr;
121         next_ = nullptr;
122     }
123     if (value_.IsEmpty()) {
124         return;
125     }
126     SetHasDelete();
127     value_.FreeGlobalHandleAddr();
128     FinalizeCallback(FinalizerState::DESTRUCTION);
129 }
130 
Ref()131 uint32_t ArkNativeReference::Ref()
132 {
133     ++refCount_;
134     if (refCount_ == 1) {
135         value_.ClearWeak();
136     }
137     return refCount_;
138 }
139 
Unref()140 uint32_t ArkNativeReference::Unref()
141 {
142     if (refCount_ == 0) {
143         return refCount_;
144     }
145     --refCount_;
146     if (value_.IsEmpty()) {
147         return refCount_;
148     }
149     if (refCount_ == 0) {
150         value_.SetWeakCallback(reinterpret_cast<void*>(this), FreeGlobalCallBack, NativeFinalizeCallBack);
151     }
152     return refCount_;
153 }
154 
Get(NativeEngine * engine)155 napi_value ArkNativeReference::Get(NativeEngine* engine)
156 {
157     if (value_.IsEmpty()) {
158         return nullptr;
159     }
160     VALID_ENGINE_CHECK(engine, engine_, engineId_);
161     Local<JSValueRef> value = value_.ToLocal(engine->GetEcmaVm());
162     return JsValueFromLocalValue(value);
163 }
164 
Get()165 napi_value ArkNativeReference::Get()
166 {
167     return Get(engine_);
168 }
169 
operator napi_value()170 ArkNativeReference::operator napi_value()
171 {
172     return Get(engine_);
173 }
174 
GetData()175 void* ArkNativeReference::GetData()
176 {
177     return data_;
178 }
179 
180 struct NapiSecondCallback {
181     NapiNativeFinalize callback_;
182     void* data_;
183     ReferenceOwnerShip ownership_;
InvokeNapiSecondCallback184     void Invoke(napi_env env, void* hint)
185     {
186         callback_(env, data_, hint);
187     }
188     // proxy of user callback
SecondFinalizeCallbackNapiSecondCallback189     static void SecondFinalizeCallback(napi_env env, void* data, void* hint)
190     {
191         NapiSecondCallback* callbackWrap = reinterpret_cast<NapiSecondCallback*>(data);
192         callbackWrap->Invoke(env, hint);
193         ArkNativeEngine* engine = reinterpret_cast<ArkNativeEngine*>(env);
194         engine->DecreaseCallbackbleRefCounter();
195 
196         if (callbackWrap->ownership_ == ReferenceOwnerShip::RUNTIME) {
197             engine->DecreaseRuntimeOwnedRefCounter();
198         }
199 
200         delete callbackWrap;
201         if (engine->IsReadyToDelete()) {
202             engine->Delete();
203         }
204     }
205 };
206 
EnqueueAsyncTask()207 void ArkNativeReference::EnqueueAsyncTask()
208 {
209     std::pair<void*, void*> pair = std::make_pair(data_, hint_);
210     RefAsyncFinalizer asyncFinalizer = std::make_pair(napiCallback_, pair);
211     // Async callback doesn't require the current engine. Use the root engine if a context is passed.
212     if (engine_->IsMainEnvContext()) {
213         engine_->GetPendingAsyncFinalizers().emplace_back(asyncFinalizer);
214     } else {
215         const_cast<ArkNativeEngine*>(engine_->GetParent())
216             ->GetPendingAsyncFinalizers()
217             .emplace_back(asyncFinalizer);
218     }
219 }
220 
EnqueueDeferredTask()221 void ArkNativeReference::EnqueueDeferredTask()
222 {
223     if (engine_->IsMainEnvContext()) {
224         std::tuple<NativeEngine*, void*, void*> tuple = std::make_tuple(engine_, data_, hint_);
225         RefFinalizer finalizer = std::make_pair(napiCallback_, tuple);
226         engine_->GetArkFinalizersPack().AddFinalizer(finalizer, nativeBindingSize_);
227     } else {
228         std::tuple<NativeEngine*, void*, void*> tuple =
229             std::make_tuple(engine_, new NapiSecondCallback { napiCallback_, data_, ownership_ }, hint_);
230         RefFinalizer finalizer = std::make_pair(NapiSecondCallback::SecondFinalizeCallback, tuple);
231         // callbackble ref counter will decrease until callback is invoked
232         const_cast<ArkNativeEngine*>(engine_->GetParent())
233             ->GetArkFinalizersPack()
234             .AddFinalizer(finalizer, nativeBindingSize_);
235     }
236 }
237 
DispatchFinalizeCallback()238 void ArkNativeReference::DispatchFinalizeCallback()
239 {
240     if (IsAsyncCall()) {
241         EnqueueAsyncTask();
242     } else {
243         EnqueueDeferredTask();
244     }
245 }
246 
FinalizeCallback(FinalizerState state)247 void ArkNativeReference::FinalizeCallback(FinalizerState state)
248 {
249     // Invoke the callback only if it is callbackble and has not already been invoked.
250     if (!GetFinalRun() && napiCallback_ && !engine_->IsInDestructor()) {
251         if (state == FinalizerState::COLLECTION) {
252             DispatchFinalizeCallback();
253         } else {
254             if (!IsAsyncCall()) {
255                 engine_->DecreaseCallbackbleRefCounter();
256             }
257             if (ownership_ == ReferenceOwnerShip::RUNTIME) {
258                 engine_->DecreaseRuntimeOwnedRefCounter();
259             }
260             napiCallback_(reinterpret_cast<napi_env>(engine_), data_, hint_);
261         }
262     }
263     data_ = nullptr;
264     hint_ = nullptr;
265     SetFinalRan();
266 
267     if (GetDeleteSelf() && !HasDelete()) {
268         delete this;
269     }
270 }
271 
FreeGlobalCallBack(void * ref)272 void ArkNativeReference::FreeGlobalCallBack(void* ref)
273 {
274     auto that = reinterpret_cast<ArkNativeReference*>(ref);
275     that->value_.FreeGlobalHandleAddr();
276 }
277 
NativeFinalizeCallBack(void * ref)278 void ArkNativeReference::NativeFinalizeCallBack(void* ref)
279 {
280     auto that = reinterpret_cast<ArkNativeReference*>(ref);
281     that->FinalizeCallback(FinalizerState::COLLECTION);
282 }
283 
SetDeleteSelf()284 void ArkNativeReference::SetDeleteSelf()
285 {
286     properties_ |= ReferencePropertiesMask::DELETE_SELF_MASK;
287 }
288 
GetDeleteSelf() const289 bool ArkNativeReference::GetDeleteSelf() const
290 {
291     return (properties_ & ReferencePropertiesMask::DELETE_SELF_MASK) != 0;
292 }
293 
GetRefCount()294 uint32_t ArkNativeReference::GetRefCount()
295 {
296     return refCount_;
297 }
298 
GetFinalRun()299 bool ArkNativeReference::GetFinalRun()
300 {
301     return (properties_ & ReferencePropertiesMask::FINAL_RAN_MASK) != 0;
302 }
303 
GetNapiValue()304 napi_value ArkNativeReference::GetNapiValue()
305 {
306     return Get();
307 }
308 
ResetFinalizer()309 void ArkNativeReference::ResetFinalizer()
310 {
311     napiCallback_ = nullptr;
312     data_ = nullptr;
313     hint_ = nullptr;
314 }
315 
IsAsyncCall() const316 bool ArkNativeReference::IsAsyncCall() const
317 {
318     return (properties_ & ReferencePropertiesMask::IS_ASYNC_CALL_MASK) != 0;
319 }
320 
HasDelete() const321 inline bool ArkNativeReference::HasDelete() const
322 {
323     return (properties_ & ReferencePropertiesMask::HAS_DELETE_MASK) != 0;
324 }
325 
SetHasDelete()326 inline void ArkNativeReference::SetHasDelete()
327 {
328     properties_ |= ReferencePropertiesMask::HAS_DELETE_MASK;
329 }
330 
SetFinalRan()331 inline void ArkNativeReference::SetFinalRan()
332 {
333     properties_ |= ReferencePropertiesMask::FINAL_RAN_MASK;
334 }
335 
336 #ifdef PANDA_JS_ETS_HYBRID_MODE
MarkFromObject()337 void ArkNativeReference::MarkFromObject()
338 {
339     value_.MarkFromObject();
340 }
341 
IsObjectAlive()342 bool ArkNativeReference::IsObjectAlive()
343 {
344     return value_.IsObjectAlive();
345 }
346 
IsValidHeapObject()347 bool ArkNativeReference::IsValidHeapObject()
348 {
349     return value_.IsValidHeapObject();
350 }
351 #endif // PANDA_JS_ETS_HYBRID_MODE
352