Skip to content

Commit d5cb46c

Browse files
committed
Convert BigInt<->Number based on library function __sig attributes
This change introduces and type to the `__sig` scheme that we using for library functions: 'p'. This letter signifies that the paramater or return value is the width of a pointer which means it will differ between wasm32 and wasm64. We use this whenever a JS function receives or returns pointer type or a size_t type. For wasm32, we don't need to do anything since the incoming value is and i32. For wasm64 we covert the incoming BigInt value to an int53/double at the JS/Wasm boundary. At the moment no checking is done on the values, which means values that don't pricely convert to JS double can be currupted/truncated. As a followup, we could consider using the checking coversion functions, or asserting in debug builds if the values don't fit within this range.
1 parent 3aeb48b commit d5cb46c

File tree

6 files changed

+74
-14
lines changed

6 files changed

+74
-14
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ jobs:
380380
executor: bionic
381381
steps:
382382
- run-tests-linux:
383-
test_targets: "wasm64.test_hello_world wasm64l.test_hello_world wasm64l.test_unistd_truncate wasm64l.test_mmap"
383+
test_targets: "wasm64.test_hello_world wasm64l.test_hello_world wasm64l.test_unistd_truncate wasm64l.test_mmap wasm64l.test_unistd_sysconf_phys_pages"
384384
test-other:
385385
executor: bionic
386386
steps:

src/jsifier.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,44 @@ function runJSify(functionsOnly) {
9090
});
9191
}
9292

93+
function convertPointerParams(snippet, sig) {
94+
// Automatically convert any incoming pointer arguments from BigInt
95+
// to double (this limits the range to int53).
96+
// And convert the return value if the function returns a pointer.
97+
return modifyFunction(snippet, (name, args, body) => {
98+
const argNames = args.split(',');
99+
let newArgs = [];
100+
let argConvertions = '';
101+
for (let i = 1; i < sig.length; i++) {
102+
const name = argNames[i - 1];
103+
if (sig[i] == 'p') {
104+
argConvertions += `${name} = Number(${name})\n`;
105+
newArgs.push(`Number(${name})`);
106+
} else {
107+
newArgs.push(name);
108+
}
109+
}
110+
newArgs = newArgs.join(',');
111+
if (sig[0] == 'p') {
112+
// For function that return a pointer need need to convert
113+
// the return value too, which means we need to wrap the
114+
// body in an inner function.
115+
return `\
116+
function ${name}(${args}) {
117+
var ret = ((${args}) => { ${body} })(${newArgs});
118+
return BigInt(ret);
119+
}`;
120+
}
121+
// Othewise no inner function is needed and we covert the arguments
122+
// before executing the function body.
123+
return `\
124+
function ${name}(${args}) {
125+
${argConvertions};
126+
${body};
127+
}`;
128+
});
129+
}
130+
93131
function processLibraryFunction(snippet, ident, finalName) {
94132
// It is possible that when printing the function as a string on Windows, the js interpreter we are in returns the string with Windows
95133
// line endings \r\n. This is undesirable, since line endings are managed in the form \n in the output for binary file writes, so
@@ -110,6 +148,12 @@ function ${name}(${args}) {
110148
return ret;
111149
}`);
112150
}
151+
if (MEMORY64) {
152+
const sig = LibraryManager.library[ident + '__sig'];
153+
if (sig && sig.includes('p')) {
154+
snippet = convertPointerParams(snippet, sig);
155+
}
156+
}
113157
return snippet;
114158
}
115159

src/library.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ LibraryManager.library = {
8787
},
8888
#endif
8989

90+
// Returns a pointer ('p'), which means an i32 on wasm32 and an i64 wasm64
91+
emscripten_get_heap_max__sig: 'p',
9092
emscripten_get_heap_max: function() {
9193
#if ALLOW_MEMORY_GROWTH
9294
// Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
@@ -357,6 +359,7 @@ LibraryManager.library = {
357359
// the wasm file standalone.
358360
#if SHRINK_LEVEL < 2 && !STANDALONE_WASM
359361

362+
emscripten_memcpy_big__sig: 'vppp',
360363
#if MIN_CHROME_VERSION < 45 || MIN_EDGE_VERSION < 14 || MIN_FIREFOX_VERSION < 34 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION < 100101
361364
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/copyWithin lists browsers that support TypedArray.prototype.copyWithin, but it
362365
// has outdated information for Safari, saying it would not support it.

src/library_syscall.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ var SyscallsLibrary = {
154154
#endif
155155
},
156156

157+
__syscall_chdir__sig: 'ip',
157158
__syscall_chdir: function(path) {
158159
path = SYSCALLS.getStr(path);
159160
FS.chdir(path);
@@ -164,22 +165,26 @@ var SyscallsLibrary = {
164165
FS.chmod(path, mode);
165166
return 0;
166167
},
168+
__syscall_rename__sig: 'ipp',
167169
__syscall_rename: function(old_path, new_path) {
168170
old_path = SYSCALLS.getStr(old_path);
169171
new_path = SYSCALLS.getStr(new_path);
170172
FS.rename(old_path, new_path);
171173
return 0;
172174
},
175+
__syscall_rmdir__sig: 'ip',
173176
__syscall_rmdir: function(path) {
174177
path = SYSCALLS.getStr(path);
175178
FS.rmdir(path);
176179
return 0;
177180
},
181+
__syscall_dup__sig: 'ii',
178182
__syscall_dup: function(fd) {
179183
var old = SYSCALLS.getStreamFromFD(fd);
180184
return FS.createStream(old, 0).fd;
181185
},
182186
__syscall_pipe__deps: ['$PIPEFS'],
187+
__syscall_pipe__sig: 'ip',
183188
__syscall_pipe: function(fdPtr) {
184189
if (fdPtr == 0) {
185190
throw new FS.ErrnoError({{{ cDefine('EFAULT') }}});
@@ -192,6 +197,7 @@ var SyscallsLibrary = {
192197

193198
return 0;
194199
},
200+
__syscall_ioctl__sig: 'iiip',
195201
__syscall_ioctl: function(fd, op, varargs) {
196202
#if SYSCALLS_REQUIRE_FILESYSTEM == 0
197203
#if SYSCALL_DEBUG
@@ -582,6 +588,7 @@ var SyscallsLibrary = {
582588
var stream = SYSCALLS.getStreamFromFD(fd);
583589
return 0; // we can't do anything synchronously; the in-memory FS is already synced to
584590
},
591+
__syscall_poll__sig: 'ipi',
585592
__syscall_poll: function(fds, nfds, timeout) {
586593
var nonzero = 0;
587594
for (var i = 0; i < nfds; i++) {
@@ -602,6 +609,7 @@ var SyscallsLibrary = {
602609
}
603610
return nonzero;
604611
},
612+
__syscall_getcwd__sig: 'ipp',
605613
__syscall_getcwd: function(buf, size) {
606614
if (size === 0) return -{{{ cDefine('EINVAL') }}};
607615
var cwd = FS.cwd();
@@ -610,25 +618,30 @@ var SyscallsLibrary = {
610618
stringToUTF8(cwd, buf, size);
611619
return cwdLengthInBytes;
612620
},
621+
__syscall_truncate64__sig: 'ipj',
613622
__syscall_truncate64: function(path, {{{ defineI64Param('length') }}}) {
614623
{{{ receiveI64ParamAsDouble('length') }}}
615624
path = SYSCALLS.getStr(path);
616625
FS.truncate(path, length);
617626
return 0;
618627
},
628+
__syscall_ftruncate64__sig: 'iij',
619629
__syscall_ftruncate64: function(fd, {{{ defineI64Param('length') }}}) {
620630
{{{ receiveI64ParamAsDouble('length') }}}
621631
FS.ftruncate(fd, length);
622632
return 0;
623633
},
634+
__syscall_stat64__sig: 'iip',
624635
__syscall_stat64: function(path, buf) {
625636
path = SYSCALLS.getStr(path);
626637
return SYSCALLS.doStat(FS.stat, path, buf);
627638
},
639+
__syscall_lstat64__sig: 'iip',
628640
__syscall_lstat64: function(path, buf) {
629641
path = SYSCALLS.getStr(path);
630642
return SYSCALLS.doStat(FS.lstat, path, buf);
631643
},
644+
__syscall_fstat64__sig: 'iip',
632645
__syscall_fstat64: function(fd, buf) {
633646
var stream = SYSCALLS.getStreamFromFD(fd);
634647
return SYSCALLS.doStat(FS.stat, stream.path, buf);
@@ -637,6 +650,7 @@ var SyscallsLibrary = {
637650
FS.fchown(fd, owner, group);
638651
return 0;
639652
},
653+
__syscall_getdents64__sig: 'iipi',
640654
__syscall_getdents64: function(fd, dirp, count) {
641655
var stream = SYSCALLS.getStreamFromFD(fd)
642656
if (!stream.getdents) {
@@ -685,6 +699,7 @@ var SyscallsLibrary = {
685699
return pos;
686700
},
687701
__syscall_fcntl64__deps: ['$setErrNo'],
702+
__syscall_fcntl64__sig: 'iipp',
688703
__syscall_fcntl64: function(fd, cmd, varargs) {
689704
#if SYSCALLS_REQUIRE_FILESYSTEM == 0
690705
#if SYSCALL_DEBUG
@@ -775,6 +790,7 @@ var SyscallsLibrary = {
775790
__syscall_fadvise64: function(fd, offset, len, advice) {
776791
return 0; // your advice is important to us (but we can't use it)
777792
},
793+
__syscall_openat__sig: 'iipip',
778794
__syscall_openat: function(dirfd, path, flags, varargs) {
779795
path = SYSCALLS.getStr(path);
780796
path = SYSCALLS.calculateAt(dirfd, path);
@@ -838,6 +854,7 @@ var SyscallsLibrary = {
838854
path = SYSCALLS.calculateAt(dirfd, path, allowEmpty);
839855
return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf);
840856
},
857+
__syscall_unlinkat__sig: 'iipi',
841858
__syscall_unlinkat: function(dirfd, path, flags) {
842859
path = SYSCALLS.getStr(path);
843860
path = SYSCALLS.calculateAt(dirfd, path);
@@ -871,6 +888,7 @@ var SyscallsLibrary = {
871888
FS.symlink(target, linkpath);
872889
return 0;
873890
},
891+
__syscall_readlinkat__sig: 'vippp',
874892
__syscall_readlinkat: function(dirfd, path, buf, bufsize) {
875893
path = SYSCALLS.getStr(path);
876894
path = SYSCALLS.calculateAt(dirfd, path);
@@ -921,6 +939,7 @@ var SyscallsLibrary = {
921939
}
922940
return 0;
923941
},
942+
__syscall_utimensat__sig: 'iippi',
924943
__syscall_utimensat: function(dirfd, path, times, flags) {
925944
path = SYSCALLS.getStr(path);
926945
#if ASSERTIONS
@@ -1043,17 +1062,6 @@ function wrapSyscallFunction(x, library, isWasi) {
10431062
});
10441063
}
10451064

1046-
if (MEMORY64 && !isWasi) {
1047-
t = modifyFunction(t, function(name, args, body) {
1048-
var argnums = args.split(",").map((a) => 'Number(' + a + ')').join();
1049-
return 'function ' + name + '(' + args + ') {\n' +
1050-
' return (function ' + name + '_inner(' + args + ') {\n' +
1051-
body +
1052-
' })(' + argnums + ');' +
1053-
'}';
1054-
});
1055-
}
1056-
10571065
library[x] = eval('(' + t + ')');
10581066
if (!library[x + '__deps']) library[x + '__deps'] = [];
10591067
library[x + '__deps'].push('$SYSCALLS');

tests/test_core.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9267,10 +9267,10 @@ def setUp(self):
92679267
corez = make_run('corez', emcc_args=['-Oz'])
92689268

92699269
# MEMORY64=1
9270-
wasm64 = make_run('wasm64', emcc_args=[], settings={'MEMORY64': 1},
9270+
wasm64 = make_run('wasm64', emcc_args=['--profiling-funcs'], settings={'MEMORY64': 1},
92719271
require_v8=True, v8_args=['--experimental-wasm-memory64'])
92729272
# MEMORY64=2, or "lowered"
9273-
wasm64l = make_run('wasm64l', emcc_args=[], settings={'MEMORY64': 2},
9273+
wasm64l = make_run('wasm64l', emcc_args=['--profiling-funcs'], settings={'MEMORY64': 2},
92749274
node_args=['--experimental-wasm-bigint'])
92759275

92769276
lto0 = make_run('lto0', emcc_args=['-flto', '-O0'])

tools/wasm2c.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ def s_to_c(s):
2020
return 'u32'
2121
elif s == 'j':
2222
return 'u64'
23+
elif s == 'p':
24+
if settings.MEMORY64:
25+
return 'u64'
26+
else:
27+
return 'u32'
2328
elif s == 'f':
2429
return 'f32'
2530
elif s == 'd':

0 commit comments

Comments
 (0)