Skip to content

Add int32 fast lane to the raw-double remainder sites#2671

Merged
lahma merged 1 commit into
sebastienros:mainfrom
lahma:perf-int-remainder-unboxed
Jul 13, 2026
Merged

Add int32 fast lane to the raw-double remainder sites#2671
lahma merged 1 commit into
sebastienros:mainfrom
lahma:perf-int-remainder-unboxed

Conversation

@lahma

@lahma lahma commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three raw-double lanes compute JS % as double % double — a native fmod call — even for the dominant integral loop-counter shapes, while the shared Remainder helper already has an integer fast path for boxed Integer operands:

  • JintAssignmentExpression.TryCompoundUnboxed, the x %= y arm
  • SimpleAssignmentExpression.TryAssignNumeric, the lhs = a % b arm
  • JintBinaryExpression.ModuloEqualityLane, the fused x % c === c stopwatch if-chain shape

Route all three through a shared RemainderUnboxed(double, double) helper: an int32 round-trip gate (NaN, ±Infinity, fractional values, out-of-int32-range operands and zero divisors all fail the round-trip equality and defer to the IEEE 754 %, which matches the ECMAScript algorithm for those cases), remainder computed in long math (int.MinValue % -1 would raise a hardware overflow in 32-bit division), and a zero remainder takes the dividend's sign bit — so negative and -0 dividends produce the spec -0.

Benchmarks (default jobs, adjacent A/B on latest main)

Benchmark main PR Δ
Stopwatch Execute 97.03 ms 92.33 ms −4.8%
Stopwatch Execute_ParsedScript 96.83 ms 92.02 ms −5.0%
Stopwatch Execute (Modern) 90.76 ms 88.93 ms −2.0%
Stopwatch Execute_ParsedScript (Modern) 91.55 ms 88.09 ms −3.8%
SunSpider crypto-md5 / math-cordic / string-fasta 53.76 / 106.33 / 70.70 ms 54.02 / 107.13 / 71.53 ms neutral (within drift)

Allocations unchanged on every row.

Correctness

New IntegerRemainderLanesPreserveSignAndSpecialCases test: 63 assertions × 3 loop passes (cache-armed lanes) across all three shapes — dividend-sign results, Object.is(x, -0) for negative and -0 dividends, % 0 → NaN, fractional fallback, int.MinValue % -1 → -0.

Gates

  • Jint.Tests: 3542 (net10.0) + 3479 (net472) passed, 0 failed
  • Jint.Tests.PublicInterface / CommonScripts: green both TFMs
  • Test262: 99,429 passed, 0 failed (an earlier run under heavy CPU contention flaked 8 known slow RegExp-literal tests at their 30 s timeout; clean re-run on an idle machine)

🤖 Generated with Claude Code

TryCompoundUnboxed, TryAssignNumeric and ModuloEqualityLane computed JS %
as double % double - a native fmod call - even for the dominant integral
loop-counter shapes, while the shared Remainder helper already had an
integer fast path for boxed Integer operands.

Route all three through a shared RemainderUnboxed helper: int32 round-trip
gate (NaN/Infinity/fractional/out-of-range/zero-divisor operands defer to
fmod), remainder in long math (int.MinValue % -1 would raise a hardware
overflow in 32-bit division), and a zero remainder takes the dividend's
sign bit so negative and -0 dividends produce the spec -0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant