Skip to content

Conversation

@Macil
Copy link

@Macil Macil commented Dec 13, 2025

Fixes denoland/deno#17171

Projects using Emscripten with pthreads don't work in Deno or Bun because those runtimes implement Web Worker APIs that Node doesn't, and Emscripten attempts to re-implement those APIs when running in Node/Deno/Bun in a way that conflicts with Deno and Bun's own implementations. This PR feature-detects Deno and Bun's postMessage implementation and avoids setting up its own conflicting implementation in that case.

Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

Nice!

We also now have some testing under bun as of #25903. Can you add 1 or more pthread-based tests to the lists of bun tests in .circleci/config.yml?

var parentPort = worker_threads['parentPort'];
parentPort.on('message', (msg) => global.onmessage?.({ data: msg }));
Object.assign(globalThis, {
postMessage: (msg) => parentPort['postMessage'](msg),
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can just be globalThis.postMessage now can't it?

And same for globalThis.self above?

(i.e. there is no point in using Object.assign for just one element, right?)

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, good idea. I've cleaned it up now in a few ways (direct assignments to globalThis properties, using globalThis consistently here instead of mixing with global (they're equal and global is deprecated), using const/let to make the variable local).

@Macil Macil force-pushed the fixThreadingForDenoAndBun branch 6 times, most recently from 60733b1 to b42b004 Compare December 13, 2025 23:03
@Macil Macil marked this pull request as draft December 13, 2025 23:03
@Macil Macil force-pushed the fixThreadingForDenoAndBun branch 6 times, most recently from 2c708ef to f9c2ff3 Compare December 14, 2025 02:55
Fixes denoland/deno#17171

Also adds several pthread tests with Bun and Deno
@Macil Macil force-pushed the fixThreadingForDenoAndBun branch from f9c2ff3 to ab5c5c6 Compare December 14, 2025 03:03
return f;
}

const parentPort = worker_threads['parentPort'];
Copy link
Author

Choose a reason for hiding this comment

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

(The lines below were relying on this variable being set in runtime_common.js, which I had moved into an if-block and made not global. I discovered this after tests failed. I figured the simplest solution was to make this code use its own local variable instead of re-introducing the global variable.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

To save on code size and keep this patch as small as possible can you revert this and hoist const parentPort = worker_threads['parentPort']; outside the if?

Also, we still use var in most places in our codebase sadly (there are a couple of reasons, that are probably not worth explaining here... i really should create an FAQ entry or some such for it).


int main() {
EM_ASM({ Promise.reject("rejected!"); });
EM_ASM({ Promise.reject(new Error("rejected!")); });
Copy link
Author

Choose a reason for hiding this comment

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

(Node transforms uncaught promise rejections into Error objects, but Deno and Bun don't do this. The test this is used in would then fail in Deno and Bun because it expected to get an Error object. To fix the test, I just made it always create an Error object. This did require me to slightly update the expected output in test/test_browser.py for the browser versions of this test.)

@Macil Macil marked this pull request as ready for review December 14, 2025 04:02
@Macil
Copy link
Author

Macil commented Dec 14, 2025

I've added some pthread tests to the Bun tests and added some Deno tests too.

(I originally added a few tests for Deno that happened to use Emscripten's PROXY_TO_PTHREAD option, but those tests failed. I spent a while debugging it so I could maybe fix that issue in this PR too, but it turns out to be because Deno doesn't implement Atomics.waitAsync.)

return config.DENO_ENGINE
return None

def get_node_bun_or_deno(self):
Copy link
Author

Choose a reason for hiding this comment

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

(I'm not sure if some increasingly specific helper functions like this were the best route to go. One alternative would have been to make the get/require_node helpers to allow Deno/Bun too because they're mostly interchangeable, but it's probably better to be explicit. Another alternative would've been to make some generic helpers that take named parameters declaring which of Node/Node-Canary/Deno/Bun are allowed.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm hoping we can just avoid this completely, but allowing NODE_JS_TEST to be set to /path/to/bun or /path/to/deno. No need for new config vars I think/hope.

Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

To keep this change small and focused can you remove all the Deno stuff and we can consider that in a separate PR.

self.js_engines = [nodejs]
self.node_args += shared.node_pthread_flags(nodejs)
if nodejs:
self.node_args += shared.node_pthread_flags(engine)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm hoping we don't need to maybe any of these test changes, and deno and bun can both just pretent to be node.

self: global,
postMessage: (msg) => parentPort['postMessage'](msg),
});
globalThis.self = globalThis;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I noticed that code here was lacking a check for node. Added in: #25948

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.

node-compat: z3-solver

2 participants