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 #ifdef ENABLE_HITRACE
21 #include "hitrace/trace.h"
22 #include "hitrace_meter.h"
23 #endif
24 #include "native_engine/native_utils.h"
25 #include "utils/log.h"
26 
ArkNativeReference(ArkNativeEngine * engine,napi_value value,uint32_t initialRefcount,bool deleteSelf,NapiNativeFinalize napiCallback,void * data,void * hint,bool isAsyncCall,size_t nativeBindingSize)27 ArkNativeReference::ArkNativeReference(ArkNativeEngine* engine,
28                                        napi_value value,
29                                        uint32_t initialRefcount,
30                                        bool deleteSelf,
31                                        NapiNativeFinalize napiCallback,
32                                        void* data,
33                                        void* hint,
34                                        bool isAsyncCall,
35                                        size_t nativeBindingSize)
36     : engine_(engine),
37       value_(engine->GetEcmaVm(), LocalValueFromJsValue(value)),
38       refCount_(initialRefcount),
39       deleteSelf_(deleteSelf),
40       isAsyncCall_(isAsyncCall),
41       napiCallback_(napiCallback),
42       data_(data),
43       hint_(hint),
44       nativeBindingSize_(nativeBindingSize)
45 {
46     ArkNativeReferenceConstructor(initialRefcount, deleteSelf);
47 }
48 
ArkNativeReference(ArkNativeEngine * engine,Local<JSValueRef> value,uint32_t initialRefcount,bool deleteSelf,NapiNativeFinalize napiCallback,void * data,void * hint,bool isAsyncCall,size_t nativeBindingSize)49 ArkNativeReference::ArkNativeReference(ArkNativeEngine* engine,
50                                        Local<JSValueRef> value,
51                                        uint32_t initialRefcount,
52                                        bool deleteSelf,
53                                        NapiNativeFinalize napiCallback,
54                                        void* data,
55                                        void* hint,
56                                        bool isAsyncCall,
57                                        size_t nativeBindingSize)
58     : engine_(engine),
59       value_(engine->GetEcmaVm(), value),
60       refCount_(initialRefcount),
61       deleteSelf_(deleteSelf),
62       isAsyncCall_(isAsyncCall),
63       napiCallback_(napiCallback),
64       data_(data),
65       hint_(hint),
66       nativeBindingSize_(nativeBindingSize)
67 {
68     ArkNativeReferenceConstructor(initialRefcount, deleteSelf);
69 }
70 
~ArkNativeReference()71 ArkNativeReference::~ArkNativeReference()
72 {
73     if (deleteSelf_ && engine_->GetReferenceManager()) {
74         engine_->GetReferenceManager()->ReleaseHandler(this);
75         prev_ = nullptr;
76         next_ = nullptr;
77     }
78     if (value_.IsEmpty()) {
79         return;
80     }
81     hasDelete_ = true;
82     value_.FreeGlobalHandleAddr();
83     FinalizeCallback(FinalizerState::DESTRUCTION);
84 }
85 
Ref()86 uint32_t ArkNativeReference::Ref()
87 {
88     ++refCount_;
89     if (refCount_ == 1) {
90         value_.ClearWeak();
91     }
92     return refCount_;
93 }
94 
Unref()95 uint32_t ArkNativeReference::Unref()
96 {
97     if (refCount_ == 0) {
98         return refCount_;
99     }
100     --refCount_;
101     if (value_.IsEmpty()) {
102         return refCount_;
103     }
104     if (refCount_ == 0) {
105         value_.SetWeakCallback(reinterpret_cast<void*>(this), FreeGlobalCallBack, NativeFinalizeCallBack);
106     }
107     return refCount_;
108 }
109 
Get(NativeEngine * engine)110 napi_value ArkNativeReference::Get(NativeEngine* engine)
111 {
112     if (value_.IsEmpty()) {
113         return nullptr;
114     }
115     if (engine != engine_) {
116         LOG_IF_SPECIAL(UNLIKELY(engine->IsCrossThreadCheckEnabled()),
117                        "param env is not equal to its owner");
118     } else if (engineId_ != engine->GetId()) {
119         LOG_IF_SPECIAL(UNLIKELY(engine->IsCrossThreadCheckEnabled()),
120                        "param env is not equal to its owner, "
121                        "current env id: %{public}" PRIu64 ", owner id: %{public}" PRIu64,
122                        engineId_, engine_->GetId());
123     }
124     Local<JSValueRef> value = value_.ToLocal(engine->GetEcmaVm());
125     return JsValueFromLocalValue(value);
126 }
127 
Get()128 napi_value ArkNativeReference::Get()
129 {
130     if (value_.IsEmpty()) {
131         return nullptr;
132     }
133     if (engineId_ != engine_->GetId()) {
134         LOG_IF_SPECIAL(UNLIKELY(engine_->IsCrossThreadCheckEnabled()),
135                        "owner env has been destroyed, "
136                        "current env id: %{public}" PRIu64 ", owner id: %{public}" PRIu64,
137                        engineId_, engine_->GetId());
138     }
139     Local<JSValueRef> value = value_.ToLocal(engine_->GetEcmaVm());
140     return JsValueFromLocalValue(value);
141 }
142 
143 ArkNativeReference::operator napi_value()
144 {
145     return Get();
146 }
147 
GetData()148 void* ArkNativeReference::GetData()
149 {
150     return data_;
151 }
152 
FinalizeCallback(FinalizerState state)153 void ArkNativeReference::FinalizeCallback(FinalizerState state)
154 {
155     if (napiCallback_ != nullptr && !engine_->IsInDestructor()) {
156         if (state == FinalizerState::COLLECTION) {
157             std::tuple<NativeEngine*, void*, void*> tuple = std::make_tuple(engine_, data_, hint_);
158             RefFinalizer finalizer = std::make_pair(napiCallback_, tuple);
159             if (isAsyncCall_) {
160                 engine_->GetPendingAsyncFinalizers().emplace_back(finalizer);
161             } else {
162                 engine_->GetArkFinalizersPack().AddFinalizer(finalizer, nativeBindingSize_);
163             }
164         } else {
165             napiCallback_(reinterpret_cast<napi_env>(engine_), data_, hint_);
166         }
167     }
168     napiCallback_ = nullptr;
169     data_ = nullptr;
170     hint_ = nullptr;
171     finalRun_ = true;
172 
173     if (deleteSelf_ && !hasDelete_) {
174         delete this;
175     }
176 }
177 
FreeGlobalCallBack(void * ref)178 void ArkNativeReference::FreeGlobalCallBack(void* ref)
179 {
180     auto that = reinterpret_cast<ArkNativeReference*>(ref);
181     that->value_.FreeGlobalHandleAddr();
182 }
183 
NativeFinalizeCallBack(void * ref)184 void ArkNativeReference::NativeFinalizeCallBack(void* ref)
185 {
186     auto that = reinterpret_cast<ArkNativeReference*>(ref);
187     that->FinalizeCallback(FinalizerState::COLLECTION);
188 }
189 
SetDeleteSelf()190 void ArkNativeReference::SetDeleteSelf()
191 {
192     deleteSelf_ = true;
193 }
194 
GetDeleteSelf() const195 bool ArkNativeReference::GetDeleteSelf() const
196 {
197     return deleteSelf_;
198 }
199 
GetRefCount()200 uint32_t ArkNativeReference::GetRefCount()
201 {
202     return refCount_;
203 }
204 
GetFinalRun()205 bool ArkNativeReference::GetFinalRun()
206 {
207     return finalRun_;
208 }
209 
GetNapiValue()210 napi_value ArkNativeReference::GetNapiValue()
211 {
212     return Get();
213 }
214 
ResetFinalizer()215 void ArkNativeReference::ResetFinalizer()
216 {
217     napiCallback_ = nullptr;
218     data_ = nullptr;
219     hint_ = nullptr;
220 }