Skip to content

Commit 10257ae

Browse files
[bigendian] Fix crash during PThread initialization (#23700)
Simple hello world output was built using the instructions from the issue and tested on s390x z/os machine. Fixes: #23689
1 parent e5fd49f commit 10257ae

File tree

6 files changed

+164
-6
lines changed

6 files changed

+164
-6
lines changed

src/lib/liblittle_endian_heap.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,82 @@ var LibraryLittleEndianHeap = {
3434

3535
$LE_HEAP_LOAD_F64: (byteOffset) =>
3636
HEAP_DATA_VIEW.getFloat64(byteOffset, true),
37+
38+
$LE_ATOMICS_NATIVE_BYTE_ORDER__postset: `
39+
LE_ATOMICS_NATIVE_BYTE_ORDER = (new Int8Array(new Int16Array([1]).buffer)[0] === 1)
40+
? [ /* little endian */
41+
(x => x),
42+
(x => x),
43+
undefined,
44+
(x => x),
45+
]
46+
: [ /* big endian */
47+
(x => x),
48+
(x => (((x & 0xff00) << 8) | ((x & 0xff) << 24)) >> 16),
49+
undefined,
50+
(x => ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8) | ((x & 0xff) << 24)),
51+
];
52+
function LE_HEAP_UPDATE() {
53+
HEAPU16.unsigned = (x => x & 0xffff);
54+
HEAPU32.unsigned = (x => x >>> 0);
55+
}
56+
`,
57+
$LE_ATOMICS_NATIVE_BYTE_ORDER: [],
58+
59+
$LE_ATOMICS_ADD: (heap, offset, value) => {
60+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
61+
const res = order(Atomics.add(heap, offset, order(value)));
62+
return heap.unsigned ? heap.unsigned(res) : res;
63+
},
64+
$LE_ATOMICS_AND: (heap, offset, value) => {
65+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
66+
const res = order(Atomics.and(heap, offset, order(value)));
67+
return heap.unsigned ? heap.unsigned(res) : res;
68+
},
69+
$LE_ATOMICS_COMPAREEXCHANGE: (heap, offset, expected, replacement) => {
70+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
71+
const res = order(Atomics.compareExchange(heap, offset, order(expected), order(replacement)));
72+
return heap.unsigned ? heap.unsigned(res) : res;
73+
},
74+
$LE_ATOMICS_EXCHANGE: (heap, offset, value) => {
75+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
76+
const res = order(Atomics.exchange(heap, offset, order(value)));
77+
return heap.unsigned ? heap.unsigned(res) : res;
78+
},
79+
$LE_ATOMICS_ISLOCKFREE: (size) => Atomics.isLockFree(size),
80+
$LE_ATOMICS_LOAD: (heap, offset) => {
81+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
82+
const res = order(Atomics.load(heap, offset));
83+
return heap.unsigned ? heap.unsigned(res) : res;
84+
},
85+
$LE_ATOMICS_NOTIFY: (heap, offset, count) => Atomics.notify(heap, offset, count),
86+
$LE_ATOMICS_OR: (heap, offset, value) => {
87+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
88+
const res = order(Atomics.or(heap, offset, order(value)));
89+
return heap.unsigned ? heap.unsigned(res) : res;
90+
},
91+
$LE_ATOMICS_STORE: (heap, offset, value) => {
92+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
93+
Atomics.store(heap, offset, order(value));
94+
},
95+
$LE_ATOMICS_SUB: (heap, offset, value) => {
96+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
97+
const res = order(Atomics.sub(heap, offset, order(value)));
98+
return heap.unsigned ? heap.unsigned(res) : res;
99+
},
100+
$LE_ATOMICS_WAIT: (heap, offset, value, timeout) => {
101+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
102+
return Atomics.wait(heap, offset, order(value), timeout);
103+
},
104+
$LE_ATOMICS_WAITASYNC: (heap, offset, value, timeout) => {
105+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
106+
return Atomics.waitAsync(heap, offset, order(value), timeout);
107+
},
108+
$LE_ATOMICS_XOR: (heap, offset, value) => {
109+
const order = LE_ATOMICS_NATIVE_BYTE_ORDER[heap.BYTES_PER_ELEMENT - 1];
110+
const res = order(Atomics.xor(heap, offset, order(value)));
111+
return heap.unsigned ? heap.unsigned(res) : res;
112+
},
37113
}
38114

39115
addToLibrary(LibraryLittleEndianHeap);

src/runtime_shared.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ var wasmOffsetConverter;
6666

6767
function updateMemoryViews() {
6868
var b = wasmMemory.buffer;
69-
#if SUPPORT_BIG_ENDIAN
70-
{{{ maybeExportHeap('HEAP_DATA_VIEW') }}} HEAP_DATA_VIEW = new DataView(b);
71-
#endif
7269
{{{ maybeExportHeap('HEAP8') }}}HEAP8 = new Int8Array(b);
7370
{{{ maybeExportHeap('HEAP16') }}}HEAP16 = new Int16Array(b);
7471
{{{ maybeExportHeap('HEAPU8') }}}HEAPU8 = new Uint8Array(b);
@@ -81,6 +78,10 @@ function updateMemoryViews() {
8178
{{{ maybeExportHeap('HEAP64') }}}HEAP64 = new BigInt64Array(b);
8279
{{{ maybeExportHeap('HEAPU64') }}}HEAPU64 = new BigUint64Array(b);
8380
#endif
81+
#if SUPPORT_BIG_ENDIAN
82+
{{{ maybeExportHeap('HEAP_DATA_VIEW') }}} HEAP_DATA_VIEW = new DataView(b);
83+
LE_HEAP_UPDATE();
84+
#endif
8485
}
8586

8687
#if ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 160000

test/js_optimizer/LittleEndianHeap-output.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,23 @@ LE_HEAP_STORE_F64(x * 8, a);
3333
HEAP[x];
3434

3535
HeAp[x];
36+
37+
LE_ATOMICS_ADD(heap, offset, value);
38+
39+
LE_ATOMICS_AND(heap, offset, value);
40+
41+
LE_ATOMICS_COMPAREEXCHANGE(heap, offset, expected, replacement);
42+
43+
LE_ATOMICS_EXCHANGE(heap, offset, value);
44+
45+
LE_ATOMICS_LOAD(heap, offset);
46+
47+
LE_ATOMICS_OR(heap, offset, value);
48+
49+
LE_ATOMICS_SUB(heap, offset, value);
50+
51+
LE_ATOMICS_WAIT(heap, offset, value, timeout);
52+
53+
LE_ATOMICS_WAITASYNC(heap, offset, value, timeout);
54+
55+
LE_ATOMICS_XOR(heap, offset, value);

test/js_optimizer/LittleEndianHeap.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,13 @@ a = HEAPF64[x]; // HEAPF64
1616
HEAPF64[x] = a;
1717
HEAP[x]; // should not be changed
1818
HeAp[x];
19+
Atomics.add(heap, offset, value);
20+
Atomics.and(heap, offset, value);
21+
Atomics.compareExchange(heap, offset, expected, replacement);
22+
Atomics.exchange(heap, offset, value);
23+
Atomics.load(heap, offset);
24+
Atomics.or(heap, offset, value);
25+
Atomics.sub(heap, offset, value);
26+
Atomics.wait(heap, offset, value, timeout);
27+
Atomics.waitAsync(heap, offset, value, timeout);
28+
Atomics.xor(heap, offset, value);

tools/acorn-optimizer.mjs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,10 +1106,21 @@ function littleEndianHeap(ast) {
11061106
recursiveWalk(ast, {
11071107
FunctionDeclaration: (node, c) => {
11081108
// do not recurse into LE_HEAP_STORE, LE_HEAP_LOAD functions
1109-
if (!(node.id.type === 'Identifier' && node.id.name.startsWith('LE_HEAP'))) {
1109+
if (
1110+
!(
1111+
node.id.type === 'Identifier' &&
1112+
(node.id.name.startsWith('LE_HEAP') || node.id.name.startsWith('LE_ATOMICS_'))
1113+
)
1114+
) {
11101115
c(node.body);
11111116
}
11121117
},
1118+
VariableDeclarator: (node, c) => {
1119+
if (!(node.id.type === 'Identifier' && node.id.name.startsWith('LE_ATOMICS_'))) {
1120+
c(node.id);
1121+
if (node.init) c(node.init);
1122+
}
1123+
},
11131124
AssignmentExpression: (node, c) => {
11141125
const target = node.left;
11151126
const value = node.right;
@@ -1160,6 +1171,27 @@ function littleEndianHeap(ast) {
11601171
}
11611172
}
11621173
},
1174+
CallExpression: (node, c) => {
1175+
if (node.arguments) {
1176+
for (var a of node.arguments) c(a);
1177+
}
1178+
if (
1179+
// Atomics.X(args) -> LE_ATOMICS_X(args)
1180+
node.callee.type === 'MemberExpression' &&
1181+
node.callee.object.type === 'Identifier' &&
1182+
node.callee.object.name === 'Atomics' &&
1183+
node.callee.property.type === 'Identifier' &&
1184+
!node.computed
1185+
) {
1186+
makeCallExpression(
1187+
node,
1188+
'LE_ATOMICS_' + node.callee.property.name.toUpperCase(),
1189+
node.arguments,
1190+
);
1191+
} else {
1192+
c(node.callee);
1193+
}
1194+
},
11631195
MemberExpression: (node, c) => {
11641196
c(node.property);
11651197
if (!isHEAPAccess(node)) {
@@ -1217,7 +1249,12 @@ function growableHeap(ast) {
12171249
recursiveWalk(ast, {
12181250
FunctionDeclaration(node, c) {
12191251
// Do not recurse into to GROWABLE_HEAP_ helper functions themselves.
1220-
if (!(node.id.type === 'Identifier' && node.id.name.startsWith('GROWABLE_HEAP_'))) {
1252+
if (
1253+
!(
1254+
node.id.type === 'Identifier' &&
1255+
(node.id.name.startsWith('GROWABLE_HEAP_') || node.id.name === 'LE_HEAP_UPDATE')
1256+
)
1257+
) {
12211258
c(node.body);
12221259
}
12231260
},

tools/link.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,21 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
11221122
'$LE_HEAP_LOAD_U32',
11231123
'$LE_HEAP_LOAD_I32',
11241124
'$LE_HEAP_LOAD_F32',
1125-
'$LE_HEAP_LOAD_F64'
1125+
'$LE_HEAP_LOAD_F64',
1126+
'$LE_ATOMICS_NATIVE_BYTE_ORDER',
1127+
'$LE_ATOMICS_ADD',
1128+
'$LE_ATOMICS_AND',
1129+
'$LE_ATOMICS_COMPAREEXCHANGE',
1130+
'$LE_ATOMICS_EXCHANGE',
1131+
'$LE_ATOMICS_ISLOCKFREE',
1132+
'$LE_ATOMICS_LOAD',
1133+
'$LE_ATOMICS_NOTIFY',
1134+
'$LE_ATOMICS_OR',
1135+
'$LE_ATOMICS_STORE',
1136+
'$LE_ATOMICS_SUB',
1137+
'$LE_ATOMICS_WAIT',
1138+
'$LE_ATOMICS_WAITASYNC',
1139+
'$LE_ATOMICS_XOR',
11261140
]
11271141

11281142
if settings.RUNTIME_DEBUG or settings.ASSERTIONS or settings.STACK_OVERFLOW_CHECK or settings.PTHREADS_PROFILING or settings.GL_ASSERTIONS:

0 commit comments

Comments
 (0)