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