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
31 changes: 31 additions & 0 deletions src/jsifier.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,35 @@ function addImplicitDeps(snippet, deps) {
'runtimeKeepalivePush',
'runtimeKeepalivePop',
'UTF8ToString',
// TODO: Consider removing getValue and setValue if they are rarely used implicitly.
'getValue',
'setValue',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if these are actually used much. Maybe add a TODO to remove them from this list?

];
for (const dep of autoDeps) {
if (snippet.includes(dep + '(')) {
deps.push('$' + dep);
}
}
// If the snippet contains eval(), it may dynamically evaluate code loaded from memory at runtime
// (for example, in emscripten_run_script where the snippet is eval(UTF8ToString(ptr))).
// Because static string matching cannot inspect what strings are stored in memory or evaluated
// at runtime, we must conservatively include all heap views whenever a snippet uses eval().
if (snippet.includes('eval(')) {
deps.push('$HEAP8', '$HEAPU8', '$HEAP16', '$HEAPU16', '$HEAP32', '$HEAPU32', '$HEAPF32', '$HEAPF64');
if (WASM_BIGINT || MEMORY64) {
Comment thread
brendandahl marked this conversation as resolved.
deps.push('$HEAP64', '$HEAPU64');
}
}
const heapDeps = [
'HEAP8', 'HEAP16', 'HEAPU8', 'HEAPU16',
'HEAP32', 'HEAPU32', 'HEAPF32', 'HEAPF64',
'HEAP64', 'HEAPU64',
];
for (const heap of heapDeps) {
if (snippet.includes(heap)) {
deps.push('$' + heap);
}
}
}

function sigToArgs(sig) {
Expand Down Expand Up @@ -408,6 +431,14 @@ export async function runJSify(outputFile, symbolsOnly) {

const symbolsNeeded = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE;
symbolsNeeded.push(...extraLibraryFuncs);

for (const fileName of [...PRE_JS_FILES, ...POST_JS_FILES]) {
const content = readFile(fileName);
addImplicitDeps(content, symbolsNeeded);
}
for (const snippet of EM_JS_SNIPPETS) {
addImplicitDeps(snippet, symbolsNeeded);
}
for (const sym of EXPORTED_RUNTIME_METHODS) {
if ('$' + sym in LibraryManager.library) {
symbolsNeeded.push('$' + sym);
Expand Down
31 changes: 20 additions & 11 deletions src/runtime_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,22 @@ var runtimeExited = false;
shouldExport = true;
}
return shouldExport;
}
};
const maybeExportHeap = (x) => {
if (shouldExportHeap(x) && MODULARIZE != 'instance') {
return `Module['${x}'] = `;
}
return '';
};
const isHeapNeeded = (x) => {
return shouldExportHeap(x) || addedLibraryItems['$' + x];
};
const updateHeap = (x, type) => {
if (isHeapNeeded(x)) {
return `${maybeExportHeap(x)}${x} = new ${type}(b);`;
}
return '';
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is almost enough complexity to just move the whole updateMemoryViews into a generator / helper. But I guess it makes sense for this incremental change to do it this way for now.

}}}


