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
|
// |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) {
var ta = new Int32Array(gsab);
// 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(ta, 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});
// Pass |gsab| to the mailbox.
setSharedObject(gsab);
// Start the worker.
evalInWorker(`
(${worker})(getSharedObject());
`);
// Wait until worker is ready.
var ta = new Int32Array(gsab);
while (Atomics.load(ta, 0) === 0);
return gsab;
}
function testGrowableSharedArrayBufferByteLength() {
var gsab = setup();
var ta = new Int32Array(gsab);
var r = 0;
// |gsab.byteLength| is a seq-cst load, so it must prevent reordering any
// other loads, including unordered loads like |ta[2]|.
while (gsab.byteLength <= 12) {
// |ta[2]| is an unordered load, so it's hoistable by default.
r += ta[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 ta[2] can't be hoisted"
);
}
testGrowableSharedArrayBufferByteLength();
|