Skip to content

Commit f8bde7c

Browse files
committed
bootstrap: build fast APIs in pre-execution
Fast APIs need to work with ArrayBuffers which we need to rebuild connections to after deserializing them from the snapshot. For now, postpone their creation until pre-execution to simplify the process. PR-URL: #32984 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]>
1 parent c943cb4 commit f8bde7c

File tree

5 files changed

+71
-51
lines changed

5 files changed

+71
-51
lines changed

lib/internal/bootstrap/node.js

-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ const rawMethods = internalBinding('process_methods');
8080

8181
const wrapped = perThreadSetup.wrapProcessMethods(rawMethods);
8282
process._rawDebug = wrapped._rawDebug;
83-
process.hrtime = wrapped.hrtime;
84-
process.hrtime.bigint = wrapped.hrtimeBigInt;
8583
process.cpuUsage = wrapped.cpuUsage;
8684
process.resourceUsage = wrapped.resourceUsage;
8785
process.memoryUsage = wrapped.memoryUsage;

lib/internal/bootstrap/pre_execution.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,19 @@ function prepareMainThreadExecution(expandArgv1 = false) {
7474
}
7575

7676
function patchProcessObject(expandArgv1) {
77+
const binding = internalBinding('process_methods');
78+
binding.patchProcessObject(process);
79+
80+
// TODO(joyeecheung): snapshot fast APIs (which need to work with
81+
// array buffers, whose connection with C++ needs to be rebuilt after
82+
// deserialization).
7783
const {
78-
patchProcessObject: patchProcessObjectNative
79-
} = internalBinding('process_methods');
84+
hrtime,
85+
hrtimeBigInt
86+
} = require('internal/process/per_thread').getFastAPIs(binding);
8087

81-
patchProcessObjectNative(process);
88+
process.hrtime = hrtime;
89+
process.hrtime.bigint = hrtimeBigInt;
8290

