Need help with emscripten port

I may not be able to help much with the pthreads-related tests, but I can help with the other two!

Feel free to just disable these, I think that asm! is incompatible with emscripten and forever will be (same true for webassembly I believe)

Yeah right now all these tests start with // ignore-platform for a bunch of platforms that don’t have jemalloc compiled. The situation isn’t that great here, and ideally tests wouldn’t try to use jemalloc at all!

In my opinion the best course of actions about that pthreads problem is to force single-threading by modifying the functions within libstd/sys and making them either do nothing or return an error, so that pthreads isn’t used at all.

Then ignore all tests that require a thread to be spawned.

Would that be ok? I don’t think any other solution will come any time soon.

I’d personally prefer to avoid stubbing out std::thread primitives for single-threaded ones and instead just proxy error codes up through the normal pathways (e.g. pthread_create should return an error, right?).

I’d be fine adding // ignore annotations for now, but we may be adding quite a few…

The problem is that it doesn’t :-/ And it’s not just pthread_create. All mutexes and rwlocks (and maybe also TLS), even when used in a single-threaded environment, also straight up crash when you lock them.

The emscripten “linker” automatically detects which pthreads symbols are used by the program and replaces them with dummy functions that print missing function and call abort(-1). This is not something specific to pthreads, it’s how the linker works.

The only way to enable pthread symbols is to use the USE_PTHREADS option, which is documented here. But as I said above it then tries to use the document object, which doesn’t exist in node.

Maybe we may want to ping kripken on this problem.

Yes, that’s around 120 tests rpass tests I think.

I just found out about this file:

Which is supposed to be included if you don’t use pthreads:

I’ll continue to investigate to see why that doesn’t work. EDIT: The answer is that it’s because the missing symbols are pthread_attr_setstack and pthread_rwlock_rdlock, which aren’t provided.

It’s probably not worth trying to use pthreads in emscripten until they work in wasm+firefox, at least by default. I think the current implementation uses incredibly expensive continuations.

He’ll be happy to help.

For the record, now that I cleaned up most of the mess in the logs the main remaining problems are, other than pthreads:

  • Exceptions don’t work. I’m going to try fixing it, but I’m not familiar with how unwinding works under the hood.
  • More worrisome, the tests that call an external C function and get back the values don’t work for u8s and u16s (1 2 3 4). They simply get back the value 0.

These are struct returns, which have very platform-specific ABIs. The Rust definition of the emscripten C ABI just reuses the arm definition. Emscripten is fairly arm-ish, but seemingly not here.

The fix is probably going to involve giving emscripten it’s own C ABI definition and futzing with the classify_ret_ty fn.

Down to 17 failures:

  • 3 missing Math_trunc. The actual error is that llvm_trunc_f64 is missing ; this error message is due to a fix attempt in my emscripten fork. This should be quite easy to fix however.
  • 4 because of wrong ABI with C code.
  • 1 because #[repr(packed)] doesn’t work correctly.
  • 1 wrong u64 alignment (but this is likely the test being wrong with its expected value).
  • 1 LLVM ERROR: invalid vector instr with the SIMD test.
  • 2 missing _Exit symbols. The tests themselves will need to be ignored since they rely on spawning a child process, but I’d like to understand why this linking error happens.
  • 5 tests that must be ignored.

The #[repr(packed)] issue is probably related to Emscripten just assumes that all u32s and all u64s are 4-bytes aligned. If it isn’t the case there isn’t even a slow path, instead it just returns the wrong value.

Down to 7 failures right now, but it becomes more and more tedious.

(hopefully I’m not spamming this topic ; I use it as a kind of “meta-issue for emscripten”)

Only 2 failures left in debug mode: the repr(packed) issue and an unsupported SIMD operation. In release mode around twenty failures, and all the new ones are caused by the strings-related problem I talked about above.

But eddyb found out that the string problem was likely caused by a faulty LLVM pass. I’m currently compiling without this line to see if it works:

1 Like

For the record the bug was actually due to the SimplifyStructRegSignatures pass, that converted some functions from the ret_type fn() signature to void fn(ret_type* output) but didn’t remove the pure attribute from them when doing so.

This led to some important function calls (like CStr::from_ptr) being stripped because LLVM thought they were useless.

1 Like

@brson Is there a reason not to merge your changes to librustc_llvm, configure and into master?

@tomaka. Yes. Unfortunately, they depend on LLVM features that only exist in emscripten’s port, like adding “js” to LLVM_TARGETS.

There may be some pieces that can be separated out.

Ah, right (I feel stupid for asking that).

I guess the right thing to do is somehow detect in the build process whether LLVM supports the JS backend?

That would be great. I don’t know how to do it though.

llvm-config can do that:

~/PATH_TO_LLVM_BIN/llvm-config --targets-built

will return a space-separated list of targets, like:

X86 JSBackend WebAssembly

I’m not exactly sure how to get that into the rust build process :\


Some updates. I’m hoping to push emscripten support across the finish line in the next 2 or so months. That is, for the project to distribute emscripten-targetting compilers and stds (whether they contain awful bugs is another matter).

The short term plan is for kripken to port emscripten’s LLVM branch forward to the same merge-base as ours, then for us to rebase onto their branch. We don’t have any immediate plans to upgrade LLVM, but in the future we’ll have try not to do it too often, because each time will force emscripten to upgrade as well. Likewise we’ll have to upgrade when they do, but they don’t anticipate needing to either. And we’ll have to tolerate temporary breakage of our emscripten support if it gets difficult to do it simultaneously. It could end in disaster. Who knows.

Once we’re on their LLVM, distributing emscripten bins is mostly a matter of turning some knobs on the CI.

In the longer term, kripken is very keen on creating a MIR->wasm backend for Rust, bypassing LLVM. If it works out then it could open up a lot of really interesting possibilities.

@tomaka is the best way to compile for emscripten still to use my ‘emscripten’ branch or do you have something more up to date? I’ll aim to rebase it onto Rust master soon.


The Reddit article that was posted a few months ago was slightly more up to date, but not by much.

Or it could end in success! I’m super happy you all are trying to make this work. Thanks for all the effort!