From d8eef83757c263672832687ac7667927a7d0c059 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Thu, 28 May 2020 00:10:22 -0500 Subject: process: use v8 fast api calls for hrtime Refs: https://github.com/nodejs/node/issues/33374 PR-URL: https://github.com/nodejs/node/pull/33600 Reviewed-By: Anna Henningsen Reviewed-By: Matteo Collina --- src/node_process_methods.cc | 131 +++++++++++++++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 33 deletions(-) (limited to 'src/node_process_methods.cc') diff --git a/src/node_process_methods.cc b/src/node_process_methods.cc index 6013dbb86b..d580f74478 100644 --- a/src/node_process_methods.cc +++ b/src/node_process_methods.cc @@ -7,6 +7,7 @@ #include "node_process.h" #include "util-inl.h" #include "uv.h" +#include "v8-fast-api-calls.h" #include "v8.h" #include @@ -33,7 +34,7 @@ namespace node { using v8::Array; using v8::ArrayBuffer; -using v8::BigUint64Array; +using v8::BackingStore; using v8::Context; using v8::Float64Array; using v8::FunctionCallbackInfo; @@ -46,7 +47,6 @@ using v8::Number; using v8::Object; using v8::String; using v8::Uint32; -using v8::Uint32Array; using v8::Value; namespace per_process { @@ -131,35 +131,6 @@ static void Cwd(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(cwd); } - -// Hrtime exposes libuv's uv_hrtime() high-resolution timer. - -// This is the legacy version of hrtime before BigInt was introduced in -// JavaScript. -// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds, -// so this function instead fills in an Uint32Array with 3 entries, -// to avoid any integer overflow possibility. -// The first two entries contain the second part of the value -// broken into the upper/lower 32 bits to be converted back in JS, -// because there is no Uint64Array in JS. -// The third entry contains the remaining nanosecond part of the value. -static void Hrtime(const FunctionCallbackInfo& args) { - uint64_t t = uv_hrtime(); - - Local ab = args[0].As()->Buffer(); - uint32_t* fields = static_cast(ab->GetBackingStore()->Data()); - - fields[0] = (t / NANOS_PER_SEC) >> 32; - fields[1] = (t / NANOS_PER_SEC) & 0xffffffff; - fields[2] = t % NANOS_PER_SEC; -} - -static void HrtimeBigInt(const FunctionCallbackInfo& args) { - Local ab = args[0].As()->Buffer(); - uint64_t* fields = static_cast(ab->GetBackingStore()->Data()); - fields[0] = uv_hrtime(); -} - static void Kill(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Local context = env->context(); @@ -452,6 +423,85 @@ static void ReallyExit(const FunctionCallbackInfo& args) { env->Exit(code); } +class FastHrtime : public BaseObject { + public: + static Local New(Environment* env) { + Local otmpl = v8::ObjectTemplate::New(env->isolate()); + otmpl->SetInternalFieldCount(FastHrtime::kInternalFieldCount); + + auto create_func = [env](auto fast_func, auto slow_func) { + auto cfunc = v8::CFunction::Make(fast_func); + return v8::FunctionTemplate::New(env->isolate(), + slow_func, + Local(), + Local(), + 0, + v8::ConstructorBehavior::kThrow, + v8::SideEffectType::kHasNoSideEffect, + &cfunc); + }; + + otmpl->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "hrtime"), + create_func(FastNumber, SlowNumber)); + otmpl->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "hrtimeBigInt"), + create_func(FastBigInt, SlowBigInt)); + + Local obj = otmpl->NewInstance(env->context()).ToLocalChecked(); + + Local ab = ArrayBuffer::New(env->isolate(), 12); + new FastHrtime(env, obj, ab->GetBackingStore()); + obj->Set( + env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "buffer"), ab) + .ToChecked(); + + return obj; + } + + private: + FastHrtime(Environment* env, + Local object, + std::shared_ptr backing_store) + : BaseObject(env, object), backing_store_(backing_store) {} + + void MemoryInfo(MemoryTracker* tracker) const override {} + + SET_MEMORY_INFO_NAME(FastHrtime) + SET_SELF_SIZE(FastHrtime) + + // This is the legacy version of hrtime before BigInt was introduced in + // JavaScript. + // The value returned by uv_hrtime() is a 64-bit int representing nanoseconds, + // so this function instead fills in an Uint32Array with 3 entries, + // to avoid any integer overflow possibility. + // The first two entries contain the second part of the value + // broken into the upper/lower 32 bits to be converted back in JS, + // because there is no Uint64Array in JS. + // The third entry contains the remaining nanosecond part of the value. + static void FastNumber(FastHrtime* receiver) { + uint64_t t = uv_hrtime(); + uint32_t* fields = static_cast(receiver->backing_store_->Data()); + fields[0] = (t / NANOS_PER_SEC) >> 32; + fields[1] = (t / NANOS_PER_SEC) & 0xffffffff; + fields[2] = t % NANOS_PER_SEC; + } + + static void SlowNumber(const FunctionCallbackInfo& args) { + FastNumber(FromJSObject(args.Holder())); + } + + static void FastBigInt(FastHrtime* receiver) { + uint64_t t = uv_hrtime(); + uint64_t* fields = static_cast(receiver->backing_store_->Data()); + fields[0] = t; + } + + static void SlowBigInt(const FunctionCallbackInfo& args) { + FastBigInt(FromJSObject(args.Holder())); + } + + std::shared_ptr backing_store_; +}; + static void InitializeProcessMethods(Local target, Local unused, Local context, @@ -475,8 +525,6 @@ static void InitializeProcessMethods(Local target, env->SetMethod(target, "_rawDebug", RawDebug); env->SetMethod(target, "memoryUsage", MemoryUsage); env->SetMethod(target, "cpuUsage", CPUUsage); - env->SetMethod(target, "hrtime", Hrtime); - env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt); env->SetMethod(target, "resourceUsage", ResourceUsage); env->SetMethod(target, "_getActiveRequests", GetActiveRequests); @@ -488,9 +536,26 @@ static void InitializeProcessMethods(Local 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(); } } // namespace node +namespace v8 { +template <> +class WrapperTraits { + public: + static const void* GetTypeInfo() { + static const int tag = 0; + return reinterpret_cast(&tag); + } +}; +} // namespace v8 + NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods, node::InitializeProcessMethods) -- cgit v1.2.1