Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1f0aad3
missing functions in link.py
slavek-kucera Aug 22, 2025
8213250
refactor LE heap conversion
slavek-kucera Aug 22, 2025
5b9e064
return name of the heap from isHEAPAccess
slavek-kucera Aug 22, 2025
5b2da5b
extract make sequence code
slavek-kucera Aug 22, 2025
4bee8f8
extract call growmemviews
slavek-kucera Aug 22, 2025
249d3eb
heap access replacement
slavek-kucera Aug 22, 2025
22c3947
fixes
slavek-kucera Aug 25, 2025
15ab549
minor cleanup
slavek-kucera Aug 25, 2025
cea89ab
add tests
slavek-kucera Aug 25, 2025
6e2fe0e
prettier
slavek-kucera Aug 25, 2025
4154c8e
allow combined options to work
slavek-kucera Aug 27, 2025
5d68fe7
skip establishStackSpace in asanifyTransform
slavek-kucera Aug 28, 2025
98aaf20
fix webidl support
slavek-kucera Aug 28, 2025
abb8438
incorrectly disabled SAFE_HEAP annotations
slavek-kucera Aug 28, 2025
9f7bb28
always suppress checkTypes
slavek-kucera Aug 28, 2025
7c75363
disable wasm2js on big endian
slavek-kucera Aug 28, 2025
1f0887d
closure does not know waitAsync
slavek-kucera Aug 28, 2025
b7cef66
closure false warning workaround
slavek-kucera Aug 29, 2025
b291737
BE flag not propagated
slavek-kucera Aug 29, 2025
bb094e3
Fix marshaling of arrays of primitive types
slavek-kucera Aug 29, 2025
1e933e9
disable incompatible tests
slavek-kucera Aug 29, 2025
e13fe0e
better waitAsync closure fix
slavek-kucera Aug 29, 2025
0a2dea1
more closure...
slavek-kucera Aug 29, 2025
07ebbe8
signature update
slavek-kucera Aug 29, 2025
5b0a5f5
and more closure...
slavek-kucera Aug 29, 2025
8561b2a
cleanup
slavek-kucera Sep 1, 2025
c93808a
one more chance for closure
slavek-kucera Sep 1, 2025
94f3e10
typo
slavek-kucera Sep 1, 2025
1cb3893
mark incompatible test
slavek-kucera Sep 1, 2025
35fafda
produce error when combining wasm2js and big endian support
slavek-kucera Sep 2, 2025
b7d947f
fix 32-64 typos
slavek-kucera Sep 10, 2025
b387bdb
adjust pthread codesizes
slavek-kucera Sep 10, 2025
468dfb1
...
slavek-kucera Sep 10, 2025
7f5fe73
missing dataview
slavek-kucera Sep 10, 2025
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
5 changes: 5 additions & 0 deletions src/closure-externs/closure-externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ var Atomics = {};
Atomics.compareExchange = function() {};
Atomics.exchange = function() {};
Atomics.wait = function() {};
/**
* @param {number=} maxWaitMilliseconds
* @suppress {duplicate, checkTypes}
*/
Atomics.waitAsync = function(i32a, index, value, maxWaitMilliseconds) {};
Atomics.notify = function() {};
Atomics.load = function() {};
Atomics.store = function() {};
Expand Down
48 changes: 48 additions & 0 deletions src/lib/libemval.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ var LibraryEmVal = {
_emval_new_array__deps: ['$Emval'],
_emval_new_array: () => Emval.toHandle([]),

#if !SUPPORT_BIG_ENDIAN
_emval_new_array_from_memory_view__deps: ['$Emval'],
_emval_new_array_from_memory_view: (view) => {
view = Emval.toValue(view);
Expand All @@ -109,6 +110,53 @@ var LibraryEmVal = {
for (var i = 0; i < view.length; i++) a[i] = view[i];
return Emval.toHandle(a);
},
_emval_array_to_memory_view__deps: ['$Emval'],
_emval_array_to_memory_view: (dst, src) => {
dst = Emval.toValue(dst);
src = Emval.toValue(src);
dst.set(src);
},
#else
_emval_new_array_from_memory_view__deps: ['$Emval'],
_emval_new_array_from_memory_view: (view) => {
view = Emval.toValue(view);
const dv = new DataView(view.buffer, view.byteOffset);
const reader = {
Int8Array: dv.getInt8,
Uint8Array: dv.getUint8,
Int16Array: dv.getInt16,
Uint16Array: dv.getUint16,
Int32Array: dv.getInt32,
Uint32Array: dv.getUint32,
BigInt64Array: dv.getBigInt64,
BigUint64Array: dv.getBigUint64,
Float32Array: dv.getFloat32,
Float64Array: dv.getFloat64,
}[view[Symbol.toStringTag]];
var a = new Array(view.length);
for (var i = 0; i < view.length; i++) a[i] = reader.call(dv, i * view.BYTES_PER_ELEMENT, true);
return Emval.toHandle(a);
},
_emval_array_to_memory_view__deps: ['$Emval'],
_emval_array_to_memory_view: (dst, src) => {
dst = Emval.toValue(dst);
src = Emval.toValue(src);
const dv = new DataView(dst.buffer, dst.byteOffset);
const writer = {
Int8Array: dv.setInt8,
Uint8Array: dv.setUint8,
Int16Array: dv.setInt16,
Uint16Array: dv.setUint16,
Int32Array: dv.setInt32,
Uint32Array: dv.setUint32,
BigInt64Array: dv.setBigInt64,
BigUint64Array: dv.setBigUint64,
Float32Array: dv.setFloat32,
Float64Array: dv.setFloat64,
}[view[Symbol.toStringTag]];
for (var i = 0; i < src.length; i++) writer.call(dv, i * view.BYTES_PER_ELEMENT, src[i], true);
},
#endif

_emval_new_object__deps: ['$Emval'],
_emval_new_object: () => Emval.toHandle({}),
Expand Down
8 changes: 0 additions & 8 deletions src/lib/libhtml5.js
Original file line number Diff line number Diff line change
Expand Up @@ -1001,10 +1001,8 @@ var LibraryHTML5 = {
$fillFullscreenChangeEventData: (eventStruct) => {
var fullscreenElement = getFullscreenElement();
var isFullscreen = !!fullscreenElement;
#if !SAFE_HEAP
// Assigning a boolean to HEAP32 with expected type coercion.
/** @suppress{checkTypes} */
#endif
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.isFullscreen, 'isFullscreen', 'i8') }}};
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.fullscreenEnabled, 'JSEvents.fullscreenEnabled()', 'i8') }}};
// If transitioning to fullscreen, report info about the element that is now fullscreen.
Expand Down Expand Up @@ -1544,10 +1542,8 @@ var LibraryHTML5 = {
$fillPointerlockChangeEventData: (eventStruct) => {
var pointerLockElement = document.pointerLockElement;
var isPointerlocked = !!pointerLockElement;
#if !SAFE_HEAP
// Assigning a boolean to HEAP32 with expected type coercion.
/** @suppress{checkTypes} */
#endif
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenPointerlockChangeEvent.isActive, 'isPointerlocked', 'i8') }}};
var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement);
var id = pointerLockElement?.id || '';
Expand Down Expand Up @@ -1746,10 +1742,8 @@ var LibraryHTML5 = {
var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ];
var visibilityState = visibilityStates.indexOf(document.visibilityState);

