Skip to content

Commit d8eef83

Browse files
committed
process: use v8 fast api calls for hrtime
Refs: #33374 PR-URL: #33600 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent e983b1c commit d8eef83

File tree

4 files changed

+136
-58
lines changed

4 files changed

+136
-58
lines changed

lib/internal/process/per_thread.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ function assert(x, msg) {
4141
function wrapProcessMethods(binding) {
4242
const {
4343
hrtime: _hrtime,
44-
hrtimeBigInt: _hrtimeBigInt,
4544
cpuUsage: _cpuUsage,
4645
memoryUsage: _memoryUsage,
4746
resourceUsage: _resourceUsage
@@ -113,10 +112,10 @@ function wrapProcessMethods(binding) {
113112
// The 3 entries filled in by the original process.hrtime contains
114113
// the upper/lower 32 bits of the second part of the value,
115114
// and the remaining nanoseconds of the value.
116-
const hrValues = new Uint32Array(3);
115+
const hrValues = new Uint32Array(_hrtime.buffer);
117116

118117
function hrtime(time) {
119-
_hrtime(hrValues);
118+
_hrtime.hrtime();
120119

121120
if (time !== undefined) {
122121
if (!ArrayIsArray(time)) {
@@ -140,9 +139,9 @@ function wrapProcessMethods(binding) {
140139

141140
// Use a BigUint64Array in the closure because this is actually a bit
142141
// faster than simply returning a BigInt from C++ in V8 7.1.
143-
const hrBigintValues = new BigUint64Array(1);
142+
const hrBigintValues = new BigUint64Array(_hrtime.buffer, 0, 1);
144143
function hrtimeBigInt() {
145-
_hrtimeBigInt(hrBigintValues);
144+
_hrtime.hrtimeBigInt();
146145
return hrBigintValues[0];
147146
}
148147

src/api/environment.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
209209
// heap based on the actual physical memory.
210210
params->constraints.ConfigureDefaults(total_memory, 0);
211211
}
212+
params->embedder_wrapper_object_index = BaseObject::InternalFields::kSlot;
213+
params->embedder_wrapper_type_index = std::numeric_limits<int>::max();
212214
}
213215

214216
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {

src/node_process_methods.cc

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "node_process.h"
88
#include "util-inl.h"
99
#include "uv.h"
10+
#include "v8-fast-api-calls.h"
1011
#include "v8.h"
1112

1213
#include <vector>
@@ -33,7 +34,7 @@ namespace node {
3334

3435
using v8::Array;
3536
using v8::ArrayBuffer;
36-
using v8::BigUint64Array;
37+
using v8::BackingStore;
3738
using v8::Context;
3839
using v8::Float64Array;
3940
using v8::FunctionCallbackInfo;
@@ -46,7 +47,6 @@ using v8::Number;
4647
using v8::Object;
4748
using v8::String;
4849
using v8::Uint32;
49-
using v8::Uint32Array;
5050
using v8::Value;
5151

5252
namespace per_process {
@@ -131,35 +131,6 @@ static void Cwd(const FunctionCallbackInfo<Value>& args) {
131131
args.GetReturnValue().Set(cwd);
132132
}
133133

134-
135-
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
136-
137-
// This is the legacy version of hrtime before BigInt was introduced in
138-
// JavaScript.
139-
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
140-
// so this function instead fills in an Uint32Array with 3 entries,
141-
// to avoid any integer overflow possibility.
142-
// The first two entries contain the second part of the value
143-
// broken into the upper/lower 32 bits to be converted back in JS,
144-
// because there is no Uint64Array in JS.
145-
// The third entry contains the remaining nanosecond part of the value.
146-
static void Hrtime(const FunctionCallbackInfo<Value>& args) {
147-
uint64_t t = uv_hrtime();
148-
149-
Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
150-
uint32_t* fields = static_cast<uint32_t*>(ab->GetBackingStore()->Data());
151-
152-
fields[0] = (t / NANOS_PER_SEC) >> 32;
153-
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
154-
fields[2] = t % NANOS_PER_SEC;
155-
}
156-
157-
static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
158-
Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
159-
uint64_t* fields = static_cast<uint64_t*>(ab->GetBackingStore()->Data());
160-
fields[0] = uv_hrtime();
161-
}
162-
163134
static void Kill(const FunctionCallbackInfo<Value>& args) {
164135
Environment* env = Environment::GetCurrent(args);
165136
Local<Context> context = env->context();
@@ -452,6 +423,85 @@ static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
452423
env->Exit(code);
453424
}
454425

426+
class FastHrtime : public BaseObject {
427+
public:
428+
static Local<Object> New(Environment* env) {
429+
Local<v8::ObjectTemplate> otmpl = v8::ObjectTemplate::New(env->isolate());
430+
otmpl->SetInternalFieldCount(FastHrtime::kInternalFieldCount);
431+
432+
auto create_func = [env](auto fast_func, auto slow_func) {
433+
auto cfunc = v8::CFunction::Make(fast_func);
434+
return v8::FunctionTemplate::New(env->isolate(),
435+
slow_func,
436+
Local<Value>(),
437+
Local<v8::Signature>(),
438+
0,
439+
v8::ConstructorBehavior::kThrow,
440+
v8::SideEffectType::kHasNoSideEffect,
441+
&cfunc);
442+
};
443+
444+
otmpl->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "hrtime"),
445+
create_func(FastNumber, SlowNumber));
446+
otmpl->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "hrtimeBigInt"),
447+
create_func(FastBigInt, SlowBigInt));
448+
449+
Local<Object> obj = otmpl->NewInstance(env->context()).ToLocalChecked();
450+
451+
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), 12);
452+
new FastHrtime(env, obj, ab->GetBackingStore());
453+
obj->Set(
454+
env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "buffer"), ab)
455+
.ToChecked();
456+
457+
return obj;
458+
}
459+
460+
private:
461+
FastHrtime(Environment* env,
462+
Local<Object> object,
463+
std::shared_ptr<v8::BackingStore> backing_store)
464+
: BaseObject(env, object), backing_store_(backing_store) {}
465+
466+
void MemoryInfo(MemoryTracker* tracker) const override {}
467+
468+
SET_MEMORY_INFO_NAME(FastHrtime)
469+
SET_SELF_SIZE(FastHrtime)
470+
471+
// This is the legacy version of hrtime before BigInt was introduced in
472+
// JavaScript.
473+
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
474+
// so this function instead fills in an Uint32Array with 3 entries,
475+
// to avoid any integer overflow possibility.
476+
// The first two entries contain the second part of the value
477+
// broken into the upper/lower 32 bits to be converted back in JS,
478+
// because there is no Uint64Array in JS.
479+
// The third entry contains the remaining nanosecond part of the value.
480+
static void FastNumber(FastHrtime* receiver) {
481+
uint64_t t = uv_hrtime();
482+
uint32_t* fields = static_cast<uint32_t*>(receiver->backing_store_->Data());
483+
fields[0] = (t / NANOS_PER_SEC) >> 32;
484+
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
485+
fields[2] = t % NANOS_PER_SEC;
486+
}
487+
488+
static void SlowNumber(const FunctionCallbackInfo<Value>& args) {
489+
FastNumber(FromJSObject<FastHrtime>(args.Holder()));
490+
}
491+
492+
static void FastBigInt(FastHrtime* receiver) {
493+
uint64_t t = uv_hrtime();
494+
uint64_t* fields = static_cast<uint64_t*>(receiver->backing_store_->Data());
495+
fields[0] = t;
496+
}
497+
498+
static void SlowBigInt(const FunctionCallbackInfo<Value>& args) {
499+
FastBigInt(FromJSObject<FastHrtime>(args.Holder()));
500+
}
501+
502+
std::shared_ptr<BackingStore> backing_store_;
503+
};
504+
455505
static void InitializeProcessMethods(Local<Object> target,
456506
Local<Value> unused,
457507
Local<Context> context,
@@ -475,8 +525,6 @@ static void InitializeProcessMethods(Local<Object> target,
475525
env->SetMethod(target, "_rawDebug", RawDebug);
476526
env->SetMethod(target, "memoryUsage", MemoryUsage);
477527
env->SetMethod(target, "cpuUsage", CPUUsage);
478-
env->SetMethod(target, "hrtime", Hrtime);
479-
env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
480528
env->SetMethod(target, "resourceUsage", ResourceUsage);
481529

482530
env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
@@ -488,9 +536,26 @@ static void InitializeProcessMethods(Local<Object> target,
488536
env->SetMethod(target, "reallyExit", ReallyExit);
489537
env->SetMethodNoSideEffect(target, "uptime", Uptime);
490538
env->SetMethod(target, "patchProcessObject", PatchProcessObject);
539+
540+
target
541+
->Set(env->context(),
542+
FIXED_ONE_BYTE_STRING(env->isolate(), "hrtime"),
543+
FastHrtime::New(env))
544+
.ToChecked();
491545
}
492546

493547
} // namespace node
494548

549+
namespace v8 {
550+
template <>
551+
class WrapperTraits<node::FastHrtime> {
552+
public:
553+
static const void* GetTypeInfo() {
554+
static const int tag = 0;
555+
return reinterpret_cast<const void*>(&tag);
556+
}
557+
};
558+
} // namespace v8
559+
495560
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
496561
node::InitializeProcessMethods)

test/cctest/test_base_object_ptr.cc

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ using v8::Isolate;
1414
using v8::Local;
1515
using v8::Object;
1616

17+
// Environments may come with existing BaseObject instances.
18+
// This variable offsets the expected BaseObject counts.
19+
static const int BASE_OBJECT_COUNT = 1;
20+
1721
class BaseObjectPtrTest : public EnvironmentTestFixture {};
1822

1923
class DummyBaseObject : public BaseObject {
@@ -47,12 +51,12 @@ TEST_F(BaseObjectPtrTest, ScopedDetached) {
4751
Env env_{handle_scope, argv};
4852
Environment* env = *env_;
4953

50-
EXPECT_EQ(env->base_object_count(), 0);
54+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT);
5155
{
5256
BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
53-
EXPECT_EQ(env->base_object_count(), 1);
57+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 1);
5458
}
55-
EXPECT_EQ(env->base_object_count(), 0);
59+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT);
5660
}
5761

5862
TEST_F(BaseObjectPtrTest, ScopedDetachedWithWeak) {
@@ -63,14 +67,14 @@ TEST_F(BaseObjectPtrTest, ScopedDetachedWithWeak) {
6367

6468
BaseObjectWeakPtr<DummyBaseObject> weak_ptr;
6569

66-
EXPECT_EQ(env->base_object_count(), 0);
70+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT);
6771
{
6872
BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
6973
weak_ptr = ptr;
70-
EXPECT_EQ(env->base_object_count(), 1);
74+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 1);
7175
}
7276
EXPECT_EQ(weak_ptr.get(), nullptr);
73-
EXPECT_EQ(env->base_object_count(), 0);
77+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT);
7478
}
7579

7680
TEST_F(BaseObjectPtrTest, Undetached) {
@@ -79,12 +83,16 @@ TEST_F(BaseObjectPtrTest, Undetached) {
7983
Env env_{handle_scope, argv};
8084
Environment* env = *env_;
8185

82-
node::AddEnvironmentCleanupHook(isolate_, [](void* arg) {
83-
EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(), 0);
84-
}, env);
86+
node::AddEnvironmentCleanupHook(
87+
isolate_,
88+
[](void* arg) {
89+
EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(),
90+
BASE_OBJECT_COUNT);
91+
},
92+
env);
8593

