Skip to content

Commit 3f056f4

Browse files
trevnorrispiscisaureus
authored andcommitted
async-wrap: explicitly pass parent
When instantiating a new AsyncWrap allow the parent AsyncWrap to be passed. This is useful for cases like TCP incoming connections, so the connection can be tied to the server receiving the connection. Because the current architecture instantiates the *Wrap inside a v8::FunctionCallback, the parent pointer is currently wrapped inside a new v8::External every time and passed as an argument. This adds ~80ns to instantiation time. A future optimization would be to add the v8::External as the data field when creating the v8::FunctionTemplate, change the pointer just before making the call then NULL'ing it out afterwards. This adds enough code complexity that it will not be attempted until the current approach demonstrates it is a bottle neck. PR-URL: nodejs/node-v0.x-archive#8110 Signed-off-by: Trevor Norris <[email protected]> Reviewed-by: Fedor Indutny <[email protected]> Reviewed-by: Alexis Campailla <[email protected]> Reviewed-by: Julien Gilli <[email protected]>
1 parent c2ca873 commit 3f056f4

12 files changed

+89
-35
lines changed

src/async-wrap-inl.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ namespace node {
3535

3636
inline AsyncWrap::AsyncWrap(Environment* env,
3737
v8::Handle<v8::Object> object,
38-
ProviderType provider)
38+
ProviderType provider,
39+
AsyncWrap* parent)
3940
: BaseObject(env, object),
4041
provider_type_(provider) {
4142
}

src/async-wrap.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ class AsyncWrap : public BaseObject {
6363

6464
inline AsyncWrap(Environment* env,
6565
v8::Handle<v8::Object> object,
66-
ProviderType provider);
66+
ProviderType provider,
67+
AsyncWrap* parent = nullptr);
6768

6869
inline virtual ~AsyncWrap() override = default;
6970

