• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "js_native_api_v8.h"
17 #include "jsvm_reference-inl.h"
18 
19 namespace v8impl {
20 
FinalizeAll(RefList * list)21 void RefTracker::FinalizeAll(RefList* list)
22 {
23     while (list->next != nullptr) {
24         list->next->Finalize();
25     }
26 }
27 
Finalize()28 void RefTracker::Finalize()
29 {
30     UNREACHABLE("Finalize need to be realized");
31 }
32 
33 // UserReference
New(JSVM_Env env,v8::Local<v8::Value> value,uint32_t initialRefcount)34 UserReference* UserReference::New(JSVM_Env env, v8::Local<v8::Value> value, uint32_t initialRefcount)
35 {
36     auto ref = new UserReference(env, value, true, initialRefcount);
37 
38     return ref;
39 }
40 
NewData(JSVM_Env env,v8::Local<v8::Data> value,uint32_t initialRefcount)41 UserReference* UserReference::NewData(JSVM_Env env, v8::Local<v8::Data> value, uint32_t initialRefcount)
42 {
43     auto ref = new UserReference(env, value, false, initialRefcount);
44 
45     return ref;
46 }
47 
UserReference(JSVM_Env env,v8::Local<v8::Data> value,bool isValue,uint32_t initialRefcount)48 UserReference::UserReference(JSVM_Env env, v8::Local<v8::Data> value, bool isValue, uint32_t initialRefcount)
49     : persistent(env->isolate, value), env(env), refcount(initialRefcount), isValue(isValue),
50       canBeWeak(isValue && CanBeHeldWeakly(value.As<v8::Value>()))
51 {
52     if (refcount == 0) {
53         SetWeak();
54     }
55 
56     Link(&env->userReferenceList);
57 }
58 
~UserReference()59 UserReference::~UserReference()
60 {
61     persistent.Reset();
62     Unlink();
63 }
64 
Finalize()65 void UserReference::Finalize()
66 {
67     persistent.Reset();
68     Unlink();
69 }
70 
RefCount()71 uint32_t UserReference::RefCount()
72 {
73     return refcount;
74 }
75 
76 // FinalizerTracker
New(JSVM_Env env,JSVM_Finalize cb,void * finalizeData,void * finalizeHint)77 FinalizerTracker* FinalizerTracker::New(JSVM_Env env, JSVM_Finalize cb, void* finalizeData, void* finalizeHint)
78 {
79     return new FinalizerTracker(env, cb, finalizeData, finalizeHint);
80 }
81 
FinalizerTracker(JSVM_Env env,JSVM_Finalize cb,void * data,void * hint)82 FinalizerTracker::FinalizerTracker(JSVM_Env env, JSVM_Finalize cb, void* data, void* hint)
83     : env(env), cb(cb), data(data), hint(hint)
84 {
85     Link(&env->finalizerList);
86 }
87 
~FinalizerTracker()88 FinalizerTracker::~FinalizerTracker()
89 {
90     Unlink();
91 }
92 
ResetFinalizer()93 void FinalizerTracker::ResetFinalizer()
94 {
95     cb = nullptr;
96     data = nullptr;
97     hint = nullptr;
98 }
99 
CallFinalizer()100 void FinalizerTracker::CallFinalizer()
101 {
102     if (!cb) {
103         return;
104     }
105 
106     JSVM_Finalize cbTemp = cb;
107     void* dataTemp = data;
108     void* hintTemp = hint;
109     ResetFinalizer();
110 
111     if (!env) {
112         cbTemp(env, dataTemp, hintTemp);
113     } else {
114         env->CallIntoModule([&](JSVM_Env env) { cbTemp(env, dataTemp, hintTemp); });
115     }
116 }
117 
Finalize()118 void FinalizerTracker::Finalize()
119 {
120     CallFinalizer();
121     delete this;
122 }
123 
RuntimeReference(JSVM_Env env,v8::Local<v8::Value> value,JSVM_Finalize cb,void * data,void * hint)124 RuntimeReference::RuntimeReference(JSVM_Env env, v8::Local<v8::Value> value, JSVM_Finalize cb, void* data, void* hint)
125     : FinalizerTracker(env, cb, data, hint), persistent(env->isolate, value)
126 {
127     DCHECK(CanBeHeldWeakly(value));
128 }
129 
New(JSVM_Env env,v8::Local<v8::Value> value,void * data)130 RuntimeReference* RuntimeReference::New(JSVM_Env env, v8::Local<v8::Value> value, void* data)
131 {
132     auto* ref = new RuntimeReference(env, value, nullptr, data, nullptr);
133     // Delete self in first pass callback
134     ref->SetWeak(false);
135 
136     return ref;
137 }
138 
New(JSVM_Env env,v8::Local<v8::Value> value,JSVM_Finalize cb,void * data,void * hint)139 RuntimeReference* RuntimeReference::New(JSVM_Env env,
140                                         v8::Local<v8::Value> value,
141                                         JSVM_Finalize cb,
142                                         void* data,
143                                         void* hint)
144 {
145     auto* ref = new RuntimeReference(env, value, cb, data, hint);
146     // Need second pass callback to call finalizer
147     ref->SetWeak(cb != nullptr);
148 
149     return ref;
150 }
151 
DeleteReference(RuntimeReference * ref)152 void RuntimeReference::DeleteReference(RuntimeReference* ref)
153 {
154     // If reference is not added into first pass callbacks, delete this direct.
155     if (ref->persistent.IsWeak()) {
156         delete ref;
157         return;
158     }
159 
160     // If reference is added into first pass callbacks, reset finalizer function.
161     ref->ResetFinalizer();
162 }
163 
SetWeak(bool needSecondPass)164 inline void RuntimeReference::SetWeak(bool needSecondPass)
165 {
166     if (needSecondPass) {
167         persistent.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
168     } else {
169         persistent.SetWeak(this, FirstPassCallbackWithoutFinalizer, v8::WeakCallbackType::kParameter);
170     }
171 }
172 
FirstPassCallback(const v8::WeakCallbackInfo<RuntimeReference> & data)173 void RuntimeReference::FirstPassCallback(const v8::WeakCallbackInfo<RuntimeReference>& data)
174 {
175     RuntimeReference* reference = data.GetParameter();
176 
177     reference->persistent.Reset();
178     reference->Finalize();
179 }
180 
SecondPassCallback(const v8::WeakCallbackInfo<RuntimeReference> & data)181 void RuntimeReference::SecondPassCallback(const v8::WeakCallbackInfo<RuntimeReference>& data)
182 {
183     RuntimeReference* reference = data.GetParameter();
184 
185     reference->Finalize();
186 }
187 
FirstPassCallbackWithoutFinalizer(const v8::WeakCallbackInfo<RuntimeReference> & data)188 void RuntimeReference::FirstPassCallbackWithoutFinalizer(const v8::WeakCallbackInfo<RuntimeReference>& data)
189 {
190     RuntimeReference* reference = data.GetParameter();
191 
192     reference->persistent.Reset();
193     delete reference;
194 }
195 
196 } // namespace v8impl