Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ See docs/process.md for more on how version tagging works.
detected automatically by the compiler, so `__deps` is no longer required for
direct JS-to-JS references (`__deps` is still supported for dependencies on
compiled C/C++ symbols or indirect dependencies). (#27995)
- In pthreads builds with `MAIN_MODULE`, workers no longer walk the main
module's whole function table, which created a JS function object for every
table entry in every worker. The main thread now passes them the table slots
of the main module's exported functions. (#28105)

6.0.13 - 10/19/26
-----------------
Expand Down
12 changes: 12 additions & 0 deletions src/lib/libaddfunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@ addToLibrary({
// First, create the map if this is the first use.
if (!functionsInTableMap) {
functionsInTableMap = new WeakMap();
#if MAIN_MODULE && PTHREADS
// Walking the main module's part of the table would create a JS wrapper
// for every function in it, in every worker. The dynamic linker only
// looks up the main module's exported functions, so workers add just the
// slots of those, as recorded by the main thread.
if (ENVIRONMENT_IS_PTHREAD && mainModuleExportSlots) {
for (var slot of mainModuleExportSlots) {
functionsInTableMap.set(getWasmTableEntry(slot), slot);
}
Comment thread
clementperon marked this conversation as resolved.
Resolved
updateTableMap(mainModuleTableSize, {{{ from64Expr('wasmTable.length') }}} - mainModuleTableSize);
} else
#endif
updateTableMap(0, {{{ from64Expr('wasmTable.length') }}});
}
return functionsInTableMap.get(func) || 0;
Expand Down
18 changes: 18 additions & 0 deletions src/lib/libdylink.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,24 @@ var LibraryDylink = {
;
},

#if PTHREADS
// Called on the main thread once the main module is instantiated. Records
// which table slots hold the main module's exported functions, which new
// workers use in getFunctionAddress.
$recordMainModuleExportSlots__internal: true,
$recordMainModuleExportSlots: (exports) => {
mainModuleTableSize = {{{ from64Expr('wasmTable.length') }}};
mainModuleExportSlots = [];
for (var symName in exports) {
var value = exports[symName];
var slot = typeof value === 'function' && getFunctionAddress(value);
if (slot) {
mainModuleExportSlots.push(slot);
}
}
},
#endif

$updateGOT__internal: true,
$updateGOT__docs: '/** @param {boolean=} replace */',
$updateGOT: (exports, replace) => {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/libpthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,8 @@ var LibraryPThread = {
// Share all modules that have been loaded so far. New workers
// won't start running threads until these are all loaded.
sharedModules,
mainModuleTableSize,
mainModuleExportSlots,
#endif
#if ASSERTIONS
workerID: worker.workerID,
Expand Down
5 changes: 5 additions & 0 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,11 @@ function getWasmImports() {
assignWasmExports(wasmExports);

#if MAIN_MODULE
#if PTHREADS
if (!ENVIRONMENT_IS_PTHREAD) {
recordMainModuleExportSlots(origExports);
}
#endif
updateGOT(origExports);
#endif

Expand Down
7 changes: 7 additions & 0 deletions src/runtime_pthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ var workerID = 0;
// Map of modules to be shared with new threads. This gets populated by the
// main thread and shared with all new workers via the initial `load` message.
var sharedModules = {};

// The main module's initial table size, and the table slots of its exported
// functions. Recorded by the main thread and shared with all new workers via
// the initial `load` message (see getFunctionAddress).
var mainModuleTableSize, mainModuleExportSlots;
#endif

var startWorker;
Expand Down Expand Up @@ -73,6 +78,8 @@ if (ENVIRONMENT_IS_PTHREAD) {
#if MAIN_MODULE
dynamicLibraries = msgData.dynamicLibraries;
sharedModules = msgData.sharedModules;
mainModuleTableSize = msgData.mainModuleTableSize;
mainModuleExportSlots = msgData.mainModuleExportSlots;
#if RUNTIME_DEBUG
dbg(`worker: received ${Object.keys(msgData.sharedModules).length} shared modules: ${Object.keys(msgData.sharedModules)}`);
#endif
Expand Down
3 changes: 3 additions & 0 deletions test/core/pthread/test_pthread_dylink.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include "test_pthread_dylink.h"
Expand All @@ -13,6 +14,8 @@ void print_addresses() {
printf("main_module: &foo_side %p -> %d\n", &foo_side, foo_side);
printf("main_module: &bar_main %p\n", &bar_main);
printf("main_module: &bar_side %p\n", &bar_side);
// Each function has one address in every module and every thread.
assert(bar_main_addr_side() == &bar_main);
}

void* thread_main(void* arg) {
Expand Down
3 changes: 3 additions & 0 deletions test/core/pthread/test_pthread_dylink.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ int bar_main(); // Function defined in main
int bar_side(); // Function defined in side

void print_addresses_side();

typedef int (*bar_func)();
bar_func bar_main_addr_side(); // &bar_main, as seen by side
4 changes: 4 additions & 0 deletions test/core/pthread/test_pthread_dylink_side.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ void print_addresses_side() {
printf("side_module: &bar_main %p\n", &bar_main);
printf("side_module: &bar_side %p\n", &bar_side);
}

bar_func bar_main_addr_side() {
return &bar_main;
}
2 changes: 2 additions & 0 deletions tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,8 @@ def limit_incoming_module_api():
settings.INCLUDE_FULL_LIBRARY = 1
# Called from preamble.js once the main module is instantiated.
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$loadDylibs']
if settings.PTHREADS:
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$recordMainModuleExportSlots']
# `__stack_pointer` is exported for PIC side modules. `__heap_base` is used
# by `$getMemory` in `libdylink.js` (cannot be in `$getMemory__deps` because
# `wasm-ld` processes stub library dependencies before synthesizing optional
Expand Down
Loading