Skip to content

Commit 5da90f5

Browse files
committed
builtins/bigint: rewrite fromString
much better for large numbers test262: 56.49% | πŸ§ͺ 50259 | 🀠 28390 | ❌ 7231 (-1) | πŸ’€ 13701 (+1) | πŸ—οΈ 32 | πŸ’₯ 177 | ⏰ 11 | πŸ“ 717
1 parent da037f0 commit 5da90f5

File tree

5 files changed

+38
-36
lines changed

5 files changed

+38
-36
lines changed

β€Žcompiler/builtins/bigint.ts

+33-31
Original file line numberDiff line numberDiff line change
@@ -76,57 +76,59 @@ export const __Porffor_bigint_fromString = (n: string|bytestring): bigint => {
7676
const len: i32 = n.length;
7777

7878
let negative: boolean = false;
79-
let end: i32 = 0;
79+
let offset: i32 = 0;
8080
if (n[0] === '-') {
8181
negative = true;
82-
end = 1;
82+
offset = 1;
8383
} else if (n[0] === '+') {
84-
end = 1;
84+
offset = 1;
8585
}
8686

8787
// n -> digits (base 2^32) (most to least significant)
8888
// 4294967294 -> [ 4294967294 ]
8989
// 4294967295 -> [ 4294967295 ]
9090
// 4294967296 -> [ 1, 0 ]
9191
// 4294967297 -> [ 1, 1 ]
92-
// 4294967298 -> [ 1, 2 ]
93-
// 9007199254740992 -> [ 2097152 ]
92+
// 9007199254740992 -> [ 2097152, 0 ]
9493
// 9007199254740993 -> [ 2097152, 1 ]
9594
// 9007199254740994 -> [ 2097152, 2 ]
96-
// 9007199254740995 -> [ 2097152, 3 ]
9795

98-
let acc: number = 0;
99-
let digits: i32[];
10096
const BASE: i32 = 0x100000000; // 2^32
97+
const digits: i32[] = Porffor.allocate(); // todo: free later
98+
digits.length = len - offset;
10199

102-
for (let i: i32 = end; i < len; i++) {
103-
const char: i32 = n.charCodeAt(i);
100+
let i: i32 = 0;
101+
let acc: number = 0;
102+
while (i < len) {
103+
const char: i32 = n.charCodeAt(offset + i);
104104
const digit: i32 = char - 48;
105-
if (digit < 0 || digit > 9) throw new SyntaxError('Invalid character in BigInt string');
106-
107-
if (acc == -1) {
108-
let carry: i32 = digit;
109-
for (let j: i32 = 0; j < digits.length; j++) {
110-
const value: i32 = digits[j] * BASE + carry;
111-
digits[j] = value % BASE;
112-
carry = Math.trunc(value / BASE);
113-
}
105+
if (Porffor.fastOr(digit < 0, digit > 9)) throw new SyntaxError('Invalid character in BigInt string');
114106

115-
if (carry > 0) digits.push(carry);
116-
} else {
117-
acc = acc * 10 + digit;
118-
if (acc >= BASE) {
119-
digits = Porffor.allocate();
120-
digits.length = 2;
121-
digits[0] = Math.floor(acc / BASE);
122-
digits[1] = acc % BASE;
123-
acc = -1;
124-
}
107+
digits[i++] = digit;
108+
acc = acc * 10 + digit;
109+
}
110+
111+
if (acc < 0x8000000000000) {
112+
// inline if small enough
113+
return acc as bigint;
114+
}
115+
116+
const result: i32[] = Porffor.allocate();
117+
while (digits.length > 0) {
118+
let carry: i32 = 0;
119+
for (let j: i32 = 0; j < digits.length; j++) {
120+
let value: i32 = carry * 10 + digits[j];
121+
let quotient: i32 = Math.floor(value / BASE);
122+
carry = value % BASE;
123+
124+
digits[j] = quotient;
125125
}
126+
127+
while (digits.length > 0 && digits[0] === 0) digits.shift();
128+
if (carry !== 0 || digits.length > 0) result.unshift(carry);
126129
}
127130

128-
if (acc == -1) return __Porffor_bigint_fromDigits(negative, digits);
129-
return (negative ? -acc : acc) as bigint;
131+
return __Porffor_bigint_fromDigits(negative, result);
130132
};
131133

132134
export const __Porffor_bigint_toString = (x: number, radix: any): string => {

β€Žcompiler/builtins_precompiled.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Žpackage.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "porffor",
33
"description": "An ahead-of-time JavaScript compiler",
4-
"version": "0.55.19",
4+
"version": "0.55.20",
55
"author": "Oliver Medhurst <[email protected]>",
66
"license": "MIT",
77
"scripts": {},

β€Žrunner/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
import fs from 'node:fs';
3-
globalThis.version = '0.55.19';
3+
globalThis.version = '0.55.20';
44

55
// deno compat
66
if (typeof process === 'undefined' && typeof Deno !== 'undefined') {

β€Žtest262/history.json

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
Β (0)