src/handle_wrap.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {
8383
HandleWrap::HandleWrap(Environment* env,
8484
Handle<Object> object,
8585
uv_handle_t* handle,
86-
AsyncWrap::ProviderType provider)
87-
: AsyncWrap(env, object, provider),
86+
AsyncWrap::ProviderType provider,
87+
AsyncWrap* parent)
88+
: AsyncWrap(env, object, provider, parent),
8889
flags_(0),
8990
handle__(handle) {
9091
handle__->data = this;

src/handle_wrap.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class HandleWrap : public AsyncWrap {
6767
HandleWrap(Environment* env,
6868
v8::Handle<v8::Object> object,
6969
uv_handle_t* handle,
70-
AsyncWrap::ProviderType provider);
70+
AsyncWrap::ProviderType provider,
71+
AsyncWrap* parent = nullptr);
7172
virtual ~HandleWrap() override;
7273

7374
private:

src/pipe_wrap.cc

+18-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "pipe_wrap.h"
2323

24+
#include "async-wrap.h"
2425
#include "env.h"
2526
#include "env-inl.h"
2627
#include "handle_wrap.h"
@@ -37,6 +38,7 @@ namespace node {
3738
using v8::Boolean;
3839
using v8::Context;
3940
using v8::EscapableHandleScope;
41+
using v8::External;
4042
using v8::Function;
4143
using v8::FunctionCallbackInfo;
4244
using v8::FunctionTemplate;
@@ -74,12 +76,13 @@ uv_pipe_t* PipeWrap::UVHandle() {
7476
}
7577

7678

77-
Local<Object> PipeWrap::Instantiate(Environment* env) {
79+
Local<Object> PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) {
7880
EscapableHandleScope handle_scope(env->isolate());
7981
CHECK_EQ(false, env->pipe_constructor_template().IsEmpty());
8082
Local<Function> constructor = env->pipe_constructor_template()->GetFunction();
8183
CHECK_EQ(false, constructor.IsEmpty());
82-
Local<Object> instance = constructor->NewInstance();
84+
Local<Value> ptr = External::New(env->isolate(), parent);
85+
Local<Object> instance = constructor->NewInstance(1, &ptr);
8386
CHECK_EQ(false, instance.IsEmpty());
8487
return handle_scope.Escape(instance);
8588
}
@@ -147,15 +150,24 @@ void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
147150
// normal function.
148151
CHECK(args.IsConstructCall());
149152
Environment* env = Environment::GetCurrent(args);
150-
new PipeWrap(env, args.This(), args[0]->IsTrue());
153+
if (args[0]->IsExternal()) {
154+
void* ptr = args[0].As<External>()->Value();
155+
new PipeWrap(env, args.This(), false, static_cast<AsyncWrap*>(ptr));
156+
} else {
157+
new PipeWrap(env, args.This(), args[0]->IsTrue(), nullptr);
158+
}
151159
}
152160

153161

154-
PipeWrap::PipeWrap(Environment* env, Handle<Object> object, bool ipc)
162+
PipeWrap::PipeWrap(Environment* env,
163+
Handle<Object> object,
164+
bool ipc,
165+
AsyncWrap* parent)
155166
: StreamWrap(env,
156167
object,
157168
reinterpret_cast<uv_stream_t*>(&handle_),
158-
AsyncWrap::PROVIDER_PIPEWRAP) {
169+
AsyncWrap::PROVIDER_PIPEWRAP,
170+
parent) {
159171
int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
160172
CHECK_EQ(r, 0); // How do we proxy this error up to javascript?
161173
// Suggestion: uv_pipe_init() returns void.
@@ -214,7 +226,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) {
214226
}
215227

216228
// Instanciate the client javascript object and handle.
217-
Local<Object> client_obj = Instantiate(env);
229+
Local<Object> client_obj = Instantiate(env, pipe_wrap);
218230

219231
// Unwrap the client javascript object.
220232
PipeWrap* wrap = Unwrap<PipeWrap>(client_obj);

src/pipe_wrap.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#ifndef SRC_PIPE_WRAP_H_
2323
#define SRC_PIPE_WRAP_H_
2424

25+
#include "async-wrap.h"
2526
#include "env.h"
2627
#include "stream_wrap.h"
2728

@@ -31,13 +32,16 @@ class PipeWrap : public StreamWrap {
3132
public:
3233
uv_pipe_t* UVHandle();
3334

34-
static v8::Local<v8::Object> Instantiate(Environment* env);
35+
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
3536
static void Initialize(v8::Handle<v8::Object> target,
3637
v8::Handle<v8::Value> unused,
3738
v8::Handle<v8::Context> context);
3839

3940
private:
40-
PipeWrap(Environment* env, v8::Handle<v8::Object> object, bool ipc);
41+
PipeWrap(Environment* env,
42+
v8::Handle<v8::Object> object,
43+
bool ipc,
44+
AsyncWrap* parent);
4145

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

src/stream_wrap.cc

+14-7
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,13 @@ void StreamWrap::Initialize(Handle<Object> target,
8181
StreamWrap::StreamWrap(Environment* env,
8282
Local<Object> object,
8383
uv_stream_t* stream,
84-
AsyncWrap::ProviderType provider)
85-
: HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(stream), provider),
84+
AsyncWrap::ProviderType provider,
85+
AsyncWrap* parent)
86+
: HandleWrap(env,
87+
object,
88+
reinterpret_cast<uv_handle_t*>(stream),
89+
provider,
90+
parent),
8691
stream_(stream),
8792
default_callbacks_(this),
8893
callbacks_(&default_callbacks_),
@@ -140,12 +145,14 @@ void StreamWrap::OnAlloc(uv_handle_t* handle,
140145

141146

142147
template <class WrapType, class UVType>
143-
static Local<Object> AcceptHandle(Environment* env, uv_stream_t* pipe) {
148+
static Local<Object> AcceptHandle(Environment* env,
149+
uv_stream_t* pipe,
150+
AsyncWrap* parent) {
144151
EscapableHandleScope scope(env->isolate());
145152
Local<Object> wrap_obj;
146153
UVType* handle;
147154

148-
wrap_obj = WrapType::Instantiate(env);
155+
wrap_obj = WrapType::Instantiate(env, parent);
149156
if (wrap_obj.IsEmpty())
150157
return Local<Object>();
151158

@@ -751,11 +758,11 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
751758

752759
Local<Object> pending_obj;
753760
if (pending == UV_TCP) {
754-
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle);
761+
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle, wrap());
755762
} else if (pending == UV_NAMED_PIPE) {
756-
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle);
763+
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle, wrap());
757764
} else if (pending == UV_UDP) {
758-
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle);
765+
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle, wrap());
759766
} else {
760767
CHECK_EQ(pending, UV_UNKNOWN_HANDLE);
761768
}

