OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Flags: --harmony-atomics --harmony-sharedarraybuffer | |
6 // | |
7 | |
8 var IntegerTypedArrayConstructors = [ | |
9 {constr: Int8Array, min: -128, max: 127}, | |
10 {constr: Int16Array, min: -32768, max: 32767}, | |
11 {constr: Int32Array, min: -0x80000000, max: 0x7fffffff}, | |
12 {constr: Uint8Array, min: 0, max: 255}, | |
13 // TODO(binji): support? | |
14 // {constr: Uint8ClampedArray, min: 0, max: 255}, | |
Jarin
2015/06/01 17:50:10
The spec has the clamped arrays, so I guess we sho
binji
2015/06/02 21:32:55
JF suggested we should push back on this. I agree,
Jarin
2015/06/03 13:30:15
Acknowledged.
| |
15 {constr: Uint16Array, min: 0, max: 65535}, | |
16 {constr: Uint32Array, min: 0, max: 0xffffffff}, | |
17 ]; | |
18 | |
19 var TypedArrayConstructors = IntegerTypedArrayConstructors.concat([ | |
20 {constr: Float32Array}, | |
21 {constr: Float64Array}, | |
22 ]); | |
23 | |
24 (function TestBadArray() { | |
25 var ab = new ArrayBuffer(16); | |
26 var u32a = new Uint32Array(16); | |
27 var sab = new SharedArrayBuffer(128); | |
28 var sf32a = new Float32Array(sab); | |
29 var sf64a = new Float64Array(sab); | |
30 | |
31 // Atomic ops required shared typed arrays | |
32 [undefined, 1, 'hi', 3.4, ab, u32a, sab].forEach(function(o) { | |
33 assertThrows(function() { Atomics.compareExchange(o, 0, 0, 0); }, | |
34 TypeError); | |
35 assertThrows(function() { Atomics.load(o, 0); }, TypeError); | |
36 assertThrows(function() { Atomics.store(o, 0, 0); }, TypeError); | |
37 assertThrows(function() { Atomics.add(o, 0, 0); }, TypeError); | |
38 assertThrows(function() { Atomics.sub(o, 0, 0); }, TypeError); | |
39 assertThrows(function() { Atomics.and(o, 0, 0); }, TypeError); | |
40 assertThrows(function() { Atomics.or(o, 0, 0); }, TypeError); | |
41 assertThrows(function() { Atomics.xor(o, 0, 0); }, TypeError); | |
42 assertThrows(function() { Atomics.exchange(o, 0, 0); }, TypeError); | |
43 }); | |
44 | |
45 // Arithmetic atomic ops require integer shared arrays | |
46 [sab, sf32a, sf64a].forEach(function(o) { | |
47 assertThrows(function() { Atomics.add(o, 0, 0); }, TypeError); | |
48 assertThrows(function() { Atomics.sub(o, 0, 0); }, TypeError); | |
49 assertThrows(function() { Atomics.and(o, 0, 0); }, TypeError); | |
50 assertThrows(function() { Atomics.or(o, 0, 0); }, TypeError); | |
51 assertThrows(function() { Atomics.xor(o, 0, 0); }, TypeError); | |
52 assertThrows(function() { Atomics.exchange(o, 0, 0); }, TypeError); | |
53 }); | |
54 })(); | |
55 | |
56 function testAtomicOp(op, ia, index, expectedIndex, name) { | |
57 for (var i = 0; i < ia.length; ++i) | |
58 ia[i] = 22; | |
59 | |
60 ia[expectedIndex] = 0; | |
61 assertEquals(0, op(ia, index, 0, 0), name); | |
62 assertEquals(0, ia[expectedIndex], name); | |
63 | |
64 for (var i = 0; i < ia.length; ++i) { | |
65 if (i == expectedIndex) continue; | |
66 assertEquals(22, ia[i], name); | |
67 } | |
68 } | |
69 | |
70 (function TestBadIndex() { | |
71 var sab = new SharedArrayBuffer(8); | |
72 var si32a = new Int32Array(sab); | |
73 | |
74 // Non-integer indexes are converted to an integer first, so they should all | |
75 // operate on index 0. | |
76 [undefined, null, false, 'hi', {}].forEach(function(i) { | |
77 var name = String(i); | |
78 | |
79 testAtomicOp(Atomics.compareExchange, si32a, i, 0, name); | |
80 testAtomicOp(Atomics.load, si32a, i, 0, name); | |
81 testAtomicOp(Atomics.store, si32a, i, 0, name); | |
82 testAtomicOp(Atomics.add, si32a, i, 0, name); | |
83 testAtomicOp(Atomics.sub, si32a, i, 0, name); | |
84 testAtomicOp(Atomics.and, si32a, i, 0, name); | |
85 testAtomicOp(Atomics.or, si32a, i, 0, name); | |
86 testAtomicOp(Atomics.xor, si32a, i, 0, name); | |
87 testAtomicOp(Atomics.exchange, si32a, i, 0, name); | |
88 }); | |
89 | |
90 // Out-of-bounds indexes should return undefined. | |
91 // TODO(binji): Should these throw RangeError instead? | |
92 [-1, 2, 100].forEach(function(i) { | |
93 var name = String(i); | |
94 assertEquals(undefined, Atomics.compareExchange(si32a, i, 0, 0), name); | |
95 assertEquals(undefined, Atomics.load(si32a, i), name); | |
96 assertEquals(undefined, Atomics.store(si32a, i, 0), name); | |
97 assertEquals(undefined, Atomics.add(si32a, i, 0), name); | |
98 assertEquals(undefined, Atomics.sub(si32a, i, 0), name); | |
99 assertEquals(undefined, Atomics.and(si32a, i, 0), name); | |
100 assertEquals(undefined, Atomics.or(si32a, i, 0), name); | |
101 assertEquals(undefined, Atomics.xor(si32a, i, 0), name); | |
102 assertEquals(undefined, Atomics.exchange(si32a, i, 0), name); | |
103 }); | |
104 })(); | |
105 | |
106 (function TestGoodIndex() { | |
107 var sab = new SharedArrayBuffer(64); | |
108 var si32a = new Int32Array(sab); | |
109 | |
110 var valueOf = {valueOf: function(){ return 3;}}; | |
111 var toString = {toString: function(){ return '3';}}; | |
112 | |
113 [3, 3.5, '3', '3.5', valueOf, toString].forEach(function(i) { | |
114 var name = String(i); | |
115 | |
116 testAtomicOp(Atomics.compareExchange, si32a, i, 3, name); | |
117 testAtomicOp(Atomics.load, si32a, i, 3, name); | |
118 testAtomicOp(Atomics.store, si32a, i, 3, name); | |
119 testAtomicOp(Atomics.add, si32a, i, 3, name); | |
120 testAtomicOp(Atomics.sub, si32a, i, 3, name); | |
121 testAtomicOp(Atomics.and, si32a, i, 3, name); | |
122 testAtomicOp(Atomics.or, si32a, i, 3, name); | |
123 testAtomicOp(Atomics.xor, si32a, i, 3, name); | |
124 testAtomicOp(Atomics.exchange, si32a, i, 3, name); | |
125 }); | |
126 })(); | |
127 | |
128 (function TestCompareExchange() { | |
129 TypedArrayConstructors.forEach(function(t) { | |
130 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
131 var sta = new t.constr(sab); | |
132 var name = Object.prototype.toString.call(sta); | |
133 for (var i = 0; i < 10; ++i) { | |
134 // sta[i] == 0, CAS will store | |
135 assertEquals(0, Atomics.compareExchange(sta, i, 0, 50), name); | |
136 assertEquals(50, sta[i], name); | |
137 | |
138 // sta[i] == 50, CAS will not store | |
139 assertEquals(50, Atomics.compareExchange(sta, i, 0, 100), name); | |
140 assertEquals(50, sta[i], name); | |
141 } | |
142 }); | |
143 | |
144 IntegerTypedArrayConstructors.forEach(function(t) { | |
145 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
146 var sta = new t.constr(sab); | |
147 var name = Object.prototype.toString.call(sta); | |
148 var range = t.max - t.min + 1; | |
149 var add; | |
150 var oldVal, oldValWrapped; | |
151 var newVal, newValWrapped; | |
152 | |
153 for (add = -range; add <= range; add += range) { | |
154 sta[0] = oldVal = 0; | |
155 newVal = t.max + add + 1; | |
156 newValWrapped = t.min; | |
157 assertEquals(oldVal, | |
158 Atomics.compareExchange(sta, 0, oldVal, newVal), name); | |
159 assertEquals(newValWrapped, sta[0], name); | |
160 | |
161 oldVal = newVal; | |
162 oldValWrapped = newValWrapped; | |
163 newVal = t.min + add - 1; | |
164 newValWrapped = t.max; | |
165 assertEquals(oldValWrapped, | |
166 Atomics.compareExchange(sta, 0, oldVal, newVal), name); | |
167 assertEquals(newValWrapped, sta[0], name); | |
168 } | |
169 }); | |
170 | |
171 // * Exact float values should be OK | |
172 // * Infinity, -Infinity should be OK (has exact representation) | |
173 // * NaN is not OK, it has many representations, cannot ensure successful CAS | |
174 // because it does a bitwise compare | |
175 [1.5, 4.25, -1e8, -Infinity, Infinity].forEach(function(v) { | |
176 var sab = new SharedArrayBuffer(10 * Float32Array.BYTES_PER_ELEMENT); | |
177 var sf32a = new Float32Array(sab); | |
178 sf32a[0] = 0; | |
179 assertEquals(0, Atomics.compareExchange(sf32a, 0, 0, v)); | |
180 assertEquals(v, sf32a[0]); | |
181 assertEquals(v, Atomics.compareExchange(sf32a, 0, v, 0)); | |
182 assertEquals(0, sf32a[0]); | |
183 | |
184 var sab2 = new SharedArrayBuffer(10 * Float64Array.BYTES_PER_ELEMENT); | |
185 var sf64a = new Float64Array(sab2); | |
186 sf64a[0] = 0; | |
187 assertEquals(0, Atomics.compareExchange(sf64a, 0, 0, v)); | |
188 assertEquals(v, sf64a[0]); | |
189 assertEquals(v, Atomics.compareExchange(sf64a, 0, v, 0)); | |
190 assertEquals(0, sf64a[0]); | |
191 }); | |
192 })(); | |
193 | |
194 (function TestLoad() { | |
195 TypedArrayConstructors.forEach(function(t) { | |
196 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
197 var sta = new t.constr(sab); | |
198 var name = Object.prototype.toString.call(sta); | |
199 for (var i = 0; i < 10; ++i) { | |
200 sta[i] = 0; | |
201 assertEquals(0, Atomics.load(sta, i), name); | |
202 sta[i] = 50; | |
203 assertEquals(50, Atomics.load(sta, i), name); | |
204 } | |
205 }); | |
206 })(); | |
207 | |
208 (function TestStore() { | |
209 TypedArrayConstructors.forEach(function(t) { | |
210 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
211 var sta = new t.constr(sab); | |
212 var name = Object.prototype.toString.call(sta); | |
213 for (var i = 0; i < 10; ++i) { | |
214 assertEquals(50, Atomics.store(sta, i, 50), name); | |
215 assertEquals(50, sta[i], name); | |
216 | |
217 assertEquals(100, Atomics.store(sta, i, 100), name); | |
218 assertEquals(100, sta[i], name); | |
219 } | |
220 }); | |
221 | |
222 IntegerTypedArrayConstructors.forEach(function(t) { | |
223 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
224 var sta = new t.constr(sab); | |
225 var name = Object.prototype.toString.call(sta); | |
226 var range = t.max - t.min + 1; | |
227 var add; | |
228 var val, valWrapped; | |
229 | |
230 for (add = -range; add <= range; add += range) { | |
231 sta[0] = 0; | |
232 val = t.max + add + 1; | |
233 valWrapped = t.min; | |
234 assertEquals(val, Atomics.store(sta, 0, val), name); | |
235 assertEquals(valWrapped, sta[0], name); | |
236 | |
237 val = t.min + add - 1; | |
238 valWrapped = t.max; | |
239 assertEquals(val, Atomics.store(sta, 0, val), name); | |
240 assertEquals(valWrapped, sta[0], name); | |
241 } | |
242 }); | |
243 | |
244 [1.5, 4.25, -1e8, -Infinity, Infinity, NaN].forEach(function(v) { | |
245 var sab = new SharedArrayBuffer(10 * Float32Array.BYTES_PER_ELEMENT); | |
246 var sf32a = new Float32Array(sab); | |
247 sf32a[0] = 0; | |
248 assertEquals(v, Atomics.store(sf32a, 0, v)); | |
249 assertEquals(v, sf32a[0]); | |
250 | |
251 var sab2 = new SharedArrayBuffer(10 * Float64Array.BYTES_PER_ELEMENT); | |
252 var sf64a = new Float64Array(sab2); | |
253 sf64a[0] = 0; | |
254 assertEquals(v, Atomics.store(sf64a, 0, v)); | |
255 assertEquals(v, sf64a[0]); | |
256 }); | |
257 })(); | |
258 | |
259 (function TestAdd() { | |
260 IntegerTypedArrayConstructors.forEach(function(t) { | |
261 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
262 var sta = new t.constr(sab); | |
263 var name = Object.prototype.toString.call(sta); | |
264 for (var i = 0; i < 10; ++i) { | |
265 assertEquals(0, Atomics.add(sta, i, 50), name); | |
266 assertEquals(50, sta[i], name); | |
267 | |
268 assertEquals(50, Atomics.add(sta, i, 70), name); | |
269 assertEquals(120, sta[i], name); | |
270 } | |
271 }); | |
272 | |
273 IntegerTypedArrayConstructors.forEach(function(t) { | |
274 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
275 var sta = new t.constr(sab); | |
276 var name = Object.prototype.toString.call(sta); | |
277 var range = t.max - t.min + 1; | |
278 var add; | |
279 | |
280 for (add = -range; add <= range; add += range) { | |
281 sta[0] = t.max; | |
282 valWrapped = t.min; | |
283 assertEquals(t.max, Atomics.add(sta, 0, add + 1), name); | |
284 assertEquals(t.min, sta[0], name); | |
285 | |
286 assertEquals(t.min, Atomics.add(sta, 0, add - 1), name); | |
287 assertEquals(t.max, sta[0], name); | |
288 } | |
289 }); | |
290 })(); | |
291 | |
292 (function TestSub() { | |
293 IntegerTypedArrayConstructors.forEach(function(t) { | |
294 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
295 var sta = new t.constr(sab); | |
296 var name = Object.prototype.toString.call(sta); | |
297 for (var i = 0; i < 10; ++i) { | |
298 sta[i] = 120; | |
299 assertEquals(120, Atomics.sub(sta, i, 50), name); | |
300 assertEquals(70, sta[i], name); | |
301 | |
302 assertEquals(70, Atomics.sub(sta, i, 70), name); | |
303 assertEquals(0, sta[i], name); | |
304 } | |
305 }); | |
306 | |
307 IntegerTypedArrayConstructors.forEach(function(t) { | |
308 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
309 var sta = new t.constr(sab); | |
310 var name = Object.prototype.toString.call(sta); | |
311 var range = t.max - t.min + 1; | |
312 var add; | |
313 | |
314 for (add = -range; add <= range; add += range) { | |
315 sta[0] = t.max; | |
316 valWrapped = t.min; | |
317 assertEquals(t.max, Atomics.sub(sta, 0, add - 1), name); | |
318 assertEquals(t.min, sta[0], name); | |
319 | |
320 assertEquals(t.min, Atomics.sub(sta, 0, add + 1), name); | |
321 assertEquals(t.max, sta[0], name); | |
322 } | |
323 }); | |
324 })(); | |
325 | |
326 (function TestAnd() { | |
327 IntegerTypedArrayConstructors.forEach(function(t) { | |
328 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
329 var sta = new t.constr(sab); | |
330 var name = Object.prototype.toString.call(sta); | |
331 for (var i = 0; i < 10; ++i) { | |
332 sta[i] = 0x3f; | |
333 assertEquals(0x3f, Atomics.and(sta, i, 0x30), name); | |
334 assertEquals(0x30, sta[i], name); | |
335 | |
336 assertEquals(0x30, Atomics.and(sta, i, 0x20), name); | |
337 assertEquals(0x20, sta[i], name); | |
338 } | |
339 }); | |
340 | |
341 IntegerTypedArrayConstructors.forEach(function(t) { | |
342 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
343 var sta = new t.constr(sab); | |
344 var name = Object.prototype.toString.call(sta); | |
345 var range = t.max - t.min + 1; | |
346 var add; | |
347 | |
348 // There's no way to wrap results with logical operators, just test that | |
349 // using an out-of-range value is properly masked. | |
350 for (add = -range; add <= range; add += range) { | |
351 sta[0] = 0xf; | |
352 assertEquals(0xf, Atomics.and(sta, 0, 0x3 + add), name); | |
353 assertEquals(0x3, sta[0], name); | |
354 } | |
355 }); | |
356 })(); | |
357 | |
358 (function TestOr() { | |
359 IntegerTypedArrayConstructors.forEach(function(t) { | |
360 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
361 var sta = new t.constr(sab); | |
362 var name = Object.prototype.toString.call(sta); | |
363 for (var i = 0; i < 10; ++i) { | |
364 sta[i] = 0x30; | |
365 assertEquals(0x30, Atomics.or(sta, i, 0x1c), name); | |
366 assertEquals(0x3c, sta[i], name); | |
367 | |
368 assertEquals(0x3c, Atomics.or(sta, i, 0x09), name); | |
369 assertEquals(0x3d, sta[i], name); | |
370 } | |
371 }); | |
372 | |
373 IntegerTypedArrayConstructors.forEach(function(t) { | |
374 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
375 var sta = new t.constr(sab); | |
376 var name = Object.prototype.toString.call(sta); | |
377 var range = t.max - t.min + 1; | |
378 var add; | |
379 | |
380 // There's no way to wrap results with logical operators, just test that | |
381 // using an out-of-range value is properly masked. | |
382 for (add = -range; add <= range; add += range) { | |
383 sta[0] = 0x12; | |
384 assertEquals(0x12, Atomics.or(sta, 0, 0x22 + add), name); | |
385 assertEquals(0x32, sta[0], name); | |
386 } | |
387 }); | |
388 })(); | |
389 | |
390 (function TestXor() { | |
391 IntegerTypedArrayConstructors.forEach(function(t) { | |
392 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
393 var sta = new t.constr(sab); | |
394 var name = Object.prototype.toString.call(sta); | |
395 for (var i = 0; i < 10; ++i) { | |
396 sta[i] = 0x30; | |
397 assertEquals(0x30, Atomics.xor(sta, i, 0x1c), name); | |
398 assertEquals(0x2c, sta[i], name); | |
399 | |
400 assertEquals(0x2c, Atomics.xor(sta, i, 0x09), name); | |
401 assertEquals(0x25, sta[i], name); | |
402 } | |
403 }); | |
404 | |
405 IntegerTypedArrayConstructors.forEach(function(t) { | |
406 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
407 var sta = new t.constr(sab); | |
408 var name = Object.prototype.toString.call(sta); | |
409 var range = t.max - t.min + 1; | |
410 var add; | |
411 | |
412 // There's no way to wrap results with logical operators, just test that | |
413 // using an out-of-range value is properly masked. | |
414 for (add = -range; add <= range; add += range) { | |
415 sta[0] = 0x12; | |
416 assertEquals(0x12, Atomics.xor(sta, 0, 0x22 + add), name); | |
417 assertEquals(0x30, sta[0], name); | |
418 } | |
419 }); | |
420 })(); | |
421 | |
422 (function TestExchange() { | |
423 IntegerTypedArrayConstructors.forEach(function(t) { | |
424 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
425 var sta = new t.constr(sab); | |
426 var name = Object.prototype.toString.call(sta); | |
427 for (var i = 0; i < 10; ++i) { | |
428 sta[i] = 0x30; | |
429 assertEquals(0x30, Atomics.exchange(sta, i, 0x1c), name); | |
430 assertEquals(0x1c, sta[i], name); | |
431 | |
432 assertEquals(0x1c, Atomics.exchange(sta, i, 0x09), name); | |
433 assertEquals(0x09, sta[i], name); | |
434 } | |
435 }); | |
436 | |
437 IntegerTypedArrayConstructors.forEach(function(t) { | |
438 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT); | |
439 var sta = new t.constr(sab); | |
440 var name = Object.prototype.toString.call(sta); | |
441 var range = t.max - t.min + 1; | |
442 var add; | |
443 | |
444 // There's no way to wrap results with logical operators, just test that | |
445 // using an out-of-range value is properly masked. | |
446 for (add = -range; add <= range; add += range) { | |
447 sta[0] = 0x12; | |
448 assertEquals(0x12, Atomics.exchange(sta, 0, 0x22 + add), name); | |
449 assertEquals(0x22, sta[0], name); | |
450 } | |
451 }); | |
452 })(); | |
453 | |
454 (function TestIsLockFree() { | |
455 // For all platforms we support, 1, 2 and 4 bytes should be lock-free. | |
456 assertEquals(true, Atomics.isLockFree(1)); | |
457 assertEquals(true, Atomics.isLockFree(2)); | |
458 assertEquals(true, Atomics.isLockFree(4)); | |
459 | |
460 // Sizes that aren't equal to a typedarray BYTES_PER_ELEMENT always return | |
461 // false. | |
462 var validSizes = {}; | |
463 TypedArrayConstructors.forEach(function(t) { | |
464 validSizes[t.constr.BYTES_PER_ELEMENT] = true; | |
465 }); | |
466 | |
467 for (var i = 0; i < 1000; ++i) { | |
468 if (!validSizes[i]) { | |
469 assertEquals(false, Atomics.isLockFree(i)); | |
470 } | |
471 } | |
472 })(); | |
OLD | NEW |