Skip to content

Commit 42df2fb

Browse files
authored
[Memory64] Core JS runtime changes for 64-bit (#15219)
* [Memory64] Core JS runtime changes for 64-bit * Code review changes
1 parent 4d73ba0 commit 42df2fb

File tree

6 files changed

+73
-16
lines changed

6 files changed

+73
-16
lines changed

src/library.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ LibraryManager.library = {
9191
utime__proxy: 'sync',
9292
utime__sig: 'iii',
9393
utime: function(path, times) {
94+
{{{ from64('times') }}};
9495
// int utime(const char *path, const struct utimbuf *times);
9596
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/utime.h.html
9697
var time;
@@ -458,6 +459,7 @@ LibraryManager.library = {
458459

459460
time__sig: 'ii',
460461
time: function(ptr) {
462+
{{{ from64('ptr') }}};
461463
var ret = (Date.now()/1000)|0;
462464
if (ptr) {
463465
{{{ makeSetValue('ptr', 0, 'ret', 'i32') }}};
@@ -3102,6 +3104,7 @@ LibraryManager.library = {
31023104
$readAsmConstArgsArray: '=[]',
31033105
$readAsmConstArgs__deps: ['$readAsmConstArgsArray'],
31043106
$readAsmConstArgs: function(sigPtr, buf) {
3107+
{{{ from64(['sigPtr', 'buf']) }}};
31053108
#if ASSERTIONS
31063109
// Nobody should have mutated _readAsmConstArgsArray underneath us to be something else than an array.
31073110
assert(Array.isArray(readAsmConstArgsArray));
@@ -3646,20 +3649,23 @@ LibraryManager.library = {
36463649
// mode are created here and imported by the module.
36473650
// Mark with `__import` so these are usable from native code. This is needed
36483651
// because, by default, only functions can be be imported.
3649-
__stack_pointer: "new WebAssembly.Global({'value': 'i32', 'mutable': true}, {{{ STACK_BASE }}})",
3652+
__stack_pointer: "new WebAssembly.Global({'value': '{{{ POINTER_TYPE }}}', 'mutable': true}, {{{ to64(STACK_BASE) }}})",
36503653
__stack_pointer__import: true,
36513654
// tell the memory segments where to place themselves
3652-
__memory_base: '{{{ GLOBAL_BASE }}}',
3655+
__memory_base: "new WebAssembly.Global({'value': '{{{ POINTER_TYPE }}}', 'mutable': false}, {{{ to64(GLOBAL_BASE) }}})",
36533656
__memory_base__import: true,
36543657
// the wasm backend reserves slot 0 for the NULL function pointer
3655-
__table_base: 1,
3658+
__table_base: "new WebAssembly.Global({'value': '{{{ POINTER_TYPE }}}', 'mutable': false}, {{{ to64(1) }}})",
36563659
__table_base__import: true,
3660+
#if MEMORY64
3661+
__table_base32: 1,
3662+
#endif
36573663
// To support such allocations during startup, track them on __heap_base and
36583664
// then when the main module is loaded it reads that value and uses it to
36593665
// initialize sbrk (the main module is relocatable itself, and so it does not
36603666
// have __heap_base hardcoded into it - it receives it from JS as an extern
36613667
// global, basically).
3662-
__heap_base: '{{{ HEAP_BASE }}}',
3668+
__heap_base: '{{{ to64(HEAP_BASE) }}}',
36633669
__heap_base__import: true,
36643670
#endif
36653671
};

src/library_formatString.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ mergeInto(LibraryManager.library, {
5252
#endif
5353
],
5454
$formatString: function(format, varargs) {
55+
{{{ from64(['format', 'varargs']) }}};
5556
#if ASSERTIONS
5657
assert((varargs & 3) === 0);
5758
#endif
@@ -470,6 +471,7 @@ mergeInto(LibraryManager.library, {
470471
// printf/puts/strlen implementations for when musl is not pulled in - very
471472
// partial. useful for tests, and when bootstrapping structInfo
472473
strlen: function(ptr) {
474+
{{{ from64('ptr') }}};
473475
var end = ptr;
474476
while (HEAPU8[end]) ++end;
475477
return end - ptr;

src/parseTools.js

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,20 @@ function isStructPointerType(type) {
197197
return !Compiletime.isNumberType(type) && type[0] == '%';
198198
}
199199

200+
const POINTER_SIZE = MEMORY64 ? 8 : 4;
201+
const POINTER_BITS = POINTER_SIZE * 8;
202+
const POINTER_TYPE = 'i' + POINTER_BITS;
203+
204+
const SIZE_TYPE = POINTER_TYPE;
205+
200206
function isPointerType(type) {
201207
return type[type.length - 1] == '*';
202208
}
203209

210+
function sizeT(x) {
211+
return MEMORY64 ? `BigInt(${x})` : x;
212+
}
213+
204214
function isArrayType(type) {
205215
return /^\[\d+\ x\ (.*)\]/.test(type);
206216
}
@@ -235,7 +245,7 @@ function isIntImplemented(type) {
235245

236246
// Note: works for iX types and structure types, not pointers (even though they are implemented as ints)
237247
function getBits(type, allowPointers) {
238-
if (allowPointers && isPointerType(type)) return 32;
248+
if (allowPointers && isPointerType(type)) return POINTER_SIZE;
239249
if (!type) return 0;
240250
if (type[0] == 'i') {
241251
const left = type.substr(1);
@@ -480,7 +490,7 @@ function checkSafeHeap() {
480490
}
481491

482492
function getHeapOffset(offset, type) {
483-
if (type == 'i64') {
493+
if (!WASM_BIGINT && Runtime.getNativeFieldSize(type) > 4 && type == 'i64') {
484494
// we emulate 64-bit integer values as 32 in asmjs-unknown-emscripten, but not double
485495
type = 'i32';
486496
}
@@ -623,7 +633,16 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
623633
return asmCoercion('SAFE_HEAP_LOAD' + ((type in Compiletime.FLOAT_TYPES) ? '_D' : '') + '(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + (!!unsigned + 0) + ')', type, unsigned ? 'u' : undefined);
624634
}
625635
}
626-
return getHeapForType(type, unsigned) + '[' + getHeapOffset(offset, type) + ']';
636+
637+
const slab = getHeapForType(type, unsigned);
638+
let ret = slab + '[' + getHeapOffset(offset, type) + ']';
639+
if (slab.substr(slab.length - 2) == '64') {
640+
ret = `Number(${ret})`;
641+
}
642+
if (forceAsm) {
643+
ret = asmCoercion(ret, type);
644+
}
645+
return ret;
627646
}
628647

629648
/**
@@ -665,7 +684,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
665684
return '(' + makeSetTempDouble(0, 'double', value) + ',' +
666685
makeSetValue(ptr, pos, makeGetTempDouble(0, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
667686
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), makeGetTempDouble(1, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
668-
} else if (type == 'i64') {
687+
} else if (!WASM_BIGINT && type == 'i64') {
669688
return '(tempI64 = [' + splitI64(value) + '],' +
670689
makeSetValue(ptr, pos, 'tempI64[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
671690
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempI64[1]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
@@ -705,7 +724,12 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
705724
return 'SAFE_HEAP_STORE' + ((type in Compiletime.FLOAT_TYPES) ? '_D' : '') + '(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ')';
706725
}
707726
}
708-
return getHeapForType(type) + '[' + getHeapOffset(offset, type) + '] = ' + value;
727+
728+
const slab = getHeapForType(type);
729+
if (slab == 'HEAPU64' || slab == 'HEAP64') {
730+
value = `BigInt(${value})`;
731+
}
732+
return slab + '[' + getHeapOffset(offset, type) + '] = ' + value;
709733
}
710734

711735
const UNROLL_LOOP_MAX = 8;
@@ -862,23 +886,29 @@ function getFastValue(a, op, b, type) {
862886

863887
function calcFastOffset(ptr, pos, noNeedFirst) {
864888
assert(!noNeedFirst);
889+
if (typeof ptr == 'bigint') ptr = Number(ptr);
890+
if (typeof pos == 'bigint') pos = Number(pos);
865891
return getFastValue(ptr, '+', pos, 'i32');
866892
}
867893

868894
function getHeapForType(type, unsigned) {
869895
assert(type);
870896
if (isPointerType(type)) {
871-
type = 'i32'; // Hardcoded 32-bit
897+
type = POINTER_TYPE;
872898
}
873899
switch (type) {
874900
case 'i1':
875901
case 'i8':
876902
return unsigned ? 'HEAPU8' : 'HEAP8';
877903
case 'i16':
878904
return unsigned ? 'HEAPU16' : 'HEAP16';
905+
case 'i64':
906+
if (WASM_BIGINT) {
907+
return unsigned ? 'HEAPU64' : 'HEAP64';
908+
}
909+
// fall through
879910
case '<4 x i32>':
880911
case 'i32':
881-
case 'i64':
882912
return unsigned ? 'HEAPU32' : 'HEAP32';
883913
case 'double':
884914
return 'HEAPF64';
@@ -908,10 +938,7 @@ function makeThrow(what) {
908938
}
909939

910940
function makeSignOp(value, type, op, force, ignore) {
911-
if (type == 'i64') {
912-
return value; // these are always assumed to be two 32-bit unsigneds.
913-
}
914-
if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
941+
if (isPointerType(type)) type = POINTER_TYPE;
915942
if (!value) return value;
916943
let bits;
917944
let full;
@@ -1292,6 +1319,26 @@ function sendI64Argument(low, high) {
12921319
return low + ', ' + high;
12931320
}
12941321

1322+
// Any function called from wasm64 may have bigint args, this function takes
1323+
// a list of variable names to convert to number.
1324+
function from64(x) {
1325+
if (!MEMORY64) {
1326+
return '';
1327+
}
1328+
if (Array.isArray(x)) {
1329+
let ret = '';
1330+
for (e of x) ret += from64(e);
1331+
return ret;
1332+
} else {
1333+
return `${x} = Number(${x});`;
1334+
}
1335+
}
1336+
1337+
function to64(x) {
1338+
if (!MEMORY64) return x;
1339+
return `BigInt(${x})`;
1340+
}
1341+
12951342
// Add assertions to catch common errors when using the Promise object we
12961343
// create on Module.ready() and return from MODULARIZE Module() invocations.
12971344
function addReadyPromiseAssertions(promise) {

src/postamble.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ function stackCheckInit() {
215215
// here.
216216
// TODO(sbc): Move writeStackCookie to native to to avoid this.
217217
#if RELOCATABLE
218-
_emscripten_stack_set_limits({{{ STACK_BASE }}}, {{{ STACK_MAX }}});
218+
_emscripten_stack_set_limits({{{ to64(STACK_BASE) }}}, {{{ to64(STACK_MAX) }}});
219219
#else
220220
_emscripten_stack_init();
221221
#endif

src/runtime_strings.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ function UTF8ArrayToString(heap, idx, maxBytesToRead) {
128128
* @return {string}
129129
*/
130130
function UTF8ToString(ptr, maxBytesToRead) {
131+
{{{ from64('ptr') }}};
131132
#if CAN_ADDRESS_2GB
132133
ptr >>>= 0;
133134
#endif

src/settings.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ var MEMORY_GROWTH_LINEAR_STEP = -1;
237237
// the full end-to-end wasm64 mode, and 2 is wasm64 for clang/lld but lowered to
238238
// wasm32 in Binaryen (such that it can run on wasm32 engines, while internally
239239
// using i64 pointers).
240+
// Assumes WASM_BIGINT.
240241
// [compile+link]
241242
var MEMORY64 = 0;
242243

0 commit comments

Comments
 (0)