From 5a8396796d1b2417963157e3635921d62e9b27d2 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 23 Sep 2018 19:24:33 +0200 Subject: [PATCH] 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. Backport-PR-URL: https://github.com/nodejs/node/pull/23247 PR-URL: https://github.com/nodejs/node/pull/23094 Reviewed-By: Joyee Cheung Reviewed-By: Daniel Bevenius Reviewed-By: James M Snell --- lib/internal/worker.js | 3 +- node.gyp | 1 - src/async_wrap.cc | 25 +++++--- src/async_wrap.h | 10 +--- src/cares_wrap.cc | 8 +-- src/env.h | 5 +- src/fs_event_wrap.cc | 2 +- src/handle_wrap.cc | 20 ++++--- src/handle_wrap.h | 4 +- src/inspector_js_api.cc | 2 +- src/js_stream.cc | 3 +- src/node_file.cc | 10 ++-- src/node_http2.cc | 8 +-- src/node_http_parser.cc | 2 +- src/node_messaging.cc | 4 +- src/node_stat_watcher.cc | 4 +- src/node_worker.cc | 2 +- src/node_wrap.h | 72 ----------------------- src/node_zlib.cc | 2 +- src/pipe_wrap.cc | 7 +-- src/process_wrap.cc | 33 +++++------ src/signal_wrap.cc | 4 +- src/stream_pipe.cc | 2 +- src/stream_wrap.cc | 70 ++++++++++++++-------- src/stream_wrap.h | 6 +- src/tcp_wrap.cc | 6 +- src/timer_wrap.cc | 5 +- src/tls_wrap.cc | 2 +- src/tty_wrap.cc | 6 +- src/udp_wrap.cc | 5 +- test/parallel/test-accessor-properties.js | 10 ++-- test/parallel/test-handle-wrap-isrefed.js | 2 - 32 files changed, 141 insertions(+), 204 deletions(-) delete mode 100644 src/node_wrap.h diff --git a/lib/internal/worker.js b/lib/internal/worker.js index ceec8469b19a9a..2cffb77e521978 100644 --- a/lib/internal/worker.js +++ b/lib/internal/worker.js @@ -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 diff --git a/node.gyp b/node.gyp index 4dcfbd16fa26ec..882f8f8aafc9a6 100644 --- a/node.gyp +++ b/node.gyp @@ -426,7 +426,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', diff --git a/src/async_wrap.cc b/src/async_wrap.cc index 404dfb2c96943d..00c71b47e4ad40 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -63,7 +63,7 @@ struct AsyncWrapObject : public AsyncWrap { static inline void New(const FunctionCallbackInfo& 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(args[0].As()->Value()); new AsyncWrapObject(env, args.This(), type); @@ -423,12 +423,16 @@ void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo& args) { args[0].As()->Value()); } -void AsyncWrap::AddWrapMethods(Environment* env, - Local constructor, - int flag) { - env->SetProtoMethod(constructor, "getAsyncId", AsyncWrap::GetAsyncId); - if (flag & kFlagHasReset) - env->SetProtoMethod(constructor, "asyncReset", AsyncWrap::AsyncReset); +Local AsyncWrap::GetConstructorTemplate(Environment* env) { + Local 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 target, @@ -524,17 +528,20 @@ void AsyncWrap::Initialize(Local target, env->set_async_hooks_promise_resolve_function(Local()); 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); } } diff --git a/src/async_wrap.h b/src/async_wrap.h index 63a3000ed1290e..d9944e12774325 100644 --- a/src/async_wrap.h +++ b/src/async_wrap.h @@ -105,11 +105,6 @@ class AsyncWrap : public BaseObject { PROVIDERS_LENGTH, }; - enum Flags { - kFlagNone = 0x0, - kFlagHasReset = 0x1 - }; - AsyncWrap(Environment* env, v8::Local object, ProviderType provider, @@ -117,9 +112,8 @@ class AsyncWrap : public BaseObject { virtual ~AsyncWrap(); - static void AddWrapMethods(Environment* env, - v8::Local constructor, - int flags = kFlagNone); + static v8::Local GetConstructorTemplate( + Environment* env); static void Initialize(v8::Local target, v8::Local unused, diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index c3984ffdbce8f0..5970ec387fa516 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -2220,7 +2220,7 @@ void Initialize(Local target, Local aiw = BaseObject::MakeLazilyInitializedJSTemplate(env); - AsyncWrap::AddWrapMethods(env, aiw); + aiw->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local addrInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"); aiw->SetClassName(addrInfoWrapString); @@ -2228,7 +2228,7 @@ void Initialize(Local target, Local niw = BaseObject::MakeLazilyInitializedJSTemplate(env); - AsyncWrap::AddWrapMethods(env, niw); + niw->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local nameInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"); niw->SetClassName(nameInfoWrapString); @@ -2236,7 +2236,7 @@ void Initialize(Local target, Local qrw = BaseObject::MakeLazilyInitializedJSTemplate(env); - AsyncWrap::AddWrapMethods(env, qrw); + qrw->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local queryWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"); qrw->SetClassName(queryWrapString); @@ -2245,7 +2245,7 @@ void Initialize(Local target, Local 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); env->SetProtoMethod(channel_wrap, "queryA", Query); diff --git a/src/env.h b/src/env.h index 8469f95614c404..80fc750f0b555a 100644 --- a/src/env.h +++ b/src/env.h @@ -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) \ diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index 1c054bbc413c0b..1444937e7a853e 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -105,7 +105,7 @@ void FSEventWrap::Initialize(Local 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); diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index 9281300146c4f3..d4c5962c35e806 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -130,13 +130,19 @@ void HandleWrap::OnClose(uv_handle_t* handle) { } } - -void HandleWrap::AddWrapMethods(Environment* env, - Local 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 HandleWrap::GetConstructorTemplate(Environment* env) { + Local 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; } diff --git a/src/handle_wrap.h b/src/handle_wrap.h index 443d28bf523933..b2722511c3c09f 100644 --- a/src/handle_wrap.h +++ b/src/handle_wrap.h @@ -73,8 +73,8 @@ class HandleWrap : public AsyncWrap { virtual void Close( v8::Local close_callback = v8::Local()); - static void AddWrapMethods(Environment* env, - v8::Local constructor); + static v8::Local GetConstructorTemplate( + Environment* env); protected: HandleWrap(Environment* env, diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 52184111f5527a..49e1dcc6e8a30c 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -307,7 +307,7 @@ void Initialize(Local target, Local 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 diff --git a/src/js_stream.cc b/src/js_stream.cc index fb530dde89bea5..e3d734c01516c2 100644 --- a/src/js_stream.cc +++ b/src/js_stream.cc @@ -202,8 +202,7 @@ void JSStream::Initialize(Local 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); env->SetProtoMethod(t, "finishShutdown", Finish); diff --git a/src/node_file.cc b/src/node_file.cc index c011d152af19f5..3d40c8e9bf4dc1 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -2250,7 +2250,7 @@ void Initialize(Local target, // Create FunctionTemplate for FSReqCallback Local fst = env->NewFunctionTemplate(NewFSReqWrap); fst->InstanceTemplate()->SetInternalFieldCount(1); - AsyncWrap::AddWrapMethods(env, fst); + fst->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local wrapString = FIXED_ONE_BYTE_STRING(isolate, "FSReqWrap"); fst->SetClassName(wrapString); target @@ -2262,7 +2262,7 @@ void Initialize(Local target, // to do anything in the constructor, so we only store the instance template. Local fh_rw = FunctionTemplate::New(isolate); fh_rw->InstanceTemplate()->SetInternalFieldCount(1); - AsyncWrap::AddWrapMethods(env, fh_rw); + fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local fhWrapString = FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap"); fh_rw->SetClassName(fhWrapString); @@ -2271,7 +2271,7 @@ void Initialize(Local target, // Create Function Template for FSReqPromise Local fpt = FunctionTemplate::New(isolate); - AsyncWrap::AddWrapMethods(env, fpt); + fpt->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local promiseString = FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise"); fpt->SetClassName(promiseString); @@ -2281,7 +2281,7 @@ void Initialize(Local target, // Create FunctionTemplate for FileHandle Local 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 fdt = fd->InstanceTemplate(); @@ -2300,7 +2300,7 @@ void Initialize(Local target, Local fdclose = FunctionTemplate::New(isolate); fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "FileHandleCloseReq")); - AsyncWrap::AddWrapMethods(env, fdclose); + fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local fdcloset = fdclose->InstanceTemplate(); fdcloset->SetInternalFieldCount(1); env->set_fdclose_constructor_template(fdcloset); diff --git a/src/node_http2.cc b/src/node_http2.cc index 1f649710a74a78..fcc83f4acc53ef 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -2960,14 +2960,14 @@ void Initialize(Local target, Local ping = FunctionTemplate::New(env->isolate()); ping->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Http2Ping")); - AsyncWrap::AddWrapMethods(env, ping); + ping->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local pingt = ping->InstanceTemplate(); pingt->SetInternalFieldCount(1); env->set_http2ping_constructor_template(pingt); Local setting = FunctionTemplate::New(env->isolate()); setting->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Http2Setting")); - AsyncWrap::AddWrapMethods(env, setting); + setting->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local settingt = setting->InstanceTemplate(); settingt->SetInternalFieldCount(1); env->set_http2settings_constructor_template(settingt); @@ -2984,7 +2984,7 @@ void Initialize(Local 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(env, stream); Local streamt = stream->InstanceTemplate(); streamt->SetInternalFieldCount(1); @@ -2997,7 +2997,7 @@ void Initialize(Local 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); diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index ee6a4c4b45ad7d..eb7a69ce752f37 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -763,7 +763,7 @@ void Initialize(Local 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); diff --git a/src/node_messaging.cc b/src/node_messaging.cc index 6dd66f243e8a20..0a79d6f9d3d36a 100644 --- a/src/node_messaging.cc +++ b/src/node_messaging.cc @@ -722,9 +722,7 @@ MaybeLocal GetMessagePortConstructor( Local 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); diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc index 91333714b28623..ca0927af662200 100644 --- a/src/node_stat_watcher.cc +++ b/src/node_stat_watcher.cc @@ -50,9 +50,7 @@ void StatWatcher::Initialize(Environment* env, Local target) { Local 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); diff --git a/src/node_worker.cc b/src/node_worker.cc index 7825c9b0f54793..ec699bb312f770 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -481,8 +481,8 @@ void InitWorker(Local target, Local 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); diff --git a/src/node_wrap.h b/src/node_wrap.h deleted file mode 100644 index 42caca2dc6452d..00000000000000 --- a/src/node_wrap.h +++ /dev/null @@ -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(obj); \ - BODY \ - } else if (env->tty_constructor_template().IsEmpty() == false && \ - env->tty_constructor_template()->HasInstance(obj)) { \ - TTYWrap* const wrap = Unwrap(obj); \ - BODY \ - } else if (env->pipe_constructor_template().IsEmpty() == false && \ - env->pipe_constructor_template()->HasInstance(obj)) { \ - PipeWrap* const wrap = Unwrap(obj); \ - BODY \ - } \ - } while (0) - -inline uv_stream_t* HandleToStream(Environment* env, - v8::Local obj) { - v8::HandleScope scope(env->isolate()); - - WITH_GENERIC_UV_STREAM(env, obj, { - if (wrap == nullptr) - return nullptr; - return reinterpret_cast(wrap->UVHandle()); - }); - - return nullptr; -} - -} // namespace node - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_NODE_WRAP_H_ diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 80ebc1836f8ef6..5def50d3b9dceb 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -759,8 +759,8 @@ void Initialize(Local target, Local z = env->NewFunctionTemplate(ZCtx::New); z->InstanceTemplate()->SetInternalFieldCount(1); + z->Inherit(AsyncWrap::GetConstructorTemplate(env)); - AsyncWrap::AddWrapMethods(env, z); env->SetProtoMethod(z, "write", ZCtx::Write); env->SetProtoMethod(z, "writeSync", ZCtx::Write); env->SetProtoMethod(z, "init", ZCtx::Init); diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index c37b88cbf1c73b..90ba87b2d55d09 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -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 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 target, // Create FunctionTemplate for PipeConnectWrap. auto cwt = BaseObject::MakeLazilyInitializedJSTemplate(env); - AsyncWrap::AddWrapMethods(env, cwt); + cwt->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local wrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"); cwt->SetClassName(wrapString); diff --git a/src/process_wrap.cc b/src/process_wrap.cc index daace375498d25..03628c856b68b4 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -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 @@ -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 stdio) { + Local handle_key = env->handle_string(); + // This property has always been set by JS land if we are in this code path. + Local handle = + stdio->Get(env->context(), handle_key).ToLocalChecked().As(); + + uv_stream_t* stream = LibuvStreamWrap::From(env, handle)->stream(); + CHECK_NOT_NULL(stream); + return stream; + } + static void ParseStdioOptions(Environment* env, Local 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_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE); - Local handle_key = env->handle_string(); - Local handle = - stdio->Get(context, handle_key).ToLocalChecked().As(); - CHECK(!handle.IsEmpty()); - options->stdio[i].data.stream = - reinterpret_cast( - Unwrap(handle)->UVHandle()); + options->stdio[i].data.stream = StreamForWrap(env, stdio); } else if (type->StrictEquals(env->wrap_string())) { - Local handle_key = env->handle_string(); - Local handle = - stdio->Get(context, handle_key).ToLocalChecked().As(); - 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 fd_key = env->fd_string(); Local fd_value = stdio->Get(context, fd_key).ToLocalChecked(); diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc index efc83036765723..d7f21db8b3e8dd 100644 --- a/src/signal_wrap.cc +++ b/src/signal_wrap.cc @@ -50,9 +50,7 @@ class SignalWrap : public HandleWrap { Local 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); diff --git a/src/stream_pipe.cc b/src/stream_pipe.cc index 90da2043af9c26..0b00f225d8ad7b 100644 --- a/src/stream_pipe.cc +++ b/src/stream_pipe.cc @@ -257,7 +257,7 @@ void InitializeStreamPipe(Local 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 diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index d1968f86280f99..ea3c98591b7409 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -67,7 +67,7 @@ void LibuvStreamWrap::Initialize(Local target, Local 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()); @@ -77,7 +77,7 @@ void LibuvStreamWrap::Initialize(Local target, Local 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()); @@ -97,20 +97,36 @@ LibuvStreamWrap::LibuvStreamWrap(Environment* env, } -void LibuvStreamWrap::AddMethods(Environment* env, - v8::Local target) { - Local 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(), - static_cast(ReadOnly | DontDelete)); - env->SetProtoMethod(target, "setBlocking", SetBlocking); - StreamBase::AddMethods(env, target); +Local LibuvStreamWrap::GetConstructorTemplate( + Environment* env) { + Local 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 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(), + static_cast(ReadOnly | DontDelete)); + env->SetProtoMethod(tmpl, "setBlocking", SetBlocking); + StreamBase::AddMethods(env, tmpl); + env->set_libuv_stream_wrap_ctor_template(tmpl); + } + return tmpl; +} + + +LibuvStreamWrap* LibuvStreamWrap::From(Environment* env, Local object) { + Local sw = env->libuv_stream_wrap_ctor_template(); + CHECK(!sw.IsEmpty() && sw->HasInstance(object)); + return Unwrap(object); } @@ -171,21 +187,25 @@ void LibuvStreamWrap::OnUvAlloc(size_t suggested_size, uv_buf_t* buf) { -template +template static Local AcceptHandle(Environment* env, LibuvStreamWrap* parent) { + static_assert(std::is_base_of::value || + std::is_base_of::value, + "Can only accept stream handles"); + EscapableHandleScope scope(env->isolate()); Local wrap_obj; - UVType* handle; wrap_obj = WrapType::Instantiate(env, parent, WrapType::SOCKET); if (wrap_obj.IsEmpty()) return Local(); - WrapType* wrap; - ASSIGN_OR_RETURN_UNWRAP(&wrap, wrap_obj, Local()); - handle = wrap->UVHandle(); + HandleWrap* wrap = Unwrap(wrap_obj); + CHECK_NOT_NULL(wrap); + uv_stream_t* stream = reinterpret_cast(wrap->GetHandle()); + CHECK_NOT_NULL(stream); - if (uv_accept(parent->stream(), reinterpret_cast(handle))) + if (uv_accept(parent->stream(), stream)) ABORT(); return scope.Escape(wrap_obj); @@ -216,11 +236,11 @@ void LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) { Local pending_obj; if (type == UV_TCP) { - pending_obj = AcceptHandle(env(), this); + pending_obj = AcceptHandle(env(), this); } else if (type == UV_NAMED_PIPE) { - pending_obj = AcceptHandle(env(), this); + pending_obj = AcceptHandle(env(), this); } else if (type == UV_UDP) { - pending_obj = AcceptHandle(env(), this); + pending_obj = AcceptHandle(env(), this); } else { CHECK_EQ(type, UV_UNKNOWN_HANDLE); } diff --git a/src/stream_wrap.h b/src/stream_wrap.h index 487a40b7ffc7f9..98f0ca4ac4fb67 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -76,6 +76,8 @@ class LibuvStreamWrap : public HandleWrap, public StreamBase { ShutdownWrap* CreateShutdownWrap(v8::Local object) override; WriteWrap* CreateWriteWrap(v8::Local object) override; + static LibuvStreamWrap* From(Environment* env, v8::Local object); + protected: LibuvStreamWrap(Environment* env, v8::Local object, @@ -84,8 +86,8 @@ class LibuvStreamWrap : public HandleWrap, public StreamBase { AsyncWrap* GetAsyncWrap() override; - static void AddMethods(Environment* env, - v8::Local target); + static v8::Local GetConstructorTemplate( + Environment* env); protected: inline void set_fd(int fd) { diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 6b29a6adfb05b2..a07ba2d61231f4 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -88,9 +88,7 @@ void TCPWrap::Initialize(Local 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 target, // Create FunctionTemplate for TCPConnectWrap. Local cwt = BaseObject::MakeLazilyInitializedJSTemplate(env); - AsyncWrap::AddWrapMethods(env, cwt); + cwt->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local wrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"); cwt->SetClassName(wrapString); diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index e02ea332ab0a86..436e3def174328 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -50,14 +50,11 @@ class TimerWrap : public HandleWrap { Environment* env = Environment::GetCurrent(context); Local constructor = env->NewFunctionTemplate(New); Local timerString = FIXED_ONE_BYTE_STRING(env->isolate(), "Timer"); + constructor->Inherit(HandleWrap::GetConstructorTemplate(env)); constructor->InstanceTemplate()->SetInternalFieldCount(1); constructor->SetClassName(timerString); env->SetTemplateMethod(constructor, "now", Now); - - AsyncWrap::AddWrapMethods(env, constructor); - HandleWrap::AddWrapMethods(env, constructor); - env->SetProtoMethod(constructor, "start", Start); env->SetProtoMethod(constructor, "stop", Stop); diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index e495b6947ea6f1..b392ab6016a5ca 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -894,7 +894,7 @@ void TLSWrap::Initialize(Local target, Local(), static_cast(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); diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 90e7ecc42fe427..516fa1ec1ff4ed 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -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 target, Local 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); diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 9a70d35cdb44e7..d1802bc4809726 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -134,8 +134,7 @@ void UDPWrap::Initialize(Local 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( @@ -144,7 +143,7 @@ void UDPWrap::Initialize(Local target, // Create FunctionTemplate for SendWrap Local swt = BaseObject::MakeLazilyInitializedJSTemplate(env); - AsyncWrap::AddWrapMethods(env, swt); + swt->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local sendWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"); swt->SetClassName(sendWrapString); diff --git a/test/parallel/test-accessor-properties.js b/test/parallel/test-accessor-properties.js index 064ef844c38e6c..0717a02672333e 100644 --- a/test/parallel/test-accessor-properties.js +++ b/test/parallel/test-accessor-properties.js @@ -30,24 +30,26 @@ const UDP = process.binding('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' ); } diff --git a/test/parallel/test-handle-wrap-isrefed.js b/test/parallel/test-handle-wrap-isrefed.js index a7257e50d98c96..5c8ada6953f4f1 100644 --- a/test/parallel/test-handle-wrap-isrefed.js +++ b/test/parallel/test-handle-wrap-isrefed.js @@ -110,8 +110,6 @@ const { kStateSymbol } = require('internal/dgram'); { const timer = setTimeout(() => {}, 500); timer.unref(); - strictEqual(Object.getPrototypeOf(timer._handle).hasOwnProperty('hasRef'), - true, 'timer_wrap: hasRef() missing'); strictEqual(timer._handle.hasRef(), false, 'timer_wrap: unref() ineffective'); timer.ref();