/src/node/src/js_native_api_v8.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef SRC_JS_NATIVE_API_V8_H_ |
2 | | #define SRC_JS_NATIVE_API_V8_H_ |
3 | | |
4 | | #include "js_native_api_types.h" |
5 | | #include "js_native_api_v8_internals.h" |
6 | | |
7 | | inline napi_status napi_clear_last_error(node_api_nogc_env env); |
8 | | |
9 | | namespace v8impl { |
10 | | |
11 | | class RefTracker { |
12 | | public: |
13 | 15.0k | RefTracker() = default; |
14 | 15.0k | virtual ~RefTracker() = default; |
15 | 0 | virtual void Finalize() {} |
16 | | |
17 | | typedef RefTracker RefList; |
18 | | |
19 | 0 | inline void Link(RefList* list) { |
20 | 0 | prev_ = list; |
21 | 0 | next_ = list->next_; |
22 | 0 | if (next_ != nullptr) { |
23 | 0 | next_->prev_ = this; |
24 | 0 | } |
25 | 0 | list->next_ = this; |
26 | 0 | } |
27 | | |
28 | 0 | inline void Unlink() { |
29 | 0 | if (prev_ != nullptr) { |
30 | 0 | prev_->next_ = next_; |
31 | 0 | } |
32 | 0 | if (next_ != nullptr) { |
33 | 0 | next_->prev_ = prev_; |
34 | 0 | } |
35 | 0 | prev_ = nullptr; |
36 | 0 | next_ = nullptr; |
37 | 0 | } |
38 | | |
39 | 15.0k | static void FinalizeAll(RefList* list) { |
40 | 15.0k | while (list->next_ != nullptr) { |
41 | 0 | list->next_->Finalize(); |
42 | 0 | } |
43 | 15.0k | } |
44 | | |
45 | | private: |
46 | | RefList* next_ = nullptr; |
47 | | RefList* prev_ = nullptr; |
48 | | }; |
49 | | |
50 | | class Finalizer; |
51 | | } // end of namespace v8impl |
52 | | |
53 | | struct napi_env__ { |
54 | | explicit napi_env__(v8::Local<v8::Context> context, |
55 | | int32_t module_api_version) |
56 | 7.52k | : isolate(context->GetIsolate()), |
57 | 7.52k | context_persistent(isolate, context), |
58 | 7.52k | module_api_version(module_api_version) { |
59 | 7.52k | napi_clear_last_error(this); |
60 | 7.52k | } |
61 | | |
62 | 173k | inline v8::Local<v8::Context> context() const { |
63 | 173k | return v8impl::PersistentToLocal::Strong(context_persistent); |
64 | 173k | } |
65 | | |
66 | 0 | inline void Ref() { refs++; } |
67 | 7.52k | inline void Unref() { |
68 | 7.52k | if (--refs == 0) DeleteMe(); |
69 | 7.52k | } |
70 | | |
71 | 0 | virtual bool can_call_into_js() const { return true; } |
72 | | |
73 | 0 | static inline void HandleThrow(napi_env env, v8::Local<v8::Value> value) { |
74 | 0 | if (env->terminatedOrTerminating()) { |
75 | 0 | return; |
76 | 0 | } |
77 | 0 | env->isolate->ThrowException(value); |
78 | 0 | } |
79 | | |
80 | | // i.e. whether v8 exited or is about to exit |
81 | 0 | inline bool terminatedOrTerminating() { |
82 | 0 | return this->isolate->IsExecutionTerminating() || !can_call_into_js(); |
83 | 0 | } |
84 | | |
85 | | // v8 uses a special exception to indicate termination, the |
86 | | // `handle_exception` callback should identify such case using |
87 | | // terminatedOrTerminating() before actually handle the exception |
88 | | template <typename T, typename U = decltype(HandleThrow)> |
89 | 7.52k | inline void CallIntoModule(T&& call, U&& handle_exception = HandleThrow) { |
90 | 7.52k | int open_handle_scopes_before = open_handle_scopes; |
91 | 7.52k | int open_callback_scopes_before = open_callback_scopes; |
92 | 7.52k | napi_clear_last_error(this); |
93 | 7.52k | call(this); |
94 | 7.52k | CHECK_EQ(open_handle_scopes, open_handle_scopes_before); |
95 | 7.52k | CHECK_EQ(open_callback_scopes, open_callback_scopes_before); |
96 | 7.52k | if (!last_exception.IsEmpty()) { |
97 | 0 | handle_exception(this, last_exception.Get(this->isolate)); |
98 | 0 | last_exception.Reset(); |
99 | 0 | } |
100 | 7.52k | } Unexecuted instantiation: void napi_env__::CallIntoModule<napi_env__::CallFinalizer(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}, void (napi_env__*, v8::Local<napi_env__::CallFinalizer(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}::Value>)>(napi_env__::CallFinalizer(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}&&, void (&&)(napi_env__*, v8::Local<napi_env__::CallFinalizer(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}::Value>)) Unexecuted instantiation: node_api.cc:void napi_env__::CallIntoModule<(anonymous namespace)::uvimpl::Work::AfterThreadPoolWork(int)::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<true, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}>((anonymous namespace)::uvimpl::Work::AfterThreadPoolWork(int)::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<true, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}) Unexecuted instantiation: void napi_env__::CallIntoModule<node_napi_env__::CallFinalizer<false>(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<false, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}>(node_napi_env__::CallFinalizer<false>(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<false, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}) Unexecuted instantiation: node_api.cc:void napi_env__::CallIntoModule<v8impl::(anonymous namespace)::ThreadSafeFunction::DispatchOne()::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<false, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}>(v8impl::(anonymous namespace)::ThreadSafeFunction::DispatchOne()::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<false, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}) Unexecuted instantiation: void napi_env__::CallIntoModule<node_napi_env__::CallFinalizer<true>(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<true, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}>(node_napi_env__::CallFinalizer<true>(void (*)(napi_env__*, void*, void*), void*, void*)::{lambda(napi_env__*)#1}&, node_napi_env__::CallbackIntoModule<true, {lambda(napi_env__*)#1}>({lambda(napi_env__*)#1}&&)::{lambda(napi_env__*, v8::Local<auto:2&&::Value>)#1}) node_api.cc:void napi_env__::CallIntoModule<napi_module_register_by_symbol(v8::Local<v8::Object>, v8::Local<v8::Value>, v8::Local<v8::Context>, napi_value__* (*)(napi_env__*, napi_value__*), int)::$_0, void (napi_env__*, v8::Local<v8::Value>)>(napi_module_register_by_symbol(v8::Local<v8::Object>, v8::Local<v8::Value>, v8::Local<v8::Context>, napi_value__* (*)(napi_env__*, napi_value__*), int)::$_0&&, void (&&)(napi_env__*, v8::Local<v8::Value>)) Line | Count | Source | 89 | 7.52k | inline void CallIntoModule(T&& call, U&& handle_exception = HandleThrow) { | 90 | 7.52k | int open_handle_scopes_before = open_handle_scopes; | 91 | 7.52k | int open_callback_scopes_before = open_callback_scopes; | 92 | 7.52k | napi_clear_last_error(this); | 93 | 7.52k | call(this); | 94 | 7.52k | CHECK_EQ(open_handle_scopes, open_handle_scopes_before); | 95 | 7.52k | CHECK_EQ(open_callback_scopes, open_callback_scopes_before); | 96 | 7.52k | if (!last_exception.IsEmpty()) { | 97 | 0 | handle_exception(this, last_exception.Get(this->isolate)); | 98 | 0 | last_exception.Reset(); | 99 | 0 | } | 100 | 7.52k | } |
Unexecuted instantiation: js_native_api_v8.cc:void napi_env__::CallIntoModule<v8impl::(anonymous namespace)::CallbackWrapperBase::InvokeCallback()::{lambda(napi_env__*)#1}, v8impl::(anonymous namespace)::CallbackWrapperBase::InvokeCallback()::{lambda(napi_env__*, v8::Local<v8impl::(anonymous namespace)::CallbackWrapperBase::InvokeCallback()::{lambda(napi_env__*)#1}::Value>)#1}>(v8impl::(anonymous namespace)::CallbackWrapperBase::InvokeCallback()::{lambda(napi_env__*)#1}&&, v8impl::(anonymous namespace)::CallbackWrapperBase::InvokeCallback()::{lambda(napi_env__*, v8::Local<v8impl::(anonymous namespace)::CallbackWrapperBase::InvokeCallback()::{lambda(napi_env__*)#1}::Value>)#1}&&) |
101 | | |
102 | | // Call finalizer immediately. |
103 | 0 | virtual void CallFinalizer(napi_finalize cb, void* data, void* hint) { |
104 | 0 | v8::HandleScope handle_scope(isolate); |
105 | 0 | CallIntoModule([&](napi_env env) { cb(env, data, hint); }); |
106 | 0 | } |
107 | | |
108 | | // Invoke finalizer from V8 garbage collector. |
109 | | void InvokeFinalizerFromGC(v8impl::RefTracker* finalizer); |
110 | | |
111 | | // Enqueue the finalizer to the napi_env's own queue of the second pass |
112 | | // weak callback. |
113 | | // Implementation should drain the queue at the time it is safe to call |
114 | | // into JavaScript. |
115 | 0 | virtual void EnqueueFinalizer(v8impl::RefTracker* finalizer) { |
116 | 0 | pending_finalizers.emplace(finalizer); |
117 | 0 | } |
118 | | |
119 | | // Remove the finalizer from the scheduled second pass weak callback queue. |
120 | | // The finalizer can be deleted after this call. |
121 | 0 | virtual void DequeueFinalizer(v8impl::RefTracker* finalizer) { |
122 | 0 | pending_finalizers.erase(finalizer); |
123 | 0 | } |
124 | | |
125 | 7.52k | virtual void DeleteMe() { |
126 | | // First we must finalize those references that have `napi_finalizer` |
127 | | // callbacks. The reason is that addons might store other references which |
128 | | // they delete during their `napi_finalizer` callbacks. If we deleted such |
129 | | // references here first, they would be doubly deleted when the |
130 | | // `napi_finalizer` deleted them subsequently. |
131 | 7.52k | v8impl::RefTracker::FinalizeAll(&finalizing_reflist); |
132 | 7.52k | v8impl::RefTracker::FinalizeAll(&reflist); |
133 | 7.52k | delete this; |
134 | 7.52k | } |
135 | | |
136 | 135k | void CheckGCAccess() { |
137 | 135k | if (module_api_version == NAPI_VERSION_EXPERIMENTAL && in_gc_finalizer) { |
138 | 0 | v8impl::OnFatalError( |
139 | 0 | nullptr, |
140 | 0 | "Finalizer is calling a function that may affect GC state.\n" |
141 | 0 | "The finalizers are run directly from GC and must not affect GC " |
142 | 0 | "state.\n" |
143 | 0 | "Use `node_api_post_finalizer` from inside of the finalizer to work " |
144 | 0 | "around this issue.\n" |
145 | 0 | "It schedules the call as a new task in the event loop."); |
146 | 0 | } |
147 | 135k | } |
148 | | |
149 | | v8::Isolate* const isolate; // Shortcut for context()->GetIsolate() |
150 | | v8impl::Persistent<v8::Context> context_persistent; |
151 | | |
152 | | v8impl::Persistent<v8::Value> last_exception; |
153 | | |
154 | | // We store references in two different lists, depending on whether they have |
155 | | // `napi_finalizer` callbacks, because we must first finalize the ones that |
156 | | // have such a callback. See `~napi_env__()` above for details. |
157 | | v8impl::RefTracker::RefList reflist; |
158 | | v8impl::RefTracker::RefList finalizing_reflist; |
159 | | // The invocation order of the finalizers is not determined. |
160 | | std::unordered_set<v8impl::RefTracker*> pending_finalizers; |
161 | | napi_extended_error_info last_error; |
162 | | int open_handle_scopes = 0; |
163 | | int open_callback_scopes = 0; |
164 | | int refs = 1; |
165 | | void* instance_data = nullptr; |
166 | | int32_t module_api_version = NODE_API_DEFAULT_MODULE_API_VERSION; |
167 | | bool in_gc_finalizer = false; |
168 | | |
169 | | protected: |
170 | | // Should not be deleted directly. Delete with `napi_env__::DeleteMe()` |
171 | | // instead. |
172 | 7.52k | virtual ~napi_env__() = default; |
173 | | }; |
174 | | |
175 | 150k | inline napi_status napi_clear_last_error(node_api_nogc_env nogc_env) { |
176 | 150k | napi_env env = const_cast<napi_env>(nogc_env); |
177 | 150k | env->last_error.error_code = napi_ok; |
178 | 150k | env->last_error.engine_error_code = 0; |
179 | 150k | env->last_error.engine_reserved = nullptr; |
180 | 150k | env->last_error.error_message = nullptr; |
181 | 150k | return napi_ok; |
182 | 150k | } |
183 | | |
184 | | inline napi_status napi_set_last_error(node_api_nogc_env nogc_env, |
185 | | napi_status error_code, |
186 | | uint32_t engine_error_code = 0, |
187 | 5.91k | void* engine_reserved = nullptr) { |
188 | 5.91k | napi_env env = const_cast<napi_env>(nogc_env); |
189 | 5.91k | env->last_error.error_code = error_code; |
190 | 5.91k | env->last_error.engine_error_code = engine_error_code; |
191 | 5.91k | env->last_error.engine_reserved = engine_reserved; |
192 | 5.91k | return error_code; |
193 | 5.91k | } |
194 | | |
195 | | #define RETURN_STATUS_IF_FALSE(env, condition, status) \ |
196 | 748k | do { \ |
197 | 748k | if (!(condition)) { \ |
198 | 5.91k | return napi_set_last_error((env), (status)); \ |
199 | 5.91k | } \ |
200 | 748k | } while (0) |
201 | | |
202 | | #define RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env, condition, status) \ |
203 | 60.2k | do { \ |
204 | 60.2k | if (!(condition)) { \ |
205 | 0 | return napi_set_last_error( \ |
206 | 0 | (env), try_catch.HasCaught() ? napi_pending_exception : (status)); \ |
207 | 0 | } \ |
208 | 60.2k | } while (0) |
209 | | |
210 | | #define CHECK_ENV(env) \ |
211 | 135k | do { \ |
212 | 135k | if ((env) == nullptr) { \ |
213 | 0 | return napi_invalid_arg; \ |
214 | 0 | } \ |
215 | 135k | } while (0) |
216 | | |
217 | | #define CHECK_ENV_NOT_IN_GC(env) \ |
218 | 135k | do { \ |
219 | 135k | CHECK_ENV((env)); \ |
220 | 135k | (env)->CheckGCAccess(); \ |
221 | 135k | } while (0) |
222 | | |
223 | | #define CHECK_ARG(env, arg) \ |
224 | 270k | RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) |
225 | | |
226 | | #define CHECK_ARG_WITH_PREAMBLE(env, arg) \ |
227 | 0 | RETURN_STATUS_IF_FALSE_WITH_PREAMBLE( \ |
228 | 0 | (env), ((arg) != nullptr), napi_invalid_arg) |
229 | | |
230 | | #define CHECK_MAYBE_EMPTY(env, maybe, status) \ |
231 | 138k | RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status)) |
232 | | |
233 | | #define CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe, status) \ |
234 | | RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsEmpty()), (status)) |
235 | | |
236 | | // NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope |
237 | | #define NAPI_PREAMBLE(env) \ |
238 | 67.7k | CHECK_ENV_NOT_IN_GC((env)); \ |
239 | 67.7k | RETURN_STATUS_IF_FALSE( \ |
240 | 67.7k | (env), (env)->last_exception.IsEmpty(), napi_pending_exception); \ |
241 | 67.7k | RETURN_STATUS_IF_FALSE((env), \ |
242 | 67.7k | (env)->can_call_into_js(), \ |
243 | 67.7k | (env->module_api_version == NAPI_VERSION_EXPERIMENTAL \ |
244 | 67.7k | ? napi_cannot_run_js \ |
245 | 67.7k | : napi_pending_exception)); \ |
246 | 67.7k | napi_clear_last_error((env)); \ |
247 | 67.7k | v8impl::TryCatch try_catch((env)) |
248 | | |
249 | | #define CHECK_TO_TYPE(env, type, context, result, src, status) \ |
250 | 60.2k | do { \ |
251 | 60.2k | CHECK_ARG((env), (src)); \ |
252 | 60.2k | auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \ |
253 | 60.2k | CHECK_MAYBE_EMPTY((env), maybe, (status)); \ |
254 | 60.2k | (result) = maybe.ToLocalChecked(); \ |
255 | 60.2k | } while (0) |
256 | | |
257 | | #define CHECK_TO_TYPE_WITH_PREAMBLE(env, type, context, result, src, status) \ |
258 | 0 | do { \ |
259 | 0 | CHECK_ARG_WITH_PREAMBLE((env), (src)); \ |
260 | 0 | auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \ |
261 | 0 | CHECK_MAYBE_EMPTY_WITH_PREAMBLE((env), maybe, (status)); \ |
262 | 0 | (result) = maybe.ToLocalChecked(); \ |
263 | 0 | } while (0) |
264 | | |
265 | | #define CHECK_TO_FUNCTION(env, result, src) \ |
266 | 0 | do { \ |
267 | 0 | CHECK_ARG((env), (src)); \ |
268 | 0 | v8::Local<v8::Value> v8value = v8impl::V8LocalValueFromJsValue((src)); \ |
269 | 0 | RETURN_STATUS_IF_FALSE((env), v8value->IsFunction(), napi_invalid_arg); \ |
270 | 0 | (result) = v8value.As<v8::Function>(); \ |
271 | 0 | } while (0) |
272 | | |
273 | | #define CHECK_TO_OBJECT(env, context, result, src) \ |
274 | 60.2k | CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected) |
275 | | |
276 | | #define CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, result, src) \ |
277 | 0 | CHECK_TO_TYPE_WITH_PREAMBLE( \ |
278 | 0 | (env), Object, (context), (result), (src), napi_object_expected) |
279 | | |
280 | | #define CHECK_TO_STRING(env, context, result, src) \ |
281 | 0 | CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected) |
282 | | |
283 | | #define GET_RETURN_STATUS(env) \ |
284 | 61.8k | (!try_catch.HasCaught() \ |
285 | 61.8k | ? napi_ok \ |
286 | 61.8k | : napi_set_last_error((env), napi_pending_exception)) |
287 | | |
288 | | #define THROW_RANGE_ERROR_IF_FALSE(env, condition, error, message) \ |
289 | 0 | do { \ |
290 | 0 | if (!(condition)) { \ |
291 | 0 | napi_throw_range_error((env), (error), (message)); \ |
292 | 0 | return napi_set_last_error((env), napi_generic_failure); \ |
293 | 0 | } \ |
294 | 0 | } while (0) |
295 | | |
296 | | #define CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe, status) \ |
297 | 22.5k | RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsEmpty()), (status)) |
298 | | |
299 | | #define STATUS_CALL(call) \ |
300 | 30.1k | do { \ |
301 | 30.1k | napi_status status = (call); \ |
302 | 30.1k | if (status != napi_ok) return status; \ |
303 | 30.1k | } while (0) |
304 | | |
305 | | namespace v8impl { |
306 | | |
307 | | //=== Conversion between V8 Handles and napi_value ======================== |
308 | | |
309 | | // This asserts v8::Local<> will always be implemented with a single |
310 | | // pointer field so that we can pass it around as a void*. |
311 | | static_assert(sizeof(v8::Local<v8::Value>) == sizeof(napi_value), |
312 | | "Cannot convert between v8::Local<v8::Value> and napi_value"); |
313 | | |
314 | 91.9k | inline napi_value JsValueFromV8LocalValue(v8::Local<v8::Value> local) { |
315 | 91.9k | return reinterpret_cast<napi_value>(*local); |
316 | 91.9k | } |
317 | | |
318 | 195k | inline v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) { |
319 | 195k | v8::Local<v8::Value> local; |
320 | 195k | memcpy(static_cast<void*>(&local), &v, sizeof(v)); |
321 | 195k | return local; |
322 | 195k | } |
323 | | |
324 | | // Adapter for napi_finalize callbacks. |
325 | | class Finalizer { |
326 | | protected: |
327 | | Finalizer(napi_env env, |
328 | | napi_finalize finalize_callback, |
329 | | void* finalize_data, |
330 | | void* finalize_hint) |
331 | 0 | : env_(env), |
332 | 0 | finalize_callback_(finalize_callback), |
333 | 0 | finalize_data_(finalize_data), |
334 | 0 | finalize_hint_(finalize_hint) {} |
335 | | |
336 | 0 | virtual ~Finalizer() = default; |
337 | | |
338 | | public: |
339 | | static Finalizer* New(napi_env env, |
340 | | napi_finalize finalize_callback = nullptr, |
341 | | void* finalize_data = nullptr, |
342 | 0 | void* finalize_hint = nullptr) { |
343 | 0 | return new Finalizer(env, finalize_callback, finalize_data, finalize_hint); |
344 | 0 | } |
345 | | |
346 | 0 | napi_finalize callback() { return finalize_callback_; } |
347 | 0 | void* data() { return finalize_data_; } |
348 | 0 | void* hint() { return finalize_hint_; } |
349 | | |
350 | | void ResetFinalizer(); |
351 | | |
352 | | protected: |
353 | | napi_env env_; |
354 | | napi_finalize finalize_callback_; |
355 | | void* finalize_data_; |
356 | | void* finalize_hint_; |
357 | | }; |
358 | | |
359 | | class TryCatch : public v8::TryCatch { |
360 | | public: |
361 | 67.7k | explicit TryCatch(napi_env env) : v8::TryCatch(env->isolate), _env(env) {} |
362 | | |
363 | 67.7k | ~TryCatch() { |
364 | 67.7k | if (HasCaught()) { |
365 | 5.91k | _env->last_exception.Reset(_env->isolate, Exception()); |
366 | 5.91k | } |
367 | 67.7k | } |
368 | | |
369 | | private: |
370 | | napi_env _env; |
371 | | }; |
372 | | |
373 | | // Ownership of a reference. |
374 | | enum class Ownership { |
375 | | // The reference is owned by the runtime. No userland call is needed to |
376 | | // destruct the reference. |
377 | | kRuntime, |
378 | | // The reference is owned by the userland. User code is responsible to delete |
379 | | // the reference with appropriate node-api calls. |
380 | | kUserland, |
381 | | }; |
382 | | |
383 | | // Wrapper around Finalizer that can be tracked. |
384 | | class TrackedFinalizer : public Finalizer, public RefTracker { |
385 | | protected: |
386 | | TrackedFinalizer(napi_env env, |
387 | | napi_finalize finalize_callback, |
388 | | void* finalize_data, |
389 | | void* finalize_hint); |
390 | | |
391 | | public: |
392 | | static TrackedFinalizer* New(napi_env env, |
393 | | napi_finalize finalize_callback, |
394 | | void* finalize_data, |
395 | | void* finalize_hint); |
396 | | ~TrackedFinalizer() override; |
397 | | |
398 | | protected: |
399 | | void Finalize() override; |
400 | | void FinalizeCore(bool deleteMe); |
401 | | }; |
402 | | |
403 | | // Wrapper around TrackedFinalizer that implements reference counting. |
404 | | class RefBase : public TrackedFinalizer { |
405 | | protected: |
406 | | RefBase(napi_env env, |
407 | | uint32_t initial_refcount, |
408 | | Ownership ownership, |
409 | | napi_finalize finalize_callback, |
410 | | void* finalize_data, |
411 | | void* finalize_hint); |
412 | | |
413 | | public: |
414 | | static RefBase* New(napi_env env, |
415 | | uint32_t initial_refcount, |
416 | | Ownership ownership, |
417 | | napi_finalize finalize_callback, |
418 | | void* finalize_data, |
419 | | void* finalize_hint); |
420 | | |
421 | | void* Data(); |
422 | | uint32_t Ref(); |
423 | | uint32_t Unref(); |
424 | | uint32_t RefCount(); |
425 | | |
426 | 0 | Ownership ownership() { return ownership_; } |
427 | | |
428 | | protected: |
429 | | void Finalize() override; |
430 | | |
431 | | private: |
432 | | uint32_t refcount_; |
433 | | Ownership ownership_; |
434 | | }; |
435 | | |
436 | | // Wrapper around v8impl::Persistent. |
437 | | class Reference : public RefBase { |
438 | | protected: |
439 | | template <typename... Args> |
440 | | Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args); |
441 | | |
442 | | public: |
443 | | static Reference* New(napi_env env, |
444 | | v8::Local<v8::Value> value, |
445 | | uint32_t initial_refcount, |
446 | | Ownership ownership, |
447 | | napi_finalize finalize_callback = nullptr, |
448 | | void* finalize_data = nullptr, |
449 | | void* finalize_hint = nullptr); |
450 | | |
451 | | virtual ~Reference(); |
452 | | uint32_t Ref(); |
453 | | uint32_t Unref(); |
454 | | v8::Local<v8::Value> Get(); |
455 | | |
456 | | protected: |
457 | | void Finalize() override; |
458 | | |
459 | | private: |
460 | | static void WeakCallback(const v8::WeakCallbackInfo<Reference>& data); |
461 | | |
462 | | void SetWeak(); |
463 | | |
464 | | v8impl::Persistent<v8::Value> persistent_; |
465 | | bool can_be_weak_; |
466 | | }; |
467 | | |
468 | | } // end of namespace v8impl |
469 | | |
470 | | #endif // SRC_JS_NATIVE_API_V8_H_ |