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: https://github.com/nodejs/node/pull/25143 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
This commit is contained in:
parent
71a380b9fe
commit
c66c0732e0
@ -15,11 +15,6 @@ const kInfo = Symbol('info');
|
||||
const messages = new Map();
|
||||
const codes = {};
|
||||
|
||||
const {
|
||||
errmap,
|
||||
UV_EAI_NODATA,
|
||||
UV_EAI_NONAME
|
||||
} = internalBinding('uv');
|
||||
const { kMaxLength } = internalBinding('buffer');
|
||||
const { defineProperty } = Object;
|
||||
|
||||
@ -237,6 +232,24 @@ function getMessage(key, args) {
|
||||
return util.format.apply(null, args);
|
||||
}
|
||||
|
||||
let uvBinding;
|
||||
|
||||
function lazyUv() {
|
||||
if (!uvBinding) {
|
||||
uvBinding = internalBinding('uv');
|
||||
}
|
||||
return uvBinding;
|
||||
}
|
||||
|
||||
function lazyErrmapGet(name) {
|
||||
uvBinding = lazyUv();
|
||||
if (!uvBinding.errmap) {
|
||||
uvBinding.errmap = uvBinding.getErrorMap();
|
||||
}
|
||||
return uvBinding.errmap.get(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This creates an error compatible with errors produced in the C++
|
||||
* function UVException using a context object with data assembled in C++.
|
||||
@ -247,7 +260,7 @@ function getMessage(key, args) {
|
||||
* @returns {Error}
|
||||
*/
|
||||
function uvException(ctx) {
|
||||
const [ code, uvmsg ] = errmap.get(ctx.errno);
|
||||
const [ code, uvmsg ] = lazyErrmapGet(ctx.errno);
|
||||
let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
|
||||
|
||||
let path;
|
||||
@ -303,7 +316,7 @@ function uvException(ctx) {
|
||||
* @returns {Error}
|
||||
*/
|
||||
function uvExceptionWithHostPort(err, syscall, address, port) {
|
||||
const [ code, uvmsg ] = errmap.get(err);
|
||||
const [ code, uvmsg ] = lazyErrmapGet(err);
|
||||
const message = `${syscall} ${code}: ${uvmsg}`;
|
||||
let details = '';
|
||||
|
||||
@ -421,7 +434,7 @@ function dnsException(code, syscall, hostname) {
|
||||
if (typeof code === 'number') {
|
||||
// FIXME(bnoordhuis) Remove this backwards compatibility nonsense and pass
|
||||
// the true error to the user. ENOTFOUND is not even a proper POSIX error!
|
||||
if (code === UV_EAI_NODATA || code === UV_EAI_NONAME) {
|
||||
if (code === lazyUv().UV_EAI_NODATA || code === lazyUv().UV_EAI_NONAME) {
|
||||
code = 'ENOTFOUND'; // Fabricated error name.
|
||||
} else {
|
||||
code = lazyInternalUtil().getSystemErrorName(code);
|
||||
|
@ -16,8 +16,6 @@ const {
|
||||
isNativeError
|
||||
} = require('internal/util/types');
|
||||
|
||||
const { errmap } = internalBinding('uv');
|
||||
|
||||
const noCrypto = !process.versions.openssl;
|
||||
|
||||
const experimentalWarnings = new Set();
|
||||
@ -250,8 +248,19 @@ function getConstructorOf(obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let uvBinding;
|
||||
function lazyErrmapGet(name) {
|
||||
if (!uvBinding) {
|
||||
uvBinding = internalBinding('uv');
|
||||
}
|
||||
if (!uvBinding.errmap) {
|
||||
uvBinding.errmap = uvBinding.getErrorMap();
|
||||
}
|
||||
return uvBinding.errmap.get(name);
|
||||
}
|
||||
|
||||
function getSystemErrorName(err) {
|
||||
const entry = errmap.get(err);
|
||||
const entry = lazyErrmapGet(err);
|
||||
return entry ? entry[0] : `Unknown system error ${err}`;
|
||||
}
|
||||
|
||||
|
79
src/uv.cc
79
src/uv.cc
@ -25,20 +25,39 @@
|
||||
#include "env-inl.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
namespace per_process {
|
||||
struct UVError {
|
||||
int value;
|
||||
const char* name;
|
||||
const char* message;
|
||||
};
|
||||
|
||||
// We only expand the macro once here to reduce the amount of code
|
||||
// generated.
|
||||
static const struct UVError uv_errors_map[] = {
|
||||
#define V(name, message) {UV_##name, #name, message},
|
||||
UV_ERRNO_MAP(V)
|
||||
#undef V
|
||||
};
|
||||
} // namespace per_process
|
||||
|
||||
namespace {
|
||||
|
||||
using v8::Array;
|
||||
using v8::Context;
|
||||
using v8::DontDelete;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::Integer;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::Map;
|
||||
using v8::Object;
|
||||
using v8::PropertyAttribute;
|
||||
using v8::ReadOnly;
|
||||
using v8::String;
|
||||
using v8::Value;
|
||||
|
||||
|
||||
void ErrName(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
if (env->options()->pending_deprecation && env->EmitErrNameWarning()) {
|
||||
@ -57,6 +76,29 @@ void ErrName(const FunctionCallbackInfo<Value>& args) {
|
||||
args.GetReturnValue().Set(OneByteString(env->isolate(), name));
|
||||
}
|
||||
|
||||
void GetErrMap(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
Isolate* isolate = env->isolate();
|
||||
Local<Context> context = env->context();
|
||||
|
||||
Local<Map> err_map = Map::New(isolate);
|
||||
|
||||
size_t errors_len = arraysize(per_process::uv_errors_map);
|
||||
for (size_t i = 0; i < errors_len; ++i) {
|
||||
const auto& error = per_process::uv_errors_map[i];
|
||||
Local<Value> arr[] = {OneByteString(isolate, error.name),
|
||||
OneByteString(isolate, error.message)};
|
||||
if (err_map
|
||||
->Set(context,
|
||||
Integer::New(isolate, error.value),
|
||||
Array::New(isolate, arr, arraysize(arr)))
|
||||
.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(err_map);
|
||||
}
|
||||
|
||||
void Initialize(Local<Object> target,
|
||||
Local<Value> unused,
|
||||
@ -70,28 +112,21 @@ void Initialize(Local<Object> target,
|
||||
->GetFunction(env->context())
|
||||
.ToLocalChecked()).FromJust();
|
||||
|
||||
#define V(name, _) NODE_DEFINE_CONSTANT(target, UV_##name);
|
||||
UV_ERRNO_MAP(V)
|
||||
#undef V
|
||||
// TODO(joyeecheung): This should be deprecated in user land in favor of
|
||||
// `util.getSystemErrorName(err)`.
|
||||
PropertyAttribute attributes =
|
||||
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
|
||||
size_t errors_len = arraysize(per_process::uv_errors_map);
|
||||
const std::string prefix = "UV_";
|
||||
for (size_t i = 0; i < errors_len; ++i) {
|
||||
const auto& error = per_process::uv_errors_map[i];
|
||||
const std::string prefixed_name = prefix + error.name;
|
||||
Local<String> name = OneByteString(isolate, prefixed_name.c_str());
|
||||
Local<Integer> value = Integer::New(isolate, error.value);
|
||||
target->DefineOwnProperty(context, name, value, attributes).FromJust();
|
||||
}
|
||||
|
||||
Local<Map> err_map = Map::New(isolate);
|
||||
|
||||
#define V(name, msg) do { \
|
||||
Local<Value> arr[] = { \
|
||||
OneByteString(isolate, #name), \
|
||||
OneByteString(isolate, msg) \
|
||||
}; \
|
||||
if (err_map->Set(context, \
|
||||
Integer::New(isolate, UV_##name), \
|
||||
Array::New(isolate, arr, arraysize(arr))).IsEmpty()) { \
|
||||
return; \
|
||||
} \
|
||||
} while (0);
|
||||
UV_ERRNO_MAP(V)
|
||||
#undef V
|
||||
|
||||
target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "errmap"),
|
||||
err_map).FromJust();
|
||||
env->SetMethod(target, "getErrorMap", GetErrMap);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user