@sproutboat/toolchain 0.4.17 → 0.4.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/acquire.test.ts +4 -1
- package/src/patch.ts +10 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @sproutboat/toolchain
|
|
2
2
|
|
|
3
|
+
## 0.4.18
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e0d0e17: Compile every unit with `-ffp-contract=off` (baronunread/sproutboat#235). On arm64, clang fused `a * b + c` into a single FMA that rounds once, where JavaScript rounds after the multiply and again after the add, so native sprouts could compute different doubles from V8 for the same code. A seeded LCG diverged at step 23.
|
|
8
|
+
|
|
3
9
|
## 0.4.17
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
package/src/acquire.test.ts
CHANGED
|
@@ -29,7 +29,8 @@ async function fixture(): Promise<{ archive: string; sha256: string }> {
|
|
|
29
29
|
" return -1;\n" +
|
|
30
30
|
"}\n" +
|
|
31
31
|
"#define PORF_CORO_STACK_SIZE (256u * 1024u)\n",
|
|
32
|
-
"compiler/index.js":
|
|
32
|
+
"compiler/index.js":
|
|
33
|
+
" '-fno-ident', '-ffunction-sections', '-fdata-sections',\n ...darwinReleaseCompileArgs,\n uSocketsArchive,\n '-lm'\n",
|
|
33
34
|
"compiler/precompile.js":
|
|
34
35
|
"const fs = require('node:fs');\n" +
|
|
35
36
|
"const path = require('node:path');\n" +
|
|
@@ -198,6 +199,8 @@ test("the default call (no url/expectedSha256 override) never touches the networ
|
|
|
198
199
|
},
|
|
199
200
|
});
|
|
200
201
|
expect(await readFile(join(dir, "runtime/index.js"), "utf8")).not.toBe("");
|
|
202
|
+
// #235: every compiled unit keeps JavaScript's separate float roundings.
|
|
203
|
+
expect(await readFile(join(dir, "compiler/index.js"), "utf8")).toContain("'-ffp-contract=off',");
|
|
201
204
|
// #168: the real vendored source takes the null guard on the `then` probe.
|
|
202
205
|
expect(await readFile(join(dir, "compiler/builtins/promise.ts"), "utf8")).toContain(
|
|
203
206
|
"if (Porffor.type(value) == Porffor.TYPES.object && value != null) {",
|
package/src/patch.ts
CHANGED
|
@@ -192,6 +192,14 @@ const CFLAGS_INJECT =
|
|
|
192
192
|
" ...(process.env.SB_EXTRA_CFLAGS ? process.env.SB_EXTRA_CFLAGS.split(' ').filter(Boolean) : []),\n";
|
|
193
193
|
const CFLAGS_MARKER = "SB_EXTRA_CFLAGS";
|
|
194
194
|
|
|
195
|
+
// baronunread/sproutboat#235: clang's default -ffp-contract=on fuses `a * b + c`
|
|
196
|
+
// into one FMA on arm64, rounding once where JavaScript rounds twice. A seeded
|
|
197
|
+
// LCG (seed * 1103515245 + 12345, past 2^53) diverged from V8 at step 23.
|
|
198
|
+
// Every compiled unit keeps JS's separate roundings with contraction off.
|
|
199
|
+
const FP_CONTRACT_ANCHOR = " '-fno-ident', '-ffunction-sections', '-fdata-sections',\n";
|
|
200
|
+
const FP_CONTRACT_INJECT = " '-ffp-contract=off', // sproutboat #235: JS rounds a * b + c twice\n";
|
|
201
|
+
const FP_CONTRACT_MARKER = "sproutboat #235";
|
|
202
|
+
|
|
195
203
|
// baronunread/sproutboat#168: Porffor represents null as an object-typed value
|
|
196
204
|
// with pointer 0, so __Porffor_promise_resolve's cheap `then` probe treated a
|
|
197
205
|
// promise resolving to null as an object and looked `then` up at memory offset
|
|
@@ -959,6 +967,7 @@ async function patchCompilerArgs(root: string): Promise<void> {
|
|
|
959
967
|
for (const [marker, anchor, inject, what] of [
|
|
960
968
|
[LINK_MARKER, LINK_ANCHOR, LINK_INJECT, "extra link args"],
|
|
961
969
|
[CFLAGS_MARKER, CFLAGS_ANCHOR, CFLAGS_INJECT, "extra compiler flags"],
|
|
970
|
+
[FP_CONTRACT_MARKER, FP_CONTRACT_ANCHOR, FP_CONTRACT_INJECT, "floating-point contraction"],
|
|
962
971
|
] as const) {
|
|
963
972
|
if (src.includes(marker)) continue;
|
|
964
973
|
const at = src.indexOf(anchor);
|
|
@@ -971,7 +980,7 @@ async function patchCompilerArgs(root: string): Promise<void> {
|
|
|
971
980
|
// Add flags to compileOnlyArgs so every generated C unit sees them and
|
|
972
981
|
// Porffor's module-build cache includes them in its compiler command.
|
|
973
982
|
src =
|
|
974
|
-
marker
|
|
983
|
+
marker !== LINK_MARKER
|
|
975
984
|
? src.slice(0, at + anchor.length) + inject + src.slice(at + anchor.length)
|
|
976
985
|
: src.slice(0, at) + inject + src.slice(at);
|
|
977
986
|
changed = true;
|