diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 1681cd2b4439d..b5bfc58576197 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -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() {}; diff --git a/src/lib/libemval.js b/src/lib/libemval.js index 00a44da42192d..38f4c8791925a 100644 --- a/src/lib/libemval.js +++ b/src/lib/libemval.js @@ -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); @@ -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({}), diff --git a/src/lib/libhtml5.js b/src/lib/libhtml5.js index 94ccce68b987f..7b07ed3d9eab9 100644 --- a/src/lib/libhtml5.js +++ b/src/lib/libhtml5.js @@ -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. @@ -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 || ''; @@ -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') }}}; }, @@ -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') }}}; } } diff --git a/src/lib/libsdl.js b/src/lib/libsdl.js index be2e06684dbdf..9d3acc379f5fd 100644 --- a/src/lib/libsdl.js +++ b/src/lib/libsdl.js @@ -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 = diff --git a/src/lib/libsigs.js b/src/lib/libsigs.js index 8dc66c98b74f1..46c2e1df16f08 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -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', diff --git a/src/runtime_asan.js b/src/runtime_asan.js index 34cafeffcf320..952db227e8d3a 100644 --- a/src/runtime_asan.js +++ b/src/runtime_asan.js @@ -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; } diff --git a/src/runtime_safe_heap.js b/src/runtime_safe_heap.js index 6f73e666d1188..53e2469ed17e3 100644 --- a/src/runtime_safe_heap.js +++ b/src/runtime_safe_heap.js @@ -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'); } diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index a57c11a944bc5..c29ce7528244d 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -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*); @@ -828,7 +829,7 @@ std::vector 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("set", v); + internal::_emval_array_to_memory_view(memoryView.as_handle(), v.as_handle()); return rv; } diff --git a/test/code_size/test_codesize_minimal_pthreads.json b/test/code_size/test_codesize_minimal_pthreads.json index 4f909f58e225c..e9250f7056faf 100644 --- a/test/code_size/test_codesize_minimal_pthreads.json +++ b/test/code_size/test_codesize_minimal_pthreads.json @@ -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)", diff --git a/test/code_size/test_codesize_minimal_pthreads_memgrowth.json b/test/code_size/test_codesize_minimal_pthreads_memgrowth.json index 6ab7a856a15ac..21416e8da0d56 100644 --- a/test/code_size/test_codesize_minimal_pthreads_memgrowth.json +++ b/test/code_size/test_codesize_minimal_pthreads_memgrowth.json @@ -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)", diff --git a/test/js_optimizer/LittleEndianGrowableHeap-output.js b/test/js_optimizer/LittleEndianGrowableHeap-output.js new file mode 100644 index 0000000000000..358688c30bf93 --- /dev/null +++ b/test/js_optimizer/LittleEndianGrowableHeap-output.js @@ -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); diff --git a/test/js_optimizer/LittleEndianGrowableHeap.js b/test/js_optimizer/LittleEndianGrowableHeap.js new file mode 100644 index 0000000000000..94d038b570f04 --- /dev/null +++ b/test/js_optimizer/LittleEndianGrowableHeap.js @@ -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); diff --git a/test/js_optimizer/LittleEndianGrowableSafeHeap-output.js b/test/js_optimizer/LittleEndianGrowableSafeHeap-output.js new file mode 100644 index 0000000000000..cdf51d93f9d5f --- /dev/null +++ b/test/js_optimizer/LittleEndianGrowableSafeHeap-output.js @@ -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); diff --git a/test/js_optimizer/LittleEndianGrowableSafeHeap.js b/test/js_optimizer/LittleEndianGrowableSafeHeap.js new file mode 100644 index 0000000000000..94d038b570f04 --- /dev/null +++ b/test/js_optimizer/LittleEndianGrowableSafeHeap.js @@ -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); diff --git a/test/js_optimizer/asanify-output.js b/test/js_optimizer/asanify-output.js index 2c196180a3c3b..a8a16afd17882 100644 --- a/test/js_optimizer/asanify-output.js +++ b/test/js_optimizer/asanify-output.js @@ -1,57 +1,57 @@ -_asan_js_store(HEAP8, x, 1); +HEAP8[_asan_js_check_index(HEAP8, x, ___asan_storeN)] = 1; -_asan_js_store(HEAP16, x, 2); +HEAP16[_asan_js_check_index(HEAP16, x, ___asan_storeN)] = 2; -_asan_js_store(HEAP32, x, 3); +HEAP32[_asan_js_check_index(HEAP32, x, ___asan_storeN)] = 3; -_asan_js_store(HEAPU8, x, 4); +HEAPU8[_asan_js_check_index(HEAPU8, x, ___asan_storeN)] = 4; -_asan_js_store(HEAPU16, x, 5); +HEAPU16[_asan_js_check_index(HEAPU16, x, ___asan_storeN)] = 5; -_asan_js_store(HEAPU32, x, 6); +HEAPU32[_asan_js_check_index(HEAPU32, x, ___asan_storeN)] = 6; -_asan_js_store(HEAPF32, x, 7); +HEAPF32[_asan_js_check_index(HEAPF32, x, ___asan_storeN)] = 7; -_asan_js_store(HEAPF64, x, 8); +HEAPF64[_asan_js_check_index(HEAPF64, x, ___asan_storeN)] = 8; -_asan_js_store(HEAP64, x, 9n); +HEAP64[_asan_js_check_index(HEAP64, x, ___asan_storeN)] = 9n; -_asan_js_store(HEAPU64, x, 10n); +HEAPU64[_asan_js_check_index(HEAPU64, x, ___asan_storeN)] = 10n; -a1 = _asan_js_load(HEAP8, x); +a1 = HEAP8[_asan_js_check_index(HEAP8, x, ___asan_loadN)]; -a2 = _asan_js_load(HEAP16, x); +a2 = HEAP16[_asan_js_check_index(HEAP16, x, ___asan_loadN)]; -a3 = _asan_js_load(HEAP32, x); +a3 = HEAP32[_asan_js_check_index(HEAP32, x, ___asan_loadN)]; -a4 = _asan_js_load(HEAPU8, x); +a4 = HEAPU8[_asan_js_check_index(HEAPU8, x, ___asan_loadN)]; -a5 = _asan_js_load(HEAPU16, x); +a5 = HEAPU16[_asan_js_check_index(HEAPU16, x, ___asan_loadN)]; -a6 = _asan_js_load(HEAPU32, x); +a6 = HEAPU32[_asan_js_check_index(HEAPU32, x, ___asan_loadN)]; -a7 = _asan_js_load(HEAPF32, x); +a7 = HEAPF32[_asan_js_check_index(HEAPF32, x, ___asan_loadN)]; -a8 = _asan_js_load(HEAPF64, x); +a8 = HEAPF64[_asan_js_check_index(HEAPF64, x, ___asan_loadN)]; -a9 = _asan_js_load(HEAP64, x); +a9 = HEAP64[_asan_js_check_index(HEAP64, x, ___asan_loadN)]; -a10 = _asan_js_load(HEAPU64, x); +a10 = HEAPU64[_asan_js_check_index(HEAPU64, x, ___asan_loadN)]; -foo = _asan_js_store(HEAPU8, 1337, 42); +foo = HEAPU8[_asan_js_check_index(HEAPU8, 1337, ___asan_storeN)] = 42; -_asan_js_load(HEAP16, bar(_asan_js_load(HEAPF64, 5))); +HEAP16[_asan_js_check_index(HEAP16, bar(HEAPF64[_asan_js_check_index(HEAPF64, 5, ___asan_loadN)]), ___asan_loadN)]; -_asan_js_store(HEAPF32, x, _asan_js_load(HEAP32, y)); +HEAPF32[_asan_js_check_index(HEAPF32, x, ___asan_storeN)] = HEAP32[_asan_js_check_index(HEAP32, y, ___asan_loadN)]; -function _asan_js_load(ptr) { - return HEAP8[ptr]; +function establishStackSpace() { + HEAP32[0]; } function somethingElse() { - return _asan_js_load(HEAP8, ptr); + return HEAP8[_asan_js_check_index(HEAP8, ptr, ___asan_loadN)]; } HEAP8.length; -_asan_js_load(HEAP8, length); +HEAP8[_asan_js_check_index(HEAP8, length, ___asan_loadN)]; diff --git a/test/js_optimizer/asanify.js b/test/js_optimizer/asanify.js index 30e4b3951ad69..6154b4a285179 100644 --- a/test/js_optimizer/asanify.js +++ b/test/js_optimizer/asanify.js @@ -29,16 +29,9 @@ foo = HEAPU8[1337] = 42; HEAP16[bar(HEAPF64[5])]; HEAPF32[x] = HEAP32[y]; -// Ignore the special asan functions themselves. that is, any JS memory access -// will turn into a function call to _asan_js_load_1 etc., which then does -// the memory access for it. It either calls into wasm to get the proper -// asan-instrumented operation, or before the wasm is ready to be called into, -// we must do the access in JS, unsafely. We should not instrument a heap -// access in these functions, as then we'd get infinite recursion - this is -// where we do actually need to still do a HEAP8[..] etc. operation without -// any ASan instrumentation. -function _asan_js_load(ptr) { - return HEAP8[ptr]; +// skip establishStackSpace, because it sets up variables used by ASan itself +function establishStackSpace() { + HEAP32[0]; } // but do handle everything else diff --git a/test/js_optimizer/safeHeap-output.js b/test/js_optimizer/safeHeap-output.js index 07745ce63e0e8..b1469f38fed78 100644 --- a/test/js_optimizer/safeHeap-output.js +++ b/test/js_optimizer/safeHeap-output.js @@ -1,57 +1,53 @@ -SAFE_HEAP_STORE(HEAP8, x, 1); +HEAP8[SAFE_HEAP_INDEX(HEAP8, x, "storing")] = 1; -SAFE_HEAP_STORE(HEAP16, x, 2); +HEAP16[SAFE_HEAP_INDEX(HEAP16, x, "storing")] = 2; -SAFE_HEAP_STORE(HEAP32, x, 3); +HEAP32[SAFE_HEAP_INDEX(HEAP32, x, "storing")] = 3; -SAFE_HEAP_STORE(HEAPU8, x, 4); +HEAPU8[SAFE_HEAP_INDEX(HEAPU8, x, "storing")] = 4; -SAFE_HEAP_STORE(HEAPU16, x, 5); +HEAPU16[SAFE_HEAP_INDEX(HEAPU16, x, "storing")] = 5; -SAFE_HEAP_STORE(HEAPU32, x, 6); +HEAPU32[SAFE_HEAP_INDEX(HEAPU32, x, "storing")] = 6; -SAFE_HEAP_STORE(HEAPF32, x, 7); +HEAPF32[SAFE_HEAP_INDEX(HEAPF32, x, "storing")] = 7; -SAFE_HEAP_STORE(HEAPF64, x, 8); +HEAPF64[SAFE_HEAP_INDEX(HEAPF64, x, "storing")] = 8; -SAFE_HEAP_STORE(HEAP64, x, 9n); +HEAP64[SAFE_HEAP_INDEX(HEAP64, x, "storing")] = 9n; -SAFE_HEAP_STORE(HEAPU64, x, 10n); +HEAPU64[SAFE_HEAP_INDEX(HEAPU64, x, "storing")] = 10n; -a1 = SAFE_HEAP_LOAD(HEAP8, x); +a1 = HEAP8[SAFE_HEAP_INDEX(HEAP8, x, "loading")]; -a2 = SAFE_HEAP_LOAD(HEAP16, x); +a2 = HEAP16[SAFE_HEAP_INDEX(HEAP16, x, "loading")]; -a3 = SAFE_HEAP_LOAD(HEAP32, x); +a3 = HEAP32[SAFE_HEAP_INDEX(HEAP32, x, "loading")]; -a4 = SAFE_HEAP_LOAD(HEAPU8, x); +a4 = HEAPU8[SAFE_HEAP_INDEX(HEAPU8, x, "loading")]; -a5 = SAFE_HEAP_LOAD(HEAPU16, x); +a5 = HEAPU16[SAFE_HEAP_INDEX(HEAPU16, x, "loading")]; -a6 = SAFE_HEAP_LOAD(HEAPU32, x); +a6 = HEAPU32[SAFE_HEAP_INDEX(HEAPU32, x, "loading")]; -a7 = SAFE_HEAP_LOAD(HEAPF32, x); +a7 = HEAPF32[SAFE_HEAP_INDEX(HEAPF32, x, "loading")]; -a8 = SAFE_HEAP_LOAD(HEAPF64, x); +a8 = HEAPF64[SAFE_HEAP_INDEX(HEAPF64, x, "loading")]; -a9 = SAFE_HEAP_LOAD(HEAP64, x); +a9 = HEAP64[SAFE_HEAP_INDEX(HEAP64, x, "loading")]; -a10 = SAFE_HEAP_LOAD(HEAPU64, x); +a10 = HEAPU64[SAFE_HEAP_INDEX(HEAPU64, x, "loading")]; -foo = SAFE_HEAP_STORE(HEAPU8, 1337, 42); +foo = HEAPU8[SAFE_HEAP_INDEX(HEAPU8, 1337, "storing")] = 42; -SAFE_HEAP_LOAD(HEAP16, bar(SAFE_HEAP_LOAD(HEAPF64, 5))); +HEAP16[SAFE_HEAP_INDEX(HEAP16, bar(HEAPF64[SAFE_HEAP_INDEX(HEAPF64, 5, "loading")]), "loading")]; -SAFE_HEAP_STORE(HEAPF32, x, SAFE_HEAP_LOAD(HEAP32, y)); - -function SAFE_HEAP_FOO(ptr) { - return HEAP8[ptr]; -} +HEAPF32[SAFE_HEAP_INDEX(HEAPF32, x, "storing")] = HEAP32[SAFE_HEAP_INDEX(HEAP32, y, "loading")]; function somethingElse() { - return SAFE_HEAP_LOAD(HEAP8, ptr); + return HEAP8[SAFE_HEAP_INDEX(HEAP8, ptr, "loading")]; } HEAP8.length; -SAFE_HEAP_LOAD(HEAP8, length); +HEAP8[SAFE_HEAP_INDEX(HEAP8, length, "loading")]; diff --git a/test/js_optimizer/safeHeap.js b/test/js_optimizer/safeHeap.js index 848f928dddc49..fe86ca12153e9 100644 --- a/test/js_optimizer/safeHeap.js +++ b/test/js_optimizer/safeHeap.js @@ -29,18 +29,6 @@ foo = HEAPU8[1337] = 42; HEAP16[bar(HEAPF64[5])]; HEAPF32[x] = HEAP32[y]; -// Ignore the special functions themselves. that is, any JS memory access -// will turn into a function call to _asan_js_load_1 etc., which then does -// the memory access for it. It either calls into wasm to get the proper -// asan-instrumented operation, or before the wasm is ready to be called into, -// we must do the access in JS, unsafely. We should not instrument a heap -// access in these functions, as then we'd get infinite recursion - this is -// where we do actually need to still do a HEAP8[..] etc. operation without -// any ASan instrumentation. -function SAFE_HEAP_FOO(ptr) { - return HEAP8[ptr]; -} - // but do handle everything else function somethingElse() { return HEAP8[ptr]; diff --git a/test/test_core.py b/test/test_core.py index f18b81aaddfe4..e24c328513ae1 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -6910,6 +6910,7 @@ def test_bullet(self, use_cmake): @crossplatform @no_wasmfs('depends on MEMFS which WASMFS does not have') @no_strict('autoconfiguring is not compatible with STRICT') + @no_big_endian('SUPPORT_BIG_ENDIAN is not propagated') def test_poppler(self): # See https://github.com/emscripten-core/emscripten/issues/20757 self.cflags.extend(['-Wno-deprecated-declarations', '-Wno-nontrivial-memaccess']) @@ -7546,6 +7547,7 @@ def test_embind_unbound_types(self): ''') self.do_runf('test.cpp', 'UnboundTypeError: Cannot call compute due to unbound types: Pi') + @no_big_endian("Accessing the array directly is not available on big endian system") def test_embind_memory_view(self): self.cflags += ['-lembind', '--post-js', 'post.js'] create_file('post.js', ''' @@ -7578,6 +7580,39 @@ def test_embind_memory_view(self): ''') self.do_runf('test.cpp', '107') + def test_embind_memory_view_be(self): + self.cflags += ['-lembind', '--post-js', 'post.js'] + create_file('post.js', ''' + function printFirstElement() { + const b = Module['getBufferView'](); + out(new DataView(b.buffer, b.byteOffset).getFloat64(0, true)); + } + ''') + create_file('test.cpp', r''' + #include + #include + #include + #include + using namespace emscripten; + + const size_t kBufferSize = 1024; + double buffer[kBufferSize]; + val getBufferView(void) { + val v = val(typed_memory_view(kBufferSize, buffer)); + return v; + } + EMSCRIPTEN_BINDINGS(my_module) { + function("getBufferView", &getBufferView); + } + + int main(int argc, char **argv) { + buffer[0] = 107; + EM_ASM(printFirstElement()); + return 0; + } + ''') + self.do_runf('test.cpp', '107') + def test_embind_inheritance(self): self.do_core_test('test_embind_inheritance.cpp', cflags=['-lembind']) @@ -7599,6 +7634,7 @@ def test_embind_unsigned(self): def test_embind_val(self): self.do_run_in_out_file_test('embind/test_val.cpp', cflags=['-lembind']) + @no_big_endian("Incompatible with SUPPORT_BIG_ENDIAN") def test_embind_val_read_pointer(self): self.do_runf('embind/test_val_read_pointer.cpp', cflags=['-lembind']) @@ -7699,6 +7735,7 @@ def test_embind_dynamic_initialization(self): '': (False,), 'safe_heap': (True,), }) + @no_big_endian("Calling TypedArray.set directly is not available on big endian system") def test_embind_i64_val(self, safe_heap): if safe_heap and '-fsanitize=address' in self.cflags: self.skipTest('asan does not work with SAFE_HEAP') @@ -8499,6 +8536,7 @@ def test_pthread_join_and_asyncify(self): # Test basic wasm2js functionality in all core compilation modes. @no_sanitize('no wasm2js support yet in sanitizers') @requires_wasm2js + @no_big_endian('wasm2js is currently not compatible with big endian') def test_wasm2js(self): if self.is_wasm2js(): self.skipTest('redundant to test wasm2js in wasm2js* mode') @@ -8509,6 +8547,7 @@ def test_wasm2js(self): @no_asan('no wasm2js support yet in asan') @requires_wasm2js @also_with_minimal_runtime + @no_big_endian('wasm2js is currently not compatible with big endian') def test_wasm2js_fallback(self): if self.is_wasm2js(): self.skipTest('redundant to test wasm2js in wasm2js* mode') diff --git a/test/test_other.py b/test/test_other.py index 0b74cdea86854..0347d48973786 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2961,6 +2961,8 @@ def test_extern_prepost(self): 'safeHeap': (['safeHeap'],), 'object-literals': ([],), 'LittleEndianHeap': (['littleEndianHeap'],), + 'LittleEndianGrowableHeap': (['growableHeap','littleEndianHeap'],), + 'LittleEndianGrowableSafeHeap': (['safeHeap','growableHeap','littleEndianHeap'],), }) @crossplatform def test_js_optimizer(self, passes, filename=None): diff --git a/tools/acorn-optimizer.mjs b/tools/acorn-optimizer.mjs index 22271d61befb9..fdc2306649a26 100755 --- a/tools/acorn-optimizer.mjs +++ b/tools/acorn-optimizer.mjs @@ -925,13 +925,17 @@ function createLiteral(value) { }; } +function makeIdentifier(name) { + return { + type: 'Identifier', + name: name, + }; +} + function makeCallExpression(node, name, args) { Object.assign(node, { type: 'CallExpression', - callee: { - type: 'Identifier', - name: name, - }, + callee: makeIdentifier(name), arguments: args, }); } @@ -956,6 +960,17 @@ function isEmscriptenHEAP(name) { } } +const littleEndianHelper = { + HEAP16: {width: 2, load: 'LE_HEAP_LOAD_I16', store: 'LE_HEAP_STORE_I16'}, + HEAPU16: {width: 2, load: 'LE_HEAP_LOAD_U16', store: 'LE_HEAP_STORE_U16'}, + HEAP32: {width: 4, load: 'LE_HEAP_LOAD_I32', store: 'LE_HEAP_STORE_I32'}, + HEAPU32: {width: 4, load: 'LE_HEAP_LOAD_U32', store: 'LE_HEAP_STORE_U32'}, + HEAP64: {width: 8, load: 'LE_HEAP_LOAD_I64', store: 'LE_HEAP_STORE_I64'}, + HEAPU64: {width: 8, load: 'LE_HEAP_LOAD_U64', store: 'LE_HEAP_STORE_U64'}, + HEAPF32: {width: 4, load: 'LE_HEAP_LOAD_F32', store: 'LE_HEAP_STORE_F32'}, + HEAPF64: {width: 8, load: 'LE_HEAP_LOAD_F64', store: 'LE_HEAP_STORE_F64'}, +}; + // Replaces each HEAP access with function call that uses DataView to enforce // LE byte order for HEAP buffer function littleEndianHeap(ast) { @@ -981,60 +996,29 @@ function littleEndianHeap(ast) { const target = node.left; const value = node.right; c(value); - if (!isHEAPAccess(target)) { - // not accessing the HEAP - c(target); - } else { + const heap = isHEAPAccess(target); + const growHeap = isGrowHEAPAccess(target); + if (heap) { // replace the heap access with LE_HEAP_STORE - const name = target.object.name; const idx = target.property; - switch (name) { - case 'HEAP8': - case 'HEAPU8': { - // no action required - storing only 1 byte - break; - } - case 'HEAP16': { - // change "name[idx] = value" to "LE_HEAP_STORE_I16(idx*2, value)" - makeCallExpression(node, 'LE_HEAP_STORE_I16', [multiply(idx, 2), value]); - break; - } - case 'HEAPU16': { - // change "name[idx] = value" to "LE_HEAP_STORE_U16(idx*2, value)" - makeCallExpression(node, 'LE_HEAP_STORE_U16', [multiply(idx, 2), value]); - break; - } - case 'HEAP32': { - // change "name[idx] = value" to "LE_HEAP_STORE_I32(idx*4, value)" - makeCallExpression(node, 'LE_HEAP_STORE_I32', [multiply(idx, 4), value]); - break; - } - case 'HEAPU32': { - // change "name[idx] = value" to "LE_HEAP_STORE_U32(idx*4, value)" - makeCallExpression(node, 'LE_HEAP_STORE_U32', [multiply(idx, 4), value]); - break; - } - case 'HEAP64': { - // change "name[idx] = value" to "LE_HEAP_STORE_I64(idx*8, value)" - makeCallExpression(node, 'LE_HEAP_STORE_I64', [multiply(idx, 8), value]); - break; - } - case 'HEAPU64': { - // change "name[idx] = value" to "LE_HEAP_STORE_U64(idx*8, value)" - makeCallExpression(node, 'LE_HEAP_STORE_U64', [multiply(idx, 8), value]); - break; - } - case 'HEAPF32': { - // change "name[idx] = value" to "LE_HEAP_STORE_F32(idx*4, value)" - makeCallExpression(node, 'LE_HEAP_STORE_F32', [multiply(idx, 4), value]); - break; - } - case 'HEAPF64': { - // change "name[idx] = value" to "LE_HEAP_STORE_F64(idx*8, value)" - makeCallExpression(node, 'LE_HEAP_STORE_F64', [multiply(idx, 8), value]); - break; - } + const helper = littleEndianHelper[heap]; + if (helper) { + // "nameXX[idx] = value" -> "LE_HEAP_STORE_XX(idx*XX, value)" + makeCallExpression(node, helper.store, [multiply(idx, helper.width), value]); } + } else if (growHeap) { + const idx = target.property; + const helper = littleEndianHelper[growHeap]; + if (helper) { + // "(growMemViews(),nameXX)[idx] = value" -> "LE_HEAP_STORE_XX((growMemViews(),idx*XX), value)" + makeCallExpression(node, helper.store, [ + makeSequence(makeCallGrowMemViews(), multiply(idx, helper.width)), + value, + ]); + } + } else { + // not accessing the HEAP + c(target); } }, CallExpression(node, c) { @@ -1059,59 +1043,28 @@ function littleEndianHeap(ast) { }, MemberExpression(node, c) { c(node.property); - if (!isHEAPAccess(node)) { - // not accessing the HEAP - c(node.object); - } else { + const heap = isHEAPAccess(node); + const growHeap = isGrowHEAPAccess(node); + if (heap) { // replace the heap access with LE_HEAP_LOAD const idx = node.property; - switch (node.object.name) { - case 'HEAP8': - case 'HEAPU8': { - // no action required - loading only 1 byte - break; - } - case 'HEAP16': { - // change "name[idx]" to "LE_HEAP_LOAD_I16(idx*2)" - makeCallExpression(node, 'LE_HEAP_LOAD_I16', [multiply(idx, 2)]); - break; - } - case 'HEAPU16': { - // change "name[idx]" to "LE_HEAP_LOAD_U16(idx*2)" - makeCallExpression(node, 'LE_HEAP_LOAD_U16', [multiply(idx, 2)]); - break; - } - case 'HEAP32': { - // change "name[idx]" to "LE_HEAP_LOAD_I32(idx*4)" - makeCallExpression(node, 'LE_HEAP_LOAD_I32', [multiply(idx, 4)]); - break; - } - case 'HEAPU32': { - // change "name[idx]" to "LE_HEAP_LOAD_U32(idx*4)" - makeCallExpression(node, 'LE_HEAP_LOAD_U32', [multiply(idx, 4)]); - break; - } - case 'HEAP64': { - // change "name[idx]" to "LE_HEAP_LOAD_I64(idx*8)" - makeCallExpression(node, 'LE_HEAP_LOAD_I64', [multiply(idx, 8)]); - break; - } - case 'HEAPU64': { - // change "name[idx]" to "LE_HEAP_LOAD_U64(idx*8)" - makeCallExpression(node, 'LE_HEAP_LOAD_U64', [multiply(idx, 8)]); - break; - } - case 'HEAPF32': { - // change "name[idx]" to "LE_HEAP_LOAD_F32(idx*4)" - makeCallExpression(node, 'LE_HEAP_LOAD_F32', [multiply(idx, 4)]); - break; - } - case 'HEAPF64': { - // change "name[idx]" to "LE_HEAP_LOAD_F64(idx*8)" - makeCallExpression(node, 'LE_HEAP_LOAD_F64', [multiply(idx, 8)]); - break; - } + const helper = littleEndianHelper[heap]; + if (helper) { + // "nameXX[idx]" -> "LE_HEAP_LOAD_XX(idx*XX)" + makeCallExpression(node, helper.load, [multiply(idx, helper.width)]); + } + } else if (growHeap) { + const idx = node.property; + const helper = littleEndianHelper[growHeap]; + if (helper) { + // "(growMemViews(),nameXX)[idx]" -> "LE_HEAP_LOAD_XX((growMemViews(),idx*XX))" + makeCallExpression(node, helper.load, [ + makeSequence(makeCallGrowMemViews(), multiply(idx, helper.width)), + ]); } + } else { + // not accessing the HEAP + c(node.object); } }, }); @@ -1136,19 +1089,19 @@ function growableHeap(ast) { c(node.body); } }, - AssignmentExpression(node) { + AssignmentExpression(node, c) { if (node.left.type !== 'Identifier') { // Don't transform `HEAPxx =` assignments. - growableHeap(node.left); + c(node.left); } - growableHeap(node.right); + c(node.right); }, - VariableDeclarator(node) { + VariableDeclarator(node, c) { // Don't transform the var declarations for HEAP8 etc // but do transform anything that sets a var to // something from HEAP8 etc if (node.init) { - growableHeap(node.init); + c(node.init); } }, Identifier(node) { @@ -1156,25 +1109,33 @@ function growableHeap(ast) { // Transform `HEAPxx` into `(growMemViews(), HEAPxx)`. // Important: don't just do `growMemViews(HEAPxx)` because `growMemViews` reassigns `HEAPxx` // and we want to get an updated value after that reassignment. - Object.assign(node, { - type: 'SequenceExpression', - expressions: [ - { - type: 'CallExpression', - callee: { - type: 'Identifier', - name: 'growMemViews', - }, - arguments: [], - }, - {...node}, - ], - }); + Object.assign(node, makeSequence(makeCallGrowMemViews(), {...node})); } }, }); } +function makeCallGrowMemViews() { + return { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'growMemViews', + }, + arguments: [], + }; +} + +function makeSequence(...expressions) { + return { + type: 'ParenthesizedExpression', + expression: { + type: 'SequenceExpression', + expressions, + } + }; +} + // Make all JS pointers unsigned. We do this by modifying things like // HEAP32[X >> 2] to HEAP32[X >>> 2]. We also need to handle the case of // HEAP32[X] and make that HEAP32[X >>> 0], things like subarray(), etc. @@ -1249,21 +1210,40 @@ function isHEAPAccess(node) { node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.computed && // notice a[X] but not a.X - isEmscriptenHEAP(node.object.name) + isEmscriptenHEAP(node.object.name) && + node.object.name + ); +} + +function isGrowHEAPAccess(node) { + if ( + node.type !== 'MemberExpression' || + !node.computed || // notice a[X] but not a.X + node.object.type !== 'ParenthesizedExpression') + return false; + const obj = node.object.expression; + return ( + obj.type === 'SequenceExpression' && + obj.expressions.length === 2 && + obj.expressions[0].type === 'CallExpression' && + obj.expressions[0].callee.type === 'Identifier' && + obj.expressions[0].callee.name === 'growMemViews' && + obj.expressions[1].type === 'Identifier' && + isEmscriptenHEAP(obj.expressions[1].name) && + obj.expressions[1].name ); } -// Replace direct HEAP* loads/stores with calls into C, in which ASan checks -// are applied. That lets ASan cover JS too. +function asanifyTransform(node, action) { + makeCallExpression(node.property, '_asan_js_check_index', [{ ...node.object }, { ...node.property }, makeIdentifier(action)]); +} +// Add ASan check to direct HEAP* loads/stores. +// That lets ASan cover JS too. function asanify(ast) { recursiveWalk(ast, { FunctionDeclaration(node, c) { - if ( - node.id.type === 'Identifier' && - (node.id.name.startsWith('_asan_js_') || node.id.name === 'establishStackSpace') - ) { - // do not recurse into this js impl function, which we use during - // startup before the wasm is ready + if (node.id.type === 'Identifier' && node.id.name === 'establishStackSpace') { + // skip establishStackSpace, because it sets up variables used by ASan itself } else { c(node.body); } @@ -1274,7 +1254,7 @@ function asanify(ast) { c(value); if (isHEAPAccess(target)) { // Instrument a store. - makeCallExpression(node, '_asan_js_store', [target.object, target.property, value]); + asanifyTransform(target, '___asan_storeN'); } else { c(target); } @@ -1285,7 +1265,7 @@ function asanify(ast) { c(node.object); } else { // Instrument a load. - makeCallExpression(node, '_asan_js_load', [node.object, node.property]); + asanifyTransform(node, '___asan_loadN'); } }, }); @@ -1300,24 +1280,19 @@ function multiply(value, by) { }; } -// Replace direct heap access with SAFE_HEAP* calls. +function safeHeapTransform(node, action) { + makeCallExpression(node.property, 'SAFE_HEAP_INDEX', [{ ...node.object }, { ...node.property }, createLiteral(action)]); +} +// Add SAFE_HEAP_INDEX check to heap access function safeHeap(ast) { recursiveWalk(ast, { - FunctionDeclaration(node, c) { - if (node.id.type === 'Identifier' && node.id.name.startsWith('SAFE_HEAP')) { - // do not recurse into this js impl function, which we use during - // startup before the wasm is ready - } else { - c(node.body); - } - }, AssignmentExpression(node, c) { const target = node.left; const value = node.right; c(value); if (isHEAPAccess(target)) { // Instrument a store. - makeCallExpression(node, 'SAFE_HEAP_STORE', [target.object, target.property, value]); + safeHeapTransform(target, 'storing'); } else { c(target); } @@ -1328,7 +1303,7 @@ function safeHeap(ast) { c(node.object); } else { // Instrument a load. - makeCallExpression(node, 'SAFE_HEAP_LOAD', [node.object, node.property]); + safeHeapTransform(node, 'loading'); } }, }); diff --git a/tools/link.py b/tools/link.py index 1d9dbcf38bcba..65ac42b47bd47 100644 --- a/tools/link.py +++ b/tools/link.py @@ -846,6 +846,8 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915 if settings.SUPPORT_BIG_ENDIAN: diagnostics.warning('experimental', '-sSUPPORT_BIG_ENDIAN is experimental, not all features are fully supported.') + if settings.WASM2JS: + exit_with_error('WASMJ2S is currently not compatible with SUPPORT_BIG_ENDIAN') if settings.WASM_ESM_INTEGRATION: diagnostics.warning('experimental', '-sWASM_ESM_INTEGRATION is still experimental and not yet supported in browsers') @@ -1221,12 +1223,16 @@ def limit_incoming_module_api(): '$LE_HEAP_STORE_I16', '$LE_HEAP_STORE_U32', '$LE_HEAP_STORE_I32', + '$LE_HEAP_STORE_U64', + '$LE_HEAP_STORE_I64', '$LE_HEAP_STORE_F32', '$LE_HEAP_STORE_F64', '$LE_HEAP_LOAD_U16', '$LE_HEAP_LOAD_I16', '$LE_HEAP_LOAD_U32', '$LE_HEAP_LOAD_I32', + '$LE_HEAP_LOAD_U64', + '$LE_HEAP_LOAD_I64', '$LE_HEAP_LOAD_F32', '$LE_HEAP_LOAD_F64', '$LE_ATOMICS_NATIVE_BYTE_ORDER', diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py index 4e6fb9f8f487a..db46d2e7afef8 100644 --- a/tools/webidl_binder.py +++ b/tools/webidl_binder.py @@ -238,12 +238,6 @@ def build_constructor(name): } return ret; }, - copy(array, view, offset) { - offset /= view.BYTES_PER_ELEMENT; - for (var i = 0; i < array.length; i++) { - view[offset + i] = array[i]; - } - }, }; /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ @@ -251,7 +245,9 @@ def build_constructor(name): if (typeof value === 'string') { var intArray = intArrayFromString(value); var offset = ensureCache.alloc(intArray, HEAP8); - ensureCache.copy(intArray, HEAP8, offset); + for (var i = 0; i < intArray.length; i++) { + HEAP8[offset + i] = intArray[i]; + } return offset; } return value; @@ -261,7 +257,9 @@ def build_constructor(name): function ensureInt8(value) { if (typeof value === 'object') { var offset = ensureCache.alloc(value, HEAP8); - ensureCache.copy(value, HEAP8, offset); + for (var i = 0; i < value.length; i++) { + HEAP8[offset + i] = value[i]; + } return offset; } return value; @@ -271,7 +269,10 @@ def build_constructor(name): function ensureInt16(value) { if (typeof value === 'object') { var offset = ensureCache.alloc(value, HEAP16); - ensureCache.copy(value, HEAP16, offset); + var heapOffset = offset / 2; + for (var i = 0; i < value.length; i++) { + HEAP16[heapOffset + i] = value[i]; + } return offset; } return value; @@ -281,7 +282,10 @@ def build_constructor(name): function ensureInt32(value) { if (typeof value === 'object') { var offset = ensureCache.alloc(value, HEAP32); - ensureCache.copy(value, HEAP32, offset); + var heapOffset = offset / 4; + for (var i = 0; i < value.length; i++) { + HEAP32[heapOffset + i] = value[i]; + } return offset; } return value; @@ -291,7 +295,10 @@ def build_constructor(name): function ensureFloat32(value) { if (typeof value === 'object') { var offset = ensureCache.alloc(value, HEAPF32); - ensureCache.copy(value, HEAPF32, offset); + var heapOffset = offset / 4; + for (var i = 0; i < value.length; i++) { + HEAPF32[heapOffset + i] = value[i]; + } return offset; } return value; @@ -301,7 +308,10 @@ def build_constructor(name): function ensureFloat64(value) { if (typeof value === 'object') { var offset = ensureCache.alloc(value, HEAPF64); - ensureCache.copy(value, HEAPF64, offset); + var heapOffset = offset / 8; + for (var i = 0; i < value.length; i++) { + HEAPF64[heapOffset + i] = value[i]; + } return offset; } return value;