emscripten-core / emscripten-core/emscripten

What is wasmTable used for?

Open
#23,673 5 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

wasmTable is too big and I want to know how to reduce size.

**Version of emscripten/emsdk:**
`
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.54 (48216dc455f2ac2670ec4f8a32f293b62a730080)
clang version 19.0.0git (https://github.com/llvm/llvm-project e769fb8699e3fa8e40623764f7713bfc783b0330)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/compiler/emsdk/upstream/bin
`

I am using wasm dynamic linking and found that during thread startup, the most time-consuming function in `createWasm` is `relocateExport->updateTableMap->getWasmTableEntry`. I then found that the query of the WebAssembly.Table object wasmTable takes too long. I also found that there are too many elements in this function table, more than 70,000 in my environment.

![Image](https://github.com/user-attachments/assets/b06bdb02-ce1e-4ba7-ad45-5b0f693f31c3)

So I traced the source of wasmTable and found that it was first initialized in the js environment, such as:
```js
var wasmTable = new WebAssembly.Table({
"initial": 79659,
"element": "anyfunc"
});
```
![Image](https://github.com/user-attachments/assets/4fc597b8-4c9b-45ec-9b73-fd90a07edcae)

Then it is passed to the wasm bytecode through wasmImports.
```wasm
(module $my.wasm
(memory $env.memory (;0;) (import "env" "memory") 1024 16384 shared)
(table $env.__indirect_function_table (;0;) (import "env" "__indirect_function_table") 79658 funcref)
(global $__stack_pointer (;0;) (import "env" "__stack_pointer") (mut i32))
(global $__memory_base (;1;) (import "env" "__memory_base") i32)
(global $__table_base (;2;) (import "env" "__table_base") i32)
(tag $env.__cpp_exception (;0;) (import "env" "__cpp_exception") (param i32))
(func $emscripten_asm_const_int (;0;) (import "env" "emscripten_asm_const_int") (param i32 i32 i32) (result i32))
...
)
```
At the beginning of the wasm bytecode, the external `__indirect_function_table` is saved, and then not far below, a large number of assignment operations are performed on this table, with detailed statements such as :
```wasm
(global $__start_em_asm (;4017;) (export "__start_em_asm") i32 (i32.const 5477320))
(global $__stop_em_asm (;4018;) (export "__stop_em_asm") i32 (i32.const 5479098))
(start $__wasm_start)
(elem $elem0 (global.get $__table_base) (ref func) (ref.func $CryptoPP::Exception::~Exception()) (ref.func $std::logic_error::~logic_error()) ...
```

and so on (there are tens of thousands of function references here)

I originally thought that these functions were interfaces provided for external references, but after checking most of the function names, I found that they were not. Most of them are internal functions and do not need to be exposed. Therefore, my question about wasmTable is:
**What is its original intention? Does the current performance meet the design expectations?**
Then I also want to know **how the compilation process controls C++ symbols not to be added to this table?**
here post my link.txt:
```txt
/home/compiler/emsdk/upstream/emscripten/em++ -s EXPORTED_RUNTIME_METHODS='[ "ccall","cwrap","allocate"]'
-s EXPORTED_FUNCTIONS='["_malloc", "_free"]'
-Wno-deprecated
-Wno-pthreads-mem-growth
-Wno-keyword-macro
-Wno-unused-command-line-argument
-Wno-int-conversion
-Wno-error=unused-but-set-variable
-Wno-error=bitwise-instead-of-logical
-s WASM=1
-s WASMFS=1
-s ENVIRONMENT=web,worker
-s USE_PTHREADS=1
-s PTHREAD_POOL_DELAY_LOAD=1
-s FULL_ES2=1
-s FULL_ES3=1
-s FORCE_FILESYSTEM=1
-s WARN_ON_UNDEFINED_SYMBOLS=1
-s WASM_MEM_MAX=1073741824
-s TOTAL_MEMORY=1073741824
-s INITIAL_MEMORY=67108864
-s TOTAL_STACK=1048576
-s ALLOW_MEMORY_GROWTH=1
-s FETCH=1
-s RESERVED_FUNCTION_POINTERS=10
-s MODULARIZE=1
-s EXPORT_ES6=1
-s EXPORT_NAME='createModule'
-s TEXTDECODER=0
-frtti
-fPIC
-fvisibility=hidden
-msimd128 -mbulk-memory
-fwasm-exceptions -sSUPPORT_LONGJMP=wasm
-lopenal
-lembind
-D__linux__=1
-Wl,--no-check-features
-g2 -O1
-s OFFSCREENCANVAS_SUPPORT=1 -s OFFSCREENCANVASES_TO_PTHREAD='#canvas'
-v -Wmost -Wno-dollar-in-identifier-extension -Wno-variadic-macros -Wno-unused-command-line-argument -Wno-gnu-zero-variadic-macro-arguments -Wno-deprecated-register -Wno-vla-extension -Wno-extra-semi -Wno-pragmas -Wno-unused-function -Wno-unused-label -Wno-unused-value -Wno-unused-variable -Wno-c99-extensions -Wno-reorder -Wno-unused-private-field -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-emcc
--js-library ./library-blob.js --post-js ./post.js
-s ASSERTIONS=0 -sSAFE_HEAP=0 --emit-symbol-map -sWASM_BIGINT -sERROR_ON_WASM_CHANGES_AFTER_LINK -sPTHREAD_POOL_SIZE="Module['pthreadPoolSize'] || 20" -sEXCEPTION_STACK_TRACES
-sMAIN_MODULE=2 -sAUTOLOAD_DYLIBS=1 /pathtp/libffmpeg_simd.wasm @CMakeFiles/myproject.dir/objects1.rsp -o myproject.js @CMakeFiles/myproject.dir/linklibs.rsp

```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.