3 ms·
I'm curious to see what the performance impact of using 64bit memory ends up being. WASM runtimes currently use a clever trick on 64bit host platforms where the
by jsheard 2y ago
I'm curious to see what the performance impact of using 64bit memory ends up being. WASM runtimes currently use a clever trick on 64bit host platforms where they allocate a solid 4GB block of virtual memory up front, and then rely on the MMU to catch out-of-bounds accesses by faulting on unmapped pages, so bounds checking is effectively free. That won't work with 64bit WASM though so runtimes will have to do old fashioned explicit bounds checking on every single heap access.
- pstoll 2y agoI also wonder what the perf overhead will be for programs that only need i32. I didn’t dig deep enough on the implementation, but these type of variadic runtime options often cause perf regressions because of all the “ifs” / lookups of type configs/parameters, etc. I just imagine some inner loops where mem.get adds a few instructions from the “if u32/64/“. Unless it ends up being seamless / no cost via loading different u32/u64 implementations. I mostly agree with the old c++ mantra of - no feature should have a runtime cost unless used.
- jsheard 2y agoI would hope it's set up such that the runtime always knows whether a memory access is 32bit or 64bit at JIT-time so it can generate unconditional native code. Runtimes that use an interpreter instead of a JIT might be hurt by having to branch every time, but interpreters being slow is already kind of a given.
- cornstalks 2y agoYes, the bitcode specifies whether a memory operation/address uses 32-bit or 64-bit addressing, so a runtime/JIT can determine this ahead of time during the static analysis phase.
- wild_pointer 2y agoCan't the same trick be used for slightly more bits? 64-bit uses 48 bits nowadays AFAIK, which is 256 TB. It's usually 50/50 for user/kernel mode. If, say, WASM takes half of the user mode address space, it's still 46 bits which is 64 TB (ought to be enough for anybody?). Or maybe I'm way off, I don't really know the specifics of the trick you're referring to.
- jsheard 2y agoThe problem is you need the virtual memory allocation to span every possible address the untrusted WASM code might try to access, so that any possible OOB operation lands in an unmapped page and triggers a fault. That's only feasible if the WASM address space is a lot smaller than the host address space. I suppose there might be a compromise where you cap a 64bit WASM instance to (for example) an effective 35bit address space, allocate 32GB of virtual memory and then generate code which masks off the top bits of pointers so OOB operations safely wrap around without having to branch, but I'm not sure if the spec allows that. IIRC illegal operations are required to throw an exception.
- Findecanor 2y agoThe trick takes advantage of 32-bit registers automatically being zero-extended to 64. It actually uses 8GB of allocated address space because WASM's address mode takes both a "pointer" and a 32-bit offset, making the effective index 33 bits. On x86-64, there are address modes that can add those and the base address in a single instruction. When that trick can't be used, I think the most efficient method would be to clamp the top of the address so that the max would land on a single guard page. On x86-64 and ARM that would be done with a `cmp`and a conditional move. RISC-V (RVA22 profile and up) has a `max` instruction. That would be typically one additional cycle. The new proposal is for using a 64-bit pointer and a 64-bit offset, which would create a 65-bit effective index. So neither method above could be used. I think each address calculation would first have to add and check for overflow, then do the bounds-check, and then add the base address to the linear memory.