From 231efb61b97b98bed91bf6ec717eb7ee76e14f33 Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Wed, 9 Jul 2025 22:29:43 +0100 Subject: [PATCH 1/4] perf_hooks: fix histogram fast call signatures --- src/histogram.cc | 54 +++++++++---------- src/histogram.h | 40 +++++--------- .../test-perf-hooks-histogram-fast-calls.js | 35 ++++++++++++ test/parallel/test-perf-hooks-histogram.js | 6 ++- 4 files changed, 77 insertions(+), 58 deletions(-) create mode 100644 test/parallel/test-perf-hooks-histogram-fast-calls.js diff --git a/src/histogram.cc b/src/histogram.cc index aa73551281d33d..18dce9da0b3638 100644 --- a/src/histogram.cc +++ b/src/histogram.cc @@ -2,6 +2,7 @@ #include "base_object-inl.h" #include "histogram-inl.h" #include "memory_tracker-inl.h" +#include "node_debug.h" #include "node_errors.h" #include "node_external_reference.h" #include "util.h" @@ -11,10 +12,8 @@ namespace node { using v8::BigInt; using v8::CFunction; using v8::Context; -using v8::FastApiCallbackOptions; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; -using v8::HandleScope; using v8::Integer; using v8::Isolate; using v8::Local; @@ -162,8 +161,8 @@ void HistogramBase::RecordDelta(const FunctionCallbackInfo& args) { (*histogram)->RecordDelta(); } -void HistogramBase::FastRecordDelta(Local unused, - Local receiver) { +void HistogramBase::FastRecordDelta(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.recordDelta"); HistogramBase* histogram; ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); (*histogram)->RecordDelta(); @@ -183,15 +182,9 @@ void HistogramBase::Record(const FunctionCallbackInfo& args) { (*histogram)->Record(value); } -void HistogramBase::FastRecord(Local unused, - Local receiver, - const int64_t value, - FastApiCallbackOptions& options) { - if (value < 1) { - HandleScope scope(options.isolate); - THROW_ERR_OUT_OF_RANGE(options.isolate, "value is out of range"); - return; - } +void HistogramBase::FastRecord(Local receiver, const int64_t value) { + DCHECK_GE(value, 1); + TRACK_V8_FAST_API_CALL("histogram.record"); HistogramBase* histogram; ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); (*histogram)->Record(value); @@ -428,9 +421,8 @@ void IntervalHistogram::Start(const FunctionCallbackInfo& args) { histogram->OnStart(args[0]->IsTrue() ? StartFlags::RESET : StartFlags::NONE); } -void IntervalHistogram::FastStart(Local unused, - Local receiver, - bool reset) { +void IntervalHistogram::FastStart(Local receiver, bool reset) { + TRACK_V8_FAST_API_CALL("histogram.start"); IntervalHistogram* histogram; ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); histogram->OnStart(reset ? StartFlags::RESET : StartFlags::NONE); @@ -442,7 +434,8 @@ void IntervalHistogram::Stop(const FunctionCallbackInfo& args) { histogram->OnStop(); } -void IntervalHistogram::FastStop(Local unused, Local receiver) { +void IntervalHistogram::FastStop(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.stop"); IntervalHistogram* histogram; ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); histogram->OnStop(); @@ -558,46 +551,51 @@ void HistogramImpl::DoReset(const FunctionCallbackInfo& args) { (*histogram)->Reset(); } -void HistogramImpl::FastReset(Local unused, Local receiver) { +void HistogramImpl::FastReset(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.reset"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); (*histogram)->Reset(); } -double HistogramImpl::FastGetCount(Local unused, Local receiver) { +double HistogramImpl::FastGetCount(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.count"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); return static_cast((*histogram)->Count()); } -double HistogramImpl::FastGetMin(Local unused, Local receiver) { +double HistogramImpl::FastGetMin(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.min"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); return static_cast((*histogram)->Min()); } -double HistogramImpl::FastGetMax(Local unused, Local receiver) { +double HistogramImpl::FastGetMax(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.max"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); return static_cast((*histogram)->Max()); } -double HistogramImpl::FastGetMean(Local unused, Local receiver) { +double HistogramImpl::FastGetMean(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.mean"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); return (*histogram)->Mean(); } -double HistogramImpl::FastGetExceeds(Local unused, - Local receiver) { +double HistogramImpl::FastGetExceeds(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.exceeds"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); return static_cast((*histogram)->Exceeds()); } -double HistogramImpl::FastGetStddev(Local unused, - Local receiver) { +double HistogramImpl::FastGetStddev(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.stddev"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); return (*histogram)->Stddev(); } -double HistogramImpl::FastGetPercentile(Local unused, - Local receiver, +double HistogramImpl::FastGetPercentile(Local receiver, const double percentile) { + TRACK_V8_FAST_API_CALL("histogram.percentile"); HistogramImpl* histogram = HistogramImpl::FromJSObject(receiver); return static_cast((*histogram)->Percentile(percentile)); } diff --git a/src/histogram.h b/src/histogram.h index 362e82e4436a90..29303bd16648da 100644 --- a/src/histogram.h +++ b/src/histogram.h @@ -101,22 +101,14 @@ class HistogramImpl { static void GetPercentilesBigInt( const v8::FunctionCallbackInfo& args); - static void FastReset(v8::Local unused, - v8::Local receiver); - static double FastGetCount(v8::Local unused, - v8::Local receiver); - static double FastGetMin(v8::Local unused, - v8::Local receiver); - static double FastGetMax(v8::Local unused, - v8::Local receiver); - static double FastGetMean(v8::Local unused, - v8::Local receiver); - static double FastGetExceeds(v8::Local unused, - v8::Local receiver); - static double FastGetStddev(v8::Local unused, - v8::Local receiver); - static double FastGetPercentile(v8::Local unused, - v8::Local receiver, + static void FastReset(v8::Local receiver); + static double FastGetCount(v8::Local receiver); + static double FastGetMin(v8::Local receiver); + static double FastGetMax(v8::Local receiver); + static double FastGetMean(v8::Local receiver); + static double FastGetExceeds(v8::Local receiver); + static double FastGetStddev(v8::Local receiver); + static double FastGetPercentile(v8::Local receiver, const double percentile); static void AddMethods(v8::Isolate* isolate, @@ -165,13 +157,8 @@ class HistogramBase final : public BaseObject, public HistogramImpl { static void RecordDelta(const v8::FunctionCallbackInfo& args); static void Add(const v8::FunctionCallbackInfo& args); - static void FastRecord( - v8::Local unused, - v8::Local receiver, - const int64_t value, - v8::FastApiCallbackOptions& options); // NOLINT(runtime/references) - static void FastRecordDelta(v8::Local unused, - v8::Local receiver); + static void FastRecord(v8::Local receiver, const int64_t value); + static void FastRecordDelta(v8::Local receiver); HistogramBase( Environment* env, @@ -243,11 +230,8 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl { static void Start(const v8::FunctionCallbackInfo& args); static void Stop(const v8::FunctionCallbackInfo& args); - static void FastStart(v8::Local unused, - v8::Local receiver, - bool reset); - static void FastStop(v8::Local unused, - v8::Local receiver); + static void FastStart(v8::Local receiver, bool reset); + static void FastStop(v8::Local receiver); BaseObject::TransferMode GetTransferMode() const override { return TransferMode::kCloneable; diff --git a/test/parallel/test-perf-hooks-histogram-fast-calls.js b/test/parallel/test-perf-hooks-histogram-fast-calls.js new file mode 100644 index 00000000000000..2017bf49ee35ed --- /dev/null +++ b/test/parallel/test-perf-hooks-histogram-fast-calls.js @@ -0,0 +1,35 @@ +// Flags: --expose-internals --no-warnings --allow-natives-syntax +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const { internalBinding } = require('internal/test/binding'); + +const histogram = require('perf_hooks').createHistogram(); + +function testFastMethods() { + histogram.record(1); + histogram.recordDelta(); + histogram.percentile(50); + histogram.reset(); +} + +eval('%PrepareFunctionForOptimization(histogram.record)'); +eval('%PrepareFunctionForOptimization(histogram.recordDelta)'); +eval('%PrepareFunctionForOptimization(histogram.percentile)'); +eval('%PrepareFunctionForOptimization(histogram.reset)'); +testFastMethods(); +eval('%OptimizeFunctionOnNextCall(histogram.record)'); +eval('%OptimizeFunctionOnNextCall(histogram.recordDelta)'); +eval('%OptimizeFunctionOnNextCall(histogram.percentile)'); +eval('%OptimizeFunctionOnNextCall(histogram.reset)'); +testFastMethods(); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('histogram.record'), 1); + assert.strictEqual(getV8FastApiCallCount('histogram.recordDelta'), 1); + assert.strictEqual(getV8FastApiCallCount('histogram.percentile'), 1); + assert.strictEqual(getV8FastApiCallCount('histogram.reset'), 1); +} diff --git a/test/parallel/test-perf-hooks-histogram.js b/test/parallel/test-perf-hooks-histogram.js index 9e76cca2f4f479..1ce35dd7619f00 100644 --- a/test/parallel/test-perf-hooks-histogram.js +++ b/test/parallel/test-perf-hooks-histogram.js @@ -40,8 +40,10 @@ const { inspect } = require('util'); code: 'ERR_INVALID_ARG_TYPE' }); }); - throws(() => h.record(0, Number.MAX_SAFE_INTEGER + 1), { - code: 'ERR_OUT_OF_RANGE' + [0, Number.MAX_SAFE_INTEGER + 1].forEach((i) => { + throws(() => h.record(i), { + code: 'ERR_OUT_OF_RANGE' + }); }); strictEqual(h.min, 1); From 86cb0c86129bb4c1e2150c4fab6519c23d985feb Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Sun, 13 Jul 2025 21:10:18 +0100 Subject: [PATCH 2/4] process: fix hrtime fast call signatures --- src/node_process.h | 25 +++++++++--------- src/node_process_methods.cc | 28 ++++++++++----------- test/parallel/test-process-hrtime-bigint.js | 15 ++++++++++- test/parallel/test-process-hrtime.js | 15 ++++++++++- 4 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/node_process.h b/src/node_process.h index b88a2f99483ad2..64393302d2cfd9 100644 --- a/src/node_process.h +++ b/src/node_process.h @@ -3,6 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +#include "node_debug.h" #include "node_snapshotable.h" #include "v8-fast-api-calls.h" #include "v8.h" @@ -72,23 +73,23 @@ class BindingData : public SnapshotableObject { SET_SELF_SIZE(BindingData) static BindingData* FromV8Value(v8::Local receiver); - static void NumberImpl(BindingData* receiver); + static void HrtimeImpl(BindingData* receiver); - static void FastNumber(v8::Local unused, - v8::Local receiver) { - NumberImpl(FromV8Value(receiver)); + static void FastHrtime(v8::Local receiver) { + TRACK_V8_FAST_API_CALL("process.hrtime"); + HrtimeImpl(FromV8Value(receiver)); } - static void SlowNumber(const v8::FunctionCallbackInfo& args); + static void SlowHrtime(const v8::FunctionCallbackInfo& args); - static void BigIntImpl(BindingData* receiver); + static void HrtimeBigIntImpl(BindingData* receiver); - static void FastBigInt(v8::Local unused, - v8::Local receiver) { - BigIntImpl(FromV8Value(receiver)); + static void FastHrtimeBigInt(v8::Local receiver) { + TRACK_V8_FAST_API_CALL("process.hrtimeBigInt"); + HrtimeBigIntImpl(FromV8Value(receiver)); } - static void SlowBigInt(const v8::FunctionCallbackInfo& args); + static void SlowHrtimeBigInt(const v8::FunctionCallbackInfo& args); static void LoadEnvFile(const v8::FunctionCallbackInfo& args); @@ -101,8 +102,8 @@ class BindingData : public SnapshotableObject { // These need to be static so that we have their addresses available to // register as external references in the snapshot at environment creation // time. - static v8::CFunction fast_number_; - static v8::CFunction fast_bigint_; + static v8::CFunction fast_hrtime_; + static v8::CFunction fast_hrtime_bigint_; }; } // namespace process diff --git a/src/node_process_methods.cc b/src/node_process_methods.cc index 51bfc633625e38..606425dac83772 100644 --- a/src/node_process_methods.cc +++ b/src/node_process_methods.cc @@ -652,22 +652,22 @@ BindingData::BindingData(Realm* realm, hrtime_buffer_.MakeWeak(); } -v8::CFunction BindingData::fast_number_(v8::CFunction::Make(FastNumber)); -v8::CFunction BindingData::fast_bigint_(v8::CFunction::Make(FastBigInt)); +CFunction BindingData::fast_hrtime_(CFunction::Make(FastHrtime)); +CFunction BindingData::fast_hrtime_bigint_(CFunction::Make(FastHrtimeBigInt)); void BindingData::AddMethods(Isolate* isolate, Local target) { SetFastMethodNoSideEffect( - isolate, target, "hrtime", SlowNumber, &fast_number_); + isolate, target, "hrtime", SlowHrtime, &fast_hrtime_); SetFastMethodNoSideEffect( - isolate, target, "hrtimeBigInt", SlowBigInt, &fast_bigint_); + isolate, target, "hrtimeBigInt", SlowHrtimeBigInt, &fast_hrtime_bigint_); } void BindingData::RegisterExternalReferences( ExternalReferenceRegistry* registry) { - registry->Register(SlowNumber); - registry->Register(SlowBigInt); - registry->Register(fast_number_); - registry->Register(fast_bigint_); + registry->Register(SlowHrtime); + registry->Register(SlowHrtimeBigInt); + registry->Register(fast_hrtime_); + registry->Register(fast_hrtime_bigint_); } BindingData* BindingData::FromV8Value(Local value) { @@ -689,14 +689,14 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const { // 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. -void BindingData::NumberImpl(BindingData* receiver) { +void BindingData::HrtimeImpl(BindingData* receiver) { uint64_t t = uv_hrtime(); receiver->hrtime_buffer_[0] = (t / NANOS_PER_SEC) >> 32; receiver->hrtime_buffer_[1] = (t / NANOS_PER_SEC) & 0xffffffff; receiver->hrtime_buffer_[2] = t % NANOS_PER_SEC; } -void BindingData::BigIntImpl(BindingData* receiver) { +void BindingData::HrtimeBigIntImpl(BindingData* receiver) { uint64_t t = uv_hrtime(); // The buffer is a Uint32Array, so we need to reinterpret it as a // Uint64Array to write the value. The buffer is valid at this scope so we @@ -706,12 +706,12 @@ void BindingData::BigIntImpl(BindingData* receiver) { fields[0] = t; } -void BindingData::SlowBigInt(const FunctionCallbackInfo& args) { - BigIntImpl(FromJSObject(args.This())); +void BindingData::SlowHrtimeBigInt(const FunctionCallbackInfo& args) { + HrtimeBigIntImpl(FromJSObject(args.This())); } -void BindingData::SlowNumber(const v8::FunctionCallbackInfo& args) { - NumberImpl(FromJSObject(args.This())); +void BindingData::SlowHrtime(const FunctionCallbackInfo& args) { + HrtimeImpl(FromJSObject(args.This())); } bool BindingData::PrepareForSerialization(Local context, diff --git a/test/parallel/test-process-hrtime-bigint.js b/test/parallel/test-process-hrtime-bigint.js index e5ce40a994d815..9d0e0e347b0179 100644 --- a/test/parallel/test-process-hrtime-bigint.js +++ b/test/parallel/test-process-hrtime-bigint.js @@ -1,10 +1,13 @@ +// Flags: --allow-natives-syntax --expose-internals --no-warnings 'use strict'; // Tests that process.hrtime.bigint() works. -require('../common'); +const common = require('../common'); const assert = require('assert'); +const { internalBinding } = require('internal/test/binding'); + const start = process.hrtime.bigint(); assert.strictEqual(typeof start, 'bigint'); @@ -12,3 +15,13 @@ const end = process.hrtime.bigint(); assert.strictEqual(typeof end, 'bigint'); assert(end - start >= 0n); + +eval('%PrepareFunctionForOptimization(process.hrtime.bigint)'); +assert(process.hrtime.bigint()); +eval('%OptimizeFunctionOnNextCall(process.hrtime.bigint)'); +assert(process.hrtime.bigint()); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('process.hrtimeBigInt'), 1); +} diff --git a/test/parallel/test-process-hrtime.js b/test/parallel/test-process-hrtime.js index 34ef514aac309b..e5815ebe10cc91 100644 --- a/test/parallel/test-process-hrtime.js +++ b/test/parallel/test-process-hrtime.js @@ -19,10 +19,13 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +// Flags: --allow-natives-syntax --expose-internals --no-warnings 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); +const { internalBinding } = require('internal/test/binding'); + // The default behavior, return an Array "tuple" of numbers const tuple = process.hrtime(); @@ -72,3 +75,13 @@ function validateTuple(tuple) { const diff = process.hrtime([0, 1e9 - 1]); assert(diff[1] >= 0); // https://github.com/nodejs/node/issues/4751 + +eval('%PrepareFunctionForOptimization(process.hrtime)'); +assert(process.hrtime()); +eval('%OptimizeFunctionOnNextCall(process.hrtime)'); +assert(process.hrtime()); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('process.hrtime'), 1); +} From e5b76160eda1518b3cf7d0bf53cc6f4552b48bd2 Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Sun, 13 Jul 2025 21:23:11 +0100 Subject: [PATCH 3/4] wasi: fix WasiFunction fast call signature --- src/node_wasi.cc | 1 - src/node_wasi.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/node_wasi.cc b/src/node_wasi.cc index 5f133bac216220..370221d3cddc20 100644 --- a/src/node_wasi.cc +++ b/src/node_wasi.cc @@ -266,7 +266,6 @@ inline void EinvalError() {} template R WASI::WasiFunction::FastCallback( - Local unused, Local receiver, Args... args, // NOLINTNEXTLINE(runtime/references) This is V8 api. diff --git a/src/node_wasi.h b/src/node_wasi.h index ef7d2e83b6728a..25551936e6be36 100644 --- a/src/node_wasi.h +++ b/src/node_wasi.h @@ -160,8 +160,7 @@ class WASI : public BaseObject, v8::Local); private: - static R FastCallback(v8::Local unused, - v8::Local receiver, + static R FastCallback(v8::Local receiver, Args..., v8::FastApiCallbackOptions&); From 9926389b8d7b2986883b6ab188241047aa7ae9cf Mon Sep 17 00:00:00 2001 From: Renegade334 Date: Sun, 13 Jul 2025 21:38:50 +0100 Subject: [PATCH 4/4] timers: fix binding fast call signatures --- src/timers.cc | 15 ++++++------- src/timers.h | 11 +++------- test/parallel/test-timers-fast-calls.js | 28 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 test/parallel/test-timers-fast-calls.js diff --git a/src/timers.cc b/src/timers.cc index bf90e68479da14..da4206187f7c7d 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -53,9 +53,8 @@ void BindingData::SlowScheduleTimer(const FunctionCallbackInfo& args) { } } -void BindingData::FastScheduleTimer(Local unused, - Local receiver, - int64_t duration) { +void BindingData::FastScheduleTimer(Local receiver, int64_t duration) { + TRACK_V8_FAST_API_CALL("timers.scheduleTimer"); ScheduleTimerImpl(FromJSObject(receiver), duration); } @@ -69,9 +68,8 @@ void BindingData::SlowToggleTimerRef( args[0]->IsTrue()); } -void BindingData::FastToggleTimerRef(Local unused, - Local receiver, - bool ref) { +void BindingData::FastToggleTimerRef(Local receiver, bool ref) { + TRACK_V8_FAST_API_CALL("timers.toggleTimerRef"); ToggleTimerRefImpl(FromJSObject(receiver), ref); } @@ -85,9 +83,8 @@ void BindingData::SlowToggleImmediateRef( args[0]->IsTrue()); } -void BindingData::FastToggleImmediateRef(Local unused, - Local receiver, - bool ref) { +void BindingData::FastToggleImmediateRef(Local receiver, bool ref) { + TRACK_V8_FAST_API_CALL("timers.toggleImmediateRef"); ToggleImmediateRefImpl(FromJSObject(receiver), ref); } diff --git a/src/timers.h b/src/timers.h index 3c3a4d60d34ae8..01cc612e8b26a2 100644 --- a/src/timers.h +++ b/src/timers.h @@ -31,23 +31,18 @@ class BindingData : public SnapshotableObject { static void SlowScheduleTimer( const v8::FunctionCallbackInfo& args); - static void FastScheduleTimer(v8::Local unused, - v8::Local receiver, + static void FastScheduleTimer(v8::Local receiver, int64_t duration); static void ScheduleTimerImpl(BindingData* data, int64_t duration); static void SlowToggleTimerRef( const v8::FunctionCallbackInfo& args); - static void FastToggleTimerRef(v8::Local unused, - v8::Local receiver, - bool ref); + static void FastToggleTimerRef(v8::Local receiver, bool ref); static void ToggleTimerRefImpl(BindingData* data, bool ref); static void SlowToggleImmediateRef( const v8::FunctionCallbackInfo& args); - static void FastToggleImmediateRef(v8::Local unused, - v8::Local receiver, - bool ref); + static void FastToggleImmediateRef(v8::Local receiver, bool ref); static void ToggleImmediateRefImpl(BindingData* data, bool ref); static void CreatePerIsolateProperties(IsolateData* isolate_data, diff --git a/test/parallel/test-timers-fast-calls.js b/test/parallel/test-timers-fast-calls.js new file mode 100644 index 00000000000000..06387f46c363d4 --- /dev/null +++ b/test/parallel/test-timers-fast-calls.js @@ -0,0 +1,28 @@ +// Flags: --allow-natives-syntax --expose-internals --no-warnings +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const { internalBinding } = require('internal/test/binding'); +const binding = internalBinding('timers'); + +function testFastCalls() { + binding.scheduleTimer(1); + binding.toggleTimerRef(true); + binding.toggleTimerRef(false); + binding.toggleImmediateRef(true); + binding.toggleImmediateRef(false); +} + +eval('%PrepareFunctionForOptimization(testFastCalls)'); +testFastCalls(); +eval('%OptimizeFunctionOnNextCall(testFastCalls)'); +testFastCalls(); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('timers.scheduleTimer'), 1); + assert.strictEqual(getV8FastApiCallCount('timers.toggleTimerRef'), 2); + assert.strictEqual(getV8FastApiCallCount('timers.toggleImmediateRef'), 2); +}