Skip to content

[Wasm64] Fix many remaining issues with wasm64_4gb and add new test configuration #20077

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 22, 2023
Merged
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
25 changes: 21 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -618,17 +618,31 @@ jobs:
title: "wasm64"
test_targets: "
wasm64
wasm64_4gb.test_hello_world
wasm64_4gb.test_em_asm
wasm64_4gb.test_async_main
wasm64_4gb.*embind*
core_2gb.test_em_asm
core_2gb.test_embind_unsigned_bigint
core_2gb.test_embind_no_rtti
wasm64l.test_bigswitch
other.test_memory64_proxies
other.test_failing_growth_wasm64"
- upload-test-results
test-wasm64_4gb:
environment:
# Only run 2 tests at a time to avoid OOM (since each tests used >4gb)
EMCC_CORES: "2"
# We don't use `bionic` here since its too old to run recent node versions:
# `/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found`
executor: linux-python
steps:
- prepare-for-tests
# The linux-python image uses /home/circleci rather than /root and jsvu
# hardcodes /root into its launcher scripts so we need to reinstall v8.
- run: rm -rf $HOME/.jsvu
- install-v8
- install-node-canary
- run-tests:
title: "wasm64_4gb"
test_targets: "wasm64_4gb"
- upload-test-results
test-jsc:
executor: linux-python
steps:
Expand Down Expand Up @@ -880,6 +894,9 @@ workflows:
- test-wasm64:
requires:
- build-linux
- test-wasm64_4gb:
requires:
- build-linux
- test-wasm64l:
requires:
- build-linux
Expand Down
8 changes: 4 additions & 4 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ addToLibrary({
// it. Returns 1 on success, 0 on error.
$growMemory: (size) => {
var b = wasmMemory.buffer;
var pages = (size - b.byteLength + 65535) >>> 16;
var pages = (size - b.byteLength + {{{ WASM_PAGE_SIZE - 1 }}}) / {{{ WASM_PAGE_SIZE }}};
#if RUNTIME_DEBUG
dbg(`emscripten_resize_heap: ${size} (+${size - b.byteLength} bytes / ${pages} pages)`);
dbg(`growMemory: ${size} (+${size - b.byteLength} bytes / ${pages} pages)`);
#endif
#if MEMORYPROFILER
var oldHeapSize = b.byteLength;
Expand Down Expand Up @@ -249,7 +249,7 @@ addToLibrary({
var maxHeapSize = getHeapMax();
if (requestedSize > maxHeapSize) {
#if ASSERTIONS
err(`Cannot enlarge memory, asked to go up to ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`);
err(`Cannot enlarge memory, requested ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`);
#endif
#if ABORTING_MALLOC
abortOnCannotGrowMemory(requestedSize);
Expand Down Expand Up @@ -693,7 +693,7 @@ addToLibrary({
// size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html

var tm_zone = {{{ makeGetValue('tm', C_STRUCTS.tm.tm_zone, 'i32') }}};
var tm_zone = {{{ makeGetValue('tm', C_STRUCTS.tm.tm_zone, '*') }}};

var date = {
tm_sec: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_sec, 'i32') }}},
Expand Down
2 changes: 1 addition & 1 deletion src/library_fs_shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ addToLibrary({
var fd = process.stdin.fd;

try {
bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, -1);
bytesRead = fs.readSync(fd, buf);
} catch(e) {
// Cross-platform differences: on Windows, reading EOF throws an exception, but on other OSes,
// reading EOF returns 0. Uniformize behavior by treating the EOF exception to return 0.
Expand Down
45 changes: 25 additions & 20 deletions src/library_int53.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,32 @@ addToLibrary({
// function $writeI53ToU64(): the implementation would be identical, and it is up to the
// C/C++ side code to interpret the resulting number as signed or unsigned as is desirable.
$writeI53ToI64: (ptr, num) => {
HEAPU32[ptr>>2] = num;
HEAPU32[ptr+4>>2] = (num - HEAPU32[ptr>>2])/4294967296;
{{{ makeSetValue('ptr', 0, 'num', 'u32') }}};
var lower = {{{ makeGetValue('ptr', 0, 'u32') }}};
{{{ makeSetValue('ptr', 4, '(num - lower)/4294967296', 'u32') }}};
#if ASSERTIONS
var deserialized = (num >= 0) ? readI53FromU64(ptr) : readI53FromI64(ptr);
if (deserialized != num) warnOnce('writeI53ToI64() out of range: serialized JS Number ' + num + ' to Wasm heap as bytes lo=' + ptrToString(HEAPU32[ptr>>2]) + ', hi=' + ptrToString(HEAPU32[ptr+4>>2]) + ', which deserializes back to ' + deserialized + ' instead!');
if (deserialized != num) warnOnce(`writeI53ToI64() out of range: serialized JS Number ${num} to Wasm heap as bytes lo=${ptrToString(HEAPU32[ptr/4])}, hi=${ptrToString(HEAPU32[ptr/4+1])}, which deserializes back to ${deserialized} instead!`);
#endif
},

// Same as writeI53ToI64, but if the double precision number does not fit within the
// 64-bit number, the number is clamped to range [-2^63, 2^63-1].
$writeI53ToI64Clamped__deps: ['$writeI53ToI64'],
$writeI53ToI64Clamped: (ptr, num) => {
if (num > 0x7FFFFFFFFFFFFFFF) {
HEAPU32[ptr>>2] = 0xFFFFFFFF;
HEAPU32[ptr+4>>2] = 0x7FFFFFFF;
{{{ makeSetValue('ptr', 0, 0xFFFFFFFF, 'u32') }}};
{{{ makeSetValue('ptr', 4, 0x7FFFFFFF, 'u32') }}};
} else if (num < -0x8000000000000000) {
HEAPU32[ptr>>2] = 0;
HEAPU32[ptr+4>>2] = 0x80000000;
{{{ makeSetValue('ptr', 0, 0, 'u32') }}};
{{{ makeSetValue('ptr', 4, 0x80000000, 'u32') }}};
} else {
HEAPU32[ptr>>2] = num;
HEAPU32[ptr+4>>2] = (num - HEAPU32[ptr>>2])/4294967296;
writeI53ToI64(ptr, num);
}
},

// Like writeI53ToI64, but throws if the passed number is out of range of int64.
$writeI53ToI64Signaling__deps: ['$writeI53ToI64'],
$writeI53ToI64Signaling: (ptr, num) => {
if (num > 0x7FFFFFFFFFFFFFFF || num < -0x8000000000000000) {
#if ASSERTIONS
Expand All @@ -51,22 +53,26 @@ addToLibrary({
throw 'RangeError:' + num;
#endif
}
HEAPU32[ptr>>2] = num;
HEAPU32[ptr+4>>2] = (num - HEAPU32[ptr>>2])/4294967296;
writeI53ToI64(ptr, num);
},

// Uint64 variant of writeI53ToI64Clamped. Writes the Number to a Uint64 variable on
// the heap, clamping out of range values to range [0, 2^64-1].
$writeI53ToU64Clamped__deps: ['$writeI53ToI64'],
$writeI53ToU64Clamped: (ptr, num) => {
if (num > 0xFFFFFFFFFFFFFFFF) HEAPU32[ptr>>2] = HEAPU32[ptr+4>>2] = 0xFFFFFFFF;
else if (num < 0) HEAPU32[ptr>>2] = HEAPU32[ptr+4>>2] = 0;
else {
HEAPU32[ptr>>2] = num;
HEAPU32[ptr+4>>2] = (num - HEAPU32[ptr>>2])/4294967296;
if (num > 0xFFFFFFFFFFFFFFFF) {
{{{ makeSetValue('ptr', 0, 0xFFFFFFFF, 'u32') }}};
{{{ makeSetValue('ptr', 4, 0xFFFFFFFF, 'u32') }}};
} else if (num < 0) {
{{{ makeSetValue('ptr', 0, 0, 'u32') }}};
{{{ makeSetValue('ptr', 4, 0, 'u32') }}};
} else {
writeI53ToI64(ptr, num);
}
},

// Like writeI53ToI64, but throws if the passed number is out of range of uint64.
$writeI53ToU64Signaling__deps: ['$writeI53ToI64'],
$writeI53ToU64Signaling: (ptr, num) => {
if (num < 0 || num > 0xFFFFFFFFFFFFFFFF) {
#if ASSERTIONS
Expand All @@ -75,22 +81,21 @@ addToLibrary({
throw 'RangeError:'+num;
#endif
}
HEAPU32[ptr>>2] = num;
HEAPU32[ptr+4>>2] = (num - HEAPU32[ptr>>2])/4294967296;
writeI53ToI64(ptr, num);
},

// Reads a 64-bit signed integer from the WebAssembly heap and
// converts it to a JavaScript Number, which can represent 53 integer bits precisely.
// TODO: Add $readI53FromI64Signaling() variant.
$readI53FromI64: (ptr) => {
return HEAPU32[ptr>>2] + HEAP32[ptr+4>>2] * 4294967296;
return {{{ makeGetValue('ptr', 0, 'u32') }}} + {{{ makeGetValue('ptr', 4, 'i32') }}} * 4294967296;
},

// Reads a 64-bit unsigned integer from the WebAssembly heap and
// converts it to a JavaScript Number, which can represent 53 integer bits precisely.
// TODO: Add $readI53FromU64Signaling() variant.
$readI53FromU64: (ptr) => {
return HEAPU32[ptr>>2] + HEAPU32[ptr+4>>2] * 4294967296;
return {{{ makeGetValue('ptr', 0, 'u32') }}} + {{{ makeGetValue('ptr', 4, 'u32') }}} * 4294967296;
},

// Converts the given signed 32-bit low-high pair to a JavaScript Number that
Expand Down
4 changes: 3 additions & 1 deletion src/library_math.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ addToLibrary({
emscripten_math_cosh: (x) => Math.cosh(x),
emscripten_math_hypot: (count, varargs) => {
var args = [];
for (var i = 0; i < count; ++i) args.push(HEAPF64[(varargs>>3) + i]);
for (var i = 0; i < count; ++i) {
args.push({{{ makeGetValue('varargs', `i * ${getNativeTypeSize('double')}`, 'double') }}});
}
return Math.hypot.apply(null, args);
},
emscripten_math_sin: (x) => Math.sin(x),
Expand Down
4 changes: 2 additions & 2 deletions src/library_nodefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,14 +272,14 @@ addToLibrary({
// Node.js < 6 compatibility: node errors on 0 length reads
if (length === 0) return 0;
try {
return fs.readSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
return fs.readSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), { position: position });
} catch (e) {
throw new FS.ErrnoError(NODEFS.convertNodeCode(e));
}
},
write(stream, buffer, offset, length, position) {
try {
return fs.writeSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
return fs.writeSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), { position: position });
} catch (e) {
throw new FS.ErrnoError(NODEFS.convertNodeCode(e));
}
Expand Down
4 changes: 2 additions & 2 deletions src/library_noderawfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ addToLibrary({
}
var seeking = typeof position != 'undefined';
if (!seeking && stream.seekable) position = stream.position;
var bytesRead = fs.readSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
var bytesRead = fs.readSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), { position: position });
// update position marker when non-seeking
if (!seeking) stream.position += bytesRead;
return bytesRead;
Expand All @@ -164,7 +164,7 @@ addToLibrary({
}
var seeking = typeof position != 'undefined';
if (!seeking && stream.seekable) position = stream.position;
var bytesWritten = fs.writeSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position);
var bytesWritten = fs.writeSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), { position: position });
// update position marker when non-seeking
if (!seeking) stream.position += bytesWritten;
return bytesWritten;
Expand Down
4 changes: 4 additions & 0 deletions src/library_pipefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ addToLibrary({
currentLength += bucket.offset - bucket.roffset;
}

#if ASSERTIONS && !(MEMORY64 && MAXIMUM_MEMORY > FOUR_GB)
#if PTHREADS
assert(buffer instanceof ArrayBuffer || buffer instanceof SharedArrayBuffer || ArrayBuffer.isView(buffer));
#else
assert(buffer instanceof ArrayBuffer || ArrayBuffer.isView(buffer));
#endif
#endif
var data = buffer.subarray(offset, offset + length);

Expand Down Expand Up @@ -149,10 +151,12 @@ addToLibrary({
write(stream, buffer, offset, length, position /* ignored */) {
var pipe = stream.node.pipe;

#if ASSERTIONS && !(MEMORY64 && MAXIMUM_MEMORY > FOUR_GB)
#if PTHREADS
assert(buffer instanceof ArrayBuffer || buffer instanceof SharedArrayBuffer || ArrayBuffer.isView(buffer));
#else
assert(buffer instanceof ArrayBuffer || ArrayBuffer.isView(buffer));
#endif
#endif
var data = buffer.subarray(offset, offset + length);

Expand Down
31 changes: 24 additions & 7 deletions src/library_syscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,30 @@ var SyscallsLibrary = {
#if ASSERTIONS
assert(SYSCALLS.varargs != undefined);
#endif
var ret = {{{ makeGetValue('SYSCALLS.varargs', 0, 'i32') }}};
SYSCALLS.varargs += 4;
var ret = {{{ makeGetValue('SYSCALLS.varargs', '-4', 'i32') }}};
#if SYSCALL_DEBUG
dbg(` (raw: "${ret}")`);
#endif
return ret;
},

#if MEMORY64
getp() {
#if ASSERTIONS
assert(SYSCALLS.varargs != undefined);
#endif
var ret = {{{ makeGetValue('SYSCALLS.varargs', 0, '*') }}};
SYSCALLS.varargs += {{{ POINTER_SIZE }}};
#if SYSCALL_DEBUG
dbg(` (raw: "${ret}")`);
#endif
return ret;
},
#else
getp() { return SYSCALLS.get() },
#endif

getStr(ptr) {
var ret = UTF8ToString(ptr);
#if SYSCALL_DEBUG
Expand Down Expand Up @@ -216,7 +233,7 @@ var SyscallsLibrary = {
if (!stream.tty) return -{{{ cDefs.ENOTTY }}};
if (stream.tty.ops.ioctl_tcgets) {
var termios = stream.tty.ops.ioctl_tcgets(stream);
var argp = SYSCALLS.get();
var argp = SYSCALLS.getp();
{{{ makeSetValue('argp', C_STRUCTS.termios.c_iflag, 'termios.c_iflag || 0', 'i32') }}};
{{{ makeSetValue('argp', C_STRUCTS.termios.c_oflag, 'termios.c_oflag || 0', 'i32') }}};
{{{ makeSetValue('argp', C_STRUCTS.termios.c_cflag, 'termios.c_cflag || 0', 'i32') }}};
Expand All @@ -242,7 +259,7 @@ var SyscallsLibrary = {
case {{{ cDefs.TCSETSF }}}: {
if (!stream.tty) return -{{{ cDefs.ENOTTY }}};
if (stream.tty.ops.ioctl_tcsets) {
var argp = SYSCALLS.get();
var argp = SYSCALLS.getp();
var c_iflag = {{{ makeGetValue('argp', C_STRUCTS.termios.c_iflag, 'i32') }}};
var c_oflag = {{{ makeGetValue('argp', C_STRUCTS.termios.c_oflag, 'i32') }}};
var c_cflag = {{{ makeGetValue('argp', C_STRUCTS.termios.c_cflag, 'i32') }}};
Expand All @@ -257,7 +274,7 @@ var SyscallsLibrary = {
}
case {{{ cDefs.TIOCGPGRP }}}: {
if (!stream.tty) return -{{{ cDefs.ENOTTY }}};
var argp = SYSCALLS.get();
var argp = SYSCALLS.getp();
{{{ makeSetValue('argp', 0, 0, 'i32') }}};
return 0;
}
Expand All @@ -266,7 +283,7 @@ var SyscallsLibrary = {
return -{{{ cDefs.EINVAL }}}; // not supported
}
case {{{ cDefs.FIONREAD }}}: {
var argp = SYSCALLS.get();
var argp = SYSCALLS.getp();
return FS.ioctl(stream, op, argp);
}
case {{{ cDefs.TIOCGWINSZ }}}: {
Expand All @@ -275,7 +292,7 @@ var SyscallsLibrary = {
if (!stream.tty) return -{{{ cDefs.ENOTTY }}};
if (stream.tty.ops.ioctl_tiocgwinsz) {
var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty);
var argp = SYSCALLS.get();
var argp = SYSCALLS.getp();
{{{ makeSetValue('argp', 0, 'winsize[0]', 'i16') }}};
{{{ makeSetValue('argp', 2, 'winsize[1]', 'i16') }}};
}
Expand Down Expand Up @@ -770,7 +787,7 @@ var SyscallsLibrary = {
return 0;
}
case {{{ cDefs.F_GETLK }}}: {
var arg = SYSCALLS.get();
var arg = SYSCALLS.getp();
var offset = {{{ C_STRUCTS.flock.l_type }}};
// We're always unlocked.
{{{ makeSetValue('arg', 'offset', cDefs.F_UNLCK, 'i16') }}};
Expand Down
4 changes: 2 additions & 2 deletions src/library_wasmfs_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ addToLibrary({
try {
// TODO: Cache open file descriptors to guarantee that opened files will
// still exist when we try to access them.
let nread = fs.readSync(fd, HEAPU8, buf_p, len, pos);
let nread = fs.readSync(fd, new Int8Array(HEAPU8.buffer, buf_p, len), { position: pos });
{{{ makeSetValue('nread_p', 0, 'nread', 'i32') }}};
} catch (e) {
if (!e.code) throw e;
Expand All @@ -201,7 +201,7 @@ addToLibrary({
try {
// TODO: Cache open file descriptors to guarantee that opened files will
// still exist when we try to access them.
let nwritten = fs.writeSync(fd, HEAPU8, buf_p, len, pos);
let nwritten = fs.writeSync(fd, new Int8Array(HEAPU8.buffer, buf_p, len), { position: pos });
{{{ makeSetValue('nwritten_p', 0, 'nwritten', 'i32') }}};
} catch (e) {
if (!e.code) throw e;
Expand Down
6 changes: 5 additions & 1 deletion src/preamble_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,15 @@ function updateMemoryViews() {
#if SUPPORT_BIG_ENDIAN
{{{ maybeExport('HEAP_DATA_VIEW') }}} HEAP_DATA_VIEW = new DataView(b);
#endif
#if MEMORY64 && MAXIMUM_MEMORY > FOUR_GB
#include "runtime_view_proxy.js"
#else
{{{ maybeExport('HEAP8') }}} HEAP8 = new Int8Array(b);
{{{ maybeExport('HEAP16') }}} HEAP16 = new Int16Array(b);
{{{ maybeExport('HEAP32') }}} HEAP32 = new Int32Array(b);
{{{ maybeExport('HEAPU8') }}} HEAPU8 = new Uint8Array(b);
{{{ maybeExport('HEAPU16') }}} HEAPU16 = new Uint16Array(b);
#endif
{{{ maybeExport('HEAP32') }}} HEAP32 = new Int32Array(b);
{{{ maybeExportIfAudioWorklet('HEAPU32') }}} HEAPU32 = new Uint32Array(b);
{{{ maybeExportIfAudioWorklet('HEAPF32') }}} HEAPF32 = new Float32Array(b);
{{{ maybeExport('HEAPF64') }}} HEAPF64 = new Float64Array(b);
Expand Down
Loading