Skip to content

Commit 4b16a58

Browse files
committedMar 15, 2017
async_hooks: introduce async_hooks.js
Getting mechanics flushed out for both the necessary JS and C++ APIs. Currenty builds and runs, but complete implementation is coming.
1 parent 7d42f1f commit 4b16a58

33 files changed

+907
-282
lines changed
 

‎lib/_stream_wrap.js

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const uv = process.binding('uv');
99
const debug = util.debuglog('stream_wrap');
1010

1111
function StreamWrap(stream) {
12+
// TODO(trevnorris): Track down everything that calls StreamWrap and make
13+
// sure the trigger id is correctly set.
1214
const handle = new JSStream();
1315

1416
this.stream = stream;

‎lib/async_hooks.js

+400
Large diffs are not rendered by default.

‎lib/internal/module.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ function stripBOM(content) {
5151
}
5252

5353
exports.builtinLibs = [
54-
'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
55-
'domain', 'events', 'fs', 'http', 'https', 'net', 'os', 'path', 'punycode',
56-
'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'tls', 'tty',
57-
'url', 'util', 'v8', 'vm', 'zlib'
54+
'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'crypto',
55+
'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', 'os',
56+
'path', 'punycode', 'querystring', 'readline', 'repl', 'stream',
57+
'string_decoder', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib'
5858
];
5959

6060
function addBuiltinLibsToObject(object) {

‎node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
'lib/internal/bootstrap_node.js',
2525
'lib/_debug_agent.js',
2626
'lib/_debugger.js',
27+
'lib/async_hooks.js',
2728
'lib/assert.js',
2829
'lib/buffer.js',
2930
'lib/child_process.js',

‎src/async-wrap-inl.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,8 @@
3636

3737
namespace node {
3838

39-
inline bool AsyncWrap::ran_init_callback() const {
40-
return static_cast<bool>(bits_ & 1);
41-
}
42-
43-
4439
inline AsyncWrap::ProviderType AsyncWrap::provider_type() const {
45-
return static_cast<ProviderType>(bits_ >> 1);
40+
return provider_type_;
4641
}
4742

4843

@@ -51,6 +46,11 @@ inline double AsyncWrap::get_id() const {
5146
}
5247

5348

49+
inline double AsyncWrap::get_trigger_id() const {
50+
return trigger_id_;
51+
}
52+
53+
5454
inline v8::Local<v8::Value> AsyncWrap::MakeCallback(
5555
const v8::Local<v8::String> symbol,
5656
int argc,

‎src/async-wrap.cc

+182-103
Large diffs are not rendered by default.

‎src/async-wrap.h

+16-15
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ class AsyncWrap : public BaseObject {
7676

7777
AsyncWrap(Environment* env,
7878
v8::Local<v8::Object> object,
79-
ProviderType provider,
80-
AsyncWrap* parent = nullptr);
79+
ProviderType provider);
8180

8281
virtual ~AsyncWrap();
8382

@@ -93,28 +92,30 @@ class AsyncWrap : public BaseObject {
9392

9493
inline double get_id() const;
9594

95+
inline double get_trigger_id() const;
96+
97+
void Reset();
98+
9699
// Only call these within a valid HandleScope.
100+
// TODO(trevnorris): These should return a MaybeLocal.
97101
v8::Local<v8::Value> MakeCallback(const v8::Local<v8::Function> cb,
98-
int argc,
99-
v8::Local<v8::Value>* argv);
102+
int argc,
103+
v8::Local<v8::Value>* argv);
100104
inline v8::Local<v8::Value> MakeCallback(const v8::Local<v8::String> symbol,
101-
int argc,
102-
v8::Local<v8::Value>* argv);
105+
int argc,
106+
v8::Local<v8::Value>* argv);
103107
inline v8::Local<v8::Value> MakeCallback(uint32_t index,
104-
int argc,
105-
v8::Local<v8::Value>* argv);
108+
int argc,
109+
v8::Local<v8::Value>* argv);
106110

107111
virtual size_t self_size() const = 0;
108112

109113
private:
110114
inline AsyncWrap();
111-
inline bool ran_init_callback() const;
112-
113-
// When the async hooks init JS function is called from the constructor it is
114-
// expected the context object will receive a _asyncQueue object property
115-
// that will be used to call pre/post in MakeCallback.
116-
uint32_t bits_;
117-
const double id_;
115+
const ProviderType provider_type_;
116+
// Because the values may be Reset(), cannot be made const.
117+
double id_;
118+
double trigger_id_;
118119
};
119120

120121
void LoadAsyncWrapperInfo(Environment* env);

‎src/cares_wrap.cc

+13
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ inline const char* ToErrorCodeString(int status) {
103103
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
104104
public:
105105
GetAddrInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
106+
~GetAddrInfoReqWrap();
106107

107108
size_t self_size() const override { return sizeof(*this); }
108109
};
@@ -114,6 +115,11 @@ GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
114115
}
115116

116117

118+
GetAddrInfoReqWrap::~GetAddrInfoReqWrap() {
119+
ClearWrap(object());
120+
}
121+
122+
117123
static void NewGetAddrInfoReqWrap(const FunctionCallbackInfo<Value>& args) {
118124
CHECK(args.IsConstructCall());
119125
}
@@ -122,6 +128,7 @@ static void NewGetAddrInfoReqWrap(const FunctionCallbackInfo<Value>& args) {
122128
class GetNameInfoReqWrap : public ReqWrap<uv_getnameinfo_t> {
123129
public:
124130
GetNameInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
131+
~GetNameInfoReqWrap();
125132

126133
size_t self_size() const override { return sizeof(*this); }
127134
};
@@ -133,6 +140,11 @@ GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env,
133140
}
134141

135142

