emscripten-core/emsdk

[bazel] Frozen Cache exception with MEMORY64=1

wrangelvid opened this issue · 13 comments

I am trying to bind a library that uses 64bits for it's hashing algorithm. In the process I ran into several bugs where I set the architecture to 64 bits with --copt=-m64 and used both -s MEMORY64=1 and -s WASM_BIGINT=1 in the linker options.

Then I got this strange error with Exception: FROZEN_CACHE is set, but cache file is missing, where I hit my debugging limits. I was told that #971 and #1405 may/should've have resolved these issues but again, I am not deep enough into bazel and embind yet to understand the caching issue.

However, to make this process easier, I created a minimum example to reproduce this problem.

You don't need -sMEMORY64 just to use 64-bit values. -sMEMORY64 is only really needed if you need to address more than 32-bits of memory.

However, if you did want to use -sMEMORY64 then I think the solution in #1405 would be the way to go.

Ah good catch. For now I only need 64 bit values. What is the recommended approach for that?

Without sMEMORY64 I would get:

wasm-ld: error: bazel-out/wasm-opt-ST-***/bin/module/_objs/hello_embind/hello_js.o: must specify -mwasm64 to process wasm64 object files

However, it wasn't clear to me where mwasm64 would come into the game. I tried the linker options, but then digged through the feature flags and documentation until I found this, which inspired me to "try" sMEMORY64.

However, if you did want to use -sMEMORY64 then I think the solution in #1405 would be the way to go.

Given the hint that sMEMORY64 injects -mwasm64, I sat down and tried to understand what the frozen cache actually wants. I added the targets one by one:

register_emscripten_toolchains(cache = {
     "configuration": ["--wasm64"],
     "targets": [
         "libprintf_long_double",
         "libembind-rtti",
         "libGL-getprocaddr",
         "libal",
         "libhtml5",
         "libstubs",
         "libnoexit",
         "libc",
         "libemmalloc",
         "libcompiler_rt",
         "libc++-noexcept",
         "libc++abi-noexcept",
         "libsockets"
     ]
 })

It compiled! In chrome I had to enable a few experimental flags:

  • chrome://flags/#experimental-wasm-memory64
  • chrome://flags/#enable-experimental-webassembly-features

My test function verified that was indeed getting 64bit values 🎉 🎉

Now the question is: How can we do this without 64bit memory and only 64 bit values to avoid the feature flag hassle?

Ah good catch. For now I only need 64 bit values. What is the recommended approach for that?

Without sMEMORY64 I would get:

wasm-ld: error: bazel-out/wasm-opt-ST-***/bin/module/_objs/hello_embind/hello_js.o: must specify -mwasm64 to process wasm64 object files

However, it wasn't clear to me where mwasm64 would come into the game. I tried the linker options, but then digged through the feature flags and documentation until I found this, which inspired me to "try" sMEMORY64.

This means that somehow hello_js.o was built with -sMEMORY64. You need to figure out who added that flag and remove it. You almost certainly don't actually want memory64 in this case.

This means that somehow hello_js.o was built with -sMEMORY64. You need to figure out who added that flag and remove it. You almost certainly don't actually want memory64 in this case.

I think this happening because I am using -m64 via copt. The library I am trying to bind requires size_t to be 64 bits:
static_assert(sizeof(size_t) == (64 / 8), "We require a 64-bit size_t");

But it looks like m64 is not only making the int and long 64 bit, but also the pointers 64 bit causes the wasm-ld error when sMEMORY64 is not specified.

Perhaps there is another way to tell Emscripten to use 64 bits in the values? sWASM_BIGINT would still give yield the static assertion.

If you need size_t to be 64-bit then yes you do need -sMEMORY64. The size_t type is linked to the pointer type so the only way to get 64-bit size_t is to have 64-bit pointers.

That seems like a rather odd requirement though. Can you link o the We require a 64-bit size_t in the source code so we can see why its needed?

Remember that wasm64 is still experimental so it would still be better to find a way to remove the requirement if you can.

I see. They are using FNV1a 64 bit hashing implemented here.
I think 32bit would do it too, although I need to check in how close we get to collisions.

Update: I wrote a small patch with 32bit hashing. A few things broke, but luckily nothing that I care about. In the long term, I anticipate wasm64 to be a more stable solution. Is there timeline for wasm64 graduating out of the experimental state?

It should be fairly soon now. I would hope in the next month.

I see. They are using FNV1a 64 bit hashing implemented here. I think 32bit would do it too, although I need to check in how close we get to collisions.

Do you have any idea why they chose to use size_t here? Surely the algorithm should work fine with the more explicit int64_t which will work regardless of the pointer size.

Do you have any idea why they chose to use size_t here? Surely the algorithm should work fine with the more explicit int64_t which will work regardless of the pointer size.

I think that comes from std::hash, which has size_t as the return type.

It should be fairly soon now. I would hope in the next month.

That's exciting! Does that encompass the experimental state here or also the experimental support for other browsers?

Once a proposal reaches stage4 that means at least 2 browser support it. In this case that will be chrome and firefox. Once stage4 is reached the next release of those browser will support wasm64 without a flag.

Great thank you!