Skip to content

Commit 3379e1c

Browse files
committed
More comments
1 parent fd20053 commit 3379e1c

File tree

4 files changed

+37
-34
lines changed

4 files changed

+37
-34
lines changed

Makefile.pre.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3118,7 +3118,7 @@ Python/emscripten_trampoline_inner.wasm: $(srcdir)/Python/emscripten_trampoline_
31183118
$$(dirname $$(dirname $(CC)))/bin/clang -o $@ $< -mgc -O2 -Wl,--no-entry -Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib
31193119

31203120
Python/emscripten_trampoline_wasm.c: Python/emscripten_trampoline_inner.wasm
3121-
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/wasm/emscripten/prepare_wat.py $< $@ getWasmTrampolineModule
3121+
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/wasm/emscripten/prepare_external_wasm.py $< $@ getWasmTrampolineModule
31223122

31233123
Python/emscripten_trampoline_wasm.o: Python/emscripten_trampoline_wasm.c
31243124
$(CC) -c $(PY_CORE_CFLAGS) -o $@ $<

Python/emscripten_trampoline.c

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,44 @@
33
#include <emscripten.h> // EM_JS, EM_JS_DEPS
44
#include <Python.h>
55

6-
// We have to be careful to work correctly with memory snapshots. Even if we are
7-
// loading a memory snapshot, we need to perform the JS initialization work.
8-
// That means we can't call the initialization code from C. Instead, we export
9-
// this function pointer to JS and then fill it in a preRun function which runs
10-
// unconditionally.
11-
/**
12-
* Backwards compatible trampoline works with all JS runtimes
13-
*/
146
EM_JS(
157
PyObject*,
168
_PyEM_TrampolineCall_inner, (int* success,
179
PyCFunctionWithKeywords func,
1810
PyObject *arg1,
1911
PyObject *arg2,
2012
PyObject *arg3), {
13+
// JavaScript fallback trampoline
2114
return wasmTable.get(func)(arg1, arg2, arg3);
2215
}
23-
try {
24-
const trampolineModule = getWasmTrampolineModule();
25-
const trampolineInstance = new WebAssembly.Instance(trampolineModule, {
26-
env: { __indirect_function_table: wasmTable, memory: wasmMemory },
27-
});
28-
_PyEM_TrampolineCall_inner = trampolineInstance.exports.trampoline_call;
29-
} catch (e) {}
16+
// Try to replace the JS definition of _PyEM_TrampolineCall_inner with a wasm
17+
// version.
18+
(function () {
19+
// iOS ships broken wasm-gc, so feature detect and turn it off
20+
const isIOS =
21+
globalThis.navigator &&
22+
(/iPad|iPhone|iPod/.test(navigator.userAgent) ||
23+
// Starting with iPadOS 13, iPads might send a platform string that looks like a desktop Mac.
24+
// To differentiate, we check if the platform is 'MacIntel' (common for Macs and newer iPads)
25+
// AND if the device has multi-touch capabilities (navigator.maxTouchPoints > 1)
26+
(navigator.platform === "MacIntel" &&
27+
typeof navigator.maxTouchPoints !== "undefined" &&
28+
navigator.maxTouchPoints > 1));
29+
if (isIOS) {
30+
return;
31+
}
32+
try {
33+
const trampolineModule = getWasmTrampolineModule();
34+
const trampolineInstance = new WebAssembly.Instance(trampolineModule, {
35+
env: { __indirect_function_table: wasmTable, memory: wasmMemory },
36+
});
37+
_PyEM_TrampolineCall_inner = trampolineInstance.exports.trampoline_call;
38+
console.log("Assigned _PyEM_TrampolineCall_inner!");
39+
} catch (e) {
40+
// Compilation error due to missing wasm-gc support, fall back to JS
41+
// trampoline
42+
}
43+
})();
3044
);
3145

3246
PyObject*

Python/emscripten_trampoline_inner.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file must be compiled with -mgc to enable the extra wasm-gc
2+
// instructions. It has to be compiled separately because not enough JS runtimes
3+
// support wasm-gc yet. If the JS runtime does not support wasm-gc (or has buggy
4+
// support like iOS), we will use the JS trampoline fallback.
5+
16
typedef void PyObject;
27

38
typedef PyObject* (*three_arg)(PyObject*, PyObject*, PyObject*);

Tools/wasm/emscripten/prepare_wat.py renamed to Tools/wasm/emscripten/prepare_external_wasm.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import argparse
44
import sys
55
from pathlib import Path
6-
from shutil import which
76

87
JS_TEMPLATE = """
98
#include "emscripten.h"
@@ -20,22 +19,7 @@
2019
}});
2120
"""
2221

23-
24-
def find_wasm_as():
25-
emcc_path = which("emcc")
26-
if not emcc_path:
27-
print("Error: emcc not found in PATH", file=sys.stderr)
28-
return None
29-
30-
wasm_as_path = Path(emcc_path).parents[1] / "bin/wasm-as"
31-
32-
if not wasm_as_path.exists():
33-
print(f"Error: wasm-as not found at {wasm_as_path}", file=sys.stderr)
34-
return None
35-
return wasm_as_path
36-
37-
38-
def compile_wat(input_file, output_file, function_name):
22+
def prepare_wasm(input_file, output_file, function_name):
3923
# Read the compiled WASM as binary and convert to hex
4024
wasm_bytes = Path(input_file).read_bytes()
4125

@@ -63,7 +47,7 @@ def main():
6347

6448
args = parser.parse_args()
6549

66-
return compile_wat(args.input_file, args.output_file, args.function_name)
50+
return prepare_wasm(args.input_file, args.output_file, args.function_name)
6751

6852

6953
if __name__ == "__main__":

0 commit comments

Comments
 (0)