Skip to content
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
3 changes: 3 additions & 0 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ const rawMethods = internalBinding('process_methods');
process.kill = wrapped.kill;
process.exit = wrapped.exit;

process.hrtime = perThreadSetup.hrtime;
process.hrtime.bigint = perThreadSetup.hrtimeBigInt;

process.openStdin = function() {
process.stdin.resume();
return process.stdin;
Expand Down
11 changes: 1 addition & 10 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,7 @@ 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 {
hrtime,
hrtimeBigInt
} = require('internal/process/per_thread').getFastAPIs(binding);

process.hrtime = hrtime;
process.hrtime.bigint = hrtimeBigInt;
require('internal/process/per_thread').refreshHrtimeBuffer();

ObjectDefineProperty(process, 'argv0', {
enumerable: true,
Expand Down
67 changes: 34 additions & 33 deletions lib/internal/process/per_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,49 +54,48 @@ function assert(x, msg) {
if (!x) throw new ERR_ASSERTION(msg || 'assertion error');
}

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

let hrValues;
let hrBigintValues;

function refreshHrtimeBuffer() {
// 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);
hrValues = new Uint32Array(binding.hrtimeBuffer);
// Use a BigUint64Array in the closure because this is actually a bit
// faster than simply returning a BigInt from C++ in V8 7.1.
hrBigintValues = new BigUint64Array(binding.hrtimeBuffer, 0, 1);
}

function hrtime(time) {
_hrtime.hrtime();
// Create the buffers.
refreshHrtimeBuffer();

if (time !== undefined) {
validateArray(time, 'time');
if (time.length !== 2) {
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
}
function hrtime(time) {
binding.hrtime();

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];
if (time !== undefined) {
validateArray(time, 'time');
if (time.length !== 2) {
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
}

return [
hrValues[0] * 0x100000000 + hrValues[1],
hrValues[2],
];
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];
}

// 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 [
hrValues[0] * 0x100000000 + hrValues[1],
hrValues[2],
];
}

return {
hrtime,
hrtimeBigInt,
};
function hrtimeBigInt() {
binding.hrtimeBigInt();
return hrBigintValues[0];
}

// The execution of this function itself should not cause any side effects.
Expand Down Expand Up @@ -396,8 +395,10 @@ function toggleTraceCategoryState(asyncHooksEnabled) {

module.exports = {
toggleTraceCategoryState,
getFastAPIs,
assert,
buildAllowedFlags,
wrapProcessMethods
wrapProcessMethods,
hrtime,
hrtimeBigInt,
refreshHrtimeBuffer,
};
45 changes: 36 additions & 9 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@
#include "callback_queue-inl.h"
#include "env.h"
#include "node.h"
#include "node_context_data.h"
#include "node_perf_common.h"
#include "util-inl.h"
#include "uv.h"
#include "v8-fast-api-calls.h"
#include "v8.h"
#include "node_perf_common.h"
#include "node_context_data.h"

#include <cstddef>
#include <cstdint>
Expand Down Expand Up @@ -1036,13 +1037,20 @@ inline void Environment::ThrowUVException(int errorno,
UVException(isolate(), errorno, syscall, message, path, dest));
}

inline v8::Local<v8::FunctionTemplate>
Environment::NewFunctionTemplate(v8::FunctionCallback callback,
v8::Local<v8::Signature> signature,
v8::ConstructorBehavior behavior,
v8::SideEffectType side_effect_type) {
return v8::FunctionTemplate::New(isolate(), callback, v8::Local<v8::Value>(),
signature, 0, behavior, side_effect_type);
inline v8::Local<v8::FunctionTemplate> Environment::NewFunctionTemplate(
v8::FunctionCallback callback,
v8::Local<v8::Signature> signature,
v8::ConstructorBehavior behavior,
v8::SideEffectType side_effect_type,
const v8::CFunction* c_function) {
return v8::FunctionTemplate::New(isolate(),
callback,
v8::Local<v8::Value>(),
signature,
0,
behavior,
side_effect_type,
c_function);
}

inline void Environment::SetMethod(v8::Local<v8::Object> that,
Expand All @@ -1063,6 +1071,25 @@ inline void Environment::SetMethod(v8::Local<v8::Object> that,
function->SetName(name_string); // NODE_SET_METHOD() compatibility.
}

inline void Environment::SetFastMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback slow_callback,
const v8::CFunction* c_function) {
v8::Local<v8::Context> context = isolate()->GetCurrentContext();
v8::Local<v8::Function> function =
NewFunctionTemplate(slow_callback,
v8::Local<v8::Signature>(),
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect,
c_function)
->GetFunction(context)
.ToLocalChecked();
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->Set(context, name_string, function).Check();
}

inline void Environment::SetMethodNoSideEffect(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback) {
Expand Down
20 changes: 12 additions & 8 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "handle_wrap.h"
#include "node.h"
#include "node_binding.h"
#include "node_external_reference.h"
#include "node_main_instance.h"
#include "node_options.h"
#include "node_perf_common.h"
Expand Down Expand Up @@ -1238,20 +1239,23 @@ class Environment : public MemoryRetainer {
const char* path = nullptr,
const char* dest = nullptr);

inline v8::Local<v8::FunctionTemplate>
NewFunctionTemplate(v8::FunctionCallback callback,
v8::Local<v8::Signature> signature =
v8::Local<v8::Signature>(),
v8::ConstructorBehavior behavior =
v8::ConstructorBehavior::kAllow,
v8::SideEffectType side_effect =
v8::SideEffectType::kHasSideEffect);
inline v8::Local<v8::FunctionTemplate> NewFunctionTemplate(
v8::FunctionCallback callback,
v8::Local<v8::Signature> signature = v8::Local<v8::Signature>(),
v8::ConstructorBehavior behavior = v8::ConstructorBehavior::kAllow,
v8::SideEffectType side_effect = v8::SideEffectType::kHasSideEffect,
const v8::CFunction* c_function = nullptr);

// Convenience methods for NewFunctionTemplate().
inline void SetMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback);

inline void SetFastMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback slow_callback,
const v8::CFunction* c_function);

inline void SetProtoMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);
Expand Down
5 changes: 5 additions & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@

#include <cinttypes>
#include <vector>
#include "v8-fast-api-calls.h"
#include "v8.h"

namespace node {

using CFunctionCallback = void (*)(v8::Local<v8::Value> receiver);

// This class manages the external references from the V8 heap
// to the C++ addresses in Node.js.
class ExternalReferenceRegistry {
public:
ExternalReferenceRegistry();

#define ALLOWED_EXTERNAL_REFERENCE_TYPES(V) \
V(CFunctionCallback) \
V(const v8::CFunctionInfo*) \
V(v8::FunctionCallback) \
V(v8::AccessorGetterCallback) \
V(v8::AccessorSetterCallback) \
Expand Down
54 changes: 54 additions & 0 deletions src/node_process.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "node_snapshotable.h"
#include "v8-fast-api-calls.h"
#include "v8.h"

namespace node {

class Environment;
class MemoryTracker;
class ExternalReferenceRegistry;

v8::MaybeLocal<v8::Object> CreateEnvVarProxy(v8::Local<v8::Context> context,
v8::Isolate* isolate);

Expand Down Expand Up @@ -38,6 +44,54 @@ v8::Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
v8::MaybeLocal<v8::Object> CreateProcessObject(Environment* env);
void PatchProcessObject(const v8::FunctionCallbackInfo<v8::Value>& args);

namespace process {
class BindingData : public SnapshotableObject {
public:
void AddMethods();
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);

SERIALIZABLE_OBJECT_METHODS()
static constexpr FastStringKey type_name{"node::process::BindingData"};
static constexpr EmbedderObjectType type_int =
EmbedderObjectType::k_process_binding_data;

BindingData(Environment* env, v8::Local<v8::Object> object);

void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(BindingData)
SET_SELF_SIZE(BindingData)

static BindingData* FromV8Value(v8::Local<v8::Value> receiver);
static void NumberImpl(BindingData* receiver);

static void FastNumber(v8::Local<v8::Value> receiver) {
NumberImpl(FromV8Value(receiver));
}

static void SlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args);

static void BigIntImpl(BindingData* receiver);

static void FastBigInt(v8::Local<v8::Value> receiver) {
BigIntImpl(FromV8Value(receiver));
}

static void SlowBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);

private:
static const size_t kBufferSize =
std::max(sizeof(uint64_t), sizeof(uint32_t) * 3);
Comment thread
joyeecheung marked this conversation as resolved.
Outdated
v8::Global<v8::ArrayBuffer> array_buffer_;
std::shared_ptr<v8::BackingStore> backing_store_;

// These need to be static so that we have their addresses available to
// register as external references in the snapshot at environment creation
// time.
static v8::CFunction fast_number_;
static v8::CFunction fast_bigint_;
};

} // namespace process
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_NODE_PROCESS_H_
Loading