#if !SAFE_HEAP
// Assigning a boolean to HEAP32 with expected type coercion.
/** @suppress{checkTypes} */
#endif
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.hidden, 'document.hidden', 'i8') }}};
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}};
},
Expand Down Expand Up @@ -1943,10 +1937,8 @@ var LibraryHTML5 = {
if (typeof e.buttons[i] == 'object') {
{{{ makeSetValue('eventStruct+i', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i8') }}};
} else {
#if !SAFE_HEAP
// Assigning a boolean to HEAP32, that's ok, but Closure would like to warn about it:
/** @suppress {checkTypes} */
#endif
{{{ makeSetValue('eventStruct+i', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i] == 1', 'i8') }}};
}
}
Expand Down
2 changes: 0 additions & 2 deletions src/lib/libsdl.js
Original file line number Diff line number Diff line change
Expand Up @@ -857,12 +857,10 @@ var LibrarySDL = {
var code = SDL.lookupKeyCodeForEvent(event);
// Ignore key events that we don't (yet) map to SDL keys
if (!code) return;
#if !SAFE_HEAP
// Assigning a boolean to HEAP8, that's alright but Closure would like to warn about it.
// TODO(https://github.com/emscripten-core/emscripten/issues/16311):
// This is kind of ugly hack. Perhaps we can find a better way?
/** @suppress{checkTypes} */
#endif
{{{ makeSetValue('SDL.keyboardState', 'code', 'down', 'i8') }}};
// TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED
SDL.modState =
Expand Down
1 change: 1 addition & 0 deletions src/lib/libsigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ sigs = {
_emscripten_thread_mailbox_await__sig: 'vp',
_emscripten_thread_set_strongref__sig: 'vp',
_emscripten_throw_longjmp__sig: 'v',
_emval_array_to_memory_view__sig: 'vpp',
_emval_await__sig: 'pp',
_emval_coro_make_promise__sig: 'ppp',
_emval_coro_suspend__sig: 'vpp',
Expand Down
11 changes: 1 addition & 10 deletions src/runtime_asan.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,5 @@ function _asan_js_check_index(arr, index, asanFn) {
const elemSize = arr.BYTES_PER_ELEMENT;
asanFn(index * elemSize, elemSize);
}
}

function _asan_js_load(arr, index) {
_asan_js_check_index(arr, index, ___asan_loadN);
return arr[index];
}

function _asan_js_store(arr, index, value) {
_asan_js_check_index(arr, index, ___asan_storeN);
return arr[index] = value;
return index;
}
8 changes: 0 additions & 8 deletions src/runtime_safe_heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ function SAFE_HEAP_INDEX(arr, idx, action) {
return idx;
}

function SAFE_HEAP_LOAD(arr, idx) {
return arr[SAFE_HEAP_INDEX(arr, idx, 'loading')];
}

function SAFE_HEAP_STORE(arr, idx, value) {
return arr[SAFE_HEAP_INDEX(arr, idx, 'storing')] = value;
}

function segfault() {
abort('segmentation fault');
}
Expand Down
3 changes: 2 additions & 1 deletion system/include/emscripten/val.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ void _emval_run_destructors(EM_DESTRUCTORS handle);

EM_VAL _emval_new_array(void);
EM_VAL _emval_new_array_from_memory_view(EM_VAL mv);
void _emval_array_to_memory_view(EM_VAL dst, EM_VAL src);
EM_VAL _emval_new_object(void);
EM_VAL _emval_new_cstring(const char*);
EM_VAL _emval_new_u8string(const char*);
Expand Down Expand Up @@ -828,7 +829,7 @@ std::vector<T> convertJSArrayToNumberVector(const val& v) {
// See https://www.ecma-international.org/ecma-262/6.0/#sec-%typedarray%.prototype.set-array-offset
// and https://www.ecma-international.org/ecma-262/6.0/#sec-tonumber
val memoryView{ typed_memory_view(l, rv.data()) };
memoryView.call<void>("set", v);
internal::_emval_array_to_memory_view(memoryView.as_handle(), v.as_handle());

return rv;
}
Expand Down
8 changes: 4 additions & 4 deletions test/code_size/test_codesize_minimal_pthreads.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 7659,
"a.out.js.gz": 3776,
"a.out.js": 7675,
"a.out.js.gz": 3780,
"a.out.nodebug.wasm": 19599,
"a.out.nodebug.wasm.gz": 9063,
"total": 27258,
"total_gz": 12839,
"total": 27274,
"total_gz": 12843,
"sent": [
"a (memory)",
"b (emscripten_get_now)",
Expand Down
8 changes: 4 additions & 4 deletions test/code_size/test_codesize_minimal_pthreads_memgrowth.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 8086,
"a.out.js.gz": 3977,
"a.out.js": 8102,
"a.out.js.gz": 3980,
"a.out.nodebug.wasm": 19600,
"a.out.nodebug.wasm.gz": 9064,
"total": 27686,
"total_gz": 13041,
"total": 27702,
"total_gz": 13044,
"sent": [
"a (memory)",
"b (emscripten_get_now)",
Expand Down
55 changes: 55 additions & 0 deletions test/js_optimizer/LittleEndianGrowableHeap-output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
a = (growMemViews(), HEAP8)[x];

(growMemViews(), HEAP8)[x] = a;

a = (growMemViews(), HEAPU8)[x];

(growMemViews(), HEAPU8)[x] = a;

a = LE_HEAP_LOAD_I16((growMemViews(), x * 2));

LE_HEAP_STORE_I16((growMemViews(), x * 2), a);

a = LE_HEAP_LOAD_U16((growMemViews(), x * 2));

LE_HEAP_STORE_U16((growMemViews(), x * 2), a);

a = LE_HEAP_LOAD_I32((growMemViews(), x * 4));

LE_HEAP_STORE_I32((growMemViews(), x * 4), a);

a = LE_HEAP_LOAD_U32((growMemViews(), x * 4));

LE_HEAP_STORE_U32((growMemViews(), x * 4), a);

a = LE_HEAP_LOAD_F32((growMemViews(), x * 4));

LE_HEAP_STORE_F32((growMemViews(), x * 4), a);

a = LE_HEAP_LOAD_F64((growMemViews(), x * 8));

LE_HEAP_STORE_F64((growMemViews(), x * 8), a);

HEAP[x];

HeAp[x];

LE_ATOMICS_ADD(heap, offset, value);

LE_ATOMICS_AND(heap, offset, value);

LE_ATOMICS_COMPAREEXCHANGE(heap, offset, expected, replacement);

LE_ATOMICS_EXCHANGE(heap, offset, value);

LE_ATOMICS_LOAD(heap, offset);

LE_ATOMICS_OR(heap, offset, value);

LE_ATOMICS_SUB(heap, offset, value);

LE_ATOMICS_WAIT(heap, offset, value, timeout);

LE_ATOMICS_WAITASYNC(heap, offset, value, timeout);

LE_ATOMICS_XOR(heap, offset, value);
28 changes: 28 additions & 0 deletions test/js_optimizer/LittleEndianGrowableHeap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
a = HEAP8[x]; // HEAP8
HEAP8[x] = a;
a = HEAPU8[x]; // HEAPU8
HEAPU8[x] = a;
a = HEAP16[x]; // HEAP16
HEAP16[x] = a;
a = HEAPU16[x]; // HEAPU16
HEAPU16[x] = a;
a = HEAP32[x]; // HEAPI32
HEAP32[x] = a;
a = HEAPU32[x]; // HEAPU32
HEAPU32[x] = a;
a = HEAPF32[x]; // HEAPF32
HEAPF32[x] = a;
a = HEAPF64[x]; // HEAPF64
HEAPF64[x] = a;
HEAP[x]; // should not be changed
HeAp[x];
Atomics.add(heap, offset, value);
Atomics.and(heap, offset, value);
Atomics.compareExchange(heap, offset, expected, replacement);
Atomics.exchange(heap, offset, value);
Atomics.load(heap, offset);
Atomics.or(heap, offset, value);
Atomics.sub(heap, offset, value);
Atomics.wait(heap, offset, value, timeout);
Atomics.waitAsync(heap, offset, value, timeout);
Atomics.xor(heap, offset, value);
55 changes: 55 additions & 0 deletions test/js_optimizer/LittleEndianGrowableSafeHeap-output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
a = (growMemViews(), HEAP8)[SAFE_HEAP_INDEX((growMemViews(), HEAP8), x, "loading")];

(growMemViews(), HEAP8)[SAFE_HEAP_INDEX((growMemViews(), HEAP8), x, "storing")] = a;

a = (growMemViews(), HEAPU8)[SAFE_HEAP_INDEX((growMemViews(), HEAPU8), x, "loading")];

(growMemViews(), HEAPU8)[SAFE_HEAP_INDEX((growMemViews(), HEAPU8), x, "storing")] = a;

a = LE_HEAP_LOAD_I16((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAP16), x, "loading") * 2));

LE_HEAP_STORE_I16((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAP16), x, "storing") * 2), a);

a = LE_HEAP_LOAD_U16((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPU16), x, "loading") * 2));

LE_HEAP_STORE_U16((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPU16), x, "storing") * 2), a);

a = LE_HEAP_LOAD_I32((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAP32), x, "loading") * 4));

