Skip to content

Conversation

slavek-kucera
Copy link
Contributor

This PR fixes issues with big endian support introduced in the following PRs:

The littleEndianHeap transform code is simplified and updated to detect the code introduced by growableHeap pass.
A new test was added to verify the combined transformation generates working code.

@slavek-kucera slavek-kucera force-pushed the fix_big_endian_after_4_0_9 branch from 83028e7 to fbe881c Compare August 25, 2025 11:04
@sbc100 sbc100 requested a review from RReverser August 25, 2025 17:20
@juj
Copy link
Collaborator

juj commented Aug 25, 2025

What hardware do you run on that is Big Endian? Are there maybe single board computers, or specific Big Endian OSes for ARM computers that would fit this target?

I'm pondering how this could be kept working in the future. I presume e.g. CircleCI doesn't have BE targets in its catalog.

@slavek-kucera
Copy link
Contributor Author

I am running it on s390x both z/linux and z/os.

The testing could be handled as described here. I am just not familiar enough with the project to implement it without a lot of research or trial and error.

@juj
Copy link
Collaborator

juj commented Aug 25, 2025

Oh that's cool, I wasn't familiar with qemu, interesting to see it can be used to run a single program invocation like that.

Gave that a spin at main...juj:emscripten:bigendian_test_suite , and indeed it does work out, and some Emscripten core tests pass at least.

@sbc100
Copy link
Collaborator

sbc100 commented Aug 25, 2025

I think we should probably add an "experimental" warning when using the BIGENDIAN setting, since its maintained at only best effort level. There are probably only one or two users our there so I think its fine for it to be incumbent upon those users to keep it alive and kicking.

@slavek-kucera
Copy link
Contributor Author

Would it be ok to pre-install the dependencies into the emscripten-ci image including the BE node binaries?
If so, we could place the node into e.g. /opt/node-be and introduce a setup-bigendian command into the ci (as documented in the juj's branch) and run a couple of basic tests.

@juj
Copy link
Collaborator

juj commented Aug 26, 2025

I think it would be good to be able to run a smoke test or two at least. Though I don't know what the capabilities of CircleCI would be.

I ran the core suite in bigendian mode locally on the contents of this PR. Many tests do pass there out of the box:

https://clbri.com/dump/emscripten/toolchain_profiler.results_20250826_1351.html

though some are still red.

Skipping individual tests in big endian mode is easy, if you would like to work through the failures in the core suite, and skip any tests that might be still failing: 46a2cdf

That way you could mark down TODOs/BUGs to get towards a passing big endian suite.

@juj
Copy link
Collaborator

juj commented Aug 26, 2025

To reproduce a red test in that graph, you can run e.g.

test/runner bigendian.test_segfault
$ test/runner bigendian.test_segfault
Running test_core: (1 tests)
test_segfault (test_core.bigendian.test_segfault) ... get_null()
new D2()
-- begin program output --
Aborted(segmentation fault, exceeded the top of the available dynamic heap when loading 1 bytes at address 1325465856. DYNAMICTOP=77824)
/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:505
  /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what);
                                        ^

RuntimeError: Aborted(segmentation fault, exceeded the top of the available dynamic heap when loading 1 bytes at address 1325465856. DYNAMICTOP=77824)
    at abort (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:505:41)
    at SAFE_HEAP_INDEX (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:389:29)
    at SAFE_HEAP_LOAD (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:398:14)
    at _fd_write (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1110:21)
    at wasm://wasm/0001fcf2:wasm-function[21]:0x7d8
    at wasm://wasm/0001fcf2:wasm-function[38]:0xe63
    at wasm://wasm/0001fcf2:wasm-function[43]:0x1c9d
    at wasm://wasm/0001fcf2:wasm-function[42]:0x134c
    at wasm://wasm/0001fcf2:wasm-function[41]:0x11c3
    at wasm://wasm/0001fcf2:wasm-function[50]:0x2169
    at wasm://wasm/0001fcf2:wasm-function[20]:0x754
    at wasm://wasm/0001fcf2:wasm-function[17]:0x6c4
    at wasm://wasm/0001fcf2:wasm-function[8]:0x4fd
    at /mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:553:12
    at callMain (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1368:15)
    at doRun (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1410:24)
    at run (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1420:5)
    at removeRunDependency (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:830:7)
    at receiveInstance (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:639:5)
    at receiveInstantiationResult (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:655:12)
    at createWasm (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:678:17)