Expand Down Expand Up @@ -161,17 +170,17 @@ function updateMemoryViews() {
#endif
var b = wasmMemory.buffer;
#endif
{{{ maybeExportHeap('HEAP8') }}}HEAP8 = new Int8Array(b);
{{{ maybeExportHeap('HEAP16') }}}HEAP16 = new Int16Array(b);
{{{ maybeExportHeap('HEAPU8') }}}HEAPU8 = new Uint8Array(b);
{{{ maybeExportHeap('HEAPU16') }}}HEAPU16 = new Uint16Array(b);
{{{ maybeExportHeap('HEAP32') }}}HEAP32 = new Int32Array(b);
{{{ maybeExportHeap('HEAPU32') }}}HEAPU32 = new Uint32Array(b);
{{{ maybeExportHeap('HEAPF32') }}}HEAPF32 = new Float32Array(b);
{{{ maybeExportHeap('HEAPF64') }}}HEAPF64 = new Float64Array(b);
{{{ updateHeap('HEAP8', 'Int8Array') }}}
{{{ updateHeap('HEAP16', 'Int16Array') }}}
{{{ updateHeap('HEAPU8', 'Uint8Array') }}}
{{{ updateHeap('HEAPU16', 'Uint16Array') }}}
{{{ updateHeap('HEAP32', 'Int32Array') }}}
{{{ updateHeap('HEAPU32', 'Uint32Array') }}}
{{{ updateHeap('HEAPF32', 'Float32Array') }}}
{{{ updateHeap('HEAPF64', 'Float64Array') }}}
#if WASM_BIGINT
{{{ maybeExportHeap('HEAP64') }}}HEAP64 = new BigInt64Array(b);
{{{ maybeExportHeap('HEAPU64') }}}HEAPU64 = new BigUint64Array(b);
{{{ updateHeap('HEAP64', 'BigInt64Array') }}}
{{{ updateHeap('HEAPU64', 'BigUint64Array') }}}
#endif
#if SUPPORT_BIG_ENDIAN
{{{ maybeExportHeap('HEAP_DATA_VIEW') }}} HEAP_DATA_VIEW = new DataView(b);
Expand Down
6 changes: 6 additions & 0 deletions src/settings_internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,5 +295,11 @@ var LOAD_SOURCE_MAP = false;

var ALIASES = [];

// Internal setting for passing EM_JS and EM_ASM function code snippets to JSifier so that
// implicit heap dependencies (e.g. HEAP8, HEAP32) can be scanned and included automatically
// without needing to search for them in Python.
// This could be removed if/when we require explicit heap dependencies (via EM_JS_DEPS).
var EM_JS_SNIPPETS = [];

// List of public setting names (Used by RETAIN_COMPILER_SETTINGS)
var PUBLIC_SETTINGS = [];
2 changes: 1 addition & 1 deletion test/codesize/audio_worklet_wasm.expected.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var m = globalThis.Module || typeof Module != "undefined" ? Module : {}, r = !!globalThis.WorkerGlobalScope, t = !!globalThis.AudioWorkletGlobalScope, u = globalThis.name == "em-ww" || t, v, K, E, G, J, x, W, P, F, D, C, X, A, Z, H;
var m = globalThis.Module || typeof Module != "undefined" ? Module : {}, r = !!globalThis.WorkerGlobalScope, t = !!globalThis.AudioWorkletGlobalScope, u = globalThis.name == "em-ww" || t, v, x, J, K, G, E, W, P, F, D, C, X, A, Z, H;

function w(a) {
v = a;
Expand Down
75 changes: 36 additions & 39 deletions test/codesize/hello_wasm_worker_wasm.expected.js
Original file line number Diff line number Diff line change
@@ -1,80 +1,77 @@
var c = Module, d = !!globalThis.WorkerGlobalScope, e = globalThis.name == "em-ww", f, g, C, q, D, m, E, v;
var c = Module, d = !!globalThis.WorkerGlobalScope, e = globalThis.name == "em-ww", f, g, B, p, C, l, D, u;

e && (onmessage = a => {
onmessage = null;
f = a = a.data;
g = a.o;
h();
c ||= {};
c.wasm = a.m;
k();
h();
a.m = a.o = 0;
});

function h() {}

e || (g = new WebAssembly.Memory({
initial: 256,
maximum: 256,
shared: !0
}), h());
}));

var l = [], n = a => {
var k = [], m = a => {
a = a.data;
var b = a._wsc;
b && m.get(b)(...a.x);
}, p = a => {
l.push(a);
}, r = () => {
q(0, !d, !e, d && 1);
}, u = {}, w = (a, b, z) => {
var t = u[a] = new Worker(c.js, {
b && l.get(b)(...a.x);
}, n = a => {
k.push(a);
}, q = () => {
p(0, !d, !e, d && 1);
}, t = {}, v = (a, b, y) => {
var r = t[a] = new Worker(c.js, {
name: "em-ww"
});
t.postMessage({
r.postMessage({
A: a,
m: v,
m: u,
o: g,
u: b,
v: z
v: y
});
t.onmessage = n;
r.onmessage = m;
return !0;
}, x = () => performance.now(), y = () => !1, A = (a, b) => {
u[a].postMessage({
}, w = () => performance.now(), x = () => !1, z = (a, b) => {
t[a].postMessage({
_wsc: b,
x: []
});
};

e && (u[0] = globalThis, addEventListener("message", p));
e && (t[0] = globalThis, addEventListener("message", n));

function B() {
function A() {
console.log("Hello from wasm worker!");
}

function k() {
E = {
d: r,
c: w,
b: x,
e: y,
f: A,
g: B,
function h() {
D = {
d: q,
c: v,
b: w,
e: x,
f: z,
g: A,
a: g
};
WebAssembly.instantiate(c.wasm, {
a: E
a: D
}).then((a => {
var b = (a.instance || a).exports;
v = a.module || c.wasm;
C = b.i;
q = b.k;
D = b.l;
m = b.j;
e ? (D(f.A, f.u, f.v), removeEventListener("message", p), l = l.forEach(n), addEventListener("message", n)) : b.h();
e || C();
u = a.module || c.wasm;
B = b.i;
p = b.k;
C = b.l;
l = b.j;
e ? (C(f.A, f.u, f.v), removeEventListener("message", n), k = k.forEach(m), addEventListener("message", m)) : b.h();
e || B();
}));
}

e || k();
e || h();
14 changes: 7 additions & 7 deletions test/codesize/hello_world_wasm.expected.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
var d = Module, e, f = new TextDecoder, g, h;
var c = Module, d = new TextDecoder, e, f, h;

WebAssembly.instantiate(d.wasm, {
WebAssembly.instantiate(c.wasm, {
a: {
a: a => {
var c = console, k = c.log;
var g = console, k = g.log;
if (a) {
for (var b = a, l = e, m = b + NaN; l[b] && !(b >= m); ) ++b;
a = f.decode(e.subarray(a, b));
a = d.decode(e.subarray(a, b));
} else a = "";
k.call(c, a);
k.call(g, a);
}
}
}).then((a => {
a = a.instance.exports;
g = a.d;
f = a.d;
h = a.b;
e = new Uint8Array(h.buffer);
a.c();
g();
f();
}));
8 changes: 4 additions & 4 deletions test/codesize/hello_world_wasm2js.expected.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var d = Module, g, h = new TextDecoder, k, l;
var d = Module, g = new TextDecoder, h, k, l;

function e(a) {
this.exports = function(q) {
Expand Down Expand Up @@ -48,8 +48,8 @@ function e(a) {
a: a => {
var q = console, u = q.log;
if (a) {
for (var n = a, c = g, f = n + void 0; c[n] && !(n >= f); ) ++n;
a = h.decode(g.subarray(a, n));
for (var n = a, c = h, f = n + void 0; c[n] && !(n >= f); ) ++n;
a = g.decode(h.subarray(a, n));
} else a = "";
u.call(q, a);
}
Expand All @@ -58,7 +58,7 @@ function e(a) {
a = a.instance.exports;
k = a.d;
l = a.b;
g = new Uint8Array(l.buffer);
h = new Uint8Array(l.buffer);
a.c();
k();
}));
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_ctors1.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19183,
"a.out.js.gz": 7971,
"a.out.js": 19083,
"a.out.js.gz": 7947,
"a.out.nodebug.wasm": 132603,
"a.out.nodebug.wasm.gz": 49939,
"total": 151786,
"total_gz": 57910,
"total": 151686,
"total_gz": 57886,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_ctors2.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19160,
"a.out.js.gz": 7957,
"a.out.js": 19060,
"a.out.js.gz": 7931,
"a.out.nodebug.wasm": 132029,
"a.out.nodebug.wasm.gz": 49599,
"total": 151189,
"total_gz": 57556,
"total": 151089,
"total_gz": 57530,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_except.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 23158,
"a.out.js.gz": 8955,
"a.out.js": 23059,
"a.out.js.gz": 8939,
"a.out.nodebug.wasm": 172523,
"a.out.nodebug.wasm.gz": 57480,
"total": 195681,
"total_gz": 66435,
"total": 195582,
"total_gz": 66419,
"sent": [
"__cxa_begin_catch",
"__cxa_end_catch",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_except_wasm.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 18982,
"a.out.js.gz": 7888,
"a.out.js": 18882,
"a.out.js.gz": 7863,
"a.out.nodebug.wasm": 147928,
"a.out.nodebug.wasm.gz": 55349,
"total": 166910,
"total_gz": 63237,
"total": 166810,
"total_gz": 63212,
"sent": [
"_abort_js",
"_tzset_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_except_wasm_legacy.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19060,
"a.out.js.gz": 7913,
"a.out.js": 18960,
"a.out.js.gz": 7888,
"a.out.nodebug.wasm": 145734,
"a.out.nodebug.wasm.gz": 54976,
"total": 164794,
"total_gz": 62889,
"total": 164694,
"total_gz": 62864,
"sent": [
"_abort_js",
"_tzset_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_lto.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 18526,
"a.out.js.gz": 7665,
"a.out.js": 18426,
"a.out.js.gz": 7640,
"a.out.nodebug.wasm": 102090,
"a.out.nodebug.wasm.gz": 39548,
"total": 120616,
"total_gz": 47213,
"total": 120516,
"total_gz": 47188,
"sent": [
"a (emscripten_resize_heap)",
"b (_setitimer_js)",
Expand Down
Loading