1 #include <stdio.h>
2 #include <cstdio>
3 #include <string>
4 #include "env-inl.h"
5 #include "gtest/gtest.h"
6 #include "js_native_api_v8.h"
7 #include "node_api_internals.h"
8 #include "node_binding.h"
9 #include "node_test_fixture.h"
10
11 namespace v8impl {
12
13 using v8::Local;
14 using v8::Object;
15
16 static napi_env addon_env;
17 static uint32_t finalizer_call_count = 0;
18
19 class JsNativeApiV8Test : public EnvironmentTestFixture {
20 private:
SetUp()21 void SetUp() override {
22 EnvironmentTestFixture::SetUp();
23 finalizer_call_count = 0;
24 }
25
TearDown()26 void TearDown() override { NodeTestFixture::TearDown(); }
27 };
28
TEST_F(JsNativeApiV8Test,Reference)29 TEST_F(JsNativeApiV8Test, Reference) {
30 const v8::HandleScope handle_scope(isolate_);
31 Argv argv;
32
33 napi_ref ref;
34 void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr, nullptr};
35 v8::WeakCallbackInfo<Reference::SecondPassCallParameterRef>::Callback
36 callback;
37 Reference::SecondPassCallParameterRef* parameter = nullptr;
38
39 {
40 Env test_env{handle_scope, argv};
41
42 node::Environment* env = *test_env;
43 node::LoadEnvironment(env, "");
44
45 napi_addon_register_func init = [](napi_env env, napi_value exports) {
46 addon_env = env;
47 return exports;
48 };
49 Local<Object> module_obj = Object::New(isolate_);
50 Local<Object> exports_obj = Object::New(isolate_);
51 napi_module_register_by_symbol(
52 exports_obj, module_obj, env->context(), init);
53 ASSERT_NE(addon_env, nullptr);
54 node_napi_env internal_env = reinterpret_cast<node_napi_env>(addon_env);
55 EXPECT_EQ(internal_env->node_env(), env);
56
57 // Create a new scope to manage the handles.
58 {
59 const v8::HandleScope handle_scope(isolate_);
60 napi_value value;
61 napi_create_object(addon_env, &value);
62 // Create a weak reference;
63 napi_add_finalizer(
64 addon_env,
65 value,
66 nullptr,
67 [](napi_env env, void* finalize_data, void* finalize_hint) {
68 finalizer_call_count++;
69 },
70 nullptr,
71 &ref);
72 parameter = reinterpret_cast<Reference*>(ref)->_secondPassParameter;
73 }
74
75 // We can hardly trigger a non-forced Garbage Collection in a stable way.
76 // Here we just invoke the weak callbacks directly.
77 // The persistant handles should be reset in the weak callback in respect
78 // to the API contract of v8 weak callbacks.
79 v8::WeakCallbackInfo<Reference::SecondPassCallParameterRef> data(
80 reinterpret_cast<v8::Isolate*>(isolate_),
81 parameter,
82 embedder_fields,
83 &callback);
84 Reference::FinalizeCallback(data);
85 EXPECT_EQ(callback, &Reference::SecondPassCallback);
86 }
87 // Env goes out of scope, the environment has been teardown. All node-api ref
88 // trackers should have been destroyed.
89
90 // Now we call the second pass callback to verify the method do not abort with
91 // memory violations.
92 v8::WeakCallbackInfo<Reference::SecondPassCallParameterRef> data(
93 reinterpret_cast<v8::Isolate*>(isolate_),
94 parameter,
95 embedder_fields,
96 nullptr);
97 Reference::SecondPassCallback(data);
98
99 // After Environment Teardown
100 EXPECT_EQ(finalizer_call_count, uint32_t(1));
101 }
102 } // namespace v8impl
103