Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bootstrap: include bootstrapped Environment in builtin snapshot #32984

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 3 additions & 18 deletions lib/buffer.js
Expand Up @@ -55,8 +55,7 @@ const {
swap32: _swap32,
swap64: _swap64,
kMaxLength,
kStringMaxLength,
zeroFill: bindingZeroFill
kStringMaxLength
} = internalBinding('buffer');
const {
getOwnNonIndexProperties,
Expand Down Expand Up @@ -102,7 +101,8 @@ const {
const {
FastBuffer,
markAsUntransferable,
addBufferPrototypeMethods
addBufferPrototypeMethods,
createUnsafeBuffer
} = require('internal/buffer');

const TypedArrayPrototype = ObjectGetPrototypeOf(Uint8ArrayPrototype);
Expand Down Expand Up @@ -132,25 +132,10 @@ const constants = ObjectDefineProperties({}, {
Buffer.poolSize = 8 * 1024;
let poolSize, poolOffset, allocPool;

// A toggle used to access the zero fill setting of the array buffer allocator
// in C++.
// |zeroFill| can be undefined when running inside an isolate where we
// do not own the ArrayBuffer allocator. Zero fill is always on in that case.
const zeroFill = bindingZeroFill || [0];

const encodingsMap = ObjectCreate(null);
for (let i = 0; i < encodings.length; ++i)
encodingsMap[encodings[i]] = i;

function createUnsafeBuffer(size) {
zeroFill[0] = 0;
try {
return new FastBuffer(size);
} finally {
zeroFill[0] = 1;
}
}

function createPool() {
poolSize = Buffer.poolSize;
allocPool = createUnsafeBuffer(poolSize).buffer;
Expand Down
11 changes: 7 additions & 4 deletions lib/internal/abort_controller.js
Expand Up @@ -55,15 +55,18 @@ function abortSignal(signal) {
signal.dispatchEvent(event);
}

// TODO(joyeecheung): V8 snapshot does not support instance member
// initializers for now:
// https://bugs.chromium.org/p/v8/issues/detail?id=10704
const kSignal = Symbol('signal');
class AbortController {
#signal = new AbortSignal();

constructor() {
this[kSignal] = new AbortSignal();
emitExperimentalWarning('AbortController');
}

get signal() { return this.#signal; }
abort() { abortSignal(this.#signal); }
get signal() { return this[kSignal]; }
abort() { abortSignal(this[kSignal]); }

[customInspectSymbol](depth, options) {
return customInspect(this, {
Expand Down
34 changes: 20 additions & 14 deletions lib/internal/bootstrap/node.js
Expand Up @@ -57,7 +57,8 @@ process.domain = null;
process._exiting = false;

// process.config is serialized config.gypi
process.config = JSONParse(internalBinding('native_module').config);
const nativeModule = internalBinding('native_module');
process.config = JSONParse(nativeModule.config);
require('internal/worker/js_transferable').setup();

// Bootstrappers for all threads, including worker threads and main thread
Expand All @@ -79,8 +80,6 @@ const rawMethods = internalBinding('process_methods');

const wrapped = perThreadSetup.wrapProcessMethods(rawMethods);
process._rawDebug = wrapped._rawDebug;
process.hrtime = wrapped.hrtime;
process.hrtime.bigint = wrapped.hrtimeBigInt;
process.cpuUsage = wrapped.cpuUsage;
process.resourceUsage = wrapped.resourceUsage;
process.memoryUsage = wrapped.memoryUsage;
Expand Down Expand Up @@ -192,21 +191,28 @@ process.assert = deprecate(
// TODO(joyeecheung): this property has not been well-maintained, should we
// deprecate it in favor of a better API?
const { isDebugBuild, hasOpenSSL, hasInspector } = config;
const features = {
inspector: hasInspector,
debug: isDebugBuild,
uv: true,
ipv6: true, // TODO(bnoordhuis) ping libuv
tls_alpn: hasOpenSSL,
tls_sni: hasOpenSSL,
tls_ocsp: hasOpenSSL,
tls: hasOpenSSL,
// This needs to be dynamic because snapshot is built without code cache.
// TODO(joyeecheung): https://github.com/nodejs/node/issues/31074
// Make it possible to build snapshot with code cache
get cached_builtins() {
return nativeModule.hasCachedBuiltins();
}
};

ObjectDefineProperty(process, 'features', {
enumerable: true,
writable: false,
configurable: false,
value: {
inspector: hasInspector,
debug: isDebugBuild,
uv: true,
ipv6: true, // TODO(bnoordhuis) ping libuv
tls_alpn: hasOpenSSL,
tls_sni: hasOpenSSL,
tls_ocsp: hasOpenSSL,
tls: hasOpenSSL,
cached_builtins: config.hasCachedBuiltins,
}
value: features
});

{
Expand Down
20 changes: 17 additions & 3 deletions lib/internal/bootstrap/pre_execution.js
Expand Up @@ -10,11 +10,17 @@ const {
getOptionValue,
shouldNotRegisterESMLoader
} = require('internal/options');
const { reconnectZeroFillToggle } = require('internal/buffer');

const { Buffer } = require('buffer');
const { ERR_MANIFEST_ASSERT_INTEGRITY } = require('internal/errors').codes;
const assert = require('internal/assert');

function prepareMainThreadExecution(expandArgv1 = false) {
// TODO(joyeecheung): this is also necessary for workers when they deserialize
// this toggle from the snapshot.
reconnectZeroFillToggle();

// Patch the process object with legacy properties and normalizations
patchProcessObject(expandArgv1);
setupTraceCategoryState();
Expand Down Expand Up @@ -68,11 +74,19 @@ function prepareMainThreadExecution(expandArgv1 = false) {
}

function patchProcessObject(expandArgv1) {
const binding = internalBinding('process_methods');
binding.patchProcessObject(process);

// TODO(joyeecheung): snapshot fast APIs (which need to work with
// array buffers, whose connection with C++ needs to be rebuilt after
// deserialization).
const {
patchProcessObject: patchProcessObjectNative
} = internalBinding('process_methods');
hrtime,
hrtimeBigInt
} = require('internal/process/per_thread').getFastAPIs(binding);

patchProcessObjectNative(process);
process.hrtime = hrtime;
process.hrtime.bigint = hrtimeBigInt;

ObjectDefineProperty(process, 'argv0', {
enumerable: true,
Expand Down
27 changes: 26 additions & 1 deletion lib/internal/buffer.js
Expand Up @@ -25,7 +25,8 @@ const {
latin1Write,
hexWrite,
ucs2Write,
utf8Write
utf8Write,
getZeroFillToggle
} = internalBinding('buffer');
const {
untransferable_object_private_symbol,
Expand Down Expand Up @@ -1019,8 +1020,32 @@ function markAsUntransferable(obj) {
setHiddenValue(obj, untransferable_object_private_symbol, true);
}

// A toggle used to access the zero fill setting of the array buffer allocator
// in C++.
// |zeroFill| can be undefined when running inside an isolate where we
// do not own the ArrayBuffer allocator. Zero fill is always on in that case.
let zeroFill = getZeroFillToggle();
function createUnsafeBuffer(size) {
zeroFill[0] = 0;
try {
return new FastBuffer(size);
} finally {
zeroFill[0] = 1;
}
}

// The connection between the JS land zero fill toggle and the
// C++ one in the NodeArrayBufferAllocator gets lost if the toggle
// is deserialized from the snapshot, because V8 owns the underlying
// memory of this toggle. This resets the connection.
function reconnectZeroFillToggle() {
zeroFill = getZeroFillToggle();
}

module.exports = {
FastBuffer,
addBufferPrototypeMethods,
markAsUntransferable,
createUnsafeBuffer,
reconnectZeroFillToggle
};