From 34fbea480215112f82f7e1a851861c4de2f7e9d2 Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Fri, 10 Jul 2026 00:42:28 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Extend=20undefined-field-i?= =?UTF-8?q?nit=20fix=20to=20congruential32=20and=20mersenne=20(#1079)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Follow-up to #1078, which restored `next()` speed for `xorshift128plus` and `xoroshiro128plus`. The same regression affects the other two generators — `congruential32` and `mersenne` — since they used the identical TypeScript **parameter properties** pattern. The rolldown 1.1.3 build emits those parameter properties as **uninitialized class-field declarations** ahead of the constructor: ```js var LinearCongruential32 = class LinearCongruential32 { seed; constructor(seed) { this.seed = seed; } ``` Under ES2022 `[[Define]]` semantics the field is first defined as `undefined` before the constructor assigns an integer, which can pin the SMI-typed state fields (`seed` for congruential32, `index` for mersenne) to V8's generic **Tagged** representation instead of the SMI-optimized one — adding per-read overhead in the hot `next()` path. ## Fix Same approach as #1078: declare the state fields with `declare` (type-only, erased at emit) and assign them in the constructor body, so the compiled output contains only the constructor assignments. - `congruential32` — `seed` - `mersenne` — `states/index` ## Verification - **Emit**: both compiled classes now emit a plain constructor, no field declarations. - **Typecheck**: `tsc --noEmit` clean under the project's strict / `isolatedDeclarations` config. - **Tests**: all 96 pass, including the seed-42 and post-jump sequence snapshots — output is bit-identical. - **Format**: `oxfmt` clean. - **Benchmark**: isolated 200M-iteration `next()` loop for congruential32, old emit vs new emit → **~60–75% faster**, directly demonstrating the Tagged-vs-SMI overhead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- _Generated by [Claude Code](https://claude.ai/code/session_015bbmT43PSrpMa3rsBsErk6)_ --------- Co-authored-by: Claude --- src/generator/congruential32.ts | 5 ++++- src/generator/mersenne.ts | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/generator/congruential32.ts b/src/generator/congruential32.ts index e8f4f46..b4a6306 100644 --- a/src/generator/congruential32.ts +++ b/src/generator/congruential32.ts @@ -26,7 +26,10 @@ const JUMP_MULTIPLIER: number = 0x76dc0001; const JUMP_INCREMENT: number = 0x369b0000; class LinearCongruential32 implements JumpableRandomGenerator { - constructor(private seed: number) {} + declare private seed: number; + constructor(seed: number) { + this.seed = seed; + } clone(): LinearCongruential32 { return new LinearCongruential32(this.seed); } diff --git a/src/generator/mersenne.ts b/src/generator/mersenne.ts index bc3d62f..502a400 100644 --- a/src/generator/mersenne.ts +++ b/src/generator/mersenne.ts @@ -25,10 +25,12 @@ const JUMP_COEFS = 'SUSgbA\\W`E[]KN2RUSo8XVU?HKBFRl11E\\KoWOg5B]XEWG;BE;1:oVK[`B^Z9Qd23^XTnhL>]Unda4f[X;_j9H5QD=cN<5H`3bW>9bk1mjoI2fK0obmAAINOV:>Mek_V9ddHmm`co>k:KOSkSbIINb1VFf>LXgP>GUAQTD>Ci>XMGkUflLlb?_FaFUk@?5N7i70@;1o68ah@IAjUDh?M1B?^??FAXKThfR<;NHk3S9YhM7STJ6`:MIE`S@7298X8W>PNK=@;lLXlK6GM1YL\\lid:J>KYS=iJ]Y>QlF>?R5_[5QeYC=66;A32Ac>OHk_ne^0g>bK:g;KFPgbGUcPR_Z=TX3H9d03bKZ2IhEPKBo>LSGWd0iFdV8CT[O6lC\\blaZ>GoAYP4clf^j1IfnZJ]QeDe2X=h?Ye:_f_Sb9Ki5GDYBF4dWeMfdg^ccPllNWM7G1\\UMdoYeOOD5^e@foA22G?ADYo5:FVG[bWo96;>3kc_c1Ab30>30;1@4F8g2hY?DJ4[LOL;ZLLKo2]jo>[KMDUcR279N_kF=3WL@Dd620bMTdA\\U9k``ef2iD9JgJ8CZBHS>F^Uk;3_ocRA>2U:4GPQ6o>5jX2HIcV3S@On6KB<[SKB?FC_AAji9agbBFkAi\\;4I\\UJ]c36Ub@[;gQACVGYE]noQ[1Kambn??QQ]S?1i0oMGOijb\\aGY6lQ^CJ?9bFle8^h_g[RQV@PnYBRI_]`B]Bh@Uk03eXGY`I16L76H28X`R>IROMeNVUdU[:lghLhPCQZ:4a<30YBZCYnXe[?;jc8gKI2QH2MjnWBm4nGCZW`aVU2a;P:aNg:Th1Y=5o78K>LQ8hW@5S?I83Lk5Xk;j5@I3o[d:4RjE^oS30:WP9gC\\i8aSI>QRE@4lP:7lDg8g2`Ql[2I8aBU\\BQ?B4_clL9Q]S;^e1Ob5[>3JER2`c7B=o]fPOWOW:M?S_4S5d@J^`[AGA7@3]DnGSCO`\\?E8HT75^d9\\:m\\m1egIfk8cd6bD9\\eU8\\n[Pb0Cgd^S0n9kGJHb]i5XodlKHc34Fhi9K>0U5WK`>7Ff2^KL=WC6:kc?e5C^a1T1:4:^S5flXlGNIj08AfO?Dh7T7dWO>E]NI9?ob7B7P_h[4TEP[EU;GllFTnSmg9:\\[N]AYRJA1U5^Blhgno:aHVYc03c3J0Vc9FjEV^M75Zfd8kVC9>iJDk`AJ[6f7DK2D^DL\\AX:6b5h31XH;RQB\\NhEVLTdhL\\b1EB0lLh<=WaO@F<;8g?VE98[B\\Kjf?DUK00Aih:D`=fLPbO?VOTEYLj^cNj5PM>jKB5HVjJ4U7lXaTQNL9<@\\1`m\\Ug@VQHd7>jW=ca0`miF7;N0F=GjoQ`RFchKMGTmn8cF@Oh4GGCm7m2`U9j93Tb>=kSERjE_J939F01I1;`^LA=ebloE2Y2:9lkh0\\X:??`H6BXF2hG1Q[dF0Q=>W=J?7C\\k1T?<;R44oW?1hY^G8Zm]ZKnfOf0eCFYo6?=D8?<`6HU5SXh1;=:23LmV_FSi;OJfV<^?GkIDPISeHg1LaGE:V3Y3K3HoEKabY`:oU;=JW7ig?S?EYb86b7n8ce\\]IRa]koiWYOm2kMBUloD>Ze@NN^Z11TM`inXYhE_I=kA`:ZF4d\\>`L@;ZP[`ENU5cL[BV6\\Z?Di76:jg3hE6oG6jFc8kP=[GS1;WSedYQW1:U4\\OF32GgmMCT3VfcUB2m4J^CPRU;8dScI]LU]^bBYA5_3:Y0N5i^?200000'; class MersenneTwister implements JumpableRandomGenerator { - constructor( - private states: number[], // states: between -0x80000000 and 0x7fffffff - private index: number, - ) {} + declare private states: number[]; // states: between -0x80000000 and 0x7fffffff + declare private index: number; + constructor(states: number[], index: number) { + this.states = states; + this.index = index; + } clone(): MersenneTwister { return new MersenneTwister(this.states.slice(), this.index); } -- 2.51.2