8694
BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::New(env);
87-
EXPECT_EQ(env->base_object_count(), 1);
95+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 1);
8896
}
8997

9098
TEST_F(BaseObjectPtrTest, GCWeak) {
@@ -101,21 +109,21 @@ TEST_F(BaseObjectPtrTest, GCWeak) {
101109
weak_ptr = ptr;
102110
ptr->MakeWeak();
103111

104-
EXPECT_EQ(env->base_object_count(), 1);
112+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 1);
105113
EXPECT_EQ(weak_ptr.get(), ptr.get());
106114
EXPECT_EQ(weak_ptr->persistent().IsWeak(), false);
107115

108116
ptr.reset();
109117
}
110118

111-
EXPECT_EQ(env->base_object_count(), 1);
119+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 1);
112120
EXPECT_NE(weak_ptr.get(), nullptr);
113121
EXPECT_EQ(weak_ptr->persistent().IsWeak(), true);
114122

115123
v8::V8::SetFlagsFromString("--expose-gc");
116124
isolate_->RequestGarbageCollectionForTesting(Isolate::kFullGarbageCollection);
117125

118-
EXPECT_EQ(env->base_object_count(), 0);
126+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT);
119127
EXPECT_EQ(weak_ptr.get(), nullptr);
120128
}
121129

@@ -126,7 +134,7 @@ TEST_F(BaseObjectPtrTest, Moveable) {
126134
Environment* env = *env_;
127135

128136
BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
129-
EXPECT_EQ(env->base_object_count(), 1);
137+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 1);
130138
BaseObjectWeakPtr<DummyBaseObject> weak_ptr { ptr };
131139
EXPECT_EQ(weak_ptr.get(), ptr.get());
132140

@@ -137,12 +145,12 @@ TEST_F(BaseObjectPtrTest, Moveable) {
137145
BaseObjectWeakPtr<DummyBaseObject> weak_ptr2 = std::move(weak_ptr);
138146
EXPECT_EQ(weak_ptr2.get(), ptr2.get());
139147
EXPECT_EQ(weak_ptr.get(), nullptr);
140-
EXPECT_EQ(env->base_object_count(), 1);
148+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 1);
141149

142150
ptr2.reset();
143151

144152
EXPECT_EQ(weak_ptr2.get(), nullptr);
145-
EXPECT_EQ(env->base_object_count(), 0);
153+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT);
146154
}
147155

148156
TEST_F(BaseObjectPtrTest, NestedClasses) {
@@ -163,14 +171,18 @@ TEST_F(BaseObjectPtrTest, NestedClasses) {
163171
Env env_{handle_scope, argv};
164172
Environment* env = *env_;
165173

166-
node::AddEnvironmentCleanupHook(isolate_, [](void* arg) {
167-
EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(), 0);
168-
}, env);
174+
node::AddEnvironmentCleanupHook(
175+
isolate_,
176+
[](void* arg) {
177+
EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(),
178+
BASE_OBJECT_COUNT);
179+
},
180+
env);
169181

170182
ObjectWithPtr* obj =
171183
new ObjectWithPtr(env, DummyBaseObject::MakeJSObject(env));
172184
obj->ptr1 = DummyBaseObject::NewDetached(env);
173185
obj->ptr2 = DummyBaseObject::New(env);
174186

175-
EXPECT_EQ(env->base_object_count(), 3);
187+
EXPECT_EQ(env->base_object_count(), BASE_OBJECT_COUNT + 3);
176188
}

0 commit comments

Comments
 (0)