From 4527ad1500a9382d78d4be6d68d6c4397d61705d Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Sat, 4 Jul 2026 19:31:15 +0300 Subject: [PATCH] Unboxed lane for relational tests against slot-stored numbers Decomposing a fully optimized function-local loop (new LoopDispatchBenchmarks) showed the for-statement machinery dominating at ~48 ns/iter: the slot-stored counter ping-pongs between its unboxed update (stores a raw double) and its loop test (re-materializes a JsNumber), and past the interned-int range every test read and update allocates (~27 B/iter). Relational comparisons (<, >, <=, >=) whose left side resolves to a slot-stored number and whose right side is a numeric literal now compare raw doubles in both boolean and value positions - no operand materialization, no JsBoolean round-trip in test position, and the counter stays unboxed for its whole lifetime. IEEE double comparisons reproduce the abstract relational operator for all four forms including NaN (undefined coerced to false). The lane resolves through the shadow-aware SlotLocationCache walk and bails to the materialized path for operator overloading, suspendable frames, const/TDZ and non-number bindings. Same-window stash A/B: LoopDispatch EmptyLoop -37% (48.5 -> 30.6 ns/iter) with allocation 2.74 MB -> 2.5 KB per op, ComparisonOnly -35.7%, DoubleAccumulator/LargeIntCounter ~-32% with Gen0 eliminated, EvalExecution hot rows ~-24% (the optimized-loop floor drops 60 -> 46 ns/iter), 3d-cube driver -6.2%, stopwatch canary within noise. New RelationalComparisonTests pin NaN, non-numeric transitions, const, +/-0 and block-shadowed bindings through the cached-eval walk. Jint.Tests 3195/3133, PublicInterface, CommonScripts, Test262 99260/0, all-TFM build. Co-Authored-By: Claude Fable 5 --- Jint.Benchmark/LoopDispatchBenchmarks.cs | 78 ++++++++++++ .../Runtime/RelationalComparisonTests.cs | 113 ++++++++++++++++++ .../Expressions/JintBinaryExpression.cs | 93 +++++++++++++- 3 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 Jint.Benchmark/LoopDispatchBenchmarks.cs create mode 100644 Jint.Tests/Runtime/RelationalComparisonTests.cs diff --git a/Jint.Benchmark/LoopDispatchBenchmarks.cs b/Jint.Benchmark/LoopDispatchBenchmarks.cs new file mode 100644 index 000000000..1aedcd373 --- /dev/null +++ b/Jint.Benchmark/LoopDispatchBenchmarks.cs @@ -0,0 +1,78 @@ +using BenchmarkDotNet.Attributes; +using Jint.Native; + +namespace Jint.Benchmark; + +/// +/// Decomposes the per-iteration cost of a hot function-local loop with every fast path engaged +/// (fixed slots, pooled env, slot caches, unboxed counters): the empty loop isolates the +/// for-statement machinery (test, update, statement dispatch), and each body row adds exactly +/// one statement on top so the delta attributes cost to that construct. 100k iterations per op. +/// +[MemoryDiagnoser] +[HideColumns("Error", "Gen0", "Gen1", "Gen2")] +public class LoopDispatchBenchmarks +{ + private Engine _engine = null!; + private Prepared