143+
GetNameInfoReqWrap::~GetNameInfoReqWrap() {
144+
ClearWrap(object());
145+
}
146+
147+
136148
static void NewGetNameInfoReqWrap(const FunctionCallbackInfo<Value>& args) {
137149
CHECK(args.IsConstructCall());
138150
}
@@ -307,6 +319,7 @@ class QueryWrap : public AsyncWrap {
307319
: AsyncWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP) {
308320
if (env->in_domain())
309321
req_wrap_obj->Set(env->domain_string(), env->domain_array()->Get(0));
322+
Wrap(req_wrap_obj, this);
310323
}
311324

312325
~QueryWrap() override {

‎src/connect_wrap.cc

+5
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,9 @@ ConnectWrap::ConnectWrap(Environment* env,
1919
Wrap(req_wrap_obj, this);
2020
}
2121

22+
23+
ConnectWrap::~ConnectWrap() {
24+
ClearWrap(object());
25+
}
26+
2227
} // namespace node

‎src/connect_wrap.h

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class ConnectWrap : public ReqWrap<uv_connect_t> {
1515
ConnectWrap(Environment* env,
1616
v8::Local<v8::Object> req_wrap_obj,
1717
AsyncWrap::ProviderType provider);
18+
~ConnectWrap();
1819

1920
size_t self_size() const override { return sizeof(*this); }
2021
};

‎src/connection_wrap.cc

+4-8
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ using v8::Value;
2323
template <typename WrapType, typename UVType>
2424
ConnectionWrap<WrapType, UVType>::ConnectionWrap(Environment* env,
2525
Local<Object> object,
26-
ProviderType provider,
27-
AsyncWrap* parent)
26+
ProviderType provider)
2827
: StreamWrap(env,
2928
object,
3029
reinterpret_cast<uv_stream_t*>(&handle_),
31-
provider,
32-
parent) {}
30+
provider) {}
3331

3432

3533
template <typename WrapType, typename UVType>
@@ -115,14 +113,12 @@ void ConnectionWrap<WrapType, UVType>::AfterConnect(uv_connect_t* req,
115113
template ConnectionWrap<PipeWrap, uv_pipe_t>::ConnectionWrap(
116114
Environment* env,
117115
Local<Object> object,
118-
ProviderType provider,
119-
AsyncWrap* parent);
116+
ProviderType provider);
120117

121118
template ConnectionWrap<TCPWrap, uv_tcp_t>::ConnectionWrap(
122119
Environment* env,
123120
Local<Object> object,
124-
ProviderType provider,
125-
AsyncWrap* parent);
121+
ProviderType provider);
126122

127123
template void ConnectionWrap<PipeWrap, uv_pipe_t>::OnConnection(
128124
uv_stream_t* handle, int status);

‎src/connection_wrap.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ class ConnectionWrap : public StreamWrap {
2222
protected:
2323
ConnectionWrap(Environment* env,
2424
v8::Local<v8::Object> object,
25-
ProviderType provider,
26-
AsyncWrap* parent);
25+
ProviderType provider);
2726
~ConnectionWrap() {
2827
}
2928

‎src/env-inl.h

+56-16
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ inline uint32_t* IsolateData::zero_fill_field() const {
8080
return zero_fill_field_;
8181
}
8282

