Skip to content

Commit

Permalink
fix: Crash during PThread initialization on big-endian machine
Browse files Browse the repository at this point in the history
  • Loading branch information
slavek-kucera committed Feb 20, 2025
1 parent 4204bc3 commit 76f6d46
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 2 deletions.
47 changes: 47 additions & 0 deletions src/lib/liblittle_endian_heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,53 @@ var LibraryLittleEndianHeap = {

$LE_HEAP_LOAD_F64: (byteOffset) =>
HEAP_DATA_VIEW.getFloat64(byteOffset, true),

$LE_ATOMICS_ADD: (heap, offset, value) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.add(heap, offset, order(value)));
},
$LE_ATOMICS_AND: (heap, offset, value) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.and(heap, offset, order(value)));
},
$LE_ATOMICS_COMPAREEXCHANGE: (heap, offset, expected, replacement) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.compareExchange(heap, offset, order(expected), order(replacement)));
},
$LE_ATOMICS_EXCHANGE: (heap, offset, value) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.exchange(heap, offset, order(value)));
},
$LE_ATOMICS_ISLOCKFREE: (size) => Atomics.isLockFree(size),
$LE_ATOMICS_LOAD: (heap, offset) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.load(heap, offset));
},
$LE_ATOMICS_NOTIFY: (heap, offset, count) => Atomics.notify(heap, offset, count),
$LE_ATOMICS_OR: (heap, offset, value) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.or(heap, offset, order(value)));
},
$LE_ATOMICS_STORE: (heap, offset, value) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
Atomics.store(heap, offset, order(value));
},
$LE_ATOMICS_SUB: (heap, offset, value) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.sub(heap, offset, order(value)));
},
$LE_ATOMICS_WAIT: (heap, offset, value, timeout) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return Atomics.wait(heap, offset, order(value), timeout);
},
$LE_ATOMICS_WAITASYNC: (heap, offset, value, timeout) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return Atomics.waitAsync(heap, offset, order(value), timeout);
},
$LE_ATOMICS_XOR: (heap, offset, value) => {
const order = nativeByteOrder[heap.BYTES_PER_ELEMENT - 1];
return order(Atomics.xor(heap, offset, order(value)));
},
}

addToLibrary(LibraryLittleEndianHeap);
41 changes: 41 additions & 0 deletions src/runtime_shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,47 @@ function updateMemoryViews() {
#endif
}

#if SUPPORT_BIG_ENDIAN
var nativeByteOrder = (() => {
var h16 = new Int16Array(1);
var h8 = new Int8Array(h16.buffer);
h16[0] = 42;
return h8[0] === 42 && h8[1] === 0; // little endian ordering
})()
? [ /* little endian */
(x => x),
(x => x),
undefined,
(x => x),
#if WASM_BIGINT
undefined,
undefined,
undefined,
(x => x),
#endif
]
: [ /* big endian */
(x => x),
(x => ((x >> 8) & 0xff) | ((x & 0xff) << 8)),
undefined,
(x => ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8) | ((x & 0xff) << 24)),
#if WASM_BIGINT
undefined,
undefined,
undefined,
(x => ((x >> BigInt(56)) & BigInt(0x000000ff))
| ((x >> BigInt(40)) & BigInt(0x0000ff00))
| ((x >> BigInt(24)) & BigInt(0x00ff0000))
| ((x >> BigInt(8)) & BigInt(0xff000000))
| ((x & BigInt(0xff000000)) << BigInt(8) )
| ((x & BigInt(0x00ff0000)) << BigInt(24))
| ((x & BigInt(0x0000ff00)) << BigInt(40))
| ((x & BigInt(0x000000ff)) << BigInt(56))
),
#endif
];
#endif

#if ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 160000
// The performance global was added to node in v16.0.0:
// https://nodejs.org/api/globals.html#performance
Expand Down
20 changes: 20 additions & 0 deletions test/js_optimizer/LittleEndianHeap-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,23 @@ LE_HEAP_STORE_F64(x * 8, a);
HEAP[x];

HeAp[x];

LE_ATOMICS_ADD(heap, offset, value);