LE_HEAP_STORE_I32((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAP32), x, "storing") * 4), a);

a = LE_HEAP_LOAD_U32((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPU32), x, "loading") * 4));

LE_HEAP_STORE_U32((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPU32), x, "storing") * 4), a);

a = LE_HEAP_LOAD_F32((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPF32), x, "loading") * 4));

LE_HEAP_STORE_F32((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPF32), x, "storing") * 4), a);

a = LE_HEAP_LOAD_F64((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPF64), x, "loading") * 8));

LE_HEAP_STORE_F64((growMemViews(), SAFE_HEAP_INDEX((growMemViews(), HEAPF64), x, "storing") * 8), a);

HEAP[x];

HeAp[x];

LE_ATOMICS_ADD(heap, offset, value);

LE_ATOMICS_AND(heap, offset, value);

LE_ATOMICS_COMPAREEXCHANGE(heap, offset, expected, replacement);

LE_ATOMICS_EXCHANGE(heap, offset, value);

LE_ATOMICS_LOAD(heap, offset);

LE_ATOMICS_OR(heap, offset, value);

LE_ATOMICS_SUB(heap, offset, value);

LE_ATOMICS_WAIT(heap, offset, value, timeout);

LE_ATOMICS_WAITASYNC(heap, offset, value, timeout);

