mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-27 06:43:19 +08:00
Borrow the array of an inline Atomics operation from its local
emitInlineAtomicsOp read its typed array with emitExpr, so every Atomics call on a local array retained the array before the atomic instruction and released it after, two out-of-line calls around one instruction. The array now goes through emitBorrowedInput: an unchanged, unboxed local owns it across the later operands and the operation, and the instruction and scr_atomics_op only read it. Fields, globals, captures and bindings an operand can reassign keep their own reference.
This commit is contained in:
@@ -1118,7 +1118,9 @@ export function emitInlineAtomicsOp(
|
||||
if (op !== 0 && op !== 1 && op !== 3 && ATOMIC_RMW[op] === undefined) return null;
|
||||
const elem = array.type.elem;
|
||||
const B = host.B;
|
||||
const receiver = host.emitExpr(array).name;
|
||||
// The instruction and scr_atomics_op borrow the array: an unchanged local
|
||||
// owns it across the later operands and the operation.
|
||||
const receiver = emitBorrowedInput(host, array).name;
|
||||
const idxValue = host.emitExpr(index);
|
||||
const operand = host.emitExpr(value);
|
||||
const swap = host.emitExpr(replacement);
|
||||
|
||||
@@ -61,3 +61,32 @@ console.log(work(new Int32Array(buffer), new Uint8Array(buffer), new Int16Array(
|
||||
expect(calls).toHaveLength(9);
|
||||
for (const call of calls) expect(call).toMatch(/\) cold$/);
|
||||
});
|
||||
|
||||
test("an unchanged local array is borrowed across Atomics operations", async () => {
|
||||
const llvm = await emittedLlvm(
|
||||
"borrow",
|
||||
`function count(buffer: SharedArrayBuffer, n: number): number {
|
||||
const cells = new Int32Array(buffer);
|
||||
for (let i = 0; i < n; i++) {
|
||||
Atomics.add(cells, 0, 1);
|
||||
Atomics.compareExchange(cells, 1, Atomics.load(cells, 1), i);
|
||||
}
|
||||
return Atomics.load(cells, 0);
|
||||
}
|
||||
function swap(buffer: SharedArrayBuffer, other: SharedArrayBuffer): number {
|
||||
let cells = new Int32Array(buffer);
|
||||
return Atomics.add(cells, ((cells = new Int32Array(other)), 0), 1);
|
||||
}
|
||||
const buffer = new SharedArrayBuffer(16);
|
||||
console.log(count(buffer, 3), swap(buffer, new SharedArrayBuffer(16)));
|
||||
`,
|
||||
);
|
||||
// The local owns the array across each operation: no reference count
|
||||
// operations around the atomic instructions.
|
||||
const counted = body(llvm, "sc_bf_count");
|
||||
expect(counted).toMatch(/atomicrmw add ptr/);
|
||||
expect(counted).not.toMatch(/call ptr @scr_bytes_retain_v/);
|
||||
// An operand that reassigns the binding releases the old array, so the
|
||||
// operation keeps its own reference.
|
||||
expect(body(llvm, "sc_bf_swap")).toMatch(/call ptr @scr_bytes_retain_v/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user