diff options
author | Gus Caplan <me@gus.host> | 2020-05-28 00:10:22 -0500 |
---|---|---|
committer | Gus Caplan <me@gus.host> | 2020-06-06 11:55:45 -0500 |
commit | d8eef83757c263672832687ac7667927a7d0c059 (patch) | |
tree | 8c4a9697dc1bbfa041ae211f961a87ebcffa7b5a /src/node_process_methods.cc | |
parent | e983b1cece7d24f7b4776798916276d30b9e419a (diff) | |
download | node-new-d8eef83757c263672832687ac7667927a7d0c059.tar.gz |
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 <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'src/node_process_methods.cc')
-rw-r--r-- | src/node_process_methods.cc | 131 |
1 files changed, 98 insertions, 33 deletions
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 <vector> @@ -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<Value>& 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<Value>& args) { - uint64_t t = uv_hrtime(); - - Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer(); - uint32_t* fields = static_cast<uint32_t*>(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<Value>& args) { - Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer(); - uint64_t* fields = static_cast<uint64_t*>(ab->GetBackingStore()->Data()); - fields[0] = uv_hrtime(); -} - static void Kill(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); Local<Context> context = env->context(); @@ -452,6 +423,85 @@ static void ReallyExit(const FunctionCallbackInfo<Value>& args) { env->Exit(code); } +class FastHrtime : public BaseObject { + public: + static Local<Object> New(Environment* env) { + Local<v8::ObjectTemplate> 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<Value>(), + Local<v8::Signature>(), + 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<Object> obj = otmpl->NewInstance(env->context()).ToLocalChecked(); + + Local<ArrayBuffer> 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> object, + std::shared_ptr<v8::BackingStore> 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<uint32_t*>(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<Value>& args) { + FastNumber(FromJSObject<FastHrtime>(args.Holder())); + } + + static void FastBigInt(FastHrtime* receiver) { + uint64_t t = uv_hrtime(); + uint64_t* fields = static_cast<uint64_t*>(receiver->backing_store_->Data()); + fields[0] = t; + } + + static void SlowBigInt(const FunctionCallbackInfo<Value>& args) { + FastBigInt(FromJSObject<FastHrtime>(args.Holder())); + } + + std::shared_ptr<BackingStore> backing_store_; +}; + static void InitializeProcessMethods(Local<Object> target, Local<Value> unused, Local<Context> context, @@ -475,8 +525,6 @@ static void InitializeProcessMethods(Local<Object> 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<Object> 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<node::FastHrtime> { + public: + static const void* GetTypeInfo() { + static const int tag = 0; + return reinterpret_cast<const void*>(&tag); + } +}; +} // namespace v8 + NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods, node::InitializeProcessMethods) |