8391
ObjectDefineProperty(process, 'argv0', {
8492
enumerable: true,

lib/internal/process/per_thread.js

+48-39
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,56 @@ function assert(x, msg) {
3737
if (!x) throw new ERR_ASSERTION(msg || 'assertion error');
3838
}
3939

40+
function getFastAPIs(binding) {
41+
const {
42+
hrtime: _hrtime
43+
} = binding.getFastAPIs();
44+
45+
// The 3 entries filled in by the original process.hrtime contains
46+
// the upper/lower 32 bits of the second part of the value,
47+
// and the remaining nanoseconds of the value.
48+
const hrValues = new Uint32Array(_hrtime.buffer);
49+
50+
function hrtime(time) {
51+
_hrtime.hrtime();
52+
53+
if (time !== undefined) {
54+
if (!ArrayIsArray(time)) {
55+
throw new ERR_INVALID_ARG_TYPE('time', 'Array', time);
56+
}
57+
if (time.length !== 2) {
58+
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
59+
}
60+
61+
const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
62+
const nsec = hrValues[2] - time[1];
63+
const needsBorrow = nsec < 0;
64+
return [needsBorrow ? sec - 1 : sec, needsBorrow ? nsec + 1e9 : nsec];
65+
}
66+
67+
return [
68+
hrValues[0] * 0x100000000 + hrValues[1],
69+
hrValues[2]
70+
];
71+
}
72+
73+
// Use a BigUint64Array in the closure because this is actually a bit
74+
// faster than simply returning a BigInt from C++ in V8 7.1.
75+
const hrBigintValues = new BigUint64Array(_hrtime.buffer, 0, 1);
76+
function hrtimeBigInt() {
77+
_hrtime.hrtimeBigInt();
78+
return hrBigintValues[0];
79+
}
80+
81+
return {
82+
hrtime,
83+
hrtimeBigInt,
84+
};
85+
}
86+
4087
// The execution of this function itself should not cause any side effects.
4188
function wrapProcessMethods(binding) {
4289
const {
43-
hrtime: _hrtime,
4490
cpuUsage: _cpuUsage,
4591
memoryUsage: _memoryUsage,
4692
resourceUsage: _resourceUsage
@@ -109,42 +155,6 @@ function wrapProcessMethods(binding) {
109155
num >= 0;
110156
}
111157

112-
// The 3 entries filled in by the original process.hrtime contains
113-
// the upper/lower 32 bits of the second part of the value,
114-
// and the remaining nanoseconds of the value.
115-
const hrValues = new Uint32Array(_hrtime.buffer);
116-
117-
function hrtime(time) {
118-
_hrtime.hrtime();
119-
120-
if (time !== undefined) {
121-
if (!ArrayIsArray(time)) {
122-
throw new ERR_INVALID_ARG_TYPE('time', 'Array', time);
123-
}
124-
if (time.length !== 2) {
125-
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
126-
}
127-
128-
const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
129-
const nsec = hrValues[2] - time[1];
130-
const needsBorrow = nsec < 0;
131-
return [needsBorrow ? sec - 1 : sec, needsBorrow ? nsec + 1e9 : nsec];
132-
}
133-
134-
return [
135-
hrValues[0] * 0x100000000 + hrValues[1],
136-
hrValues[2]
137-
];
138-
}
139-
140-
// Use a BigUint64Array in the closure because this is actually a bit
141-
// faster than simply returning a BigInt from C++ in V8 7.1.
142-
const hrBigintValues = new BigUint64Array(_hrtime.buffer, 0, 1);
143-
function hrtimeBigInt() {
144-
_hrtime.hrtimeBigInt();
145-
return hrBigintValues[0];
146-
}
147-
148158
const memValues = new Float64Array(5);
149159
function memoryUsage() {
150160
_memoryUsage(memValues);
@@ -225,8 +235,6 @@ function wrapProcessMethods(binding) {
225235

226236
return {
227237
_rawDebug,
228-
hrtime,
229-
hrtimeBigInt,
230238
cpuUsage,
231239
resourceUsage,
232240
memoryUsage,
@@ -356,6 +364,7 @@ function toggleTraceCategoryState(asyncHooksEnabled) {
356364

357365
module.exports = {
358366
toggleTraceCategoryState,
367+
getFastAPIs,
359368
assert,
360369
buildAllowedFlags,
361370
wrapProcessMethods

src/node_process_methods.cc

+11-6
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,16 @@ class FastHrtime : public BaseObject {
504504
std::shared_ptr<BackingStore> backing_store_;
505505
};
506506

507+
static void GetFastAPIs(const FunctionCallbackInfo<Value>& args) {
508+
Environment* env = Environment::GetCurrent(args);
509+
Local<Object> ret = Object::New(env->isolate());
510+
ret->Set(env->context(),
511+
FIXED_ONE_BYTE_STRING(env->isolate(), "hrtime"),
512+
FastHrtime::New(env))
513+
.ToChecked();
514+
args.GetReturnValue().Set(ret);
515+
}
516+
507517
static void InitializeProcessMethods(Local<Object> target,
508518
Local<Value> unused,
509519
Local<Context> context,
@@ -534,12 +544,7 @@ static void InitializeProcessMethods(Local<Object> target,
534544
env->SetMethod(target, "reallyExit", ReallyExit);
535545
env->SetMethodNoSideEffect(target, "uptime", Uptime);
536546
env->SetMethod(target, "patchProcessObject", PatchProcessObject);
537-
538-
target
539-
->Set(env->context(),
540-
FIXED_ONE_BYTE_STRING(env->isolate(), "hrtime"),
541-
FastHrtime::New(env))
542-
.ToChecked();
547+
env->SetMethod(target, "getFastAPIs", GetFastAPIs);
543548
}
544549

545550
} // namespace node

test/cctest/test_base_object_ptr.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ using v8::Object;
1616

1717
// Environments may come with existing BaseObject instances.
1818
// This variable offsets the expected BaseObject counts.
19-
static const int BASE_OBJECT_COUNT = 1;
19+
static const int BASE_OBJECT_COUNT = 0;
2020

2121
class BaseObjectPtrTest : public EnvironmentTestFixture {};
2222

0 commit comments

Comments
 (0)