Skip to content

Commit 3a4f387

Browse files
joyeecheungtargos
authored andcommitted
process: support hrtime in the snapshot
Put the hrtime backing store in the process methods binding data so that it can be integrated into the snapshot builder. For now we simply discard the contents of the hrtime buffer during serialization and create new buffers upon deserialization because the contents are only useful in a synchronous call. This also moves the helper function for creating V8 FastAPI methods into `Environment::SetFastMethod()` for code reuse. The v8::CFunction need to be created before the Environment is created so that we have the CTypeInfo address available for external reference registration. PR-URL: #40649 Refs: #35711 Refs: #37476 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 88b57bc commit 3a4f387

10 files changed

Lines changed: 253 additions & 179 deletions

File tree

‎lib/internal/bootstrap/node.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ const rawMethods = internalBinding('process_methods');
162162
process.kill=wrapped.kill;
163163
process.exit=wrapped.exit;
164164

165+
process.hrtime=perThreadSetup.hrtime;
166+
process.hrtime.bigint=perThreadSetup.hrtimeBigInt;
167+
165168
process.openStdin=function(){
166169
process.stdin.resume();
167170
returnprocess.stdin;

‎lib/internal/bootstrap/pre_execution.js‎

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,7 @@ function patchProcessObject(expandArgv1) {
8282
constbinding=internalBinding('process_methods');
8383
binding.patchProcessObject(process);
8484

85-
// TODO(joyeecheung): snapshot fast APIs (which need to work with
86-
// array buffers, whose connection with C++ needs to be rebuilt after
87-
// deserialization).
88-
const{
89-
hrtime,
90-
hrtimeBigInt
91-
}=require('internal/process/per_thread').getFastAPIs(binding);
92-
93-
process.hrtime=hrtime;
94-
process.hrtime.bigint=hrtimeBigInt;
85+
require('internal/process/per_thread').refreshHrtimeBuffer();
9586

9687
ObjectDefineProperty(process,'argv0',{
9788
enumerable: true,

‎lib/internal/process/per_thread.js‎

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -54,49 +54,48 @@ function assert(x, msg) {
5454
if(!x)thrownewERR_ASSERTION(msg||'assertion error');
5555
}
5656

57-
functiongetFastAPIs(binding){
58-
const{
59-
hrtime: _hrtime
60-
}=binding.getFastAPIs();
57+
constbinding=internalBinding('process_methods');
58+
59+
lethrValues;
60+
lethrBigintValues;
6161

62+
functionrefreshHrtimeBuffer(){
6263
// The 3 entries filled in by the original process.hrtime contains
6364
// the upper/lower 32 bits of the second part of the value,
6465
// and the remaining nanoseconds of the value.
65-
consthrValues=newUint32Array(_hrtime.buffer);
66+
hrValues=newUint32Array(binding.hrtimeBuffer);
67+
// Use a BigUint64Array in the closure because this is actually a bit
68+
// faster than simply returning a BigInt from C++ in V8 7.1.
69+
hrBigintValues=newBigUint64Array(binding.hrtimeBuffer,0,1);
70+
}
6671

67-
functionhrtime(time){
68-
_hrtime.hrtime();
72+
// Create the buffers.
73+
refreshHrtimeBuffer();
6974

70-
if(time!==undefined){
71-
validateArray(time,'time');
72-
if(time.length!==2){
73-
thrownewERR_OUT_OF_RANGE('time',2,time.length);
74-
}
75+
functionhrtime(time){
76+
binding.hrtime();
7577

76-
constsec=(hrValues[0]*0x100000000+hrValues[1])-time[0];
77-
constnsec=hrValues[2]-time[1];
78-
constneedsBorrow=nsec<0;
79-
return[needsBorrow ? sec-1 : sec,needsBorrow ? nsec+1e9 : nsec];
78+
if(time!==undefined){
79+
validateArray(time,'time');
80+
if(time.length!==2){
81+
thrownewERR_OUT_OF_RANGE('time',2,time.length);
8082
}
8183

82-
return[
83-
hrValues[0]*0x100000000+hrValues[1],
84-
hrValues[2],
85-
];
84+
constsec=(hrValues[0]*0x100000000+hrValues[1])-time[0];
85+
constnsec=hrValues[2]-time[1];
86+
constneedsBorrow=nsec<0;
87+
return[needsBorrow ? sec-1 : sec,needsBorrow ? nsec+1e9 : nsec];
8688
}
8789

88-
// Use a BigUint64Array in the closure because this is actually a bit
89-
// faster than simply returning a BigInt from C++ in V8 7.1.
90-
consthrBigintValues=newBigUint64Array(_hrtime.buffer,0,1);
91-
functionhrtimeBigInt(){
92-
_hrtime.hrtimeBigInt();
93-
returnhrBigintValues[0];
94-
}
90+
return[
91+
hrValues[0]*0x100000000+hrValues[1],
92+
hrValues[2],
93+
];
94+
}
9595

96-
return{
97-
hrtime,
98-
hrtimeBigInt,
99-
};
96+
functionhrtimeBigInt(){
97+
binding.hrtimeBigInt();
98+
returnhrBigintValues[0];
10099
}
101100

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

397396
module.exports={
398397
toggleTraceCategoryState,
399-
getFastAPIs,
400398
assert,
401399
buildAllowedFlags,
402-
wrapProcessMethods
400+
wrapProcessMethods,
401+
hrtime,
402+
hrtimeBigInt,
403+
refreshHrtimeBuffer,
403404
};

‎src/env-inl.h‎

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@
2929
#include"callback_queue-inl.h"
3030
#include"env.h"
3131
#include"node.h"
32+
#include"node_context_data.h"
33+
#include"node_perf_common.h"
3234
#include"util-inl.h"
3335
#include"uv.h"
36+
#include"v8-fast-api-calls.h"
3437
#include"v8.h"
35-
#include"node_perf_common.h"
36-
#include"node_context_data.h"
3738

3839
#include<cstddef>
3940
#include<cstdint>
@@ -1036,13 +1037,20 @@ inline void Environment::ThrowUVException(int errorno,
10361037
UVException(isolate(), errorno, syscall, message, path, dest));
10371038
}
10381039

1039-
inline v8::Local<v8::FunctionTemplate>
1040-
Environment::NewFunctionTemplate(v8::FunctionCallback callback,
1041-
v8::Local<v8::Signature> signature,
1042-
v8::ConstructorBehavior behavior,
1043-
v8::SideEffectType side_effect_type) {
1044-
returnv8::FunctionTemplate::New(isolate(), callback, v8::Local<v8::Value>(),
1045-
signature, 0, behavior, side_effect_type);
1040+
inline v8::Local<v8::FunctionTemplate> Environment::NewFunctionTemplate(
1041+
v8::FunctionCallback callback,
1042+
v8::Local<v8::Signature> signature,
1043+
v8::ConstructorBehavior behavior,
1044+
v8::SideEffectType side_effect_type,
1045+
const v8::CFunction* c_function) {
1046+
returnv8::FunctionTemplate::New(isolate(),
1047+
callback,
1048+
v8::Local<v8::Value>(),
1049+
signature,
1050+
0,
1051+
behavior,
1052+
side_effect_type,
1053+
c_function);
10461054
}
10471055

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

1074+
inlinevoidEnvironment::SetFastMethod(v8::Local<v8::Object> that,
1075+
constchar* name,
1076+
v8::FunctionCallback slow_callback,
1077+
const v8::CFunction* c_function) {
1078+
v8::Local<v8::Context> context = isolate()->GetCurrentContext();
1079+
v8::Local<v8::Function> function =
1080+
NewFunctionTemplate(slow_callback,
1081+
v8::Local<v8::Signature>(),
1082+
v8::ConstructorBehavior::kThrow,
1083+
v8::SideEffectType::kHasNoSideEffect,
1084+
c_function)
1085+
->GetFunction(context)
1086+
.ToLocalChecked();
1087+
const v8::NewStringType type = v8::NewStringType::kInternalized;
1088+
v8::Local<v8::String> name_string =
1089+
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
1090+
that->Set(context, name_string, function).Check();
1091+
}
1092+
10661093
inlinevoidEnvironment::SetMethodNoSideEffect(v8::Local<v8::Object> that,
10671094
constchar* name,
10681095
v8::FunctionCallback callback) {

‎src/env.h‎

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include"handle_wrap.h"
3535
#include"node.h"
3636
#include"node_binding.h"
37+
#include"node_external_reference.h"
3738
#include"node_main_instance.h"
3839
#include"node_options.h"
3940
#include"node_perf_common.h"
@@ -1239,20 +1240,23 @@ class Environment : public MemoryRetainer {
12391240
constchar* path = nullptr,
12401241
constchar* dest = nullptr);
12411242

1242-
inline v8::Local<v8::FunctionTemplate>
1243-
NewFunctionTemplate(v8::FunctionCallback callback,
1244-
v8::Local<v8::Signature> signature =
1245-
v8::Local<v8::Signature>(),
1246-
v8::ConstructorBehavior behavior =
1247-
v8::ConstructorBehavior::kAllow,
1248-
v8::SideEffectType side_effect =
1249-
v8::SideEffectType::kHasSideEffect);
1243+
inline v8::Local<v8::FunctionTemplate> NewFunctionTemplate(
1244+
v8::FunctionCallback callback,
1245+
v8::Local<v8::Signature> signature = v8::Local<v8::Signature>(),
1246+
v8::ConstructorBehavior behavior = v8::ConstructorBehavior::kAllow,
1247+
v8::SideEffectType side_effect = v8::SideEffectType::kHasSideEffect,
1248+
const v8::CFunction* c_function = nullptr);
12501249

12511250
// Convenience methods for NewFunctionTemplate().
12521251
inlinevoidSetMethod(v8::Local<v8::Object> that,
12531252
constchar* name,
12541253
v8::FunctionCallback callback);
12551254

1255+
inlinevoidSetFastMethod(v8::Local<v8::Object> that,
1256+
constchar* name,
1257+
v8::FunctionCallback slow_callback,
1258+
const v8::CFunction* c_function);
1259+
12561260
inlinevoidSetProtoMethod(v8::Local<v8::FunctionTemplate> that,
12571261
constchar* name,
12581262
v8::FunctionCallback callback);

‎src/node_external_reference.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55

66
#include<cinttypes>
77
#include<vector>
8+
#include"v8-fast-api-calls.h"
89
#include"v8.h"
910

1011
namespacenode {
1112

13+
using CFunctionCallback = void (*)(v8::Local<v8::Value> receiver);
14+
1215
// This class manages the external references from the V8 heap
1316
// to the C++ addresses in Node.js.
1417
classExternalReferenceRegistry {
1518
public:
1619
ExternalReferenceRegistry();
1720

1821
#defineALLOWED_EXTERNAL_REFERENCE_TYPES(V) \
22+
V(CFunctionCallback) \
23+
V(const v8::CFunctionInfo*) \
1924
V(v8::FunctionCallback) \
2025
V(v8::AccessorGetterCallback) \
2126
V(v8::AccessorSetterCallback) \

‎src/node_process.h‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33

44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

6+
#include"node_snapshotable.h"
7+
#include"v8-fast-api-calls.h"
68
#include"v8.h"
79

810
namespacenode {
911

12+
classEnvironment;
13+
classMemoryTracker;
14+
classExternalReferenceRegistry;
15+
1016
v8::MaybeLocal<v8::Object> CreateEnvVarProxy(v8::Local<v8::Context> context,
1117
v8::Isolate* isolate);
1218

@@ -38,6 +44,54 @@ v8::Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
3844
v8::MaybeLocal<v8::Object> CreateProcessObject(Environment* env);
3945
voidPatchProcessObject(const v8::FunctionCallbackInfo<v8::Value>& args);
4046

47+
namespaceprocess {
48+
classBindingData : publicSnapshotableObject {
49+
public:
50+
voidAddMethods();
51+
staticvoidRegisterExternalReferences(ExternalReferenceRegistry* registry);
52+
53+
SERIALIZABLE_OBJECT_METHODS()
54+
staticconstexpr FastStringKey type_name{"node::process::BindingData"};
55+
staticconstexpr EmbedderObjectType type_int =
56+
EmbedderObjectType::k_process_binding_data;
57+
58+
BindingData(Environment* env, v8::Local<v8::Object> object);
59+
60+
voidMemoryInfo(MemoryTracker* tracker) constoverride;
61+
SET_MEMORY_INFO_NAME(BindingData)
62+
SET_SELF_SIZE(BindingData)
63+
64+
static BindingData* FromV8Value(v8::Local<v8::Value> receiver);
65+
staticvoidNumberImpl(BindingData* receiver);
66+
67+
staticvoidFastNumber(v8::Local<v8::Value> receiver) {
68+
NumberImpl(FromV8Value(receiver));
69+
}
70+
71+
staticvoidSlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args);
72+
73+
staticvoidBigIntImpl(BindingData* receiver);
74+
75+
staticvoidFastBigInt(v8::Local<v8::Value> receiver) {
76+
BigIntImpl(FromV8Value(receiver));
77+
}
78+
79+
staticvoidSlowBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
80+
81+
private:
82+
staticconstexprsize_tkBufferSize =
83+
std::max(sizeof(uint64_t), sizeof(uint32_t) * 3);
84+
v8::Global<v8::ArrayBuffer> array_buffer_;
85+
std::shared_ptr<v8::BackingStore> backing_store_;
86+
87+
// These need to be static so that we have their addresses available to
88+
// register as external references in the snapshot at environment creation
89+
// time.
90+
static v8::CFunction fast_number_;
91+
static v8::CFunction fast_bigint_;
92+
};
93+
94+
} // namespace process
4195
} // namespace node
4296
#endif// defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
4397
#endif// SRC_NODE_PROCESS_H_

0 commit comments

Comments
 (0)