LE_ATOMICS_XOR(heap, offset, value);
28 changes: 28 additions & 0 deletions test/js_optimizer/LittleEndianGrowableSafeHeap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
a = HEAP8[x]; // HEAP8
HEAP8[x] = a;
a = HEAPU8[x]; // HEAPU8
HEAPU8[x] = a;
a = HEAP16[x]; // HEAP16
HEAP16[x] = a;
a = HEAPU16[x]; // HEAPU16
HEAPU16[x] = a;
a = HEAP32[x]; // HEAPI32
HEAP32[x] = a;
a = HEAPU32[x]; // HEAPU32
HEAPU32[x] = a;
a = HEAPF32[x]; // HEAPF32
HEAPF32[x] = a;
a = HEAPF64[x]; // HEAPF64
HEAPF64[x] = a;
HEAP[x]; // should not be changed
HeAp[x];
Atomics.add(heap, offset, value);
Atomics.and(heap, offset, value);
Atomics.compareExchange(heap, offset, expected, replacement);
Atomics.exchange(heap, offset, value);
Atomics.load(heap, offset);
Atomics.or(heap, offset, value);
Atomics.sub(heap, offset, value);
Atomics.wait(heap, offset, value, timeout);
Atomics.waitAsync(heap, offset, value, timeout);
Atomics.xor(heap, offset, value);
Loading