1 #include "node.h"
2
3 #include <assert.h>
4 #include <vector>
5
6 namespace {
7
8 using node::AsyncResource;
9 using v8::External;
10 using v8::Function;
11 using v8::FunctionCallbackInfo;
12 using v8::Integer;
13 using v8::Isolate;
14 using v8::Local;
15 using v8::MaybeLocal;
16 using v8::Object;
17 using v8::String;
18 using v8::Value;
19
20 int custom_async_resource_destructor_calls = 0;
21
22 class CustomAsyncResource : public AsyncResource {
23 public:
CustomAsyncResource(Isolate * isolate,Local<Object> resource)24 CustomAsyncResource(Isolate* isolate, Local<Object> resource)
25 : AsyncResource(isolate, resource, "CustomAsyncResource") {}
~CustomAsyncResource()26 ~CustomAsyncResource() {
27 custom_async_resource_destructor_calls++;
28 }
29 };
30
CreateAsyncResource(const FunctionCallbackInfo<Value> & args)31 void CreateAsyncResource(const FunctionCallbackInfo<Value>& args) {
32 Isolate* isolate = args.GetIsolate();
33 assert(args[0]->IsObject());
34 AsyncResource* r;
35 if (args[1]->IsInt32()) {
36 r = new AsyncResource(isolate, args[0].As<Object>(), "foobär",
37 args[1].As<Integer>()->Value());
38 } else {
39 r = new AsyncResource(isolate, args[0].As<Object>(), "foobär");
40 }
41
42 args.GetReturnValue().Set(
43 External::New(isolate, static_cast<void*>(r)));
44 }
45
DestroyAsyncResource(const FunctionCallbackInfo<Value> & args)46 void DestroyAsyncResource(const FunctionCallbackInfo<Value>& args) {
47 assert(args[0]->IsExternal());
48 auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
49 delete r;
50 }
51
CallViaFunction(const FunctionCallbackInfo<Value> & args)52 void CallViaFunction(const FunctionCallbackInfo<Value>& args) {
53 Isolate* isolate = args.GetIsolate();
54 assert(args[0]->IsExternal());
55 auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
56
57 Local<String> name =
58 String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal)
59 .ToLocalChecked();
60 Local<Value> fn =
61 r->get_resource()->Get(isolate->GetCurrentContext(), name)
62 .ToLocalChecked();
63 assert(fn->IsFunction());
64
65 Local<Value> arg = Integer::New(isolate, 42);
66 MaybeLocal<Value> ret = r->MakeCallback(fn.As<Function>(), 1, &arg);
67 args.GetReturnValue().Set(ret.FromMaybe(Local<Value>()));
68 }
69
CallViaString(const FunctionCallbackInfo<Value> & args)70 void CallViaString(const FunctionCallbackInfo<Value>& args) {
71 Isolate* isolate = args.GetIsolate();
72 assert(args[0]->IsExternal());
73 auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
74
75 Local<String> name =
76 String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal)
77 .ToLocalChecked();
78
79 Local<Value> arg = Integer::New(isolate, 42);
80 MaybeLocal<Value> ret = r->MakeCallback(name, 1, &arg);
81 args.GetReturnValue().Set(ret.FromMaybe(Local<Value>()));
82 }
83
CallViaUtf8Name(const FunctionCallbackInfo<Value> & args)84 void CallViaUtf8Name(const FunctionCallbackInfo<Value>& args) {
85 Isolate* isolate = args.GetIsolate();
86 assert(args[0]->IsExternal());
87 auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
88
89 Local<Value> arg = Integer::New(isolate, 42);
90 MaybeLocal<Value> ret = r->MakeCallback("methöd", 1, &arg);
91 args.GetReturnValue().Set(ret.FromMaybe(Local<Value>()));
92 }
93
GetAsyncId(const FunctionCallbackInfo<Value> & args)94 void GetAsyncId(const FunctionCallbackInfo<Value>& args) {
95 assert(args[0]->IsExternal());
96 auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
97 args.GetReturnValue().Set(r->get_async_id());
98 }
99
GetTriggerAsyncId(const FunctionCallbackInfo<Value> & args)100 void GetTriggerAsyncId(const FunctionCallbackInfo<Value>& args) {
101 assert(args[0]->IsExternal());
102 auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
103 args.GetReturnValue().Set(r->get_trigger_async_id());
104 }
105
GetResource(const FunctionCallbackInfo<Value> & args)106 void GetResource(const FunctionCallbackInfo<Value>& args) {
107 assert(args[0]->IsExternal());
108 auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
109 args.GetReturnValue().Set(r->get_resource());
110 }
111
RunSubclassTest(const FunctionCallbackInfo<Value> & args)112 void RunSubclassTest(const FunctionCallbackInfo<Value>& args) {
113 Isolate* isolate = args.GetIsolate();
114 Local<Object> obj = Object::New(isolate);
115
116 assert(custom_async_resource_destructor_calls == 0);
117 CustomAsyncResource* resource = new CustomAsyncResource(isolate, obj);
118 delete static_cast<AsyncResource*>(resource);
119 assert(custom_async_resource_destructor_calls == 1);
120 }
121
Initialize(Local<Object> exports)122 void Initialize(Local<Object> exports) {
123 NODE_SET_METHOD(exports, "createAsyncResource", CreateAsyncResource);
124 NODE_SET_METHOD(exports, "destroyAsyncResource", DestroyAsyncResource);
125 NODE_SET_METHOD(exports, "callViaFunction", CallViaFunction);
126 NODE_SET_METHOD(exports, "callViaString", CallViaString);
127 NODE_SET_METHOD(exports, "callViaUtf8Name", CallViaUtf8Name);
128 NODE_SET_METHOD(exports, "getAsyncId", GetAsyncId);
129 NODE_SET_METHOD(exports, "getTriggerAsyncId", GetTriggerAsyncId);
130 NODE_SET_METHOD(exports, "getResource", GetResource);
131 NODE_SET_METHOD(exports, "runSubclassTest", RunSubclassTest);
132 }
133
134 } // anonymous namespace
135
136 NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
137