OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Flags: --allow-natives-syntax --harmony-sharedarraybuffer | 5 // Flags: --allow-natives-syntax --harmony-sharedarraybuffer |
6 | 6 |
7 (function TestFailsWithNonSharedArray() { | 7 (function TestFailsWithNonSharedArray() { |
8 var ab = new ArrayBuffer(16); | 8 var ab = new ArrayBuffer(16); |
9 | 9 |
10 var i8a = new Int8Array(ab); | 10 var i8a = new Int8Array(ab); |
11 var i16a = new Int16Array(ab); | 11 var i16a = new Int16Array(ab); |
12 var i32a = new Int32Array(ab); | 12 var i32a = new Int32Array(ab); |
13 var ui8a = new Uint8Array(ab); | 13 var ui8a = new Uint8Array(ab); |
14 var ui8ca = new Uint8ClampedArray(ab); | 14 var ui8ca = new Uint8ClampedArray(ab); |
15 var ui16a = new Uint16Array(ab); | 15 var ui16a = new Uint16Array(ab); |
16 var ui32a = new Uint32Array(ab); | 16 var ui32a = new Uint32Array(ab); |
17 var f32a = new Float32Array(ab); | 17 var f32a = new Float32Array(ab); |
18 var f64a = new Float64Array(ab); | 18 var f64a = new Float64Array(ab); |
19 | 19 |
20 [i8a, i16a, i32a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function( | 20 [i8a, i16a, i32a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function( |
21 ta) { | 21 ta) { |
22 assertThrows(function() { Atomics.futexWait(ta, 0, 0); }); | 22 assertThrows(function() { Atomics.wait(ta, 0, 0); }); |
23 assertThrows(function() { Atomics.futexWake(ta, 0, 1); }); | 23 assertThrows(function() { Atomics.wake(ta, 0, 1); }); |
24 assertThrows(function() { Atomics.futexWakeOrRequeue(ta, 0, 1, 0, 0); }); | |
25 }); | 24 }); |
26 })(); | 25 })(); |
27 | 26 |
28 (function TestFailsWithNonSharedInt32Array() { | 27 (function TestFailsWithNonSharedInt32Array() { |
29 var sab = new SharedArrayBuffer(16); | 28 var sab = new SharedArrayBuffer(16); |
30 | 29 |
31 var i8a = new Int8Array(sab); | 30 var i8a = new Int8Array(sab); |
32 var i16a = new Int16Array(sab); | 31 var i16a = new Int16Array(sab); |
33 var ui8a = new Uint8Array(sab); | 32 var ui8a = new Uint8Array(sab); |
34 var ui8ca = new Uint8ClampedArray(sab); | 33 var ui8ca = new Uint8ClampedArray(sab); |
35 var ui16a = new Uint16Array(sab); | 34 var ui16a = new Uint16Array(sab); |
36 var ui32a = new Uint32Array(sab); | 35 var ui32a = new Uint32Array(sab); |
37 var f32a = new Float32Array(sab); | 36 var f32a = new Float32Array(sab); |
38 var f64a = new Float64Array(sab); | 37 var f64a = new Float64Array(sab); |
39 | 38 |
40 [i8a, i16a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function( | 39 [i8a, i16a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function( |
41 ta) { | 40 ta) { |
42 assertThrows(function() { Atomics.futexWait(ta, 0, 0); }); | 41 assertThrows(function() { Atomics.wait(ta, 0, 0); }); |
43 assertThrows(function() { Atomics.futexWake(ta, 0, 1); }); | 42 assertThrows(function() { Atomics.wake(ta, 0, 1); }); |
44 assertThrows(function() { Atomics.futexWakeOrRequeue(ta, 0, 1, 0, 0); }); | |
45 }); | 43 }); |
46 })(); | 44 })(); |
47 | 45 |
48 (function TestInvalidIndex() { | 46 (function TestInvalidIndex() { |
49 var sab = new SharedArrayBuffer(16); | 47 var sab = new SharedArrayBuffer(16); |
50 var i32a = new Int32Array(sab); | 48 var i32a = new Int32Array(sab); |
51 | 49 |
52 // Valid indexes are 0-3. | 50 // Valid indexes are 0-3. |
53 [-1, 4, 100].forEach(function(invalidIndex) { | 51 [-1, 4, 100].forEach(function(invalidIndex) { |
54 assertThrows(function() { | 52 assertThrows(function() { |
55 Atomics.futexWait(i32a, invalidIndex, 0); | 53 Atomics.wait(i32a, invalidIndex, 0); |
56 }, RangeError); | 54 }, RangeError); |
57 assertThrows(function() { | 55 assertThrows(function() { |
58 Atomics.futexWake(i32a, invalidIndex, 0); | 56 Atomics.wake(i32a, invalidIndex, 0); |
59 }, RangeError); | 57 }, RangeError); |
60 var validIndex = 0; | 58 var validIndex = 0; |
61 assertThrows(function() { | |
62 Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex); | |
63 }, RangeError); | |
64 assertThrows(function() { | |
65 Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex); | |
66 }, RangeError); | |
67 }); | 59 }); |
68 | 60 |
69 i32a = new Int32Array(sab, 8); | 61 i32a = new Int32Array(sab, 8); |
70 [-1, 2, 100].forEach(function(invalidIndex) { | 62 [-1, 2, 100].forEach(function(invalidIndex) { |
71 assertThrows(function() { | 63 assertThrows(function() { |
72 Atomics.futexWait(i32a, invalidIndex, 0); | 64 Atomics.wait(i32a, invalidIndex, 0); |
73 }, RangeError); | 65 }, RangeError); |
74 assertThrows(function() { | 66 assertThrows(function() { |
75 Atomics.futexWake(i32a, invalidIndex, 0); | 67 Atomics.wake(i32a, invalidIndex, 0); |
76 }, RangeError); | 68 }, RangeError); |
77 var validIndex = 0; | 69 var validIndex = 0; |
78 assertThrows(function() { | |
79 Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex); | |
80 }, RangeError); | |
81 assertThrows(function() { | |
82 Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex); | |
83 }, RangeError); | |
84 }); | 70 }); |
85 })(); | 71 })(); |
86 | 72 |
87 (function TestWaitTimeout() { | 73 (function TestWaitTimeout() { |
88 var i32a = new Int32Array(new SharedArrayBuffer(16)); | 74 var i32a = new Int32Array(new SharedArrayBuffer(16)); |
89 var waitMs = 100; | 75 var waitMs = 100; |
90 var startTime = new Date(); | 76 var startTime = new Date(); |
91 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, waitMs)); | 77 assertEquals("timed-out", Atomics.wait(i32a, 0, 0, waitMs)); |
92 var endTime = new Date(); | 78 var endTime = new Date(); |
93 assertTrue(endTime - startTime >= waitMs); | 79 assertTrue(endTime - startTime >= waitMs); |
94 })(); | 80 })(); |
95 | 81 |
96 (function TestWaitNotEqual() { | 82 (function TestWaitNotEqual() { |
97 var sab = new SharedArrayBuffer(16); | 83 var sab = new SharedArrayBuffer(16); |
98 var i32a = new Int32Array(sab); | 84 var i32a = new Int32Array(sab); |
99 assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 42)); | 85 assertEquals("not-equal", Atomics.wait(i32a, 0, 42)); |
100 | 86 |
101 i32a = new Int32Array(sab, 8); | 87 i32a = new Int32Array(sab, 8); |
102 i32a[0] = 1; | 88 i32a[0] = 1; |
103 assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 0)); | 89 assertEquals("not-equal", Atomics.wait(i32a, 0, 0)); |
104 })(); | 90 })(); |
105 | 91 |
106 (function TestWaitNegativeTimeout() { | 92 (function TestWaitNegativeTimeout() { |
107 var i32a = new Int32Array(new SharedArrayBuffer(16)); | 93 var i32a = new Int32Array(new SharedArrayBuffer(16)); |
108 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -1)); | 94 assertEquals("timed-out", Atomics.wait(i32a, 0, 0, -1)); |
109 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -Infinity)); | 95 assertEquals("timed-out", Atomics.wait(i32a, 0, 0, -Infinity)); |
110 })(); | 96 })(); |
111 | 97 |
112 //// WORKER ONLY TESTS | 98 //// WORKER ONLY TESTS |
113 | 99 |
114 if (this.Worker) { | 100 if (this.Worker) { |
115 | 101 |
116 var TestWaitWithTimeout = function(timeout) { | 102 var TestWaitWithTimeout = function(timeout) { |
117 var sab = new SharedArrayBuffer(16); | 103 var sab = new SharedArrayBuffer(16); |
118 var i32a = new Int32Array(sab); | 104 var i32a = new Int32Array(sab); |
119 | 105 |
120 var workerScript = | 106 var workerScript = |
121 `onmessage = function(msg) { | 107 `onmessage = function(msg) { |
122 var i32a = new Int32Array(msg.sab, msg.offset); | 108 var i32a = new Int32Array(msg.sab, msg.offset); |
123 var result = Atomics.futexWait(i32a, 0, 0, ${timeout}); | 109 var result = Atomics.wait(i32a, 0, 0, ${timeout}); |
124 postMessage(result); | 110 postMessage(result); |
125 };`; | 111 };`; |
126 | 112 |
127 var worker = new Worker(workerScript); | 113 var worker = new Worker(workerScript); |
128 worker.postMessage({sab: sab, offset: offset}, [sab]); | 114 worker.postMessage({sab: sab, offset: offset}, [sab]); |
129 | 115 |
130 // Spin until the worker is waiting on the futex. | 116 // Spin until the worker is waiting on the futex. |
131 while (%AtomicsFutexNumWaitersForTesting(i32a, 0) != 1) {} | 117 while (%AtomicsNumWaitersForTesting(i32a, 0) != 1) {} |
132 | 118 |
133 Atomics.futexWake(i32a, 0, 1); | 119 Atomics.wake(i32a, 0, 1); |
134 assertEquals(Atomics.OK, worker.getMessage()); | 120 assertEquals("ok", worker.getMessage()); |
135 worker.terminate(); | 121 worker.terminate(); |
136 | 122 |
137 var worker2 = new Worker(workerScript); | 123 var worker2 = new Worker(workerScript); |
138 var offset = 8; | 124 var offset = 8; |
139 var i32a2 = new Int32Array(sab, offset); | 125 var i32a2 = new Int32Array(sab, offset); |
140 worker2.postMessage({sab: sab, offset: offset}, [sab]); | 126 worker2.postMessage({sab: sab, offset: offset}, [sab]); |
141 | 127 |
142 // Spin until the worker is waiting on the futex. | 128 // Spin until the worker is waiting on the futex. |
143 while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 1) {} | 129 while (%AtomicsNumWaitersForTesting(i32a2, 0) != 1) {} |
144 Atomics.futexWake(i32a2, 0, 1); | 130 Atomics.wake(i32a2, 0, 1); |
145 assertEquals(Atomics.OK, worker2.getMessage()); | 131 assertEquals("ok", worker2.getMessage()); |
146 worker2.terminate(); | 132 worker2.terminate(); |
147 | 133 |
148 // Futex should work when index and buffer views are different, but | 134 // Futex should work when index and buffer views are different, but |
149 // the real address is the same. | 135 // the real address is the same. |
150 var worker3 = new Worker(workerScript); | 136 var worker3 = new Worker(workerScript); |
151 i32a2 = new Int32Array(sab, 4); | 137 i32a2 = new Int32Array(sab, 4); |
152 worker3.postMessage({sab: sab, offset: 8}, [sab]); | 138 worker3.postMessage({sab: sab, offset: 8}, [sab]); |
153 | 139 |
154 // Spin until the worker is waiting on the futex. | 140 // Spin until the worker is waiting on the futex. |
155 while (%AtomicsFutexNumWaitersForTesting(i32a2, 1) != 1) {} | 141 while (%AtomicsNumWaitersForTesting(i32a2, 1) != 1) {} |
156 Atomics.futexWake(i32a2, 1, 1); | 142 Atomics.wake(i32a2, 1, 1); |
157 assertEquals(Atomics.OK, worker3.getMessage()); | 143 assertEquals("ok", worker3.getMessage()); |
158 worker3.terminate(); | 144 worker3.terminate(); |
159 }; | 145 }; |
160 | 146 |
161 // Test various infinite timeouts | 147 // Test various infinite timeouts |
162 TestWaitWithTimeout(undefined); | 148 TestWaitWithTimeout(undefined); |
163 TestWaitWithTimeout(NaN); | 149 TestWaitWithTimeout(NaN); |
164 TestWaitWithTimeout(Infinity); | 150 TestWaitWithTimeout(Infinity); |
165 | 151 |
166 | 152 |
167 (function TestWakeMulti() { | 153 (function TestWakeMulti() { |
168 var sab = new SharedArrayBuffer(20); | 154 var sab = new SharedArrayBuffer(20); |
169 var i32a = new Int32Array(sab); | 155 var i32a = new Int32Array(sab); |
170 | 156 |
171 // SAB values: | 157 // SAB values: |
172 // i32a[id], where id in range [0, 3]: | 158 // i32a[id], where id in range [0, 3]: |
173 // 0 => Worker |id| is still waiting on the futex | 159 // 0 => Worker |id| is still waiting on the futex |
174 // 1 => Worker |id| is not waiting on futex, but has not be reaped by the | 160 // 1 => Worker |id| is not waiting on futex, but has not be reaped by the |
175 // main thread. | 161 // main thread. |
176 // 2 => Worker |id| has been reaped. | 162 // 2 => Worker |id| has been reaped. |
177 // | 163 // |
178 // i32a[4]: | 164 // i32a[4]: |
179 // always 0. Each worker is waiting on this index. | 165 // always 0. Each worker is waiting on this index. |
180 | 166 |
181 var workerScript = | 167 var workerScript = |
182 `onmessage = function(msg) { | 168 `onmessage = function(msg) { |
183 var id = msg.id; | 169 var id = msg.id; |
184 var i32a = new Int32Array(msg.sab); | 170 var i32a = new Int32Array(msg.sab); |
185 | 171 |
186 // Wait on i32a[4] (should be zero). | 172 // Wait on i32a[4] (should be zero). |
187 var result = Atomics.futexWait(i32a, 4, 0); | 173 var result = Atomics.wait(i32a, 4, 0); |
188 // Set i32a[id] to 1 to notify the main thread which workers were | 174 // Set i32a[id] to 1 to notify the main thread which workers were |
189 // woken up. | 175 // woken up. |
190 Atomics.store(i32a, id, 1); | 176 Atomics.store(i32a, id, 1); |
191 postMessage(result); | 177 postMessage(result); |
192 };`; | 178 };`; |
193 | 179 |
194 var id; | 180 var id; |
195 var workers = []; | 181 var workers = []; |
196 for (id = 0; id < 4; id++) { | 182 for (id = 0; id < 4; id++) { |
197 workers[id] = new Worker(workerScript); | 183 workers[id] = new Worker(workerScript); |
198 workers[id].postMessage({sab: sab, id: id}, [sab]); | 184 workers[id].postMessage({sab: sab, id: id}, [sab]); |
199 } | 185 } |
200 | 186 |
201 // Spin until all workers are waiting on the futex. | 187 // Spin until all workers are waiting on the futex. |
202 while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {} | 188 while (%AtomicsNumWaitersForTesting(i32a, 4) != 4) {} |
203 | 189 |
204 // Wake up three waiters. | 190 // Wake up three waiters. |
205 assertEquals(3, Atomics.futexWake(i32a, 4, 3)); | 191 assertEquals(3, Atomics.wake(i32a, 4, 3)); |
206 | 192 |
207 var wokenCount = 0; | 193 var wokenCount = 0; |
208 var waitingId = 0 + 1 + 2 + 3; | 194 var waitingId = 0 + 1 + 2 + 3; |
209 while (wokenCount < 3) { | 195 while (wokenCount < 3) { |
210 for (id = 0; id < 4; id++) { | 196 for (id = 0; id < 4; id++) { |
211 // Look for workers that have not yet been reaped. Set i32a[id] to 2 | 197 // Look for workers that have not yet been reaped. Set i32a[id] to 2 |
212 // when they've been processed so we don't look at them again. | 198 // when they've been processed so we don't look at them again. |
213 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { | 199 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { |
214 assertEquals(Atomics.OK, workers[id].getMessage()); | 200 assertEquals("ok", workers[id].getMessage()); |
215 workers[id].terminate(); | 201 workers[id].terminate(); |
216 waitingId -= id; | 202 waitingId -= id; |
217 wokenCount++; | 203 wokenCount++; |
218 } | 204 } |
219 } | 205 } |
220 } | 206 } |
221 | 207 |
222 assertEquals(3, wokenCount); | 208 assertEquals(3, wokenCount); |
223 assertEquals(0, Atomics.load(i32a, waitingId)); | 209 assertEquals(0, Atomics.load(i32a, waitingId)); |
224 assertEquals(1, %AtomicsFutexNumWaitersForTesting(i32a, 4)); | 210 assertEquals(1, %AtomicsNumWaitersForTesting(i32a, 4)); |
225 | 211 |
226 // Finally wake the last waiter. | 212 // Finally wake the last waiter. |
227 assertEquals(1, Atomics.futexWake(i32a, 4, 1)); | 213 assertEquals(1, Atomics.wake(i32a, 4, 1)); |
228 assertEquals(Atomics.OK, workers[waitingId].getMessage()); | 214 assertEquals("ok", workers[waitingId].getMessage()); |
229 workers[waitingId].terminate(); | 215 workers[waitingId].terminate(); |
230 | 216 |
231 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, 4)); | 217 assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 4)); |
232 | 218 |
233 })(); | 219 })(); |
234 | 220 |
235 (function TestWakeOrRequeue() { | |
236 var sab = new SharedArrayBuffer(24); | |
237 var i32a = new Int32Array(sab); | |
238 | |
239 // SAB values: | |
240 // i32a[id], where id in range [0, 3]: | |
241 // 0 => Worker |id| is still waiting on the futex | |
242 // 1 => Worker |id| is not waiting on futex, but has not be reaped by the | |
243 // main thread. | |
244 // 2 => Worker |id| has been reaped. | |
245 // | |
246 // i32a[4]: | |
247 // always 0. Each worker will initially wait on this index. | |
248 // | |
249 // i32a[5]: | |
250 // always 0. Requeued workers will wait on this index. | |
251 | |
252 var workerScript = | |
253 `onmessage = function(msg) { | |
254 var id = msg.id; | |
255 var i32a = new Int32Array(msg.sab); | |
256 | |
257 var result = Atomics.futexWait(i32a, 4, 0, Infinity); | |
258 Atomics.store(i32a, id, 1); | |
259 postMessage(result); | |
260 };`; | |
261 | |
262 var workers = []; | |
263 for (id = 0; id < 4; id++) { | |
264 workers[id] = new Worker(workerScript); | |
265 workers[id].postMessage({sab: sab, id: id}, [sab]); | |
266 } | |
267 | |
268 // Spin until all workers are waiting on the futex. | |
269 while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {} | |
270 | |
271 var index1 = 4; | |
272 var index2 = 5; | |
273 | |
274 // If futexWakeOrRequeue is called with the incorrect value, it shouldn't | |
275 // wake any waiters. | |
276 assertEquals(Atomics.NOTEQUAL, | |
277 Atomics.futexWakeOrRequeue(i32a, index1, 1, 42, index2)); | |
278 | |
279 assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a, index1)); | |
280 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2)); | |
281 | |
282 // Now wake with the correct value. | |
283 assertEquals(1, Atomics.futexWakeOrRequeue(i32a, index1, 1, 0, index2)); | |
284 | |
285 // The workers that are still waiting should atomically be transferred to | |
286 // the new index. | |
287 assertEquals(3, %AtomicsFutexNumWaitersForTesting(i32a, index2)); | |
288 | |
289 // The woken worker may not have been scheduled yet. Look for which thread | |
290 // has set its i32a value to 1. | |
291 var wokenCount = 0; | |
292 while (wokenCount < 1) { | |
293 for (id = 0; id < 4; id++) { | |
294 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { | |
295 wokenCount++; | |
296 } | |
297 } | |
298 } | |
299 | |
300 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1)); | |
301 | |
302 // Wake the remaining waiters. | |
303 assertEquals(3, Atomics.futexWake(i32a, index2, 3)); | |
304 | |
305 // As above, wait until the workers have been scheduled. | |
306 wokenCount = 0; | |
307 while (wokenCount < 3) { | |
308 for (id = 0; id < 4; id++) { | |
309 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { | |
310 wokenCount++; | |
311 } | |
312 } | |
313 } | |
314 | |
315 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1)); | |
316 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2)); | |
317 | |
318 for (id = 0; id < 4; ++id) { | |
319 assertEquals(Atomics.OK, workers[id].getMessage()); | |
320 } | |
321 | |
322 // Test futexWakeOrRequeue on offset typed array | |
323 var offset = 16; | |
324 sab = new SharedArrayBuffer(24); | |
325 i32a = new Int32Array(sab); | |
326 var i32a2 = new Int32Array(sab, offset); | |
327 | |
328 for (id = 0; id < 4; id++) { | |
329 workers[id].postMessage({sab: sab, id: id}, [sab]); | |
330 } | |
331 | |
332 while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 4) { } | |
333 | |
334 index1 = 0; | |
335 index2 = 1; | |
336 assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a2, index1)); | |
337 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index2)); | |
338 | |
339 assertEquals(2, Atomics.futexWakeOrRequeue(i32a2, index1, 2, 0, index2)); | |
340 assertEquals(2, %AtomicsFutexNumWaitersForTesting(i32a2, index2)); | |
341 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index1)); | |
342 | |
343 assertEquals(2, Atomics.futexWake(i32a2, index2, 2)); | |
344 | |
345 for (id = 0; id < 4; ++id) { | |
346 assertEquals(Atomics.OK, workers[id].getMessage()); | |
347 workers[id].terminate(); | |
348 } | |
349 | |
350 })(); | |
351 | |
352 } | 221 } |
OLD | NEW |