Skip to content

Commit 419f18d

Browse files
committed
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 <trev.norris@gmail.com> Reviewed-by: Fedor Indutny <fedor@indutny.com> Reviewed-by: Alexis Campailla <alexis@janeasystems.com> Reviewed-by: Julien Gilli <julien.gilli@joyent.com>
1 parent 1293f0a commit 419f18d

12 files changed

Lines changed: 89 additions & 38 deletions

src/async-wrap-inl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ namespace node {
3636

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

src/async-wrap.h

Lines changed: 2 additions & 1 deletion
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 = NULL);
6768

6869
inline ~AsyncWrap();
6970

src/handle_wrap.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,9 @@ void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {
9090
HandleWrap::HandleWrap(Environment* env,
9191
Handle<Object> object,
9292
uv_handle_t* handle,
93-
AsyncWrap::ProviderType provider)
94-
: AsyncWrap(env, object, provider),
93+
AsyncWrap::ProviderType provider,
94+
AsyncWrap* parent)
95+
: AsyncWrap(env, object, provider, parent),
9596
flags_(0),
9697
handle__(handle) {
9798
handle__->data = this;

src/handle_wrap.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ class HandleWrap : public AsyncWrap {
6363
HandleWrap(Environment* env,
6464
v8::Handle<v8::Object> object,
6565
uv_handle_t* handle,
66-
AsyncWrap::ProviderType provider);
66+
AsyncWrap::ProviderType provider,
67+
AsyncWrap* parent = NULL);
6768
virtual ~HandleWrap();
6869

6970
private:

src/pipe_wrap.cc

Lines changed: 18 additions & 7 deletions
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
assert(!env->pipe_constructor_template().IsEmpty());
8082
Local<Function> constructor = env->pipe_constructor_template()->GetFunction();
8183
assert(!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
assert(!instance.IsEmpty());
8487
return handle_scope.Escape(instance);
8588
}
@@ -150,17 +153,25 @@ void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
150153
// Therefore we assert that we are not trying to call this as a
151154
// normal function.
152155
assert(args.IsConstructCall());
153-
HandleScope handle_scope(args.GetIsolate());
154156
Environment* env = Environment::GetCurrent(args.GetIsolate());
155-
new PipeWrap(env, args.This(), args[0]->IsTrue());
157+
if (args[0]->IsExternal()) {
158+
void* ptr = args[0].As<External>()->Value();
159+
new PipeWrap(env, args.This(), false, static_cast<AsyncWrap*>(ptr));
160+
} else {
161+
new PipeWrap(env, args.This(), args[0]->IsTrue(), NULL);
162+
}
156163
}
157164

158165

159-
PipeWrap::PipeWrap(Environment* env, Handle<Object> object, bool ipc)
166+
PipeWrap::PipeWrap(Environment* env,
167+
Handle<Object> object,
168+
bool ipc,
169+
AsyncWrap* parent)
160170
: StreamWrap(env,
161171
object,
162172
reinterpret_cast<uv_stream_t*>(&handle_),
163-
AsyncWrap::PROVIDER_PIPEWRAP) {
173+
AsyncWrap::PROVIDER_PIPEWRAP,
174+
parent) {
164175
int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
165176
assert(r == 0); // How do we proxy this error up to javascript?
166177
// Suggestion: uv_pipe_init() returns void.
@@ -232,7 +243,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) {
232243
}
233244

234245
// Instanciate the client javascript object and handle.
235-
Local<Object> client_obj = Instantiate(env);
246+
Local<Object> client_obj = Instantiate(env, pipe_wrap);
236247

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

src/pipe_wrap.h

Lines changed: 6 additions & 2 deletions
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

Lines changed: 14 additions & 7 deletions
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_),
@@ -145,12 +150,14 @@ void StreamWrap::OnAlloc(uv_handle_t* handle,
145150

146151

147152
template <class WrapType, class UVType>
148-
static Local<Object> AcceptHandle(Environment* env, uv_stream_t* pipe) {
153+
static Local<Object> AcceptHandle(Environment* env,
154+
uv_stream_t* pipe,
155+
AsyncWrap* parent) {
149156
EscapableHandleScope scope(env->isolate());
150157
Local<Object> wrap_obj;
151158
UVType* handle;
152159

153-
wrap_obj = WrapType::Instantiate(env);
160+
wrap_obj = WrapType::Instantiate(env, parent);
154161
if (wrap_obj.IsEmpty())
155162
return Local<Object>();
156163

@@ -743,11 +750,11 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
743750

744751
Local<Object> pending_obj;
745752
if (pending == UV_TCP) {
746-
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle);
753+
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle, wrap());
747754
} else if (pending == UV_NAMED_PIPE) {
748-
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle);
755+
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle, wrap());
749756
} else if (pending == UV_UDP) {
750-
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle);
757+
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle, wrap());
751758
} else {
752759
assert(pending == UV_UNKNOWN_HANDLE);
753760
}

src/stream_wrap.h

Lines changed: 2 additions & 1 deletion
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 = NULL);
181182

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

src/tcp_wrap.cc

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace node {
3838

3939
using v8::Context;
4040
using v8::EscapableHandleScope;
41+
using v8::External;
4142
using v8::Function;
4243
using v8::FunctionCallbackInfo;
4344
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
assert(env->tcp_constructor_template().IsEmpty() == false);
7677
Local<Function> constructor = env->tcp_constructor_template()->GetFunction();
7778
assert(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
assert(instance.IsEmpty() == false);
8082
return handle_scope.Escape(instance);
8183
}
@@ -171,18 +173,26 @@ void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
171173
// Therefore we assert that we are not trying to call this as a
172174
// normal function.
173175
assert(args.IsConstructCall());
174-
HandleScope handle_scope(args.GetIsolate());
175176
Environment* env = Environment::GetCurrent(args.GetIsolate());
176-
TCPWrap* wrap = new TCPWrap(env, args.This());
177+
TCPWrap* wrap;
178+
if (args.Length() == 0) {
179+
wrap = new TCPWrap(env, args.This(), NULL);
180+
} else if (args[0]->IsExternal()) {
181+
void* ptr = args[0].As<External>()->Value();
182+
wrap = new TCPWrap(env, args.This(), static_cast<AsyncWrap*>(ptr));
183+
} else {
184+
UNREACHABLE();
185+
}
177186
assert(wrap);
178187
}
179188

180189

181-
TCPWrap::TCPWrap(Environment* env, Handle<Object> object)
190+
TCPWrap::TCPWrap(Environment* env, Handle<Object> object, AsyncWrap* parent)
182191
: StreamWrap(env,
183192
object,
184193
reinterpret_cast<uv_stream_t*>(&handle_),
185-
AsyncWrap::PROVIDER_TCPWRAP) {
194+
AsyncWrap::PROVIDER_TCPWRAP,
195+
parent) {
186196
int r = uv_tcp_init(env->event_loop(), &handle_);
187197
assert(r == 0); // How do we proxy this error up to javascript?
188198
// Suggestion: uv_tcp_init() returns void.
@@ -365,7 +375,8 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
365375

366376
if (status == 0) {
367377
// Instantiate the client javascript object and handle.
368-
Local<Object> client_obj = Instantiate(env);
378+
Local<Object> client_obj =
379+
Instantiate(env, static_cast<AsyncWrap*>(tcp_wrap));
369380

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

src/tcp_wrap.h

Lines changed: 3 additions & 2 deletions
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);

0 commit comments

Comments
 (0)