Skip to content

Commit 6e32d6b

Browse files
committed
[wasm64] making JS bindings wasm64 aware
1 parent aeecd77 commit 6e32d6b

12 files changed

+138
-49
lines changed

src/library_exceptions.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ var LibraryExceptions = {
1313
$ExceptionInfoAttrs: {
1414
// ExceptionInfo native structure layout.
1515
DESTRUCTOR_OFFSET: 0,
16-
REFCOUNT_OFFSET: Runtime.POINTER_SIZE,
17-
TYPE_OFFSET: Runtime.POINTER_SIZE + 4,
18-
CAUGHT_OFFSET: Runtime.POINTER_SIZE + 8,
19-
RETHROWN_OFFSET: Runtime.POINTER_SIZE + 9,
16+
REFCOUNT_OFFSET: {{{ `${POINTER_SIZE}` }}},
17+
TYPE_OFFSET: {{{ `${POINTER_SIZE}` }}} + 4,
18+
CAUGHT_OFFSET: {{{ `${POINTER_SIZE}` }}} + 8,
19+
RETHROWN_OFFSET: {{{ `${POINTER_SIZE}` }}} + 9,
2020

2121
// Total structure size with padding, should be multiple of allocation alignment.
22-
SIZE: alignMemory(Runtime.POINTER_SIZE + 10)
22+
SIZE: alignMemory({{{ `${POINTER_SIZE}` }}} + 10)
2323
},
2424

2525
$ExceptionInfo__deps: ['$ExceptionInfoAttrs'],
@@ -134,12 +134,12 @@ var LibraryExceptions = {
134134
};
135135

136136
this.set_adjusted_ptr = function(adjustedPtr) {
137-
var ptrSize = {{{ Runtime.POINTER_SIZE }}};
137+
var ptrSize = {{{ `${POINTER_SIZE}` }}};
138138
{{{ makeSetValue('this.ptr', 'ptrSize', 'adjustedPtr', '*') }}};
139139
};
140140

141141
this.get_adjusted_ptr = function() {
142-
var ptrSize = {{{ Runtime.POINTER_SIZE }}};
142+
var ptrSize = {{{ `${POINTER_SIZE}` }}};
143143
return {{{ makeGetValue('this.ptr', 'ptrSize', '*') }}};
144144
};
145145

@@ -165,7 +165,7 @@ var LibraryExceptions = {
165165
};
166166

167167
if (ptr === undefined) {
168-
this.ptr = _malloc({{{ Runtime.POINTER_SIZE * 2 }}});
168+
this.ptr = _malloc({{{ `${POINTER_SIZE}` * 2 }}});
169169
this.set_adjusted_ptr(0);
170170
} else {
171171
this.ptr = ptr;

src/library_glfw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,7 @@ var LibraryGLFW = {
12281228
glfwGetMonitors: function(count) {
12291229
setValue(count, 1, 'i32');
12301230
if (!GLFW.monitors) {
1231-
GLFW.monitors = {{{ makeMalloc('glfwGetMonitors', Runtime.POINTER_SIZE) }}};
1231+
GLFW.monitors = {{{ makeMalloc('glfwGetMonitors', `${POINTER_SIZE}`) }}};
12321232
setValue(GLFW.monitors, 1, 'i32');
12331233
}
12341234
return GLFW.monitors;

src/library_wasi.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,16 @@ var WasiLibrary = {
7676

7777
args_sizes_get__sig: 'iii',
7878
args_sizes_get: function(pargc, pargv_buf_size) {
79+
{{{ from64(['pargc', 'pargv_buf_size']) }}};
7980
#if MAIN_READS_PARAMS
80-
{{{ makeSetValue('pargc', 0, 'mainArgs.length', 'i32') }}};
81+
{{{ makeSetValue('pargc', 0, 'mainArgs.length', `${POINTER_TYPE}`) }}};
8182
var bufSize = 0;
8283
mainArgs.forEach(function(arg) {
8384
bufSize += arg.length + 1;
8485
});
85-
{{{ makeSetValue('pargv_buf_size', 0, 'bufSize', 'i32') }}};
86+
{{{ makeSetValue('pargv_buf_size', 0, 'bufSize', `${POINTER_TYPE}`) }}};
8687
#else
87-
{{{ makeSetValue('pargc', 0, '0', 'i32') }}};
88+
{{{ makeSetValue('pargc', 0, '0', `${POINTER_TYPE}`) }}};
8889
#endif
8990
return 0;
9091
},
@@ -94,11 +95,12 @@ var WasiLibrary = {
9495
args_get__deps: ['$writeAsciiToMemory'],
9596
#endif
9697
args_get: function(argv, argv_buf) {
98+
{{{ from64(['argv', 'argv_buf']) }}};
9799
#if MAIN_READS_PARAMS
98100
var bufSize = 0;
99101
mainArgs.forEach(function(arg, i) {
100102
var ptr = argv_buf + bufSize;
101-
{{{ makeSetValue('argv', 'i * 4', 'ptr', 'i32') }}};
103+
{{{ makeSetValue('argv', `i*${POINTER_SIZE}`, 'ptr', `${POINTER_TYPE}`) }}};
102104
writeAsciiToMemory(arg, ptr);
103105
bufSize += arg.length + 1;
104106
});
@@ -163,7 +165,7 @@ var WasiLibrary = {
163165
#if SYSCALLS_REQUIRE_FILESYSTEM == 0 && (!MINIMAL_RUNTIME || EXIT_RUNTIME)
164166
$flush_NO_FILESYSTEM: function() {
165167
// flush anything remaining in the buffers during shutdown
166-
if (typeof _fflush !== 'undefined') _fflush(0);
168+
if (typeof _fflush !== 'undefined') _fflush({{{ sizeT(0) }}});
167169
var buffers = SYSCALLS.buffers;
168170
if (buffers[1].length) SYSCALLS.printChar(1, {{{ charCode("\n") }}});
169171
if (buffers[2].length) SYSCALLS.printChar(2, {{{ charCode("\n") }}});
@@ -175,22 +177,23 @@ var WasiLibrary = {
175177
#endif
176178
fd_write__sig: 'iiiii',
177179
fd_write: function(fd, iov, iovcnt, pnum) {
180+
{{{ from64(['iov', 'iovcnt', 'pnum']) }}};
178181
#if SYSCALLS_REQUIRE_FILESYSTEM
179182
var stream = SYSCALLS.getStreamFromFD(fd);
180183
var num = SYSCALLS.doWritev(stream, iov, iovcnt);
181184
#else
182185
// hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0
183186
var num = 0;
184187
for (var i = 0; i < iovcnt; i++) {
185-
var ptr = {{{ makeGetValue('iov', 'i*8', 'i32') }}};
186-
var len = {{{ makeGetValue('iov', 'i*8 + 4', 'i32') }}};
188+
var ptr = {{{ makeGetValue('iov', `i*${POINTER_SIZE}*2`, `${POINTER_TYPE}`) }}};
189+
var len = {{{ makeGetValue('iov', `i*${POINTER_SIZE}*2 + ${POINTER_SIZE}`, `${POINTER_TYPE}`) }}};
187190
for (var j = 0; j < len; j++) {
188191
SYSCALLS.printChar(fd, HEAPU8[ptr+j]);
189192
}
190193
num += len;
191194
}
192195
#endif // SYSCALLS_REQUIRE_FILESYSTEM
193-
{{{ makeSetValue('pnum', 0, 'num', 'i32') }}}
196+
{{{ makeSetValue('pnum', 0, 'num', `${POINTER_TYPE}`) }}}
194197
return 0;
195198
},
196199

src/parseTools.js

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,18 @@ function isStructPointerType(type) {
162162
return !Compiletime.isNumberType(type) && type[0] == '%';
163163
}
164164

165+
let POINTER_SIZE = MEMORY64 ? 8 : 4;
166+
let POINTER_BITS = POINTER_SIZE * 8;
167+
let POINTER_TYPE = 'i' + POINTER_BITS;
168+
165169
function isPointerType(type) {
166170
return type[type.length-1] == '*';
167171
}
168172

173+
function sizeT(x) {
174+
return MEMORY64 ? `BigInt(${x})` : x;
175+
}
176+
169177
function isArrayType(type) {
170178
return /^\[\d+\ x\ (.*)\]/.test(type);
171179
}
@@ -200,7 +208,7 @@ function isIntImplemented(type) {
200208

201209
// Note: works for iX types and structure types, not pointers (even though they are implemented as ints)
202210
function getBits(type, allowPointers) {
203-
if (allowPointers && isPointerType(type)) return 32;
211+
if (allowPointers && isPointerType(type)) return pointerBits();
204212
if (!type) return 0;
205213
if (type[0] == 'i') {
206214
var left = type.substr(1);
@@ -437,12 +445,6 @@ function checkSafeHeap() {
437445
}
438446

439447
function getHeapOffset(offset, type) {
440-
if (Runtime.getNativeFieldSize(type) > 4) {
441-
if (type == 'i64') {
442-
type = 'i32'; // we emulate 64-bit integer values as 32 in asmjs-unknown-emscripten, but not double
443-
}
444-
}
445-
446448
var sz = Runtime.getNativeTypeSize(type);
447449
var shifts = Math.log(sz)/Math.LN2;
448450
offset = '(' + offset + ')';
@@ -584,7 +586,11 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
584586
return asmCoercion('SAFE_HEAP_LOAD' + ((type in Compiletime.FLOAT_TYPES) ? '_D' : '') + '(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + (!!unsigned+0) + ')', type, unsigned ? 'u' : undefined);
585587
}
586588
}
587-
var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']';
589+
var slab = makeGetSlabs(ptr, type, false, unsigned)[0];
590+
var ret = slab + '[' + getHeapOffset(offset, type) + ']';
591+
if (slab.substr(slab.length - 2) == '64') {
592+
ret = `Number(${ret})`;
593+
}
588594
if (forceAsm) {
589595
ret = asmCoercion(ret, type);
590596
}
@@ -621,10 +627,6 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
621627
return '(' + makeSetTempDouble(0, 'double', value) + ',' +
622628
makeSetValue(ptr, pos, makeGetTempDouble(0, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
623629
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), makeGetTempDouble(1, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
624-
} else if (type == 'i64') {
625-
return '(tempI64 = [' + splitI64(value) + '],' +
626-
makeSetValue(ptr, pos, 'tempI64[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
627-
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempI64[1]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
628630
}
629631

630632
var bits = getBits(type);
@@ -664,7 +666,12 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
664666
return 'SAFE_HEAP_STORE' + ((type in Compiletime.FLOAT_TYPES) ? '_D' : '') + '(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ')';
665667
}
666668
}
667-
return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type) + ']=' + value }).join(sep);
669+
return makeGetSlabs(ptr, type, true).map(function(slab) {
670+
if (slab.substr(slab.length - 2) == '64') {
671+
value = `BigInt(${value})`;
672+
}
673+
return slab + '[' + getHeapOffset(offset, type) + ']=' + value
674+
}).join(sep);
668675
}
669676

670677
var UNROLL_LOOP_MAX = 8;
@@ -819,12 +826,13 @@ function calcFastOffset(ptr, pos, noNeedFirst) {
819826

820827
function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
821828
assert(type);
822-
if (isPointerType(type)) type = 'i32'; // Hardcoded 32-bit
829+
if (isPointerType(type)) type = POINTER_TYPE;
823830
switch(type) {
824831
case 'i1': case 'i8': return [unsigned ? 'HEAPU8' : 'HEAP8']; break;
825832
case 'i16': return [unsigned ? 'HEAPU16' : 'HEAP16']; break;
826833
case '<4 x i32>':
827-
case 'i32': case 'i64': return [unsigned ? 'HEAPU32' : 'HEAP32']; break;
834+
case 'i32': return [unsigned ? 'HEAPU32' : 'HEAP32']; break;
835+
case 'i64': return [unsigned ? 'HEAPU64' : 'HEAP64']; break;
828836
case 'double': return ['HEAPF64'];
829837
case '<4 x float>':
830838
case 'float': return ['HEAPF32'];
@@ -862,10 +870,7 @@ function makeThrow(what) {
862870
}
863871

864872
function makeSignOp(value, type, op, force, ignore) {
865-
if (type == 'i64') {
866-
return value; // these are always assumed to be two 32-bit unsigneds.
867-
}
868-
if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
873+
if (isPointerType(type)) type = POINTER_TYPE;
869874
if (!value) return value;
870875
var bits, full;
871876
if (type[0] === 'i') {
@@ -1214,6 +1219,20 @@ function sendI64Argument(low, high) {
12141219
}
12151220
}
12161221

1222+
// Any function called from wasm64 may have bigint args, this function takes
1223+
// a list of variable names to convert to number.
1224+
function from64(x) {
1225+
if (!MEMORY64)
1226+
return '';
1227+
if (Array.isArray(x)) {
1228+
var ret = '';
1229+
for (e of x) ret += from64(e);
1230+
return ret;
1231+
} else {
1232+
return `${x} = Number(${x});`;
1233+
}
1234+
}
1235+
12171236
// Add assertions to catch common errors when using the Promise object we
12181237
// create on Module.ready() and return from MODULARIZE Module() invocations.
12191238
function addReadyPromiseAssertions(promise) {

src/postamble.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ function callMain(args) {
144144
args = args || [];
145145

146146
var argc = args.length+1;
147-
var argv = stackAlloc((argc + 1) * {{{ Runtime.POINTER_SIZE }}});
147+
var argv = stackAlloc((argc + 1) * {{{ `${POINTER_SIZE}` }}});
148148
HEAP32[argv >> 2] = allocateUTF8OnStack(thisProgram);
149149
for (var i = 1; i < argc; i++) {
150150
HEAP32[(argv >> 2) + i] = allocateUTF8OnStack(args[i - 1]);
@@ -163,7 +163,7 @@ function callMain(args) {
163163

164164
#if ABORT_ON_WASM_EXCEPTIONS
165165
// See abortWrapperDepth in preamble.js!
166-
abortWrapperDepth += 2;
166+
abortWrapperDepth += 2;
167167
#endif
168168

169169
#if PROXY_TO_PTHREAD
@@ -222,7 +222,7 @@ function callMain(args) {
222222

223223
#if ABORT_ON_WASM_EXCEPTIONS
224224
// See abortWrapperDepth in preamble.js!
225-
abortWrapperDepth -= 2;
225+
abortWrapperDepth -= 2;
226226
#endif
227227
}
228228
}

src/preamble.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ var HEAP,
256256
HEAP32,
257257
/** @type {Uint32Array} */
258258
HEAPU32,
259+
/** @type {BigInt64Array} */
260+
HEAP64,
261+
/** @type {BigUint64Array} */
262+
HEAPU64,
259263
/** @type {Float32Array} */
260264
HEAPF32,
261265
/** @type {Float64Array} */
@@ -266,9 +270,11 @@ function updateGlobalBufferAndViews(buf) {
266270
Module['HEAP8'] = HEAP8 = new Int8Array(buf);
267271
Module['HEAP16'] = HEAP16 = new Int16Array(buf);
268272
Module['HEAP32'] = HEAP32 = new Int32Array(buf);
273+
Module['HEAP64'] = HEAP64 = new BigInt64Array(buf);
269274
Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf);
270275
Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf);
271276
Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf);
277+
Module['HEAPU64'] = HEAPU64 = new BigUint64Array(buf);
272278
Module['HEAPF32'] = HEAPF32 = new Float32Array(buf);
273279
Module['HEAPF64'] = HEAPF64 = new Float64Array(buf);
274280
}
@@ -728,6 +734,50 @@ function instrumentWasmTableWithAbort() {
728734
}
729735
#endif
730736

737+
#if MEMORY64
738+
// In memory64 mode wasm pointers are 64-bit. To support that in JS we must use
739+
// BigInts. For now we keep JS as much the same as it always was, that is,
740+
// stackAlloc() receives and returns a Number from the JS point of view -
741+
// we translate BigInts automatically for that.
742+
function instrumentWasmExportsForMemory64(exports) {
743+
var instExports = {};
744+
for (var name in exports) {
745+
(function(name) {
746+
var original = exports[name];
747+
var replacement = original;
748+
if (name === 'stackAlloc' || name === 'malloc') {
749+
// get one i64, return an i64
750+
replacement = function(x) {
751+
var r = Number(original(BigInt(x)));
752+
return r;
753+
};
754+
} else if (name === 'free') {
755+
// get one i64
756+
replacement = function(x) {
757+
original(BigInt(x));
758+
};
759+
} else if (name === 'emscripten_stack_get_end' ||
760+
name === 'emscripten_stack_get_base' ||
761+
name === 'emscripten_stack_get_current') {
762+
// return an i64
763+
replacement = function(x) {
764+
var r = Number(original(x));
765+
return r;
766+
};
767+
} else if (name === 'main') {
768+
// get a i64 as second arg
769+
replacement = function(x, y) {
770+
var r = original(x, BigInt(y));
771+
return r;
772+
};
773+
}
774+
instExports[name] = replacement;
775+
})(name);
776+
}
777+
return instExports;
778+
}
779+
#endif MEMORY64
780+
731781
var wasmBinaryFile = '{{{ WASM_BINARY_FILE }}}';
732782
if (!isDataURI(wasmBinaryFile)) {
733783
wasmBinaryFile = locateFile(wasmBinaryFile);
@@ -819,6 +869,10 @@ function createWasm() {
819869
exports = relocateExports(exports, {{{ GLOBAL_BASE }}});
820870
#endif
821871

872+
#if MEMORY64
873+
exports = instrumentWasmExportsForMemory64(exports);
874+
#endif
875+
822876
#if ASYNCIFY
823877
exports = Asyncify.instrumentWasmExports(exports);
824878
#endif

src/runtime.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ var Compiletime = {
2121
// code used both at compile time and runtime is defined here, then put on
2222
// the Runtime object for compile time and support.js for the generated code
2323

24+
function getPointerSize() {
25+
return MEMORY64 ? 8 : 4;
26+
}
27+
2428
function getNativeTypeSize(type) {
2529
switch (type) {
2630
case 'i1': case 'i8': return 1;
@@ -31,7 +35,7 @@ function getNativeTypeSize(type) {
3135
case 'double': return 8;
3236
default: {
3337
if (type[type.length-1] === '*') {
34-
return 4; // A pointer
38+
return getPointerSize();
3539
} else if (type[0] === 'i') {
3640
var bits = Number(type.substr(1));
3741
assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type);
@@ -58,8 +62,8 @@ var Runtime = {
5862
return Math.max(getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
5963
},
6064

61-
POINTER_SIZE: 4,
62-
QUANTUM_SIZE: 4,
65+
POINTER_SIZE: getPointerSize(),
66+
QUANTUM_SIZE: getPointerSize(),
6367
};
6468

6569
// Additional runtime elements, that need preprocessing

0 commit comments

Comments
 (0)