src: use JS inheritance for AsyncWrap

For all classes descending from `AsyncWrap`, use JS inheritance
instead of manually adding methods to the individual classes.

This allows cleanup of some code around transferring handles
over IPC.

PR-URL: https://github.com/nodejs/node/pull/23094
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Anna Henningsen 2018-09-23 19:24:33 +02:00
parent 2ebdba1229
commit d527dde360
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
30 changed files with 140 additions and 198 deletions

View File

@ -73,7 +73,8 @@ Object.setPrototypeOf(MessagePort.prototype, EventEmitter.prototype);
delete MessagePort.prototype.stop;
delete MessagePort.prototype.drain;
delete MessagePort.prototype.hasRef;
delete MessagePort.prototype.getAsyncId;
MessagePort.prototype.ref = MessagePortPrototype.ref;
MessagePort.prototype.unref = MessagePortPrototype.unref;
// A communication channel consisting of a handle (that wraps around an
// uv_async_t) which can receive information from other threads and emits

View File

@ -422,7 +422,6 @@
'src/node_root_certs.h',
'src/node_version.h',
'src/node_watchdog.h',
'src/node_wrap.h',
'src/node_revert.h',
'src/node_i18n.h',
'src/node_worker.h',

View File

@ -64,7 +64,7 @@ struct AsyncWrapObject : public AsyncWrap {
static inline void New(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args.IsConstructCall());
CHECK(env->async_wrap_constructor_template()->HasInstance(args.This()));
CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This()));
CHECK(args[0]->IsUint32());
auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value());
new AsyncWrapObject(env, args.This(), type);
@ -424,12 +424,16 @@ void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
args[0].As<Number>()->Value());
}
void AsyncWrap::AddWrapMethods(Environment* env,
Local<FunctionTemplate> constructor,
int flag) {
env->SetProtoMethod(constructor, "getAsyncId", AsyncWrap::GetAsyncId);
if (flag & kFlagHasReset)
env->SetProtoMethod(constructor, "asyncReset", AsyncWrap::AsyncReset);
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
if (tmpl.IsEmpty()) {
tmpl = env->NewFunctionTemplate(nullptr);
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
env->SetProtoMethod(tmpl, "getAsyncId", AsyncWrap::GetAsyncId);
env->SetProtoMethod(tmpl, "asyncReset", AsyncWrap::AsyncReset);
env->set_async_wrap_ctor_template(tmpl);
}
return tmpl;
}
void AsyncWrap::Initialize(Local<Object> target,
@ -525,17 +529,20 @@ void AsyncWrap::Initialize(Local<Object> target,
env->set_async_hooks_promise_resolve_function(Local<Function>());
env->set_async_hooks_binding(target);
// TODO(addaleax): This block might better work as a
// AsyncWrapObject::Initialize() or AsyncWrapObject::GetConstructorTemplate()
// function.
{
auto class_name = FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap");
auto function_template = env->NewFunctionTemplate(AsyncWrapObject::New);
function_template->SetClassName(class_name);
AsyncWrap::AddWrapMethods(env, function_template);
function_template->Inherit(AsyncWrap::GetConstructorTemplate(env));
auto instance_template = function_template->InstanceTemplate();
instance_template->SetInternalFieldCount(1);
auto function =
function_template->GetFunction(env->context()).ToLocalChecked();
target->Set(env->context(), class_name, function).FromJust();
env->set_async_wrap_constructor_template(function_template);
env->set_async_wrap_object_ctor_template(function_template);
}
}

View File

@ -104,11 +104,6 @@ class AsyncWrap : public BaseObject {
PROVIDERS_LENGTH,
};
enum Flags {
kFlagNone = 0x0,
kFlagHasReset = 0x1
};
AsyncWrap(Environment* env,
v8::Local<v8::Object> object,
ProviderType provider,
@ -116,9 +111,8 @@ class AsyncWrap : public BaseObject {
virtual ~AsyncWrap();
static void AddWrapMethods(Environment* env,
v8::Local<v8::FunctionTemplate> constructor,
int flags = kFlagNone);
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
static void Initialize(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,

View File

@ -2220,7 +2220,7 @@ void Initialize(Local<Object> target,
Local<FunctionTemplate> aiw =
BaseObject::MakeLazilyInitializedJSTemplate(env);
AsyncWrap::AddWrapMethods(env, aiw);
aiw->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> addrInfoWrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap");
aiw->SetClassName(addrInfoWrapString);
@ -2228,7 +2228,7 @@ void Initialize(Local<Object> target,
Local<FunctionTemplate> niw =
BaseObject::MakeLazilyInitializedJSTemplate(env);
AsyncWrap::AddWrapMethods(env, niw);
niw->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> nameInfoWrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap");
niw->SetClassName(nameInfoWrapString);
@ -2236,7 +2236,7 @@ void Initialize(Local<Object> target,
Local<FunctionTemplate> qrw =
BaseObject::MakeLazilyInitializedJSTemplate(env);
AsyncWrap::AddWrapMethods(env, qrw);
qrw->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> queryWrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap");
qrw->SetClassName(queryWrapString);
@ -2245,7 +2245,7 @@ void Initialize(Local<Object> target,
Local<FunctionTemplate> channel_wrap =
env->NewFunctionTemplate(ChannelWrap::New);
channel_wrap->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, channel_wrap);
channel_wrap->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(channel_wrap, "queryAny", Query<QueryAnyWrap>);
env->SetProtoMethod(channel_wrap, "queryA", Query<QueryAWrap>);

View File

@ -319,7 +319,8 @@ struct PackageConfig {
V(async_hooks_destroy_function, v8::Function) \
V(async_hooks_init_function, v8::Function) \
V(async_hooks_promise_resolve_function, v8::Function) \
V(async_wrap_constructor_template, v8::FunctionTemplate) \
V(async_wrap_object_ctor_template, v8::FunctionTemplate) \
V(async_wrap_ctor_template, v8::FunctionTemplate) \
V(buffer_prototype_object, v8::Object) \
V(context, v8::Context) \
V(domain_callback, v8::Function) \
@ -329,6 +330,7 @@ struct PackageConfig {
V(filehandlereadwrap_template, v8::ObjectTemplate) \
V(fsreqpromise_constructor_template, v8::ObjectTemplate) \
V(fs_use_promises_symbol, v8::Symbol) \
V(handle_wrap_ctor_template, v8::FunctionTemplate) \
V(host_import_module_dynamically_callback, v8::Function) \
V(host_initialize_import_meta_object_callback, v8::Function) \
V(http2ping_constructor_template, v8::ObjectTemplate) \
@ -336,6 +338,7 @@ struct PackageConfig {
V(http2stream_constructor_template, v8::ObjectTemplate) \
V(immediate_callback_function, v8::Function) \
V(inspector_console_api_object, v8::Object) \
V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \
V(message_port, v8::Object) \
V(message_port_constructor_template, v8::FunctionTemplate) \
V(pipe_constructor_template, v8::FunctionTemplate) \

View File

@ -105,7 +105,7 @@ void FSEventWrap::Initialize(Local<Object> target,
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(fsevent_string);
AsyncWrap::AddWrapMethods(env, t);
t->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "start", Start);
env->SetProtoMethod(t, "close", Close);

View File

@ -130,13 +130,19 @@ void HandleWrap::OnClose(uv_handle_t* handle) {
}
}
void HandleWrap::AddWrapMethods(Environment* env,
Local<FunctionTemplate> t) {
env->SetProtoMethod(t, "close", HandleWrap::Close);
env->SetProtoMethodNoSideEffect(t, "hasRef", HandleWrap::HasRef);
env->SetProtoMethod(t, "ref", HandleWrap::Ref);
env->SetProtoMethod(t, "unref", HandleWrap::Unref);
Local<FunctionTemplate> HandleWrap::GetConstructorTemplate(Environment* env) {
Local<FunctionTemplate> tmpl = env->handle_wrap_ctor_template();
if (tmpl.IsEmpty()) {
tmpl = env->NewFunctionTemplate(nullptr);
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "HandleWrap"));
tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(tmpl, "close", HandleWrap::Close);
env->SetProtoMethodNoSideEffect(tmpl, "hasRef", HandleWrap::HasRef);
env->SetProtoMethod(tmpl, "ref", HandleWrap::Ref);
env->SetProtoMethod(tmpl, "unref", HandleWrap::Unref);
env->set_handle_wrap_ctor_template(tmpl);
}
return tmpl;
}

View File

@ -73,8 +73,8 @@ class HandleWrap : public AsyncWrap {
virtual void Close(
v8::Local<v8::Value> close_callback = v8::Local<v8::Value>());
static void AddWrapMethods(Environment* env,
v8::Local<v8::FunctionTemplate> constructor);
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
protected:
HandleWrap(Environment* env,

View File

@ -307,7 +307,7 @@ void Initialize(Local<Object> target, Local<Value> unused,
env->NewFunctionTemplate(JSBindingsConnection::New);
tmpl->InstanceTemplate()->SetInternalFieldCount(1);
tmpl->SetClassName(conn_str);
AsyncWrap::AddWrapMethods(env, tmpl);
tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(tmpl, "dispatch", JSBindingsConnection::Dispatch);
env->SetProtoMethod(tmpl, "disconnect", JSBindingsConnection::Disconnect);
target

View File

@ -202,8 +202,7 @@ void JSStream::Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "JSStream");
t->SetClassName(jsStreamString);
t->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, t);
t->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "finishWrite", Finish<WriteWrap>);
env->SetProtoMethod(t, "finishShutdown", Finish<ShutdownWrap>);

View File

@ -2250,7 +2250,7 @@ void Initialize(Local<Object> target,
// Create FunctionTemplate for FSReqCallback
Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
fst->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, fst);
fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> wrapString =
FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
fst->SetClassName(wrapString);
@ -2263,7 +2263,7 @@ void Initialize(Local<Object> target,
// to do anything in the constructor, so we only store the instance template.
Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, fh_rw);
fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> fhWrapString =
FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
fh_rw->SetClassName(fhWrapString);
@ -2272,7 +2272,7 @@ void Initialize(Local<Object> target,
// Create Function Template for FSReqPromise
Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
AsyncWrap::AddWrapMethods(env, fpt);
fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> promiseString =
FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
fpt->SetClassName(promiseString);
@ -2282,7 +2282,7 @@ void Initialize(Local<Object> target,
// Create FunctionTemplate for FileHandle
Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
AsyncWrap::AddWrapMethods(env, fd);
fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(fd, "close", FileHandle::Close);
env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
Local<ObjectTemplate> fdt = fd->InstanceTemplate();
@ -2301,7 +2301,7 @@ void Initialize(Local<Object> target,
Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
"FileHandleCloseReq"));
AsyncWrap::AddWrapMethods(env, fdclose);
fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
fdcloset->SetInternalFieldCount(1);
env->set_fdclose_constructor_template(fdcloset);

View File

@ -2960,14 +2960,14 @@ void Initialize(Local<Object> target,
Local<FunctionTemplate> ping = FunctionTemplate::New(env->isolate());
ping->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Http2Ping"));
AsyncWrap::AddWrapMethods(env, ping);
ping->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<ObjectTemplate> pingt = ping->InstanceTemplate();
pingt->SetInternalFieldCount(1);
env->set_http2ping_constructor_template(pingt);
Local<FunctionTemplate> setting = FunctionTemplate::New(env->isolate());
setting->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Http2Setting"));
AsyncWrap::AddWrapMethods(env, setting);
setting->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<ObjectTemplate> settingt = setting->InstanceTemplate();
settingt->SetInternalFieldCount(1);
env->set_http2settings_constructor_template(settingt);
@ -2984,7 +2984,7 @@ void Initialize(Local<Object> target,
env->SetProtoMethod(stream, "respond", Http2Stream::Respond);
env->SetProtoMethod(stream, "rstStream", Http2Stream::RstStream);
env->SetProtoMethod(stream, "refreshState", Http2Stream::RefreshState);
AsyncWrap::AddWrapMethods(env, stream);
stream->Inherit(AsyncWrap::GetConstructorTemplate(env));
StreamBase::AddMethods<Http2Stream>(env, stream);
Local<ObjectTemplate> streamt = stream->InstanceTemplate();
streamt->SetInternalFieldCount(1);
@ -2997,7 +2997,7 @@ void Initialize(Local<Object> target,
env->NewFunctionTemplate(Http2Session::New);
session->SetClassName(http2SessionClassName);
session->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, session);
session->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(session, "origin", Http2Session::Origin);
env->SetProtoMethod(session, "altsvc", Http2Session::AltSvc);
env->SetProtoMethod(session, "ping", Http2Session::Ping);

View File

@ -763,7 +763,7 @@ void Initialize(Local<Object> target,
#undef V
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), methods);
AsyncWrap::AddWrapMethods(env, t);
t->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "close", Parser::Close);
env->SetProtoMethod(t, "free", Parser::Free);
env->SetProtoMethod(t, "execute", Parser::Execute);

View File

@ -722,9 +722,7 @@ MaybeLocal<Function> GetMessagePortConstructor(
Local<FunctionTemplate> m = env->NewFunctionTemplate(MessagePort::New);
m->SetClassName(env->message_port_constructor_string());
m->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, m);
HandleWrap::AddWrapMethods(env, m);
m->Inherit(HandleWrap::GetConstructorTemplate(env));
env->SetProtoMethod(m, "postMessage", MessagePort::PostMessage);
env->SetProtoMethod(m, "start", MessagePort::Start);

View File

@ -50,9 +50,7 @@ void StatWatcher::Initialize(Environment* env, Local<Object> target) {
Local<String> statWatcherString =
FIXED_ONE_BYTE_STRING(env->isolate(), "StatWatcher");
t->SetClassName(statWatcherString);
AsyncWrap::AddWrapMethods(env, t);
HandleWrap::AddWrapMethods(env, t);
t->Inherit(HandleWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "start", StatWatcher::Start);

View File

@ -482,8 +482,8 @@ void InitWorker(Local<Object> target,
Local<FunctionTemplate> w = env->NewFunctionTemplate(Worker::New);
w->InstanceTemplate()->SetInternalFieldCount(1);
w->Inherit(AsyncWrap::GetConstructorTemplate(env));
AsyncWrap::AddWrapMethods(env, w);
env->SetProtoMethod(w, "startThread", Worker::StartThread);
env->SetProtoMethod(w, "stopThread", Worker::StopThread);
env->SetProtoMethod(w, "ref", Worker::Ref);

View File

@ -1,72 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SRC_NODE_WRAP_H_
#define SRC_NODE_WRAP_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "env.h"
#include "pipe_wrap.h"
#include "tcp_wrap.h"
#include "tty_wrap.h"
#include "uv.h"
#include "v8.h"
namespace node {
// TODO(addaleax): Use real inheritance for the JS object templates to avoid
// this unnecessary case switching.
#define WITH_GENERIC_UV_STREAM(env, obj, BODY) \
do { \
if (env->tcp_constructor_template().IsEmpty() == false && \
env->tcp_constructor_template()->HasInstance(obj)) { \
TCPWrap* const wrap = Unwrap<TCPWrap>(obj); \
BODY \
} else if (env->tty_constructor_template().IsEmpty() == false && \
env->tty_constructor_template()->HasInstance(obj)) { \
TTYWrap* const wrap = Unwrap<TTYWrap>(obj); \
BODY \
} else if (env->pipe_constructor_template().IsEmpty() == false && \
env->pipe_constructor_template()->HasInstance(obj)) { \
PipeWrap* const wrap = Unwrap<PipeWrap>(obj); \
BODY \
} \
} while (0)
inline uv_stream_t* HandleToStream(Environment* env,
v8::Local<v8::Object> obj) {
v8::HandleScope scope(env->isolate());
WITH_GENERIC_UV_STREAM(env, obj, {
if (wrap == nullptr)
return nullptr;
return reinterpret_cast<uv_stream_t*>(wrap->UVHandle());
});
return nullptr;
}
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_NODE_WRAP_H_

View File

@ -755,8 +755,8 @@ void Initialize(Local<Object> target,
Local<FunctionTemplate> z = env->NewFunctionTemplate(ZCtx::New);
z->InstanceTemplate()->SetInternalFieldCount(1);
z->Inherit(AsyncWrap::GetConstructorTemplate(env));
AsyncWrap::AddWrapMethods(env, z);
env->SetProtoMethod(z, "write", ZCtx::Write<true>);
env->SetProtoMethod(z, "writeSync", ZCtx::Write<false>);
env->SetProtoMethod(z, "init", ZCtx::Init);

View File

@ -28,7 +28,6 @@
#include "node.h"
#include "node_buffer.h"
#include "node_internals.h"
#include "node_wrap.h"
#include "connect_wrap.h"
#include "stream_base-inl.h"
#include "stream_wrap.h"
@ -78,9 +77,7 @@ void PipeWrap::Initialize(Local<Object> target,
t->SetClassName(pipeString);
t->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, t);
HandleWrap::AddWrapMethods(env, t);
LibuvStreamWrap::AddMethods(env, t);
t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "bind", Bind);
env->SetProtoMethod(t, "listen", Listen);
@ -98,7 +95,7 @@ void PipeWrap::Initialize(Local<Object> target,
// Create FunctionTemplate for PipeConnectWrap.
auto cwt = BaseObject::MakeLazilyInitializedJSTemplate(env);
AsyncWrap::AddWrapMethods(env, cwt);
cwt->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> wrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap");
cwt->SetClassName(wrapString);

View File

@ -20,10 +20,9 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "env-inl.h"
#include "handle_wrap.h"
#include "node_internals.h"
#include "node_wrap.h"
#include "stream_base-inl.h"
#include "stream_wrap.h"
#include "util-inl.h"
#include <string.h>
@ -58,8 +57,7 @@ class ProcessWrap : public HandleWrap {
FIXED_ONE_BYTE_STRING(env->isolate(), "Process");
constructor->SetClassName(processString);
AsyncWrap::AddWrapMethods(env, constructor);
HandleWrap::AddWrapMethods(env, constructor);
constructor->Inherit(HandleWrap::GetConstructorTemplate(env));
env->SetProtoMethod(constructor, "spawn", Spawn);
env->SetProtoMethod(constructor, "kill", Kill);
@ -92,6 +90,17 @@ class ProcessWrap : public HandleWrap {
MarkAsUninitialized();
}
static uv_stream_t* StreamForWrap(Environment* env, Local<Object> stdio) {
Local<String> handle_key = env->handle_string();
// This property has always been set by JS land if we are in this code path.
Local<Object> handle =
stdio->Get(env->context(), handle_key).ToLocalChecked().As<Object>();
uv_stream_t* stream = LibuvStreamWrap::From(env, handle)->stream();
CHECK_NOT_NULL(stream);
return stream;
}
static void ParseStdioOptions(Environment* env,
Local<Object> js_options,
uv_process_options_t* options) {
@ -115,22 +124,10 @@ class ProcessWrap : public HandleWrap {
} else if (type->StrictEquals(env->pipe_string())) {
options->stdio[i].flags = static_cast<uv_stdio_flags>(
UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE);
Local<String> handle_key = env->handle_string();
Local<Object> handle =
stdio->Get(context, handle_key).ToLocalChecked().As<Object>();
CHECK(!handle.IsEmpty());
options->stdio[i].data.stream =
reinterpret_cast<uv_stream_t*>(
Unwrap<PipeWrap>(handle)->UVHandle());
options->stdio[i].data.stream = StreamForWrap(env, stdio);
} else if (type->StrictEquals(env->wrap_string())) {
Local<String> handle_key = env->handle_string();
Local<Object> handle =
stdio->Get(context, handle_key).ToLocalChecked().As<Object>();
uv_stream_t* stream = HandleToStream(env, handle);
CHECK_NOT_NULL(stream);
options->stdio[i].flags = UV_INHERIT_STREAM;
options->stdio[i].data.stream = stream;
options->stdio[i].data.stream = StreamForWrap(env, stdio);
} else {
Local<String> fd_key = env->fd_string();
Local<Value> fd_value = stdio->Get(context, fd_key).ToLocalChecked();

View File

@ -50,9 +50,7 @@ class SignalWrap : public HandleWrap {
Local<String> signalString =
FIXED_ONE_BYTE_STRING(env->isolate(), "Signal");
constructor->SetClassName(signalString);
AsyncWrap::AddWrapMethods(env, constructor);
HandleWrap::AddWrapMethods(env, constructor);
constructor->Inherit(HandleWrap::GetConstructorTemplate(env));
env->SetProtoMethod(constructor, "start", Start);
env->SetProtoMethod(constructor, "stop", Stop);

View File

@ -257,7 +257,7 @@ void InitializeStreamPipe(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "StreamPipe");
env->SetProtoMethod(pipe, "unpipe", StreamPipe::Unpipe);
env->SetProtoMethod(pipe, "start", StreamPipe::Start);
AsyncWrap::AddWrapMethods(env, pipe);
pipe->Inherit(AsyncWrap::GetConstructorTemplate(env));
pipe->SetClassName(stream_pipe_string);
pipe->InstanceTemplate()->SetInternalFieldCount(1);
target

View File

@ -66,7 +66,7 @@ void LibuvStreamWrap::Initialize(Local<Object> target,
Local<String> wrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap");
sw->SetClassName(wrapString);
AsyncWrap::AddWrapMethods(env, sw);
sw->Inherit(AsyncWrap::GetConstructorTemplate(env));
target->Set(wrapString, sw->GetFunction(env->context()).ToLocalChecked());
env->set_shutdown_wrap_template(sw->InstanceTemplate());
@ -76,7 +76,7 @@ void LibuvStreamWrap::Initialize(Local<Object> target,
Local<String> writeWrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap");
ww->SetClassName(writeWrapString);
AsyncWrap::AddWrapMethods(env, ww);
ww->Inherit(AsyncWrap::GetConstructorTemplate(env));
target->Set(writeWrapString,
ww->GetFunction(env->context()).ToLocalChecked());
env->set_write_wrap_template(ww->InstanceTemplate());
@ -96,20 +96,36 @@ LibuvStreamWrap::LibuvStreamWrap(Environment* env,
}
void LibuvStreamWrap::AddMethods(Environment* env,
v8::Local<v8::FunctionTemplate> target) {
Local<FunctionTemplate> get_write_queue_size =
FunctionTemplate::New(env->isolate(),
GetWriteQueueSize,
env->as_external(),
Signature::New(env->isolate(), target));
target->PrototypeTemplate()->SetAccessorProperty(
env->write_queue_size_string(),
get_write_queue_size,
Local<FunctionTemplate>(),
static_cast<PropertyAttribute>(ReadOnly | DontDelete));
env->SetProtoMethod(target, "setBlocking", SetBlocking);
StreamBase::AddMethods<LibuvStreamWrap>(env, target);
Local<FunctionTemplate> LibuvStreamWrap::GetConstructorTemplate(
Environment* env) {
Local<FunctionTemplate> tmpl = env->libuv_stream_wrap_ctor_template();
if (tmpl.IsEmpty()) {
tmpl = env->NewFunctionTemplate(nullptr);
tmpl->SetClassName(
FIXED_ONE_BYTE_STRING(env->isolate(), "LibuvStreamWrap"));
tmpl->Inherit(HandleWrap::GetConstructorTemplate(env));
Local<FunctionTemplate> get_write_queue_size =
FunctionTemplate::New(env->isolate(),
GetWriteQueueSize,
env->as_external(),
Signature::New(env->isolate(), tmpl));
tmpl->PrototypeTemplate()->SetAccessorProperty(
env->write_queue_size_string(),
get_write_queue_size,
Local<FunctionTemplate>(),
static_cast<PropertyAttribute>(ReadOnly | DontDelete));
env->SetProtoMethod(tmpl, "setBlocking", SetBlocking);
StreamBase::AddMethods<LibuvStreamWrap>(env, tmpl);
env->set_libuv_stream_wrap_ctor_template(tmpl);
}
return tmpl;
}
LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local<Object> object) {
Local<FunctionTemplate> sw = env->libuv_stream_wrap_ctor_template();
CHECK(!sw.IsEmpty() && sw->HasInstance(object));
return Unwrap<LibuvStreamWrap>(object);
}
@ -170,21 +186,25 @@ void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) {
template <class WrapType, class UVType>
template <class WrapType>
static Local<Object> AcceptHandle(Environment* env, LibuvStreamWrap* parent) {
static_assert(std::is_base_of<LibuvStreamWrap, WrapType>::value ||
std::is_base_of<UDPWrap, WrapType>::value,
"Can only accept stream handles");
EscapableHandleScope scope(env->isolate());
Local<Object> wrap_obj;
UVType* handle;
wrap_obj = WrapType::Instantiate(env, parent, WrapType::SOCKET);
if (wrap_obj.IsEmpty())
return Local<Object>();
WrapType* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, wrap_obj, Local<Object>());
handle = wrap->UVHandle();
HandleWrap* wrap = Unwrap<HandleWrap>(wrap_obj);
CHECK_NOT_NULL(wrap);
uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(wrap->GetHandle());
CHECK_NOT_NULL(stream);
if (uv_accept(parent->stream(), reinterpret_cast<uv_stream_t*>(handle)))
if (uv_accept(parent->stream(), stream))
ABORT();
return scope.Escape(wrap_obj);
@ -209,11 +229,11 @@ void LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) {
Local<Object> pending_obj;
if (type == UV_TCP) {
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(env(), this);
pending_obj = AcceptHandle<TCPWrap>(env(), this);
} else if (type == UV_NAMED_PIPE) {
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(env(), this);
pending_obj = AcceptHandle<PipeWrap>(env(), this);
} else if (type == UV_UDP) {
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(env(), this);
pending_obj = AcceptHandle<UDPWrap>(env(), this);
} else {
CHECK_EQ(type, UV_UNKNOWN_HANDLE);
}

View File

@ -76,6 +76,8 @@ class LibuvStreamWrap : public HandleWrap, public StreamBase {
ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
WriteWrap* CreateWriteWrap(v8::Local<v8::Object> object) override;
static LibuvStreamWrap* From(Environment* env, v8::Local<v8::Object> object);
protected:
LibuvStreamWrap(Environment* env,
v8::Local<v8::Object> object,
@ -84,8 +86,8 @@ class LibuvStreamWrap : public HandleWrap, public StreamBase {
AsyncWrap* GetAsyncWrap() override;
static void AddMethods(Environment* env,
v8::Local<v8::FunctionTemplate> target);
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
protected:
inline void set_fd(int fd) {

View File

@ -88,9 +88,7 @@ void TCPWrap::Initialize(Local<Object> target,
t->InstanceTemplate()->Set(env->onread_string(), Null(env->isolate()));
t->InstanceTemplate()->Set(env->onconnection_string(), Null(env->isolate()));
AsyncWrap::AddWrapMethods(env, t, AsyncWrap::kFlagHasReset);
HandleWrap::AddWrapMethods(env, t);
LibuvStreamWrap::AddMethods(env, t);
t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "open", Open);
env->SetProtoMethod(t, "bind", Bind);
@ -115,7 +113,7 @@ void TCPWrap::Initialize(Local<Object> target,
// Create FunctionTemplate for TCPConnectWrap.
Local<FunctionTemplate> cwt =
BaseObject::MakeLazilyInitializedJSTemplate(env);
AsyncWrap::AddWrapMethods(env, cwt);
cwt->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> wrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap");
cwt->SetClassName(wrapString);

View File

@ -891,7 +891,7 @@ void TLSWrap::Initialize(Local<Object> target,
Local<FunctionTemplate>(),
static_cast<PropertyAttribute>(ReadOnly | DontDelete));
AsyncWrap::AddWrapMethods(env, t, AsyncWrap::kFlagHasReset);
t->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(t, "receive", Receive);
env->SetProtoMethod(t, "start", Start);
env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode);

View File

@ -24,7 +24,6 @@
#include "env-inl.h"
#include "handle_wrap.h"
#include "node_buffer.h"
#include "node_wrap.h"
#include "stream_base-inl.h"
#include "stream_wrap.h"
#include "util-inl.h"
@ -52,10 +51,7 @@ void TTYWrap::Initialize(Local<Object> target,
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
t->SetClassName(ttyString);
t->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, t);
HandleWrap::AddWrapMethods(env, t);
LibuvStreamWrap::AddMethods(env, t);
t->Inherit(LibuvStreamWrap::GetConstructorTemplate(env));
env->SetProtoMethodNoSideEffect(t, "getWindowSize", TTYWrap::GetWindowSize);
env->SetProtoMethod(t, "setRawMode", SetRawMode);

View File

@ -135,8 +135,7 @@ void UDPWrap::Initialize(Local<Object> target,
env->SetProtoMethod(t, "setTTL", SetTTL);
env->SetProtoMethod(t, "bufferSize", BufferSize);
AsyncWrap::AddWrapMethods(env, t);
HandleWrap::AddWrapMethods(env, t);
t->Inherit(HandleWrap::GetConstructorTemplate(env));
target->Set(udpString, t->GetFunction(env->context()).ToLocalChecked());
env->set_udp_constructor_function(
@ -145,7 +144,7 @@ void UDPWrap::Initialize(Local<Object> target,
// Create FunctionTemplate for SendWrap
Local<FunctionTemplate> swt =
BaseObject::MakeLazilyInitializedJSTemplate(env);
AsyncWrap::AddWrapMethods(env, swt);
swt->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> sendWrapString =
FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap");
swt->SetClassName(sendWrapString);

View File

@ -32,24 +32,26 @@ const UDP = internalBinding('udp_wrap').UDP;
UDP.prototype.fd;
}, TypeError);
const StreamWrapProto = Object.getPrototypeOf(TTY.prototype);
// Should not throw for Object.getOwnPropertyDescriptor
assert.strictEqual(
typeof Object.getOwnPropertyDescriptor(TTY.prototype, 'bytesRead'),
typeof Object.getOwnPropertyDescriptor(StreamWrapProto, 'bytesRead'),
'object'
);
assert.strictEqual(
typeof Object.getOwnPropertyDescriptor(TTY.prototype, 'fd'),
typeof Object.getOwnPropertyDescriptor(StreamWrapProto, 'fd'),
'object'
);
assert.strictEqual(
typeof Object.getOwnPropertyDescriptor(TTY.prototype, '_externalStream'),
typeof Object.getOwnPropertyDescriptor(StreamWrapProto, '_externalStream'),
'object'
);
assert.strictEqual(
typeof Object.getOwnPropertyDescriptor(UDP.prototype, 'fd'),
typeof Object.getOwnPropertyDescriptor(StreamWrapProto, 'fd'),
'object'
);
}