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