Skip to content

Commit dd6667d

Browse files
joyeecheungtargos
authored andcommitted
src: lazily load internalBinding('uv') and build the errmap lazily
This removes the `internalBinding('uv')` call from the normal bootstrap for now, and avoids building `errmap` by default which expands to a lot of calls into V8. PR-URL: #25143 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
1 parent c7d2dbd commit dd6667d

File tree

3 files changed

+90
-33
lines changed

3 files changed

+90
-33
lines changed

lib/internal/errors.js

+21-8
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ const kInfo = Symbol('info');
1515
const messages = new Map();
1616
const codes = {};
1717

18-
const {
19-
errmap,
20-
UV_EAI_NODATA,
21-
UV_EAI_NONAME
22-
} = internalBinding('uv');
2318
const { kMaxLength } = internalBinding('buffer');
2419
const { defineProperty } = Object;
2520

@@ -237,6 +232,24 @@ function getMessage(key, args) {
237232
return util.format.apply(null, args);
238233
}
239234

235+
let uvBinding;
236+
237+
function lazyUv() {
238+
if (!uvBinding) {
239+
uvBinding = internalBinding('uv');
240+
}
241+
return uvBinding;
242+
}
243+
244+
function lazyErrmapGet(name) {
245+
uvBinding = lazyUv();
246+
if (!uvBinding.errmap) {
247+
uvBinding.errmap = uvBinding.getErrorMap();
248+
}
249+
return uvBinding.errmap.get(name);
250+
}
251+
252+
240253
/**
241254
* This creates an error compatible with errors produced in the C++
242255
* function UVException using a context object with data assembled in C++.
@@ -247,7 +260,7 @@ function getMessage(key, args) {
247260
* @returns {Error}
248261
*/
249262
function uvException(ctx) {
250-
const [ code, uvmsg ] = errmap.get(ctx.errno);
263+
const [ code, uvmsg ] = lazyErrmapGet(ctx.errno);
251264
let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
252265

253266
let path;
@@ -303,7 +316,7 @@ function uvException(ctx) {
303316
* @returns {Error}
304317
*/
305318
function uvExceptionWithHostPort(err, syscall, address, port) {
306-
const [ code, uvmsg ] = errmap.get(err);
319+
const [ code, uvmsg ] = lazyErrmapGet(err);
307320
const message = `${syscall} ${code}: ${uvmsg}`;
308321
let details = '';
309322

@@ -421,7 +434,7 @@ function dnsException(code, syscall, hostname) {
421434
if (typeof code === 'number') {
422435
// FIXME(bnoordhuis) Remove this backwards compatibility nonsense and pass
423436
// the true error to the user. ENOTFOUND is not even a proper POSIX error!
424-
if (code === UV_EAI_NODATA || code === UV_EAI_NONAME) {
437+
if (code === lazyUv().UV_EAI_NODATA || code === lazyUv().UV_EAI_NONAME) {
425438
code = 'ENOTFOUND'; // Fabricated error name.
426439
} else {
427440
code = lazyInternalUtil().getSystemErrorName(code);

lib/internal/util.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ const {
1616
isNativeError
1717
} = internalBinding('types');
1818

19-
const { errmap } = internalBinding('uv');
20-
2119
const noCrypto = !process.versions.openssl;
2220

2321
const experimentalWarnings = new Set();
@@ -250,8 +248,19 @@ function getConstructorOf(obj) {
250248
return null;
251249
}
252250

251+
let uvBinding;
252+
function lazyErrmapGet(name) {
253+
if (!uvBinding) {
254+
uvBinding = internalBinding('uv');
255+
}
256+
if (!uvBinding.errmap) {
257+
uvBinding.errmap = uvBinding.getErrorMap();
258+
}
259+
return uvBinding.errmap.get(name);
260+
}
261+
253262
function getSystemErrorName(err) {
254-
const entry = errmap.get(err);
263+
const entry = lazyErrmapGet(err);
255264
return entry ? entry[0] : `Unknown system error ${err}`;
256265
}
257266

src/uv.cc

+57-22
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,39 @@
2525
#include "env-inl.h"
2626

2727
namespace node {
28+
29+
namespace per_process {
30+
struct UVError {
31+
int value;
32+
const char* name;
33+
const char* message;
34+
};
35+
36+
// We only expand the macro once here to reduce the amount of code
37+
// generated.
38+
static const struct UVError uv_errors_map[] = {
39+
#define V(name, message) {UV_##name, #name, message},
40+
UV_ERRNO_MAP(V)
41+
#undef V
42+
};
43+
} // namespace per_process
44+
2845
namespace {
2946

3047
using v8::Array;
3148
using v8::Context;
49+
using v8::DontDelete;
3250
using v8::FunctionCallbackInfo;
3351
using v8::Integer;
3452
using v8::Isolate;
3553
using v8::Local;
3654
using v8::Map;
3755
using v8::Object;
56+
using v8::PropertyAttribute;
57+
using v8::ReadOnly;
3858
using v8::String;
3959
using v8::Value;
4060

41-
4261
void ErrName(const FunctionCallbackInfo<Value>& args) {
4362
Environment* env = Environment::GetCurrent(args);
4463
if (env->options()->pending_deprecation && env->EmitErrNameWarning()) {
@@ -57,6 +76,29 @@ void ErrName(const FunctionCallbackInfo<Value>& args) {
5776
args.GetReturnValue().Set(OneByteString(env->isolate(), name));
5877
}
5978

79+
void GetErrMap(const FunctionCallbackInfo<Value>& args) {
80+
Environment* env = Environment::GetCurrent(args);
81+
Isolate* isolate = env->isolate();
82+
Local<Context> context = env->context();
83+
84+
Local<Map> err_map = Map::New(isolate);
85+
86+
size_t errors_len = arraysize(per_process::uv_errors_map);
87+
for (size_t i = 0; i < errors_len; ++i) {
88+
const auto& error = per_process::uv_errors_map[i];
89+
Local<Value> arr[] = {OneByteString(isolate, error.name),
90+
OneByteString(isolate, error.message)};
91+
if (err_map
92+
->Set(context,
93+
Integer::New(isolate, error.value),
94+
Array::New(isolate, arr, arraysize(arr)))
95+
.IsEmpty()) {
96+
return;
97+
}
98+
}
99+
100+
args.GetReturnValue().Set(err_map);
101+
}
60102

61103
void Initialize(Local<Object> target,
62104
Local<Value> unused,
@@ -70,28 +112,21 @@ void Initialize(Local<Object> target,
70112
->GetFunction(env->context())
71113
.ToLocalChecked()).FromJust();
72114

73-
#define V(name, _) NODE_DEFINE_CONSTANT(target, UV_##name);
74-
UV_ERRNO_MAP(V)
75-
#undef V
76-
77-
Local<Map> err_map = Map::New(isolate);
78-
79-
#define V(name, msg) do { \
80-
Local<Value> arr[] = { \
81-
OneByteString(isolate, #name), \
82-
OneByteString(isolate, msg) \
83-
}; \
84-
if (err_map->Set(context, \
85-
Integer::New(isolate, UV_##name), \
86-
Array::New(isolate, arr, arraysize(arr))).IsEmpty()) { \
87-
return; \
88-
} \
89-
} while (0);
90-
UV_ERRNO_MAP(V)
91-
#undef V
115+
// TODO(joyeecheung): This should be deprecated in user land in favor of
116+
// `util.getSystemErrorName(err)`.
117+
PropertyAttribute attributes =
118+
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
119+
size_t errors_len = arraysize(per_process::uv_errors_map);
120+
const std::string prefix = "UV_";
121+
for (size_t i = 0; i < errors_len; ++i) {
122+
const auto& error = per_process::uv_errors_map[i];
123+
const std::string prefixed_name = prefix + error.name;
124+
Local<String> name = OneByteString(isolate, prefixed_name.c_str());
125+
Local<Integer> value = Integer::New(isolate, error.value);
126+
target->DefineOwnProperty(context, name, value, attributes).FromJust();
127+
}
92128

93-
target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "errmap"),
94-
err_map).FromJust();
129+
env->SetMethod(target, "getErrorMap", GetErrMap);
95130
}
96131

97132
} // anonymous namespace

0 commit comments

Comments
 (0)