Coverage Report

Created: 2025-08-03 10:06

/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_