Thrown at:
    at abort (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:505:41)
    at SAFE_HEAP_INDEX (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:389:29)
    at SAFE_HEAP_LOAD (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:398:14)
    at _fd_write (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1110:21)
    at $func21 (wasm://wasm/0001fcf2:1:2009)
    at $func38 (wasm://wasm/0001fcf2:1:3684)
    at $func43 (wasm://wasm/0001fcf2:1:7326)
    at $func42 (wasm://wasm/0001fcf2:1:4941)
    at $func41 (wasm://wasm/0001fcf2:1:4548)
    at $func50 (wasm://wasm/0001fcf2:1:8554)


Node.js v22.16.0
-- end program output --
FAIL

======================================================================
FAIL: test_segfault (test_core.bigendian.test_segfault)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/test/test_core.py", line 304, in decorated
    f(self, *args, **kwargs)
  File "/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/test/test_core.py", line 1784, in test_segfault
    self.do_run(src, 'marfoosh')
  File "/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/test/common.py", line 1969, in do_run
    return self._build_and_run(filename, expected_output, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/test/common.py", line 2020, in _build_and_run
    js_output = self.run_js(js_file, engine, args,
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/test/common.py", line 1600, in run_js
    self.fail('JS subprocess failed (%s): %s (expected=%s).  Output:\n%s' % (error.cmd, error.returncode, assert_returncode, ret))
AssertionError: JS subprocess failed (qemu-s390x -L /usr/s390x-linux-gnu/ /mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/nodebe/node-v22.16.0-linux-s390x/bin/node --stack-trace-limit=50 --trace-uncaught /mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js): 1 (expected=0).  Output:
Aborted(segmentation fault, exceeded the top of the available dynamic heap when loading 1 bytes at address 1325465856. DYNAMICTOP=77824)
/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:505
  /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what);
                                        ^

RuntimeError: Aborted(segmentation fault, exceeded the top of the available dynamic heap when loading 1 bytes at address 1325465856. DYNAMICTOP=77824)
    at abort (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:505:41)
    at SAFE_HEAP_INDEX (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:389:29)
    at SAFE_HEAP_LOAD (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:398:14)
    at _fd_write (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1110:21)
    at wasm://wasm/0001fcf2:wasm-function[21]:0x7d8
    at wasm://wasm/0001fcf2:wasm-function[38]:0xe63
    at wasm://wasm/0001fcf2:wasm-function[43]:0x1c9d
    at wasm://wasm/0001fcf2:wasm-function[42]:0x134c
    at wasm://wasm/0001fcf2:wasm-function[41]:0x11c3
    at wasm://wasm/0001fcf2:wasm-function[50]:0x2169
    at wasm://wasm/0001fcf2:wasm-function[20]:0x754
    at wasm://wasm/0001fcf2:wasm-function[17]:0x6c4
    at wasm://wasm/0001fcf2:wasm-function[8]:0x4fd
    at /mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:553:12
    at callMain (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1368:15)
    at doRun (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1410:24)
    at run (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1420:5)
    at removeRunDependency (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:830:7)
    at receiveInstance (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:639:5)
    at receiveInstantiationResult (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:655:12)
    at createWasm (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:678:17)
Thrown at:
    at abort (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:505:41)
    at SAFE_HEAP_INDEX (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:389:29)
    at SAFE_HEAP_LOAD (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:398:14)
    at _fd_write (/mnt/ssd1000/emscripten_buildbot/worker_root/x10dax-linux-mint22/emscripten_x10dax/build/emscripten/main/out/test/src.js:1110:21)
    at $func21 (wasm://wasm/0001fcf2:1:2009)
    at $func38 (wasm://wasm/0001fcf2:1:3684)
    at $func43 (wasm://wasm/0001fcf2:1:7326)
    at $func42 (wasm://wasm/0001fcf2:1:4941)
    at $func41 (wasm://wasm/0001fcf2:1:4548)
    at $func50 (wasm://wasm/0001fcf2:1:8554)


Node.js v22.16.0


----------------------------------------------------------------------
Ran 1 test in 30.909s

FAILED (failures=1)

@slavek-kucera
Copy link
Contributor Author

It looks like most of the failing tests are SAFE_HEAP and asan related and then x86 specific.

As far as I can tell, the SAFE_HEAP is currently incompatible with both big endian and growable heap support. I'd say the same is true for the asan support (for the same reason).

@slavek-kucera
Copy link
Contributor Author

I think there might be a way to make all these options compatible.
The only transforms that actually have to replace the HEAPxx[idx] code seems to be the littleEndianHeap and growableHeap.

The safeHeap and asanify only perform checks on the index so they could be implemented as HEAPxx[idx] => HEAPxx[func(HEAPxx, idx)] transforms, where func returns idx and they could be easily composed (f1(HEAPxx, f2(HEAPxx, idx))).
The growableHeap and littleEndianHeap are compatible with this PR and so they could run last in that order.

I could look into that after this PR is merged.

@juj
Copy link
Collaborator

juj commented Aug 26, 2025

I should be able to plop in a run of the core suite with the big endian Node.js on my test lab CI at http://clbri.com:8010/#/builders

Posted a PR emscripten-core/emsdk#1590 that will help automate the setup of the big endian Node on the CI, it should be a trivial one-liner setup then.

@sbc100
Copy link
Collaborator

sbc100 commented Aug 26, 2025

I should be able to plop in a run of the core suite with the big endian Node.js on my test lab CI at http://clbri.com:8010/#/builders

Posted a PR emscripten-core/emsdk#1590 that will help automate the setup of the big endian Node on the CI, it should be a trivial one-liner setup then.

Regarding the NODE_JS config setting, you can use NODE_JS_TEST (used to run tests) which is separate setting to NODE_JS (used during compilation). The former defaults to the latter.

@slavek-kucera
Copy link
Contributor Author

I put together a patch that would make all the options compatible slavek-kucera/emscripten@fix_big_endian_after_4_0_9...fix_big_endian_other_options_preview

I was able to successfully run with -pthread -sALLOW_MEMORY_GROWTH=1 -sSAFE_HEAP=1 -sSUPPORT_BIG_ENDIAN=1 -sPROXY_TO_PTHREAD=1 -sEXIT_RUNTIME=1 on both little and big endian platform.

@juj
Copy link
Collaborator

juj commented Aug 27, 2025

Regarding the NODE_JS config setting, you can use NODE_JS_TEST (used to run tests) which is separate setting to NODE_JS (used during compilation). The former defaults to the latter.

Gave that a try, though there seems to be some interaction with js_engines variable that either needs some manual configuring that I missed, or maybe something that js_engines didn't anticipate with NODE_JS_TEST variable? Posted at #25063 (comment) about that.

Also, posted PR #25068 to land the bigendian0 suite.

@slavek-kucera
Copy link
Contributor Author

I'm currently on vacation so can't look in depth but I think the right fix here should be just reordering transforms. I theory they shouldn't have to know about each other.

The transforms are replacing the very identifiers other transforms are looking for, so I don't think this is correct.

@RReverser
Copy link
Collaborator

The transforms are replacing the very identifiers other transforms are looking for, so I don't think this is correct.

Yeah sorry, I realised that shortly after posting my comment, so deleted it but I guess not quickly enough.

Your approach from the last comment, combining the transforms, seems like a better one.

@juj
Copy link
Collaborator

juj commented Aug 27, 2025

I put together a patch that would make all the options compatible slavek-kucera/emscripten@fix_big_endian_after_4_0_9...fix_big_endian_other_options_preview

I ran the bigendian suite with these patches on top. Definitely more tests pass now, here is the result I got:

https://clbri.com/dump/emscripten/toolchain_profiler.results_20250827_1943.html

@juj
Copy link
Collaborator

juj commented Aug 27, 2025

After #25074 lands, the big endian test suite will be live on emscripten linux x64 runner at http://clbri.com:8010/#/builders

That CI is my test lab CI, so not sure if it will be able to live indefinitely, though I'll try to keep it alive into the future.

It will be a post-landing runner unfortunately, so will only run the bigendian0 suite on Emscripten's main branch after code has landed to it. But it should show the latest status then.

@sbc100
Copy link
Collaborator

sbc100 commented Aug 27, 2025

After #25074 lands, the big endian test suite will be live on emscripten linux x64 runner at http://clbri.com:8010/#/builders

That CI is my test lab CI, so not sure if it will be able to live indefinitely, though I'll try to keep it alive into the future.

It will be a post-landing runner unfortunately, so will only run the bigendian0 suite on Emscripten's main branch after code has landed to it. But it should show the latest status then.

We also run a bunch of post-landing test suites on the "Test Suites" running here: https://ci.chromium.org/p/emscripten-releases/g/main/console. We consider that an "FYI bot" which is what chromium calls bots that don't close the tree, and could , therefore, be red to long-ish periods of time.

We should probably document here in test_core.py which of the core test configurations are maintained in FYI/best-effort/post-landing way.

For configurations such as bigendian I don't really think its reasonable for the core team them green at all times so FYI/best-effort/post-landing is where I think it belongs.

@juj
Copy link
Collaborator

juj commented Aug 27, 2025

Ok, all the necessary pieces for the bigendian0 suite infra have landed in emsdk and emscripten repository. This was the first live run of that suite against Emscripten main branch: http://clbri.com:8010/#/builders/11/builds/303

sbc100 added a commit that referenced this pull request Aug 28, 2025
Support for big endian targets is "best effort" and not fully supported
or tested.

Also, as far as I'm aware there is only one or two users of this feature
so I think it makes sense for it to stay as "best effort" for the
foreseeable future.

See #25042
@slavek-kucera
Copy link
Contributor Author

slavek-kucera commented Aug 28, 2025

Looking through the last test report, there is still a few SSE/AVX tests running.
As for the webidl tests, I am not using this feature so I am not familiar with how it works, but I suspect the problem might be here where the code won't use the little endian transforms.

@juj
Copy link
Collaborator

juj commented Aug 28, 2025

You can go ahead and mark any still failing tests as @no_big_endian('TODO: Fails with error xyz') to get the suite looking green for the tests that do pass. That will then give a foothold over keeping track of the passing tests to stay green in the Emscripten main branch.

@slavek-kucera slavek-kucera force-pushed the fix_big_endian_after_4_0_9 branch from 9108c9b to 71e47ac Compare August 28, 2025 07:59
@slavek-kucera
Copy link
Contributor Author

It looks like with node24 even the EH tests are passing.

As far as I can tell. The only problem is with test_modularize_instance_embind. It is as if the littleEndian transform is not applied at all, I am not sure why at the moment.

@juj
Copy link
Collaborator

juj commented Aug 28, 2025

I ran the test suites on top of this PR, at http://clbri.com:8010/#/builders/11/builds/321

Looks like this is in a very good shape now, only few reds remaining.

/** @suppress {checkTypes} */
return Atomics.waitAsync(heap, offset, order(value), timeout);
// this is suppressing incorrect closure JSC_INEXISTENT_PROPERTY warning that cannot be suppress via annotation
return Atomics.waitAsync && Atomics.waitAsync(heap, offset, order(value), timeout);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try adding Atomics.waitAsync to this list:

var Atomics = {};
Atomics.compareExchange = function() {};
Atomics.exchange = function() {};
Atomics.wait = function() {};
Atomics.notify = function() {};
Atomics.load = function() {};
Atomics.store = function() {};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like any way you define it, there is a test case that breaks.

Copy link
Collaborator

@juj juj Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting.. can you list some test cases that croak with the different approaches?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think each of the following failed differently due to the closure compiler warning

  • test_modularize_closure_pre
  • test_closure_full_js_library_pthread
  • test_audio_worklet_minimal_runtime_pthreads_and_closure

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see. Try with the following:

diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js
index 1681cd2b4..b5bfc5857 100644
--- a/src/closure-externs/closure-externs.js
+++ b/src/closure-externs/closure-externs.js
@@ -64,6 +64,11 @@ var Atomics = {};
 Atomics.compareExchange = function() {};
 Atomics.exchange = function() {};
 Atomics.wait = function() {};
+/**
+ * @param {number=} maxWaitMilliseconds
+ * @suppress {duplicate, checkTypes}
+ */
+Atomics.waitAsync = function(i32a, index, value, maxWaitMilliseconds) {};
 Atomics.notify = function() {};
 Atomics.load = function() {};
 Atomics.store = function() {};

I think that should help Closure avoid tripping itself up in different build modes.

@slavek-kucera slavek-kucera force-pushed the fix_big_endian_after_4_0_9 branch from 9c35bdf to 68f51b9 Compare August 29, 2025 12:34
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.

4 participants