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

[v18.x] backport startup performance patches #46425

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
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.26',
'v8_embedder_string': '-node.27',

##### V8 defaults for Node.js #####

Expand Down
7 changes: 6 additions & 1 deletion deps/v8/src/snapshot/deserializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ void Deserializer<IsolateT>::PostProcessNewJSReceiver(
reinterpret_cast<uint8_t*>(backing_store) + data_view.byte_offset());
} else if (InstanceTypeChecker::IsJSTypedArray(instance_type)) {
auto typed_array = JSTypedArray::cast(raw_obj);
// Note: ByteArray objects must not be deferred s.t. they are
// available here for is_on_heap(). See also: CanBeDeferred.
// Fixup typed array pointers.
if (typed_array.is_on_heap()) {
typed_array.AddExternalPointerCompensationForDeserialization(
Expand Down Expand Up @@ -517,7 +519,10 @@ void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map,
// to |ObjectDeserializer::CommitPostProcessedObjects()|.
new_allocation_sites_.push_back(Handle<AllocationSite>::cast(obj));
} else {
DCHECK(CanBeDeferred(*obj));
// We dont defer ByteArray because JSTypedArray needs the base_pointer
// ByteArray immediately if it's on heap.
DCHECK(CanBeDeferred(*obj) ||
InstanceTypeChecker::IsByteArray(instance_type));
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion deps/v8/src/snapshot/serializer-deserializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@ bool SerializerDeserializer::CanBeDeferred(HeapObject o) {
// 3. JS objects with embedder fields cannot be deferred because the
// serialize/deserialize callbacks need the back reference immediately to
// identify the object.
// 4. ByteArray cannot be deferred as JSTypedArray needs the base_pointer
// ByteArray immediately if it's on heap.
// TODO(leszeks): Could we defer string serialization if forward references
// were resolved after object post processing?
return !o.IsMap() && !o.IsInternalizedString() &&
!(o.IsJSObject() && JSObject::cast(o).GetEmbedderFieldCount() > 0);
!(o.IsJSObject() && JSObject::cast(o).GetEmbedderFieldCount() > 0) &&
!o.IsByteArray();
}

void SerializerDeserializer::RestoreExternalReferenceRedirector(
Expand Down
40 changes: 40 additions & 0 deletions deps/v8/test/cctest/test-serialize.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4990,6 +4990,46 @@ UNINITIALIZED_TEST(SnapshotCreatorAnonClassWithKeep) {
delete[] blob.data;
}

UNINITIALIZED_TEST(SnapshotCreatorDontDeferByteArrayForTypedArray) {
DisableAlwaysOpt();
v8::StartupData blob;
{
v8::SnapshotCreator creator;
v8::Isolate* isolate = creator.GetIsolate();
{
v8::HandleScope handle_scope(isolate);

v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CompileRun(
"const z = new Uint8Array(1);\n"
"class A { \n"
" static x() { \n"
" } \n"
"} \n"
"class B extends A {} \n"
"B.foo = ''; \n"
"class C extends B {} \n"
"class D extends C {} \n"
"class E extends B {} \n"
"function F() {} \n"
"Object.setPrototypeOf(F, D); \n");
creator.SetDefaultContext(context);
}

blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
CHECK(blob.raw_size > 0 && blob.data != nullptr);
}
{
SnapshotCreator creator(nullptr, &blob);
v8::Isolate* isolate = creator.GetIsolate();
v8::HandleScope scope(isolate);
USE(v8::Context::New(isolate));
}
delete[] blob.data;
}

class V8_NODISCARD DisableLazySourcePositionScope {
public:
DisableLazySourcePositionScope()
Expand Down
24 changes: 12 additions & 12 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const {
lazyDOMException,
normalizeEncoding,
kIsEncodingSymbol,
defineLazyProperties,
} = require('internal/util');
const {
isAnyArrayBuffer,
Expand Down Expand Up @@ -128,15 +129,6 @@ const {
createUnsafeBuffer,
} = require('internal/buffer');

const {
Blob,
resolveObjectURL,
} = require('internal/blob');

const {
File,
} = require('internal/file');

FastBuffer.prototype.constructor = Buffer;
Buffer.prototype = FastBuffer.prototype;
addBufferPrototypeMethods(Buffer.prototype);
Expand Down Expand Up @@ -1382,9 +1374,6 @@ function isAscii(input) {
}

module.exports = {
Blob,
File,
resolveObjectURL,
Buffer,
SlowBuffer,
transcode,
Expand Down Expand Up @@ -1413,3 +1402,14 @@ ObjectDefineProperties(module.exports, {
set(val) { INSPECT_MAX_BYTES = val; },
},
});

defineLazyProperties(
module.exports,
'internal/blob',
['Blob', 'resolveObjectURL'],
);
defineLazyProperties(
module.exports,
'internal/file',
['File'],
);
26 changes: 12 additions & 14 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const {
custom: kCustomPromisifiedSymbol,
},
SideEffectFreeRegExpPrototypeExec,
defineLazyProperties,
} = require('internal/util');
const {
constants: {
Expand Down Expand Up @@ -125,11 +126,6 @@ const {
validatePrimitiveStringAfterArrayBufferView,
warnOnNonPortableTemplate,
} = require('internal/fs/utils');
const {
Dir,
opendir,
opendirSync,
} = require('internal/fs/dir');
const {
CHAR_FORWARD_SLASH,
CHAR_BACKWARD_SLASH,
Expand All @@ -146,9 +142,6 @@ const {
validateString,
} = require('internal/validators');

const watchers = require('internal/fs/watchers');
const ReadFileContext = require('internal/fs/read_file_context');

let truncateWarn = true;
let fs;

Expand Down Expand Up @@ -392,6 +385,7 @@ function checkAborted(signal, callback) {
function readFile(path, options, callback) {
callback = maybeCallback(callback || options);
options = getOptions(options, { flag: 'r' });
const ReadFileContext = require('internal/fs/read_file_context');
const context = new ReadFileContext(callback, options.encoding);
context.isUserFd = isFd(path); // File descriptor ownership

Expand Down Expand Up @@ -2422,12 +2416,13 @@ function watch(filename, options, listener) {
if (options.recursive === undefined) options.recursive = false;
if (options.recursive && !(isOSX || isWindows))
throw new ERR_FEATURE_UNAVAILABLE_ON_PLATFORM('watch recursively');

const watchers = require('internal/fs/watchers');
const watcher = new watchers.FSWatcher();
watcher[watchers.kFSWatchStart](filename,
options.persistent,
options.recursive,
options.encoding);

if (listener) {
watcher.addListener('change', listener);
}
Expand Down Expand Up @@ -2486,7 +2481,7 @@ function watchFile(filename, options, listener) {
validateFunction(listener, 'listener');

stat = statWatchers.get(filename);

const watchers = require('internal/fs/watchers');
if (stat === undefined) {
stat = new watchers.StatWatcher(options.bigint);
stat[watchers.kFSStatWatcherStart](filename,
Expand All @@ -2512,7 +2507,7 @@ function unwatchFile(filename, listener) {
const stat = statWatchers.get(filename);

if (stat === undefined) return;

const watchers = require('internal/fs/watchers');
if (typeof listener === 'function') {
const beforeListenerCount = stat.listenerCount('change');
stat.removeListener('change', listener);
Expand Down Expand Up @@ -3116,8 +3111,6 @@ module.exports = fs = {
mkdtempSync,
open,
openSync,
opendir,
opendirSync,
readdir,
readdirSync,
read,
Expand Down Expand Up @@ -3157,7 +3150,6 @@ module.exports = fs = {
writeSync,
writev,
writevSync,
Dir,
Dirent,
Stats,

Expand Down Expand Up @@ -3203,6 +3195,12 @@ module.exports = fs = {
_toUnixTimestamp: toUnixTimestamp,
};

defineLazyProperties(
fs,
'internal/fs/dir',
['Dir', 'opendir', 'opendirSync'],
);

ObjectDefineProperties(fs, {
F_OK: { __proto__: null, enumerable: true, value: F_OK || 0 },
R_OK: { __proto__: null, enumerable: true, value: R_OK || 0 },
Expand Down
3 changes: 1 addition & 2 deletions lib/internal/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ const {
Symbol,
} = primordials;

const promiseHooks = require('internal/promise_hooks');

const async_wrap = internalBinding('async_wrap');
const { setCallbackTrampoline } = async_wrap;
/* async_hook_fields is a Uint32Array wrapping the uint32_t array of
Expand Down Expand Up @@ -382,6 +380,7 @@ function updatePromiseHookMode() {
initHook = destroyTracking;
}
if (stopPromiseHook) stopPromiseHook();
const promiseHooks = require('internal/promise_hooks');
stopPromiseHook = promiseHooks.createHook({
init: initHook,
before: promiseBeforeHook,
Expand Down