83-
inline Environment::AsyncHooks::AsyncHooks() {
84-
for (int i = 0; i < kFieldsCount; i++) fields_[i] = 0;
83+
inline Environment::AsyncHooks::AsyncHooks() : fields_(), uid_fields_() {
8584
}
8685

8786
inline uint32_t* Environment::AsyncHooks::fields() {
@@ -92,12 +91,12 @@ inline int Environment::AsyncHooks::fields_count() const {
9291
return kFieldsCount;
9392
}
9493

95-
inline bool Environment::AsyncHooks::callbacks_enabled() {
96-
return fields_[kEnableCallbacks] != 0;
94+
inline double* Environment::AsyncHooks::uid_fields() {
95+
return uid_fields_;
9796
}
9897

99-
inline void Environment::AsyncHooks::set_enable_callbacks(uint32_t flag) {
100-
fields_[kEnableCallbacks] = flag;
98+
inline int Environment::AsyncHooks::uid_fields_count() const {
99+
return kUidFieldsCount;
101100
}
102101

103102
inline Environment::AsyncCallbackScope::AsyncCallbackScope(Environment* env)
@@ -192,7 +191,6 @@ inline Environment::Environment(IsolateData* isolate_data,
192191
printed_error_(false),
193192
trace_sync_io_(false),
194193
makecallback_cntr_(0),
195-
async_wrap_id_(0),
196194
debugger_agent_(this),
197195
#if HAVE_INSPECTOR
198196
inspector_agent_(this),
@@ -258,11 +256,6 @@ inline v8::Isolate* Environment::isolate() const {
258256
return isolate_;
259257
}
260258

261-
inline bool Environment::async_wrap_callbacks_enabled() const {
262-
// The const_cast is okay, it doesn't violate conceptual const-ness.
263-
return const_cast<Environment*>(this)->async_hooks()->callbacks_enabled();
264-
}
265-
266259
inline bool Environment::in_domain() const {
267260
// The const_cast is okay, it doesn't violate conceptual const-ness.
268261
return using_domains() &&
@@ -341,14 +334,61 @@ inline void Environment::set_trace_sync_io(bool value) {
341334
trace_sync_io_ = value;
342335
}
343336

344-
inline double Environment::get_async_wrap_uid() {
345-
return ++async_wrap_id_;
346-
}
347-
348337
inline std::vector<double>* Environment::destroy_ids_list() {
349338
return &destroy_ids_list_;
350339
}
351340

341+
inline double Environment::new_async_uid() {
342+
return ++async_hooks()->uid_fields()[AsyncHooks::kAsyncUidCntr];
343+
}
344+
345+
inline double Environment::current_async_id() {
346+
return async_hooks()->uid_fields()[AsyncHooks::kCurrentId];
347+
}
348+
349+
inline double Environment::exchange_current_async_id(const double id) {
350+
const double oid = async_hooks()->uid_fields()[AsyncHooks::kCurrentId];
351+
async_hooks()->uid_fields()[AsyncHooks::kCurrentId] = id;
352+
return oid;
353+
}
354+
355+
inline double Environment::trigger_id() {
356+
return async_hooks()->uid_fields()[AsyncHooks::kTriggerId];
357+
}
358+
359+
inline double Environment::exchange_trigger_id(const double id) {
360+
const double oid = async_hooks()->uid_fields()[AsyncHooks::kTriggerId];
361+
async_hooks()->uid_fields()[AsyncHooks::kTriggerId] = id;
362+
return oid;
363+
}
364+
365+
inline double Environment::exchange_init_trigger_id(const double id) {
366+
auto uid_fields = async_hooks()->uid_fields();
367+
double tid = uid_fields[AsyncHooks::kInitTriggerId];
368+
uid_fields[AsyncHooks::kInitTriggerId] = id;
369+
if (tid <= 0) tid = uid_fields[AsyncHooks::kScopedTriggerId];
370+
if (tid <= 0) tid = uid_fields[AsyncHooks::kCurrentId];
371+
return tid;
372+
}
373+
374+
inline void Environment::set_init_trigger_id(const double id) {
375+
async_hooks()->uid_fields()[AsyncHooks::kInitTriggerId] = id;
376+
}
377+
378+
inline void Environment::erase_fd_async_id(int fd) {
379+
fd_async_id_map_.erase(fd);
380+
}
381+
382+
inline node_fd_async_ids Environment::get_fd_async_id(int fd) {
383+
return fd_async_id_map_[fd];
384+
}
385+
386+
inline void Environment::insert_fd_async_ids(int fd,
387+
double async_id,
388+
double trigger_id) {
389+
fd_async_id_map_[fd] = { async_id, trigger_id };
390+
}
391+
352392
inline double* Environment::heap_statistics_buffer() const {
353393
CHECK_NE(heap_statistics_buffer_, nullptr);
354394
return heap_statistics_buffer_;

‎src/env.h

+96-11
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include <stdint.h>
4040
#include <vector>
41+
#include <unordered_map>
4142

4243
// Caveat emptor: we're going slightly crazy with macros here but the end
4344
// hopefully justifies the means. We have a lot of per-context properties
@@ -82,7 +83,6 @@ namespace node {
8283
V(address_string, "address") \
8384
V(args_string, "args") \
8485
V(async, "async") \
85-
V(async_queue_string, "_asyncQueue") \
8686
V(buffer_string, "buffer") \
8787
V(bytes_string, "bytes") \
8888
V(bytes_parsed_string, "bytesParsed") \
@@ -282,6 +282,11 @@ struct node_ares_task {
282282
RB_ENTRY(node_ares_task) node;
283283
};
284284

285+
struct node_fd_async_ids {
286+
double async_id;
287+
double trigger_id;
288+
};
289+
285290
RB_HEAD(node_ares_task_list, node_ares_task);
286291

287292
class IsolateData {
@@ -322,22 +327,90 @@ class Environment {
322327
public:
323328
class AsyncHooks {
324329
public:
330+
// Reason for both UidFields and Fields are that one is stored as a double*
331+
// and the other as a uint32_t*.
332+
enum UidFields {
333+
kAsyncUidCntr,
334+
kCurrentId,
335+
kTriggerId,
336+
kInitTriggerId,
337+
kScopedTriggerId,
338+
kUidFieldsCount,
339+
};
340+
341+
enum Fields {
342+
kInit,
343+
kBefore,
344+
kAfter,
345+
kDestroy,
346+
kActiveHooks,
347+
kFieldsCount,
348+
};
349+
325350
inline uint32_t* fields();
326351
inline int fields_count() const;
327-
inline bool callbacks_enabled();
328-
inline void set_enable_callbacks(uint32_t flag);
352+
inline double* uid_fields();
353+
inline int uid_fields_count() const;
354+
355+
class InitScope {
356+
public:
357+
explicit InitScope(Environment* env, double init_trigger_id)
358+
: uid_fields_(env->async_hooks()->uid_fields()),
359+
init_trigger_id_(uid_fields_[AsyncHooks::kScopedTriggerId]) {
360+
uid_fields_[AsyncHooks::kScopedTriggerId] = init_trigger_id;
361+
}
362+
~InitScope() {
363+
uid_fields_[AsyncHooks::kScopedTriggerId] = init_trigger_id_;
364+
}
365+
private:
366+
double* uid_fields_;
367+
const double init_trigger_id_;
368+
369+
DISALLOW_COPY_AND_ASSIGN(InitScope);
370+
};
371+
372+
// ExecScope is meant for use in MakeCallback, to maintained stacked
373+
// state.
374+
// TODO(trevnorris): This conflicts with how emitBefore/emitAfter work
375+
// (manually tracking the stacks in a JS array). Technically they should
376+
// play nicely together, but write tests to prove this.
377+
class ExecScope {
378+
public:
379+
explicit ExecScope(Environment* env, double id, double trigger_id)
380+
: uid_fields_(env->async_hooks()->uid_fields()),
381+
id_(uid_fields_[AsyncHooks::kCurrentId]),
382+
trigger_id_(uid_fields_[AsyncHooks::kTriggerId]),
383+
disposed_(false) {
384+
uid_fields_[AsyncHooks::kCurrentId] = id;
385+
uid_fields_[AsyncHooks::kTriggerId] = trigger_id;
386+
}
387+
~ExecScope() {
388+
if (disposed_) return;
389+
Dispose();
390+
}
391+
void Dispose() {
392+
disposed_ = true;
393+
uid_fields_[AsyncHooks::kCurrentId] = id_;
394+
uid_fields_[AsyncHooks::kTriggerId] = trigger_id_;
395+
}
396+
397+
private:
398+
double* uid_fields_;
399+
const double id_;
400+
const double trigger_id_;
401+
bool disposed_;
402+
403+
DISALLOW_COPY_AND_ASSIGN(ExecScope);
404+
};
329405

330406
private:
331407
friend class Environment; // So we can call the constructor.
332408
inline AsyncHooks();
333409

334-
enum Fields {
335-
// Set this to not zero if the init hook should be called.
336-
kEnableCallbacks,
337-
kFieldsCount
338-
};
339-
340410
uint32_t fields_[kFieldsCount];
411+
// Gives us 2^53-1 unique ids. Good enough for now and makes the operation
412+
// cheaper in JS.
413+
double uid_fields_[kUidFieldsCount];
341414

342415
DISALLOW_COPY_AND_ASSIGN(AsyncHooks);
343416
};
@@ -442,7 +515,6 @@ class Environment {
442515

443516
inline v8::Isolate* isolate() const;
444517
inline uv_loop_t* event_loop() const;
445-
inline bool async_wrap_callbacks_enabled() const;
446518
inline bool in_domain() const;
447519
inline uint32_t watched_providers() const;
448520

@@ -479,7 +551,19 @@ class Environment {
479551
void PrintSyncTrace() const;
480552
inline void set_trace_sync_io(bool value);
481553

482-
inline double get_async_wrap_uid();
554+
// The necessary API for async_hooks.
555+
inline double new_async_uid();
556+
inline double current_async_id();
557+
inline double exchange_current_async_id(const double id);
558+
inline double trigger_id();
559+
inline double exchange_trigger_id(const double id);
560+
inline double exchange_init_trigger_id(const double id);
561+
inline void set_init_trigger_id(const double id);
562+
563+
// For propagating hook id's with a file descriptor.
564+
inline void erase_fd_async_id(int fd);
565+
inline node_fd_async_ids get_fd_async_id(int fd);
566+
inline void insert_fd_async_ids(int fd, double async_id, double trigger_id);
483567

484568
// List of id's that have been destroyed and need the destroy() cb called.
485569
inline std::vector<double>* destroy_ids_list();
@@ -583,6 +667,7 @@ class Environment {
583667
size_t makecallback_cntr_;
584668
double async_wrap_id_;
585669
std::vector<double> destroy_ids_list_;
670+
std::unordered_map<int, node_fd_async_ids> fd_async_id_map_;
586671
debugger::Agent debugger_agent_;
587672
#if HAVE_INSPECTOR
588673
inspector::Agent inspector_agent_;

‎src/handle_wrap.cc

+2-3
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,8 @@ void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {
9090
HandleWrap::HandleWrap(Environment* env,
9191
Local<Object> object,
9292
uv_handle_t* handle,
93-
AsyncWrap::ProviderType provider,
94-
AsyncWrap* parent)
95-
: AsyncWrap(env, object, provider, parent),
93+
AsyncWrap::ProviderType provider)
94+
: AsyncWrap(env, object, provider),
9695
state_(kInitialized),
9796
handle_(handle) {
9897
handle_->data = this;

‎src/handle_wrap.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ class HandleWrap : public AsyncWrap {
7474
HandleWrap(Environment* env,
7575
v8::Local<v8::Object> object,
7676
uv_handle_t* handle,
77-
AsyncWrap::ProviderType provider,
78-
AsyncWrap* parent = nullptr);
77+
AsyncWrap::ProviderType provider);
7978
~HandleWrap() override;
8079

8180
private:

‎src/js_stream.cc

+3-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ namespace node {
1212

1313
using v8::Array;
1414
using v8::Context;
15-
using v8::External;
1615
using v8::FunctionCallbackInfo;
1716
using v8::FunctionTemplate;
1817
using v8::HandleScope;
@@ -21,8 +20,8 @@ using v8::Object;
2120
using v8::Value;
2221

2322

24-
JSStream::JSStream(Environment* env, Local<Object> obj, AsyncWrap* parent)
25-
: AsyncWrap(env, obj, AsyncWrap::PROVIDER_JSSTREAM, parent),
23+
JSStream::JSStream(Environment* env, Local<Object> obj)
24+
: AsyncWrap(env, obj, AsyncWrap::PROVIDER_JSSTREAM),
2625
StreamBase(env) {
2726
node::Wrap(obj, this);
2827
MakeWeak<JSStream>(this);
@@ -115,17 +114,7 @@ void JSStream::New(const FunctionCallbackInfo<Value>& args) {
115114
// normal function.
116115
CHECK(args.IsConstructCall());
117116
Environment* env = Environment::GetCurrent(args);
118-
JSStream* wrap;
119-
120-
if (args.Length() == 0) {
121-
wrap = new JSStream(env, args.This(), nullptr);
122-
} else if (args[0]->IsExternal()) {
123-
void* ptr = args[0].As<External>()->Value();
124-
wrap = new JSStream(env, args.This(), static_cast<AsyncWrap*>(ptr));
125-
} else {
126-
UNREACHABLE();
127-
}
128-
CHECK(wrap);
117+
new JSStream(env, args.This());
129118
}
130119

131120

‎src/js_stream.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class JSStream : public AsyncWrap, public StreamBase {
3333
size_t self_size() const override { return sizeof(*this); }
3434

3535
protected:
36-
JSStream(Environment* env, v8::Local<v8::Object> obj, AsyncWrap* parent);
36+
JSStream(Environment* env, v8::Local<v8::Object> obj);
3737

3838
AsyncWrap* GetAsyncWrap() override;
3939

‎src/node.cc

+12-42
Original file line numberDiff line numberDiff line change
@@ -1228,21 +1228,13 @@ Local<Value> MakeCallback(Environment* env,
12281228
// If you hit this assertion, you forgot to enter the v8::Context first.
12291229
CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
12301230

1231-
Local<Function> before_fn = env->async_hooks_before_function();
1232-
Local<Function> after_fn = env->async_hooks_after_function();
12331231
Local<Object> object, domain;
1234-
bool ran_init_callback = false;
12351232
bool has_domain = false;
12361233

12371234
Environment::AsyncCallbackScope callback_scope(env);
12381235

1239-
// TODO(trevnorris): Adding "_asyncQueue" to the "this" in the init callback
1240-
// is a horrible way to detect usage. Rethink how detection should happen.
12411236
if (recv->IsObject()) {
12421237
object = recv.As<Object>();
1243-
Local<Value> async_queue_v = object->Get(env->async_queue_string());
1244-
if (async_queue_v->IsObject())
1245-
ran_init_callback = true;
12461238
}
12471239

12481240
if (env->using_domains()) {
@@ -1266,34 +1258,8 @@ Local<Value> MakeCallback(Environment* env,
12661258
}
12671259
}
12681260

1269-
if (ran_init_callback && !before_fn.IsEmpty()) {
1270-
TryCatch try_catch(env->isolate());
1271-
MaybeLocal<Value> ar = before_fn->Call(env->context(), object, 0, nullptr);
1272-
if (ar.IsEmpty()) {
1273-
ClearFatalExceptionHandlers(env);
1274-
FatalException(env->isolate(), try_catch);
1275-
return Local<Value>();
1276-
}
1277-
}
1278-
12791261
Local<Value> ret = callback->Call(recv, argc, argv);
12801262

1281-
if (ran_init_callback && !after_fn.IsEmpty()) {
1282-
Local<Value> did_throw = Boolean::New(env->isolate(), ret.IsEmpty());
1283-
// Currently there's no way to retrieve an uid from node::MakeCallback().
1284-
// This needs to be fixed.
1285-
Local<Value> vals[] =
1286-
{ Undefined(env->isolate()).As<Value>(), did_throw };
1287-
TryCatch try_catch(env->isolate());
1288-
MaybeLocal<Value> ar =
1289-
after_fn->Call(env->context(), object, arraysize(vals), vals);
1290-
if (ar.IsEmpty()) {
1291-
ClearFatalExceptionHandlers(env);
1292-
FatalException(env->isolate(), try_catch);
1293-
return Local<Value>();
1294-
}
1295-
}
1296-
12971263
if (ret.IsEmpty()) {
12981264
// NOTE: For backwards compatibility with public API we return Undefined()
12991265
// if the top level call threw.
@@ -1337,21 +1303,21 @@ Local<Value> MakeCallback(Environment* env,
13371303

13381304

13391305
Local<Value> MakeCallback(Environment* env,
1340-
Local<Object> recv,
1341-
Local<String> symbol,
1342-
int argc,
1343-
Local<Value> argv[]) {
1306+
Local<Object> recv,
1307+
Local<String> symbol,
1308+
int argc,
1309+
Local<Value> argv[]) {
13441310
Local<Value> cb_v = recv->Get(symbol);
13451311
CHECK(cb_v->IsFunction());
13461312
return MakeCallback(env, recv.As<Value>(), cb_v.As<Function>(), argc, argv);
13471313
}
13481314

13491315

13501316
Local<Value> MakeCallback(Environment* env,
1351-
Local<Object> recv,
1352-
const char* method,
1353-
int argc,
1354-
Local<Value> argv[]) {
1317+
Local<Object> recv,
1318+
const char* method,
1319+
int argc,
1320+
Local<Value> argv[]) {
13551321
Local<String> method_string = OneByteString(env->isolate(), method);
13561322
return MakeCallback(env, recv, method_string, argc, argv);
13571323
}
@@ -4455,6 +4421,10 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
44554421
}
44564422

44574423
env.set_trace_sync_io(trace_sync_io);
4424+
// A current_async_id() of 1 means bootstrap phase. Now that the bootstrap
4425+
// phase is complete set the global id to 0 to let the internals know that
4426+
// everything points to the void.
4427+
env.exchange_current_async_id(0);
44584428

44594429
// Enable debugger
44604430
if (debug_enabled)

‎src/node_file.cc

+39-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,10 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
110110
Wrap(object(), this);
111111
}
112112

113-
~FSReqWrap() { ReleaseEarly(); }
113+
~FSReqWrap() {
114+
ReleaseEarly();
115+
ClearWrap(object());
116+
}
114117

115118
void* operator new(size_t size) = delete;
116119
void* operator new(size_t size, char* storage) { return storage; }
@@ -217,6 +220,9 @@ static void After(uv_fs_t *req) {
217220
break;
218221

219222
case UV_FS_OPEN:
223+
env->insert_fd_async_ids(req->result,
224+
req_wrap->get_id(),
225+
env->exchange_init_trigger_id(0));
220226
argv[1] = Integer::New(env->isolate(), req->result);
221227
break;
222228

@@ -432,6 +438,9 @@ static void Close(const FunctionCallbackInfo<Value>& args) {
432438
return TYPE_ERROR("fd must be a file descriptor");
433439

434440
int fd = args[0]->Int32Value();
441+
// TODO(trevnorris): Won't these values be needed for the destroy callbacks?
442+
// XXX Wouldn't fd_async_id_map_[n][1] be the triggerId of the close() call?
443+
env->erase_fd_async_id(fd);
435444

436445
if (args[1]->IsObject()) {
437446
ASYNC_CALL(close, args[1], UTF8, fd)
@@ -1073,6 +1082,10 @@ static void Open(const FunctionCallbackInfo<Value>& args) {
10731082
ASYNC_CALL(open, args[3], UTF8, *path, flags, mode)
10741083
} else {
10751084
SYNC_CALL(open, *path, *path, flags, mode)
1085+
// TODO(trevnorris): Is this really necessary for sync calls?
1086+
env->insert_fd_async_ids(SYNC_RESULT,
1087+
env->current_async_id(),
1088+
env->trigger_id());
10761089
args.GetReturnValue().Set(SYNC_RESULT);
10771090
}
10781091
}
@@ -1496,6 +1509,29 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
14961509
}
14971510
}
14981511

1512+
1513+
// To use this pass in a Float64Array(2) as the second argument. The asyncId
1514+
// and triggerId will be written to both indexes. This is much faster than
1515+
// creating and returning an Array.
1516+
static void GetIdsFromFd(const FunctionCallbackInfo<Value>& args) {
1517+
Environment* env = Environment::GetCurrent(args);
1518+
if (!args[0]->IsInt32())
1519+
return TYPE_ERROR("fd must be an int");
1520+
if (!args[1]->IsFloat64Array())
1521+
return TYPE_ERROR("arr must be a Float64Array");
1522+
1523+
Local<Float64Array> arr = args[1].As<Float64Array>();
1524+
if (arr->Length() < 2)
1525+
return env->ThrowRangeError("typed array is not large enough");
1526+
1527+
double* ptr = reinterpret_cast<double*>(arr->Buffer()->GetContents().Data());
1528+
node_fd_async_ids slot = env->get_fd_async_id(args[0]->Int32Value());
1529+
ptr[0] = slot.async_id;
1530+
ptr[1] = slot.trigger_id;
1531+
args.GetReturnValue().Set(arr);
1532+
}
1533+
1534+
14991535
void FSInitialize(const FunctionCallbackInfo<Value>& args) {
15001536
Local<Function> stats_constructor = args[0].As<Function>();
15011537
CHECK(stats_constructor->IsFunction());
@@ -1552,6 +1588,8 @@ void InitFs(Local<Object> target,
15521588

15531589
env->SetMethod(target, "mkdtemp", Mkdtemp);
15541590

1591+
env->SetMethod(target, "getIdsFromFd", GetIdsFromFd);
1592+
15551593
StatWatcher::Initialize(env, target);
15561594

15571595
// Create FunctionTemplate for FSReqWrap

‎src/node_http_parser.cc

+2
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ class Parser : public AsyncWrap {
475475
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
476476
// Should always be called from the same context.
477477
CHECK_EQ(env, parser->env());
478+
// The parser is being reused. Reset the uid and call init() callbacks.
479+
parser->Reset();
478480
parser->Init(type);
479481
}
480482

‎src/pipe_wrap.cc

+6-13
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ namespace node {
3838

3939
using v8::Context;
4040
using v8::EscapableHandleScope;
41-
using v8::External;
4241
using v8::Function;
4342
using v8::FunctionCallbackInfo;
4443
using v8::FunctionTemplate;
@@ -47,15 +46,16 @@ using v8::Local;
4746
using v8::Object;
4847
using v8::Value;
4948

49+
using AsyncHooks = Environment::AsyncHooks;
5050

5151
Local<Object> PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) {
5252
EscapableHandleScope handle_scope(env->isolate());
53+
AsyncHooks::InitScope init_scope(env, parent->get_id());
5354
CHECK_EQ(false, env->pipe_constructor_template().IsEmpty());
5455
Local<Function> constructor = env->pipe_constructor_template()->GetFunction();
5556
CHECK_EQ(false, constructor.IsEmpty());
56-
Local<Value> ptr = External::New(env->isolate(), parent);
5757
Local<Object> instance =
58-
constructor->NewInstance(env->context(), 1, &ptr).ToLocalChecked();
58+
constructor->NewInstance(env->context()).ToLocalChecked();
5959
return handle_scope.Escape(instance);
6060
}
6161

@@ -113,23 +113,16 @@ void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
113113
// normal function.
114114
CHECK(args.IsConstructCall());
115115
Environment* env = Environment::GetCurrent(args);
116-
if (args[0]->IsExternal()) {
117-
void* ptr = args[0].As<External>()->Value();
118-
new PipeWrap(env, args.This(), false, static_cast<AsyncWrap*>(ptr));
119-
} else {
120-
new PipeWrap(env, args.This(), args[0]->IsTrue(), nullptr);
121-
}
116+
new PipeWrap(env, args.This(), args[0]->IsTrue());
122117
}
123118

124119

125120
PipeWrap::PipeWrap(Environment* env,
126121
Local<Object> object,
127-
bool ipc,
128-
AsyncWrap* parent)
122+
bool ipc)
129123
: ConnectionWrap(env,
130124
object,
131-
AsyncWrap::PROVIDER_PIPEWRAP,
132-
parent) {
125+
AsyncWrap::PROVIDER_PIPEWRAP) {
133126
int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
134127
CHECK_EQ(r, 0); // How do we proxy this error up to javascript?
135128
// Suggestion: uv_pipe_init() returns void.

‎src/pipe_wrap.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ class PipeWrap : public ConnectionWrap<PipeWrap, uv_pipe_t> {
4242
private:
4343
PipeWrap(Environment* env,
4444
v8::Local<v8::Object> object,
45-
bool ipc,
46-
AsyncWrap* parent);
45+
bool ipc);
4746

4847
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
4948
static void Bind(const v8::FunctionCallbackInfo<v8::Value>& args);

‎src/req-wrap-inl.h

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ template <typename T>
3030
ReqWrap<T>::~ReqWrap() {
3131
CHECK_EQ(req_.data, this); // Assert that someone has called Dispatched().
3232
CHECK_EQ(false, persistent().IsEmpty());
33-
ClearWrap(object());
3433
persistent().Reset();
3534
}
3635

‎src/stream_base-inl.h

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ using v8::PropertyCallbackInfo;
2323
using v8::String;
2424
using v8::Value;
2525

26+
using AsyncHooks = Environment::AsyncHooks;
27+
2628
template <class Base>
2729
void StreamBase::AddMethods(Environment* env,
2830
Local<FunctionTemplate> t,
@@ -134,6 +136,7 @@ void StreamBase::JSMethod(const FunctionCallbackInfo<Value>& args) {
134136
if (!wrap->IsAlive())
135137
return args.GetReturnValue().Set(UV_EINVAL);
136138

139+
AsyncHooks::InitScope init_scope(handle->env(), handle->get_id());
137140
args.GetReturnValue().Set((wrap->*Method)(args));
138141
}
139142

‎src/stream_base.cc

+13
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ int StreamBase::Shutdown(const FunctionCallbackInfo<Value>& args) {
5353
CHECK(args[0]->IsObject());
5454
Local<Object> req_wrap_obj = args[0].As<Object>();
5555

56+
AsyncWrap* wrap = GetAsyncWrap();
57+
if (wrap != nullptr)
58+
env->set_init_trigger_id(wrap->get_id());
5659
ShutdownWrap* req_wrap = new ShutdownWrap(env,
5760
req_wrap_obj,
5861
this,
@@ -129,6 +132,10 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
129132
if (storage_size > INT_MAX)
130133
return UV_ENOBUFS;
131134

135+
AsyncWrap* wrap = GetAsyncWrap();
136+
// TODO(trevnorris): Would like to catalog every case when wrap == nullptr.
137+
if (wrap != nullptr)
138+
env->set_init_trigger_id(wrap->get_id());
132139
WriteWrap* req_wrap = WriteWrap::New(env,
133140
req_wrap_obj,
134141
this,
@@ -192,6 +199,7 @@ int StreamBase::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
192199
CHECK(Buffer::HasInstance(args[1]));
193200
Environment* env = Environment::GetCurrent(args);
194201

202+
AsyncWrap* wrap = GetAsyncWrap();
195203
Local<Object> req_wrap_obj = args[0].As<Object>();
196204
const char* data = Buffer::Data(args[1]);
197205
size_t length = Buffer::Length(args[1]);
@@ -211,6 +219,8 @@ int StreamBase::WriteBuffer(const FunctionCallbackInfo<Value>& args) {
211219
goto done;
212220
CHECK_EQ(count, 1);
213221

222+
if (wrap != nullptr)
223+
env->set_init_trigger_id(wrap->get_id());
214224
// Allocate, or write rest
215225
req_wrap = WriteWrap::New(env, req_wrap_obj, this, AfterWrite);
216226

@@ -239,6 +249,7 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
239249
CHECK(args[0]->IsObject());
240250
CHECK(args[1]->IsString());
241251

252+
AsyncWrap* wrap = GetAsyncWrap();
242253
Local<Object> req_wrap_obj = args[0].As<Object>();
243254
Local<String> string = args[1].As<String>();
244255
Local<Object> send_handle_obj;
@@ -292,6 +303,8 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
292303
CHECK_EQ(count, 1);
293304
}
294305

306+
if (wrap != nullptr)
307+
env->set_init_trigger_id(wrap->get_id());
295308
req_wrap = WriteWrap::New(env, req_wrap_obj, this, AfterWrite, storage_size);
296309

297310
data = req_wrap->Extra();

‎src/stream_base.h

+8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ class ShutdownWrap : public ReqWrap<uv_shutdown_t>,
5353
Wrap(req_wrap_obj, this);
5454
}
5555

56+
~ShutdownWrap() {
57+
ClearWrap(object());
58+
}
59+
5660
static void NewShutdownWrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
5761
CHECK(args.IsConstructCall());
5862
}
@@ -106,6 +110,10 @@ class WriteWrap: public ReqWrap<uv_write_t>,
106110
Wrap(obj, this);
107111
}
108112

113+
~WriteWrap() {
114+
ClearWrap(object());
115+
}
116+
109117
void* operator new(size_t size) = delete;
110118
void* operator new(size_t size, char* storage) { return storage; }
111119

‎src/stream_wrap.cc

+2-4
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,11 @@ void StreamWrap::Initialize(Local<Object> target,
8181
StreamWrap::StreamWrap(Environment* env,
8282
Local<Object> object,
8383
uv_stream_t* stream,
84-
AsyncWrap::ProviderType provider,
85-
AsyncWrap* parent)
84+
AsyncWrap::ProviderType provider)
8685
: HandleWrap(env,
8786
object,
8887
reinterpret_cast<uv_handle_t*>(stream),
89-
provider,
90-
parent),
88+
provider),
9189
StreamBase(env),
9290
stream_(stream) {
9391
set_after_write_cb({ OnAfterWriteImpl, this });

‎src/stream_wrap.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,7 @@ class StreamWrap : public HandleWrap, public StreamBase {
8181
StreamWrap(Environment* env,
8282
v8::Local<v8::Object> object,
8383
uv_stream_t* stream,
84-
AsyncWrap::ProviderType provider,
85-
AsyncWrap* parent = nullptr);
84+
AsyncWrap::ProviderType provider);
8685

8786
~StreamWrap() {
8887
}

‎src/tcp_wrap.cc

+9-16
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ namespace node {
4040
using v8::Boolean;
4141
using v8::Context;
4242
using v8::EscapableHandleScope;
43-
using v8::External;
4443
using v8::Function;
4544
using v8::FunctionCallbackInfo;
4645
using v8::FunctionTemplate;
@@ -51,15 +50,17 @@ using v8::Object;
5150
using v8::String;
5251
using v8::Value;
5352

53+
using AsyncHooks = Environment::AsyncHooks;
54+
5455

5556
Local<Object> TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
5657
EscapableHandleScope handle_scope(env->isolate());
58+
AsyncHooks::InitScope init_scope(env, parent->get_id());
5759
CHECK_EQ(env->tcp_constructor_template().IsEmpty(), false);
5860
Local<Function> constructor = env->tcp_constructor_template()->GetFunction();
5961
CHECK_EQ(constructor.IsEmpty(), false);
60-
Local<Value> ptr = External::New(env->isolate(), parent);
6162
Local<Object> instance =
62-
constructor->NewInstance(env->context(), 1, &ptr).ToLocalChecked();
63+
constructor->NewInstance(env->context()).ToLocalChecked();
6364
return handle_scope.Escape(instance);
6465
}
6566

@@ -133,24 +134,14 @@ void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
133134
// normal function.
134135
CHECK(args.IsConstructCall());
135136
Environment* env = Environment::GetCurrent(args);
136-
TCPWrap* wrap;
137-
if (args.Length() == 0) {
138-
wrap = new TCPWrap(env, args.This(), nullptr);
139-
} else if (args[0]->IsExternal()) {
140-
void* ptr = args[0].As<External>()->Value();
141-
wrap = new TCPWrap(env, args.This(), static_cast<AsyncWrap*>(ptr));
142-
} else {
143-
UNREACHABLE();
144-
}
145-
CHECK(wrap);
137+
new TCPWrap(env, args.This());
146138
}
147139

148140

149-
TCPWrap::TCPWrap(Environment* env, Local<Object> object, AsyncWrap* parent)
141+
TCPWrap::TCPWrap(Environment* env, Local<Object> object)
150142
: ConnectionWrap(env,
151143
object,
152-
AsyncWrap::PROVIDER_TCPWRAP,
153-
parent) {
144+
AsyncWrap::PROVIDER_TCPWRAP) {
154145
int r = uv_tcp_init(env->event_loop(), &handle_);
155146
CHECK_EQ(r, 0); // How do we proxy this error up to javascript?
156147
// Suggestion: uv_tcp_init() returns void.
@@ -278,6 +269,7 @@ void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
278269
int err = uv_ip4_addr(*ip_address, port, &addr);
279270

280271
if (err == 0) {
272+
env->set_init_trigger_id(wrap->get_id());
281273
ConnectWrap* req_wrap =
282274
new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP);
283275
err = uv_tcp_connect(req_wrap->req(),
@@ -313,6 +305,7 @@ void TCPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
313305
int err = uv_ip6_addr(*ip_address, port, &addr);
314306

315307
if (err == 0) {
308+
env->set_init_trigger_id(wrap->get_id());
316309
ConnectWrap* req_wrap =
317310
new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP);
318311
err = uv_tcp_connect(req_wrap->req(),

‎src/tcp_wrap.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class TCPWrap : public ConnectionWrap<TCPWrap, uv_tcp_t> {
4646
int (*F)(const typename T::HandleType*, sockaddr*, int*)>
4747
friend void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>&);
4848

49-
TCPWrap(Environment* env, v8::Local<v8::Object> object, AsyncWrap* parent);
49+
TCPWrap(Environment* env, v8::Local<v8::Object> object);
5050
~TCPWrap();
5151

5252
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);

‎src/udp_wrap.cc

+15-14
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ namespace node {
3737
using v8::Array;
3838
using v8::Context;
3939
using v8::EscapableHandleScope;
40-
using v8::External;
4140
using v8::FunctionCallbackInfo;
4241
using v8::FunctionTemplate;
4342
using v8::HandleScope;
@@ -50,10 +49,13 @@ using v8::String;
5049
using v8::Undefined;
5150
using v8::Value;
5251

52+
using AsyncHooks = Environment::AsyncHooks;
53+
5354

5455
class SendWrap : public ReqWrap<uv_udp_send_t> {
5556
public:
5657
SendWrap(Environment* env, Local<Object> req_wrap_obj, bool have_callback);
58+
~SendWrap();
5759
inline bool have_callback() const;
5860
size_t msg_size;
5961
size_t self_size() const override { return sizeof(*this); }
@@ -62,6 +64,11 @@ class SendWrap : public ReqWrap<uv_udp_send_t> {
6264
};
6365

6466

67+
SendWrap::~SendWrap() {
68+
ClearWrap(object());
69+
}
70+
71+
6572
SendWrap::SendWrap(Environment* env,
6673
Local<Object> req_wrap_obj,
6774
bool have_callback)
@@ -81,7 +88,7 @@ static void NewSendWrap(const FunctionCallbackInfo<Value>& args) {
8188
}
8289

8390

84-
UDPWrap::UDPWrap(Environment* env, Local<Object> object, AsyncWrap* parent)
91+
UDPWrap::UDPWrap(Environment* env, Local<Object> object)
8592
: HandleWrap(env,
8693
object,
8794
reinterpret_cast<uv_handle_t*>(&handle_),
@@ -148,15 +155,7 @@ void UDPWrap::Initialize(Local<Object> target,
148155
void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
149156
CHECK(args.IsConstructCall());
150157
Environment* env = Environment::GetCurrent(args);
151-
if (args.Length() == 0) {
152-
new UDPWrap(env, args.This(), nullptr);
153-
} else if (args[0]->IsExternal()) {
154-
new UDPWrap(env,
155-
args.This(),
156-
static_cast<AsyncWrap*>(args[0].As<External>()->Value()));
157-
} else {
158-
UNREACHABLE();
159-
}
158+
new UDPWrap(env, args.This());
160159
}
161160

162161

@@ -296,6 +295,7 @@ void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
296295
node::Utf8Value address(env->isolate(), args[4]);
297296
const bool have_callback = args[5]->IsTrue();
298297

298+
env->set_init_trigger_id(wrap->get_id());
299299
SendWrap* req_wrap = new SendWrap(env, req_wrap_obj, have_callback);
300300
size_t msg_size = 0;
301301

@@ -443,11 +443,12 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
443443

444444
Local<Object> UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
445445
EscapableHandleScope scope(env->isolate());
446+
AsyncHooks::InitScope init_scope(env, parent->get_id());
446447
// If this assert fires then Initialize hasn't been called yet.
447448
CHECK_EQ(env->udp_constructor_function().IsEmpty(), false);
448-
Local<Value> ptr = External::New(env->isolate(), parent);
449-
return scope.Escape(env->udp_constructor_function()
450-
->NewInstance(env->context(), 1, &ptr).ToLocalChecked());
449+
Local<Object> instance = env->udp_constructor_function()
450+
->NewInstance(env->context()).ToLocalChecked();
451+
return scope.Escape(instance);
451452
}
452453

453454

‎src/udp_wrap.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class UDPWrap: public HandleWrap {
6868
int (*F)(const typename T::HandleType*, sockaddr*, int*)>
6969
friend void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>&);
7070

71-
UDPWrap(Environment* env, v8::Local<v8::Object> object, AsyncWrap* parent);
71+
UDPWrap(Environment* env, v8::Local<v8::Object> object);
7272

7373
static void DoBind(const v8::FunctionCallbackInfo<v8::Value>& args,
7474
int family);

0 commit comments

Comments
 (0)
Please sign in to comment.