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 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
  • Loading branch information
joyeecheung committed Jul 14, 2020
commit c7007ca59fa2a84527f09413bd0e9bbe93ee7a01
2 changes: 0 additions & 2 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,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
14 changes: 11 additions & 3 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,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
87 changes: 48 additions & 39 deletions lib/internal/process/per_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,56 @@ function assert(x, msg) {
if (!x) throw new ERR_ASSERTION(msg || 'assertion error');
}

function getFastAPIs(binding) {
const {
hrtime: _hrtime
} = binding.getFastAPIs();

// The 3 entries filled in by the original process.hrtime contains
// the upper/lower 32 bits of the second part of the value,
// and the remaining nanoseconds of the value.
const hrValues = new Uint32Array(_hrtime.buffer);

function hrtime(time) {
_hrtime.hrtime();

if (time !== undefined) {
if (!ArrayIsArray(time)) {
throw new ERR_INVALID_ARG_TYPE('time', 'Array', time);
}
if (time.length !== 2) {
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
}

const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
const nsec = hrValues[2] - time[1];
const needsBorrow = nsec < 0;
return [needsBorrow ? sec - 1 : sec, needsBorrow ? nsec + 1e9 : nsec];
}

return [
hrValues[0] * 0x100000000 + hrValues[1],
hrValues[2]
];
}

// Use a BigUint64Array in the closure because this is actually a bit
// faster than simply returning a BigInt from C++ in V8 7.1.
const hrBigintValues = new BigUint64Array(_hrtime.buffer, 0, 1);
function hrtimeBigInt() {
_hrtime.hrtimeBigInt();
return hrBigintValues[0];
}

return {
hrtime,
hrtimeBigInt,
};
}

// The execution of this function itself should not cause any side effects.
function wrapProcessMethods(binding) {
const {
hrtime: _hrtime,
cpuUsage: _cpuUsage,
memoryUsage: _memoryUsage,
resourceUsage: _resourceUsage
Expand Down Expand Up @@ -109,42 +155,6 @@ function wrapProcessMethods(binding) {
num >= 0;
}

// The 3 entries filled in by the original process.hrtime contains
// the upper/lower 32 bits of the second part of the value,
// and the remaining nanoseconds of the value.
const hrValues = new Uint32Array(_hrtime.buffer);

function hrtime(time) {
_hrtime.hrtime();

if (time !== undefined) {
if (!ArrayIsArray(time)) {
throw new ERR_INVALID_ARG_TYPE('time', 'Array', time);
}
if (time.length !== 2) {
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
}

const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
const nsec = hrValues[2] - time[1];
const needsBorrow = nsec < 0;
return [needsBorrow ? sec - 1 : sec, needsBorrow ? nsec + 1e9 : nsec];
}

return [
hrValues[0] * 0x100000000 + hrValues[1],
hrValues[2]
];
}

// Use a BigUint64Array in the closure because this is actually a bit
// faster than simply returning a BigInt from C++ in V8 7.1.
const hrBigintValues = new BigUint64Array(_hrtime.buffer, 0, 1);
function hrtimeBigInt() {
_hrtime.hrtimeBigInt();
return hrBigintValues[0];
}

const memValues = new Float64Array(5);
function memoryUsage() {
_memoryUsage(memValues);
Expand Down Expand Up @@ -225,8 +235,6 @@ function wrapProcessMethods(binding) {

return {
_rawDebug,
hrtime,
hrtimeBigInt,
cpuUsage,
resourceUsage,
memoryUsage,
Expand Down Expand Up @@ -356,6 +364,7 @@ function toggleTraceCategoryState(asyncHooksEnabled) {

module.exports = {
toggleTraceCategoryState,
getFastAPIs,
assert,
buildAllowedFlags,
wrapProcessMethods
Expand Down
17 changes: 11 additions & 6 deletions src/node_process_methods.cc
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,16 @@ class FastHrtime : public BaseObject {
std::shared_ptr<BackingStore> backing_store_;
};

static void GetFastAPIs(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Local<Object> ret = Object::New(env->isolate());
ret->Set(env->context(),
FIXED_ONE_BYTE_STRING(env->isolate(), "hrtime"),
FastHrtime::New(env))
.ToChecked();
args.GetReturnValue().Set(ret);
}

static void InitializeProcessMethods(Local<Object> target,
Local<Value> unused,
Local<Context> context,
Expand Down Expand Up @@ -534,12 +544,7 @@ static void InitializeProcessMethods(Local<Object> target,
env->SetMethod(target, "reallyExit", ReallyExit);
env->SetMethodNoSideEffect(target, "uptime", Uptime);
env->SetMethod(target, "patchProcessObject", PatchProcessObject);

target
->Set(env->context(),
FIXED_ONE_BYTE_STRING(env->isolate(), "hrtime"),
FastHrtime::New(env))
.ToChecked();
env->SetMethod(target, "getFastAPIs", GetFastAPIs);
}

} // namespace node
Expand Down
2 changes: 1 addition & 1 deletion test/cctest/test_base_object_ptr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ using v8::Object;

// Environments may come with existing BaseObject instances.
// This variable offsets the expected BaseObject counts.
static const int BASE_OBJECT_COUNT = 1;
static const int BASE_OBJECT_COUNT = 0;

class BaseObjectPtrTest : public EnvironmentTestFixture {};

Expand Down