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 messages = new Map();
|
||||||
const codes = {};
|
const codes = {};
|
||||||
|
|
||||||
const {
|
|
||||||
errmap,
|
|
||||||
UV_EAI_NODATA,
|
|
||||||
UV_EAI_NONAME
|
|
||||||
} = internalBinding('uv');
|
|
||||||
const { kMaxLength } = internalBinding('buffer');
|
const { kMaxLength } = internalBinding('buffer');
|
||||||
const { defineProperty } = Object;
|
const { defineProperty } = Object;
|
||||||
|
|
||||||
@ -237,6 +232,24 @@ function getMessage(key, args) {
|
|||||||
return util.format.apply(null, 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++
|
* This creates an error compatible with errors produced in the C++
|
||||||
* function UVException using a context object with data assembled in C++.
|
* function UVException using a context object with data assembled in C++.
|
||||||
@ -247,7 +260,7 @@ function getMessage(key, args) {
|
|||||||
* @returns {Error}
|
* @returns {Error}
|
||||||
*/
|
*/
|
||||||
function uvException(ctx) {
|
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 message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
|
||||||
|
|
||||||
let path;
|
let path;
|
||||||
@ -303,7 +316,7 @@ function uvException(ctx) {
|
|||||||
* @returns {Error}
|
* @returns {Error}
|
||||||
*/
|
*/
|
||||||
function uvExceptionWithHostPort(err, syscall, address, port) {
|
function uvExceptionWithHostPort(err, syscall, address, port) {
|
||||||
const [ code, uvmsg ] = errmap.get(err);
|
const [ code, uvmsg ] = lazyErrmapGet(err);
|
||||||
const message = `${syscall} ${code}: ${uvmsg}`;
|
const message = `${syscall} ${code}: ${uvmsg}`;
|
||||||
let details = '';
|
let details = '';
|
||||||
|
|
||||||
@ -421,7 +434,7 @@ function dnsException(code, syscall, hostname) {
|
|||||||
if (typeof code === 'number') {
|
if (typeof code === 'number') {
|
||||||
// FIXME(bnoordhuis) Remove this backwards compatibility nonsense and pass
|
// FIXME(bnoordhuis) Remove this backwards compatibility nonsense and pass
|
||||||
// the true error to the user. ENOTFOUND is not even a proper POSIX error!
|
// 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.
|
code = 'ENOTFOUND'; // Fabricated error name.
|
||||||
} else {
|
} else {
|
||||||
code = lazyInternalUtil().getSystemErrorName(code);
|
code = lazyInternalUtil().getSystemErrorName(code);
|
||||||
|
@ -16,8 +16,6 @@ const {
|
|||||||
isNativeError
|
isNativeError
|
||||||
} = require('internal/util/types');
|
} = require('internal/util/types');
|
||||||
|
|
||||||
const { errmap } = internalBinding('uv');
|
|
||||||
|
|
||||||
const noCrypto = !process.versions.openssl;
|
const noCrypto = !process.versions.openssl;
|
||||||
|
|
||||||
const experimentalWarnings = new Set();
|
const experimentalWarnings = new Set();
|
||||||
@ -250,8 +248,19 @@ function getConstructorOf(obj) {
|
|||||||
return null;
|
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) {
|
function getSystemErrorName(err) {
|
||||||
const entry = errmap.get(err);
|
const entry = lazyErrmapGet(err);
|
||||||
return entry ? entry[0] : `Unknown system error ${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"
|
#include "env-inl.h"
|
||||||
|
|
||||||
namespace node {
|
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 {
|
namespace {
|
||||||
|
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
|
using v8::DontDelete;
|
||||||
using v8::FunctionCallbackInfo;
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::Integer;
|
using v8::Integer;
|
||||||
using v8::Isolate;
|
using v8::Isolate;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
using v8::Map;
|
using v8::Map;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
|
using v8::PropertyAttribute;
|
||||||
|
using v8::ReadOnly;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
|
|
||||||
void ErrName(const FunctionCallbackInfo<Value>& args) {
|
void ErrName(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
if (env->options()->pending_deprecation && env->EmitErrNameWarning()) {
|
if (env->options()->pending_deprecation && env->EmitErrNameWarning()) {
|
||||||
@ -57,6 +76,29 @@ void ErrName(const FunctionCallbackInfo<Value>& args) {
|
|||||||
args.GetReturnValue().Set(OneByteString(env->isolate(), name));
|
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,
|
void Initialize(Local<Object> target,
|
||||||
Local<Value> unused,
|
Local<Value> unused,
|
||||||
@ -70,28 +112,21 @@ void Initialize(Local<Object> target,
|
|||||||
->GetFunction(env->context())
|
->GetFunction(env->context())
|
||||||
.ToLocalChecked()).FromJust();
|
.ToLocalChecked()).FromJust();
|
||||||
|
|
||||||
#define V(name, _) NODE_DEFINE_CONSTANT(target, UV_##name);
|
// TODO(joyeecheung): This should be deprecated in user land in favor of
|
||||||
UV_ERRNO_MAP(V)
|
// `util.getSystemErrorName(err)`.
|
||||||
#undef V
|
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);
|
env->SetMethod(target, "getErrorMap", GetErrMap);
|
||||||
|
|
||||||
#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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user