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
3435using v8::Array;
3536using v8::ArrayBuffer;
36- using v8::BigUint64Array ;
37+ using v8::BackingStore ;
3738using v8::Context;
3839using v8::Float64Array;
3940using v8::FunctionCallbackInfo;
@@ -46,7 +47,6 @@ using v8::Number;
4647using v8::Object;
4748using v8::String;
4849using v8::Uint32;
49- using v8::Uint32Array;
5050using v8::Value;
5151
5252namespace 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-
163134static 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+
455505static 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+
495560NODE_MODULE_CONTEXT_AWARE_INTERNAL (process_methods,
496561 node::InitializeProcessMethods)
0 commit comments