Browse Source

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: https://github.com/joyent/node/pull/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>
v0.11.15-release
Trevor Norris 10 years ago
parent
commit
419f18d2e2
  1. 3
      src/async-wrap-inl.h
  2. 3
      src/async-wrap.h
  3. 5
      src/handle_wrap.cc
  4. 3
      src/handle_wrap.h
  5. 25
      src/pipe_wrap.cc
  6. 8
      src/pipe_wrap.h
  7. 21
      src/stream_wrap.cc
  8. 3
      src/stream_wrap.h
  9. 25
      src/tcp_wrap.cc
  10. 5
      src/tcp_wrap.h
  11. 21
      src/udp_wrap.cc
  12. 5
      src/udp_wrap.h

3
src/async-wrap-inl.h

@ -36,7 +36,8 @@ namespace node {
inline AsyncWrap::AsyncWrap(Environment* env, inline AsyncWrap::AsyncWrap(Environment* env,
v8::Handle<v8::Object> object, v8::Handle<v8::Object> object,
ProviderType provider) ProviderType provider,
AsyncWrap* parent)
: BaseObject(env, object), : BaseObject(env, object),
provider_type_(provider) { provider_type_(provider) {
} }

3
src/async-wrap.h

@ -63,7 +63,8 @@ class AsyncWrap : public BaseObject {
inline AsyncWrap(Environment* env, inline AsyncWrap(Environment* env,
v8::Handle<v8::Object> object, v8::Handle<v8::Object> object,
ProviderType provider); ProviderType provider,
AsyncWrap* parent = NULL);
inline ~AsyncWrap(); inline ~AsyncWrap();

5
src/handle_wrap.cc

@ -90,8 +90,9 @@ void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {
HandleWrap::HandleWrap(Environment* env, HandleWrap::HandleWrap(Environment* env,
Handle<Object> object, Handle<Object> object,
uv_handle_t* handle, uv_handle_t* handle,
AsyncWrap::ProviderType provider) AsyncWrap::ProviderType provider,
: AsyncWrap(env, object, provider), AsyncWrap* parent)
: AsyncWrap(env, object, provider, parent),
flags_(0), flags_(0),
handle__(handle) { handle__(handle) {
handle__->data = this; handle__->data = this;

3
src/handle_wrap.h

@ -63,7 +63,8 @@ class HandleWrap : public AsyncWrap {
HandleWrap(Environment* env, HandleWrap(Environment* env,
v8::Handle<v8::Object> object, v8::Handle<v8::Object> object,
uv_handle_t* handle, uv_handle_t* handle,
AsyncWrap::ProviderType provider); AsyncWrap::ProviderType provider,
AsyncWrap* parent = NULL);
virtual ~HandleWrap(); virtual ~HandleWrap();
private: private:

25
src/pipe_wrap.cc

@ -21,6 +21,7 @@
#include "pipe_wrap.h" #include "pipe_wrap.h"
#include "async-wrap.h"
#include "env.h" #include "env.h"
#include "env-inl.h" #include "env-inl.h"
#include "handle_wrap.h" #include "handle_wrap.h"
@ -37,6 +38,7 @@ namespace node {
using v8::Boolean; using v8::Boolean;
using v8::Context; using v8::Context;
using v8::EscapableHandleScope; using v8::EscapableHandleScope;
using v8::External;
using v8::Function; using v8::Function;
using v8::FunctionCallbackInfo; using v8::FunctionCallbackInfo;
using v8::FunctionTemplate; using v8::FunctionTemplate;
@ -74,12 +76,13 @@ uv_pipe_t* PipeWrap::UVHandle() {
} }
Local<Object> PipeWrap::Instantiate(Environment* env) { Local<Object> PipeWrap::Instantiate(Environment* env, AsyncWrap* parent) {
EscapableHandleScope handle_scope(env->isolate()); EscapableHandleScope handle_scope(env->isolate());
assert(!env->pipe_constructor_template().IsEmpty()); assert(!env->pipe_constructor_template().IsEmpty());
Local<Function> constructor = env->pipe_constructor_template()->GetFunction(); Local<Function> constructor = env->pipe_constructor_template()->GetFunction();
assert(!constructor.IsEmpty()); assert(!constructor.IsEmpty());
Local<Object> instance = constructor->NewInstance(); Local<Value> ptr = External::New(env->isolate(), parent);
Local<Object> instance = constructor->NewInstance(1, &ptr);
assert(!instance.IsEmpty()); assert(!instance.IsEmpty());
return handle_scope.Escape(instance); return handle_scope.Escape(instance);
} }
@ -150,17 +153,25 @@ void PipeWrap::New(const FunctionCallbackInfo<Value>& args) {
// Therefore we assert that we are not trying to call this as a // Therefore we assert that we are not trying to call this as a
// normal function. // normal function.
assert(args.IsConstructCall()); assert(args.IsConstructCall());
HandleScope handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate());
new PipeWrap(env, args.This(), args[0]->IsTrue()); if (args[0]->IsExternal()) {
void* ptr = args[0].As<External>()->Value();
new PipeWrap(env, args.This(), false, static_cast<AsyncWrap*>(ptr));
} else {
new PipeWrap(env, args.This(), args[0]->IsTrue(), NULL);
}
} }
PipeWrap::PipeWrap(Environment* env, Handle<Object> object, bool ipc) PipeWrap::PipeWrap(Environment* env,
Handle<Object> object,
bool ipc,
AsyncWrap* parent)
: StreamWrap(env, : StreamWrap(env,
object, object,
reinterpret_cast<uv_stream_t*>(&handle_), reinterpret_cast<uv_stream_t*>(&handle_),
AsyncWrap::PROVIDER_PIPEWRAP) { AsyncWrap::PROVIDER_PIPEWRAP,
parent) {
int r = uv_pipe_init(env->event_loop(), &handle_, ipc); int r = uv_pipe_init(env->event_loop(), &handle_, ipc);
assert(r == 0); // How do we proxy this error up to javascript? assert(r == 0); // How do we proxy this error up to javascript?
// Suggestion: uv_pipe_init() returns void. // Suggestion: uv_pipe_init() returns void.
@ -232,7 +243,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) {
} }
// Instanciate the client javascript object and handle. // Instanciate the client javascript object and handle.
Local<Object> client_obj = Instantiate(env); Local<Object> client_obj = Instantiate(env, pipe_wrap);
// Unwrap the client javascript object. // Unwrap the client javascript object.
PipeWrap* wrap = Unwrap<PipeWrap>(client_obj); PipeWrap* wrap = Unwrap<PipeWrap>(client_obj);

8
src/pipe_wrap.h

@ -22,6 +22,7 @@
#ifndef SRC_PIPE_WRAP_H_ #ifndef SRC_PIPE_WRAP_H_
#define SRC_PIPE_WRAP_H_ #define SRC_PIPE_WRAP_H_
#include "async-wrap.h"
#include "env.h" #include "env.h"
#include "stream_wrap.h" #include "stream_wrap.h"
@ -31,13 +32,16 @@ class PipeWrap : public StreamWrap {
public: public:
uv_pipe_t* UVHandle(); uv_pipe_t* UVHandle();
static v8::Local<v8::Object> Instantiate(Environment* env); static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
static void Initialize(v8::Handle<v8::Object> target, static void Initialize(v8::Handle<v8::Object> target,
v8::Handle<v8::Value> unused, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context); v8::Handle<v8::Context> context);
private: private:
PipeWrap(Environment* env, v8::Handle<v8::Object> object, bool ipc); PipeWrap(Environment* env,
v8::Handle<v8::Object> object,
bool ipc,
AsyncWrap* parent);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Bind(const v8::FunctionCallbackInfo<v8::Value>& args); static void Bind(const v8::FunctionCallbackInfo<v8::Value>& args);

21
src/stream_wrap.cc

@ -81,8 +81,13 @@ void StreamWrap::Initialize(Handle<Object> target,
StreamWrap::StreamWrap(Environment* env, StreamWrap::StreamWrap(Environment* env,
Local<Object> object, Local<Object> object,
uv_stream_t* stream, uv_stream_t* stream,
AsyncWrap::ProviderType provider) AsyncWrap::ProviderType provider,
: HandleWrap(env, object, reinterpret_cast<uv_handle_t*>(stream), provider), AsyncWrap* parent)
: HandleWrap(env,
object,
reinterpret_cast<uv_handle_t*>(stream),
provider,
parent),
stream_(stream), stream_(stream),
default_callbacks_(this), default_callbacks_(this),
callbacks_(&default_callbacks_), callbacks_(&default_callbacks_),
@ -145,12 +150,14 @@ void StreamWrap::OnAlloc(uv_handle_t* handle,
template <class WrapType, class UVType> template <class WrapType, class UVType>
static Local<Object> AcceptHandle(Environment* env, uv_stream_t* pipe) { static Local<Object> AcceptHandle(Environment* env,
uv_stream_t* pipe,
AsyncWrap* parent) {
EscapableHandleScope scope(env->isolate()); EscapableHandleScope scope(env->isolate());
Local<Object> wrap_obj; Local<Object> wrap_obj;
UVType* handle; UVType* handle;
wrap_obj = WrapType::Instantiate(env); wrap_obj = WrapType::Instantiate(env, parent);
if (wrap_obj.IsEmpty()) if (wrap_obj.IsEmpty())
return Local<Object>(); return Local<Object>();
@ -743,11 +750,11 @@ void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
Local<Object> pending_obj; Local<Object> pending_obj;
if (pending == UV_TCP) { if (pending == UV_TCP) {
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle); pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env, handle, wrap());
} else if (pending == UV_NAMED_PIPE) { } else if (pending == UV_NAMED_PIPE) {
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle); pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env, handle, wrap());
} else if (pending == UV_UDP) { } else if (pending == UV_UDP) {
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle); pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env, handle, wrap());
} else { } else {
assert(pending == UV_UNKNOWN_HANDLE); assert(pending == UV_UNKNOWN_HANDLE);
} }

3
src/stream_wrap.h

@ -177,7 +177,8 @@ class StreamWrap : public HandleWrap {
StreamWrap(Environment* env, StreamWrap(Environment* env,
v8::Local<v8::Object> object, v8::Local<v8::Object> object,
uv_stream_t* stream, uv_stream_t* stream,
AsyncWrap::ProviderType provider); AsyncWrap::ProviderType provider,
AsyncWrap* parent = NULL);
~StreamWrap() { ~StreamWrap() {
if (!callbacks_gc_ && callbacks_ != &default_callbacks_) { if (!callbacks_gc_ && callbacks_ != &default_callbacks_) {

25
src/tcp_wrap.cc

@ -38,6 +38,7 @@ namespace node {
using v8::Context; using v8::Context;
using v8::EscapableHandleScope; using v8::EscapableHandleScope;
using v8::External;
using v8::Function; using v8::Function;
using v8::FunctionCallbackInfo; using v8::FunctionCallbackInfo;
using v8::FunctionTemplate; using v8::FunctionTemplate;
@ -70,12 +71,13 @@ static void NewTCPConnectWrap(const FunctionCallbackInfo<Value>& args) {
} }
Local<Object> TCPWrap::Instantiate(Environment* env) { Local<Object> TCPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
EscapableHandleScope handle_scope(env->isolate()); EscapableHandleScope handle_scope(env->isolate());
assert(env->tcp_constructor_template().IsEmpty() == false); assert(env->tcp_constructor_template().IsEmpty() == false);
Local<Function> constructor = env->tcp_constructor_template()->GetFunction(); Local<Function> constructor = env->tcp_constructor_template()->GetFunction();
assert(constructor.IsEmpty() == false); assert(constructor.IsEmpty() == false);
Local<Object> instance = constructor->NewInstance(); Local<Value> ptr = External::New(env->isolate(), parent);
Local<Object> instance = constructor->NewInstance(1, &ptr);
assert(instance.IsEmpty() == false); assert(instance.IsEmpty() == false);
return handle_scope.Escape(instance); return handle_scope.Escape(instance);
} }
@ -171,18 +173,26 @@ void TCPWrap::New(const FunctionCallbackInfo<Value>& args) {
// Therefore we assert that we are not trying to call this as a // Therefore we assert that we are not trying to call this as a
// normal function. // normal function.
assert(args.IsConstructCall()); assert(args.IsConstructCall());
HandleScope handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate());
TCPWrap* wrap = new TCPWrap(env, args.This()); TCPWrap* wrap;
if (args.Length() == 0) {
wrap = new TCPWrap(env, args.This(), NULL);
} else if (args[0]->IsExternal()) {
void* ptr = args[0].As<External>()->Value();
wrap = new TCPWrap(env, args.This(), static_cast<AsyncWrap*>(ptr));
} else {
UNREACHABLE();
}
assert(wrap); assert(wrap);
} }
TCPWrap::TCPWrap(Environment* env, Handle<Object> object) TCPWrap::TCPWrap(Environment* env, Handle<Object> object, AsyncWrap* parent)
: StreamWrap(env, : StreamWrap(env,
object, object,
reinterpret_cast<uv_stream_t*>(&handle_), reinterpret_cast<uv_stream_t*>(&handle_),
AsyncWrap::PROVIDER_TCPWRAP) { AsyncWrap::PROVIDER_TCPWRAP,
parent) {
int r = uv_tcp_init(env->event_loop(), &handle_); int r = uv_tcp_init(env->event_loop(), &handle_);
assert(r == 0); // How do we proxy this error up to javascript? assert(r == 0); // How do we proxy this error up to javascript?
// Suggestion: uv_tcp_init() returns void. // Suggestion: uv_tcp_init() returns void.
@ -365,7 +375,8 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
if (status == 0) { if (status == 0) {
// Instantiate the client javascript object and handle. // Instantiate the client javascript object and handle.
Local<Object> client_obj = Instantiate(env); Local<Object> client_obj =
Instantiate(env, static_cast<AsyncWrap*>(tcp_wrap));
// Unwrap the client javascript object. // Unwrap the client javascript object.
TCPWrap* wrap = Unwrap<TCPWrap>(client_obj); TCPWrap* wrap = Unwrap<TCPWrap>(client_obj);

5
src/tcp_wrap.h

@ -22,6 +22,7 @@
#ifndef SRC_TCP_WRAP_H_ #ifndef SRC_TCP_WRAP_H_
#define SRC_TCP_WRAP_H_ #define SRC_TCP_WRAP_H_
#include "async-wrap.h"
#include "env.h" #include "env.h"
#include "stream_wrap.h" #include "stream_wrap.h"
@ -29,7 +30,7 @@ namespace node {
class TCPWrap : public StreamWrap { class TCPWrap : public StreamWrap {
public: public:
static v8::Local<v8::Object> Instantiate(Environment* env); static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
static void Initialize(v8::Handle<v8::Object> target, static void Initialize(v8::Handle<v8::Object> target,
v8::Handle<v8::Value> unused, v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context); v8::Handle<v8::Context> context);
@ -37,7 +38,7 @@ class TCPWrap : public StreamWrap {
uv_tcp_t* UVHandle(); uv_tcp_t* UVHandle();
private: private:
TCPWrap(Environment* env, v8::Handle<v8::Object> object); TCPWrap(Environment* env, v8::Handle<v8::Object> object, AsyncWrap* parent);
~TCPWrap(); ~TCPWrap();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args); static void New(const v8::FunctionCallbackInfo<v8::Value>& args);

21
src/udp_wrap.cc

@ -34,6 +34,8 @@
namespace node { namespace node {
using v8::Context; using v8::Context;
using v8::EscapableHandleScope;
using v8::External;
using v8::Function; using v8::Function;
using v8::FunctionCallbackInfo; using v8::FunctionCallbackInfo;
using v8::FunctionTemplate; using v8::FunctionTemplate;
@ -78,7 +80,7 @@ static void NewSendWrap(const FunctionCallbackInfo<Value>& args) {
} }
UDPWrap::UDPWrap(Environment* env, Handle<Object> object) UDPWrap::UDPWrap(Environment* env, Handle<Object> object, AsyncWrap* parent)
: HandleWrap(env, : HandleWrap(env,
object, object,
reinterpret_cast<uv_handle_t*>(&handle_), reinterpret_cast<uv_handle_t*>(&handle_),
@ -143,9 +145,16 @@ void UDPWrap::Initialize(Handle<Object> target,
void UDPWrap::New(const FunctionCallbackInfo<Value>& args) { void UDPWrap::New(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall()); CHECK(args.IsConstructCall());
HandleScope handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate());
new UDPWrap(env, args.This()); if (args.Length() == 0) {
new UDPWrap(env, args.This(), NULL);
} else if (args[0]->IsExternal()) {
new UDPWrap(env,
args.This(),
static_cast<AsyncWrap*>(args[0].As<External>()->Value()));
} else {
UNREACHABLE();
}
} }
@ -443,10 +452,12 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
} }
Local<Object> UDPWrap::Instantiate(Environment* env) { Local<Object> UDPWrap::Instantiate(Environment* env, AsyncWrap* parent) {
// If this assert fires then Initialize hasn't been called yet. // If this assert fires then Initialize hasn't been called yet.
assert(env->udp_constructor_function().IsEmpty() == false); assert(env->udp_constructor_function().IsEmpty() == false);
return env->udp_constructor_function()->NewInstance(); EscapableHandleScope scope(env->isolate());
Local<Value> ptr = External::New(env->isolate(), parent);
return scope.Escape(env->udp_constructor_function()->NewInstance(1, &ptr));
} }

5
src/udp_wrap.h

@ -22,6 +22,7 @@
#ifndef SRC_UDP_WRAP_H_ #ifndef SRC_UDP_WRAP_H_
#define SRC_UDP_WRAP_H_ #define SRC_UDP_WRAP_H_
#include "async-wrap.h"
#include "env.h" #include "env.h"
#include "handle_wrap.h" #include "handle_wrap.h"
#include "req_wrap.h" #include "req_wrap.h"
@ -53,11 +54,11 @@ class UDPWrap: public HandleWrap {
static void SetBroadcast(const v8::FunctionCallbackInfo<v8::Value>& args); static void SetBroadcast(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetTTL(const v8::FunctionCallbackInfo<v8::Value>& args); static void SetTTL(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Local<v8::Object> Instantiate(Environment* env); static v8::Local<v8::Object> Instantiate(Environment* env, AsyncWrap* parent);
uv_udp_t* UVHandle(); uv_udp_t* UVHandle();
private: private:
UDPWrap(Environment* env, v8::Handle<v8::Object> object); UDPWrap(Environment* env, v8::Handle<v8::Object> object, AsyncWrap* parent);
virtual ~UDPWrap(); virtual ~UDPWrap();
static void DoBind(const v8::FunctionCallbackInfo<v8::Value>& args, static void DoBind(const v8::FunctionCallbackInfo<v8::Value>& args,

Loading…
Cancel
Save