src/stream_wrap.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ class StreamWrap : public HandleWrap {
177177
StreamWrap(Environment* env,
178178
v8::Local<v8::Object> object,
179179
uv_stream_t* stream,
180-
AsyncWrap::ProviderType provider);
180+
AsyncWrap::ProviderType provider,
181+
AsyncWrap* parent = nullptr);
181182

182183
~StreamWrap() {
183184
if (!callbacks_gc_ && callbacks_ != &default_callbacks_) {

src/tcp_wrap.cc

+18-6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace node {
3939
using v8::Boolean;
4040
using v8::Context;
4141
using v8::EscapableHandleScope;
42+
using v8::External;
4243
using v8::Function;
4344
using v8::FunctionCallbackInfo;
4445
using v8::FunctionTemplate;
@@ -70,12 +71,13 @@ static void NewTCPConnectWrap(const FunctionCallbackInfo<Value>& args) {
7071
}
7172

7273

73-
Local<Object> TCPWrap::Instantiate(Environment* env) {
74+
Local<Object> TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
7475
EscapableHandleScope handle_scope(env->isolate());
7576
CHECK_EQ(env->tcp_constructor_template().IsEmpty(), false);
7677
Local<Function> constructor = env->tcp_constructor_template()->GetFunction();
7778
CHECK_EQ(constructor.IsEmpty(), false);
78-
Local<Object> instance = constructor->NewInstance();
79+
Local<Value> ptr = External::New(env->isolate(), parent);
80+
Local<Object> instance = constructor->NewInstance(1, &ptr);
7981
CHECK_EQ(instance.IsEmpty(), false);
8082
return handle_scope.Escape(instance);
8183
}
@@ -166,16 +168,25 @@ void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
166168
// normal function.
167169
CHECK(args.IsConstructCall());
168170
Environment* env = Environment::GetCurrent(args);
169-
TCPWrap* wrap = new TCPWrap(env, args.This());
171+
TCPWrap* wrap;
172+
if (args.Length() == 0) {
173+
wrap = new TCPWrap(env, args.This(), nullptr);
174+
} else if (args[0]->IsExternal()) {
175+
void* ptr = args[0].As<External>()->Value();
176+
wrap = new TCPWrap(env, args.This(), static_cast<AsyncWrap*>(ptr));
177+
} else {
178+
UNREACHABLE();
179+
}
170180
CHECK(wrap);
171181
}
172182

173183

174-
TCPWrap::TCPWrap(Environment* env, Handle<Object> object)
184+
TCPWrap::TCPWrap(Environment* env, Handle<Object> object, AsyncWrap* parent)
175185
: StreamWrap(env,
176186
object,
177187
reinterpret_cast<uv_stream_t*>(&handle_),
178-
AsyncWrap::PROVIDER_TCPWRAP) {
188+
AsyncWrap::PROVIDER_TCPWRAP,
189+
parent) {
179190
int r = uv_tcp_init(env->event_loop(), &handle_);
180191
CHECK_EQ(r, 0); // How do we proxy this error up to javascript?
181192
// Suggestion: uv_tcp_init() returns void.
@@ -325,7 +336,8 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
325336

326337
if (status == 0) {
327338
// Instantiate the client javascript object and handle.
328-
Local<Object> client_obj = Instantiate(env);
339+
Local<Object> client_obj =
340+
Instantiate(env, static_cast<AsyncWrap*>(tcp_wrap));
329341

330342
// Unwrap the client javascript object.
331343
TCPWrap* wrap = Unwrap<TCPWrap>(client_obj);

src/tcp_wrap.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,23 @@
2222
#ifndef SRC_TCP_WRAP_H_
2323
#define SRC_TCP_WRAP_H_
2424

25+
#include "async-wrap.h"
2526
#include "env.h"
2627
#include "stream_wrap.h"
2728

2829
namespace node {
2930

3031
class TCPWrap : public StreamWrap {
3132
public:
32-
static v8::Local<v8::Object> Instantiate(Environment* env);
33+
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
3334
static void Initialize(v8::Handle<v8::Object> target,
3435
v8::Handle<v8::Value> unused,
3536
v8::Handle<v8::Context> context);
3637

3738
uv_tcp_t* UVHandle();
3839

3940
private:
40-
TCPWrap(Environment* env, v8::Handle<v8::Object> object);
41+
TCPWrap(Environment* env, v8::Handle<v8::Object> object, AsyncWrap* parent);
4142
~TCPWrap();
4243

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

src/udp_wrap.cc

+16-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
namespace node {
3535

3636
using v8::Context;
37+
using v8::EscapableHandleScope;
38+
using v8::External;
3739
using v8::Function;
3840
using v8::FunctionCallbackInfo;
3941
using v8::FunctionTemplate;
@@ -78,7 +80,7 @@ static void NewSendWrap(const FunctionCallbackInfo<Value>& args) {
7880
}
7981

8082

81-
UDPWrap::UDPWrap(Environment* env, Handle<Object> object)
83+
UDPWrap::UDPWrap(Environment* env, Handle<Object> object, AsyncWrap* parent)
8284
: HandleWrap(env,
8385
object,
8486
reinterpret_cast<uv_handle_t*>(&handle_),
@@ -140,7 +142,15 @@ void UDPWrap::Initialize(Handle<Object> target,
140142
void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
141143
CHECK(args.IsConstructCall());
142144
Environment* env = Environment::GetCurrent(args);
143-
new UDPWrap(env, args.This());
145+
if (args.Length() == 0) {
146+
new UDPWrap(env, args.This(), nullptr);
147+
} else if (args[0]->IsExternal()) {
148+
new UDPWrap(env,
149+
args.This(),
150+
static_cast<AsyncWrap*>(args[0].As<External>()->Value()));
151+
} else {
152+
UNREACHABLE();
153+
}
144154
}
145155

146156

@@ -423,10 +433,12 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
423433
}
424434

425435

426-
Local<Object> UDPWrap::Instantiate(Environment* env) {
436+
Local<Object> UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
427437
// If this assert fires then Initialize hasn't been called yet.
428438
CHECK_EQ(env->udp_constructor_function().IsEmpty(), false);
429-
return env->udp_constructor_function()->NewInstance();
439+
EscapableHandleScope scope(env->isolate());
440+
Local<Value> ptr = External::New(env->isolate(), parent);
441+
return scope.Escape(env->udp_constructor_function()->NewInstance(1, &ptr));
430442
}
431443

432444

src/udp_wrap.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#ifndef SRC_UDP_WRAP_H_
2323
#define SRC_UDP_WRAP_H_
2424

25+
#include "async-wrap.h"
2526
#include "env.h"
2627
#include "handle_wrap.h"
2728
#include "req_wrap.h"
@@ -53,11 +54,11 @@ class UDPWrap: public HandleWrap {
5354
static void SetBroadcast(const v8::FunctionCallbackInfo<v8::Value>& args);
5455
static void SetTTL(const v8::FunctionCallbackInfo<v8::Value>& args);
5556

56-
static v8::Local<v8::Object> Instantiate(Environment* env);
57+
static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
5758
uv_udp_t* UVHandle();
5859

5960
private:
60-
UDPWrap(Environment* env, v8::Handle<v8::Object> object);
61+
UDPWrap(Environment* env, v8::Handle<v8::Object> object, AsyncWrap* parent);
6162

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

0 commit comments

Comments
 (0)