1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
// |jit-test| --enable-arraybuffer-resizable; skip-if: !ArrayBuffer.prototype.resize||!this.SharedArrayBuffer||helperThreadCount()===0
function setup() {
// Shared memory locations:
//
// 0: Lock
// 1: Sleep
// 2: Data
// 3: Unused
function worker(gsab, sab) {
var ta = new Int32Array(gsab);
var ta2 = new Int32Array(sab);
// Notify the main thread that the worker is ready.
Atomics.store(ta, 0, 1);
// Sleep to give the main thread time to execute and tier-up the loop.
Atomics.wait(ta, 1, 0, 500);
// Modify the memory read in the loop.
Atomics.store(ta2, 2, 1);
// Sleep again to give the main thread time to execute the loop.
Atomics.wait(ta, 1, 0, 100);
// Grow the buffer. This modifies the loop condition.
gsab.grow(16);
}
var gsab = new SharedArrayBuffer(12, {maxByteLength: 16});
var sab = new SharedArrayBuffer(12);
// Start the worker.
{
let buffers = [gsab, sab];
// Shared memory locations:
//
// 0: Number of buffers
// 1: Ready-Flag Worker
// 2: Ready-Flag Main
let sync = new Int32Array(new SharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT));
sync[0] = buffers.length;
setSharedObject(sync.buffer);
evalInWorker(`
let buffers = [];
let sync = new Int32Array(getSharedObject());
let n = sync[0];
for (let i = 0; i < n; ++i) {
// Notify we're ready to receive.
Atomics.store(sync, 1, 1);
// Wait until buffer is in mailbox.
while (Atomics.compareExchange(sync, 2, 1, 0) !== 1);
buffers.push(getSharedObject());
}
(${worker})(...buffers);
`);
for (let buffer of buffers) {
// Wait until worker is ready.
while (Atomics.compareExchange(sync, 1, 1, 0) !== 1);
setSharedObject(buffer);
// Notify buffer is in mailbox.
Atomics.store(sync, 2, 1);
}
}
// Wait until worker is ready.
var ta = new Int32Array(gsab);
while (Atomics.load(ta, 0) === 0);
return {gsab, sab};
}
function testGrowableSharedArrayBufferByteLength() {
var {gsab, sab} = setup();
var ta2 = new Int32Array(sab);
var r = 0;
// |gsab.byteLength| is a seq-cst load, so it must prevent reordering any
// other loads, including unordered loads like |ta2[2]|.
while (gsab.byteLength <= 12) {
// |ta2[2]| is an unordered load, so it's hoistable by default.
r += ta2[2];
}
// The memory location is first modified and then the buffer is grown, so we
// must observe reads of the modified memory location before exiting the loop.
assertEq(
r > 0,
true,
"gsab.byteLength acts as a memory barrier, so ta2[2] can't be hoisted"
);
}
testGrowableSharedArrayBufferByteLength();
|