LE_ATOMICS_AND(heap, offset, value);

LE_ATOMICS_COMPAREEXCHANGE(heap, offset, expected, replacement);

LE_ATOMICS_EXCHANGE(heap, offset, value);

LE_ATOMICS_LOAD(heap, offset);

LE_ATOMICS_OR(heap, offset, value);

LE_ATOMICS_SUB(heap, offset, value);

LE_ATOMICS_WAIT(heap, offset, value, timeout);

LE_ATOMICS_WAITASYNC(heap, offset, value, timeout);

LE_ATOMICS_XOR(heap, offset, value);
10 changes: 10 additions & 0 deletions test/js_optimizer/LittleEndianHeap.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,13 @@ a = HEAPF64[x]; // HEAPF64
HEAPF64[x] = a;
HEAP[x]; // should not be changed
HeAp[x];
Atomics.add(heap, offset, value);
Atomics.and(heap, offset, value);
Atomics.compareExchange(heap, offset, expected, replacement);
Atomics.exchange(heap, offset, value);
Atomics.load(heap, offset);
Atomics.or(heap, offset, value);
Atomics.sub(heap, offset, value);
Atomics.wait(heap, offset, value, timeout);
Atomics.waitAsync(heap, offset, value, timeout);
Atomics.xor(heap, offset, value);
27 changes: 26 additions & 1 deletion tools/acorn-optimizer.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1106,10 +1106,17 @@ function littleEndianHeap(ast) {
recursiveWalk(ast, {
FunctionDeclaration: (node, c) => {
// do not recurse into LE_HEAP_STORE, LE_HEAP_LOAD functions
if (!(node.id.type === 'Identifier' && node.id.name.startsWith('LE_HEAP'))) {
if (!(node.id.type === 'Identifier' && (node.id.name.startsWith('LE_HEAP') || node.id.name.startsWith('LE_ATOMICS_')))) {
c(node.body);
}
},
VariableDeclarator: (node, c) => {
if (!(node.id.type === 'Identifier' && node.id.name.startsWith('LE_ATOMICS_'))) {
c(node.id);
if (node.init)
c(node.init)
}
},
AssignmentExpression: (node, c) => {
const target = node.left;
const value = node.right;
Expand Down Expand Up @@ -1160,6 +1167,24 @@ function littleEndianHeap(ast) {
}
}
},
CallExpression: (node, c) => {
if (node.arguments) {
for (var a of node.arguments)
c(a);
}
if ( // Atomics.X(args) -> LE_ATOMICS_X(args)
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'Atomics' &&
node.callee.property.type === 'Identifier' &&
!node.computed
) {
makeCallExpression(node, 'LE_ATOMICS_' + node.callee.property.name.toUpperCase(), node.arguments);
}
else {
c(node.callee);
}
},
MemberExpression: (node, c) => {
c(node.property);
if (!isHEAPAccess(node)) {
Expand Down
15 changes: 14 additions & 1 deletion tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,20 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
'$LE_HEAP_LOAD_U32',
'$LE_HEAP_LOAD_I32',
'$LE_HEAP_LOAD_F32',
'$LE_HEAP_LOAD_F64'
'$LE_HEAP_LOAD_F64',
'$LE_ATOMICS_ADD',
'$LE_ATOMICS_AND',
'$LE_ATOMICS_COMPAREEXCHANGE',
'$LE_ATOMICS_EXCHANGE',
'$LE_ATOMICS_ISLOCKFREE',
'$LE_ATOMICS_LOAD',
'$LE_ATOMICS_NOTIFY',
'$LE_ATOMICS_OR',
'$LE_ATOMICS_STORE',
'$LE_ATOMICS_SUB',
'$LE_ATOMICS_WAIT',
'$LE_ATOMICS_WAITASYNC',
'$LE_ATOMICS_XOR',
]

if settings.RUNTIME_DEBUG or settings.ASSERTIONS or settings.STACK_OVERFLOW_CHECK or settings.PTHREADS_PROFILING or settings.GL_ASSERTIONS:
Expand Down

0 comments on commit 76f6d46

Please sign in to comment.