Skip to content

Commit d93c48b

Browse files
committed
src: use ObjectTemplate for creating stream req objs
This allows V8 to avoid preparing a execution context for the constructor, to give a (kinda) small but noticeable perf gain. Benchmarks (only this commit): $ ./node benchmark/compare.js --new ./node --old ./node-master --filter net-c2s.js --set len=10 --set type=asc --runs 360 net | Rscript benchmark/compare.R [01:15:27|% 100| 1/1 files | 720/720 runs | 1/1 configs]: Done confidence improvement accuracy (*) (**) (***) net/net-c2s.js dur=5 type='asc' len=10 *** 0.69 % ±0.31% ±0.41% ±0.53% PR-URL: #18936 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 12b9ec0 commit d93c48b

File tree

4 files changed

+25
-9
lines changed

4 files changed

+25
-9
lines changed

src/env.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ struct PackageConfig {
329329
V(script_context_constructor_template, v8::FunctionTemplate) \
330330
V(script_data_constructor_function, v8::Function) \
331331
V(secure_context_constructor_template, v8::FunctionTemplate) \
332-
V(shutdown_wrap_constructor_function, v8::Function) \
332+
V(shutdown_wrap_template, v8::ObjectTemplate) \
333333
V(tcp_constructor_template, v8::FunctionTemplate) \
334334
V(tick_callback_function, v8::Function) \
335335
V(timers_callback_function, v8::Function) \
@@ -338,7 +338,7 @@ struct PackageConfig {
338338
V(udp_constructor_function, v8::Function) \
339339
V(vm_parsing_context_symbol, v8::Symbol) \
340340
V(url_constructor_function, v8::Function) \
341-
V(write_wrap_constructor_function, v8::Function) \
341+
V(write_wrap_template, v8::ObjectTemplate) \
342342
V(fs_use_promises_symbol, v8::Symbol)
343343

344344
class Environment;

src/stream_base-inl.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,9 @@ inline int StreamBase::Shutdown(v8::Local<v8::Object> req_wrap_obj) {
164164

165165
if (req_wrap_obj.IsEmpty()) {
166166
req_wrap_obj =
167-
env->shutdown_wrap_constructor_function()
167+
env->shutdown_wrap_template()
168168
->NewInstance(env->context()).ToLocalChecked();
169+
StreamReq::ResetObject(req_wrap_obj);
169170
}
170171

171172
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(GetAsyncWrap());
@@ -203,8 +204,9 @@ inline StreamWriteResult StreamBase::Write(
203204

204205
if (req_wrap_obj.IsEmpty()) {
205206
req_wrap_obj =
206-
env->write_wrap_constructor_function()
207+
env->write_wrap_template()
207208
->NewInstance(env->context()).ToLocalChecked();
209+
StreamReq::ResetObject(req_wrap_obj);
208210
}
209211

210212
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(GetAsyncWrap());
@@ -427,6 +429,15 @@ inline void StreamReq::Done(int status, const char* error_str) {
427429
OnDone(status);
428430
}
429431

432+
inline void StreamReq::ResetObject(v8::Local<v8::Object> obj) {
433+
#ifdef DEBUG
434+
CHECK_GT(obj->InternalFieldCount(), StreamReq::kStreamReqField);
435+
#endif
436+
ClearWrap(obj);
437+
obj->SetAlignedPointerInInternalField(StreamReq::kStreamReqField, nullptr);
438+
}
439+
440+
430441
} // namespace node
431442

432443
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

src/stream_base.h

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ class StreamReq {
4646

4747
static StreamReq* FromObject(v8::Local<v8::Object> req_wrap_obj);
4848

49+
// Sets all internal fields of `req_wrap_obj` to `nullptr`.
50+
// This is what the `WriteWrap` and `ShutdownWrap` JS constructors do,
51+
// and what we use in C++ after creating these objects from their
52+
// v8::ObjectTemplates, to avoid the overhead of calling the
53+
// constructor explicitly.
54+
static inline void ResetObject(v8::Local<v8::Object> req_wrap_obj);
55+
4956
protected:
5057
virtual void OnDone(int status) = 0;
5158

src/stream_wrap.cc

+3-5
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ void LibuvStreamWrap::Initialize(Local<Object> target,
6060
auto is_construct_call_callback =
6161
[](const FunctionCallbackInfo<Value>& args) {
6262
CHECK(args.IsConstructCall());
63-
ClearWrap(args.This());
64-
args.This()->SetAlignedPointerInInternalField(
65-
StreamReq::kStreamReqField, nullptr);
63+
StreamReq::ResetObject(args.This());
6664
};
6765
Local<FunctionTemplate> sw =
6866
FunctionTemplate::New(env->isolate(), is_construct_call_callback);
@@ -72,7 +70,7 @@ void LibuvStreamWrap::Initialize(Local<Object> target,
7270
sw->SetClassName(wrapString);
7371
AsyncWrap::AddWrapMethods(env, sw);
7472
target->Set(wrapString, sw->GetFunction());
75-
env->set_shutdown_wrap_constructor_function(sw->GetFunction());
73+
env->set_shutdown_wrap_template(sw->InstanceTemplate());
7674

7775
Local<FunctionTemplate> ww =
7876
FunctionTemplate::New(env->isolate(), is_construct_call_callback);
@@ -82,7 +80,7 @@ void LibuvStreamWrap::Initialize(Local<Object> target,
8280
ww->SetClassName(writeWrapString);
8381
AsyncWrap::AddWrapMethods(env, ww);
8482
target->Set(writeWrapString, ww->GetFunction());
85-
env->set_write_wrap_constructor_function(ww->GetFunction());
83+
env->set_write_wrap_template(ww->InstanceTemplate());
8684
}
8785

8886

0 commit comments

Comments
 (0)