blob: bf27eb46d54f3f3420e3a75f8eac3a81aebdb7ed [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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-sharedarraybuffer
6//
7
8function toRangeWrapped(value) {
9 var range = this.max - this.min + 1;
10 while (value < this.min) {
11 value += range;
12 }
13 while (value > this.max) {
14 value -= range;
15 }
16 return value;
17}
18
19function toRangeClamped(value) {
20 if (value < this.min) return this.min;
21 if (value > this.max) return this.max;
22 return value;
23}
24
25function makeConstructorObject(constr, min, max, toRange) {
26 var o = {constr: constr, min: min, max: max};
27 o.toRange = toRange.bind(o);
28 return o;
29}
30
31var IntegerTypedArrayConstructors = [
32 makeConstructorObject(Int8Array, -128, 127, toRangeWrapped),
33 makeConstructorObject(Int16Array, -32768, 32767, toRangeWrapped),
34 makeConstructorObject(Int32Array, -0x80000000, 0x7fffffff, toRangeWrapped),
35 makeConstructorObject(Uint8Array, 0, 255, toRangeWrapped),
36 makeConstructorObject(Uint8ClampedArray, 0, 255, toRangeClamped),
37 makeConstructorObject(Uint16Array, 0, 65535, toRangeWrapped),
38 makeConstructorObject(Uint32Array, 0, 0xffffffff, toRangeWrapped),
39];
40
41(function TestBadArray() {
42 var ab = new ArrayBuffer(16);
43 var u32a = new Uint32Array(16);
44 var sab = new SharedArrayBuffer(128);
45 var sf32a = new Float32Array(sab);
46 var sf64a = new Float64Array(sab);
47
48 // Atomic ops required integer shared typed arrays
49 [undefined, 1, 'hi', 3.4, ab, u32a, sab, sf32a, sf64a].forEach(function(o) {
50 assertThrows(function() { Atomics.compareExchange(o, 0, 0, 0); },
51 TypeError);
52 assertThrows(function() { Atomics.load(o, 0); }, TypeError);
53 assertThrows(function() { Atomics.store(o, 0, 0); }, TypeError);
54 assertThrows(function() { Atomics.add(o, 0, 0); }, TypeError);
55 assertThrows(function() { Atomics.sub(o, 0, 0); }, TypeError);
56 assertThrows(function() { Atomics.and(o, 0, 0); }, TypeError);
57 assertThrows(function() { Atomics.or(o, 0, 0); }, TypeError);
58 assertThrows(function() { Atomics.xor(o, 0, 0); }, TypeError);
59 assertThrows(function() { Atomics.exchange(o, 0, 0); }, TypeError);
60 });
61})();
62
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063(function TestBadIndex() {
64 var sab = new SharedArrayBuffer(8);
65 var si32a = new Int32Array(sab);
66 var si32a2 = new Int32Array(sab, 4);
67
Ben Murdochda12d292016-06-02 14:46:10 +010068 // Non-integer indexes should throw RangeError.
69 var nonInteger = [1.4, '1.4', NaN, -Infinity, Infinity, undefined, 'hi', {}];
70 nonInteger.forEach(function(i) {
71 assertThrows(function() { Atomics.compareExchange(si32a, i, 0); },
72 RangeError);
73 assertThrows(function() { Atomics.load(si32a, i, 0); }, RangeError);
74 assertThrows(function() { Atomics.store(si32a, i, 0); }, RangeError);
75 assertThrows(function() { Atomics.add(si32a, i, 0); }, RangeError);
76 assertThrows(function() { Atomics.sub(si32a, i, 0); }, RangeError);
77 assertThrows(function() { Atomics.and(si32a, i, 0); }, RangeError);
78 assertThrows(function() { Atomics.or(si32a, i, 0); }, RangeError);
79 assertThrows(function() { Atomics.xor(si32a, i, 0); }, RangeError);
80 assertThrows(function() { Atomics.exchange(si32a, i, 0); }, RangeError);
81 }, RangeError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082
Ben Murdochda12d292016-06-02 14:46:10 +010083 // Out-of-bounds indexes should throw RangeError.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 [-1, 2, 100].forEach(function(i) {
Ben Murdochda12d292016-06-02 14:46:10 +010085 assertThrows(function() { Atomics.compareExchange(si32a, i, 0, 0); },
86 RangeError);
87 assertThrows(function() { Atomics.load(si32a, i); }, RangeError);
88 assertThrows(function() { Atomics.store(si32a, i, 0); }, RangeError);
89 assertThrows(function() { Atomics.add(si32a, i, 0); }, RangeError);
90 assertThrows(function() { Atomics.sub(si32a, i, 0); }, RangeError);
91 assertThrows(function() { Atomics.and(si32a, i, 0); }, RangeError);
92 assertThrows(function() { Atomics.or(si32a, i, 0); }, RangeError);
93 assertThrows(function() { Atomics.xor(si32a, i, 0); }, RangeError);
94 assertThrows(function() { Atomics.exchange(si32a, i, 0); }, RangeError);
95 }, RangeError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096
Ben Murdochda12d292016-06-02 14:46:10 +010097 // Out-of-bounds indexes for array with offset should throw RangeError.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098 [-1, 1, 100].forEach(function(i) {
Ben Murdochda12d292016-06-02 14:46:10 +010099 assertThrows(function() { Atomics.compareExchange(si32a2, i, 0, 0); });
100 assertThrows(function() { Atomics.load(si32a2, i); }, RangeError);
101 assertThrows(function() { Atomics.store(si32a2, i, 0); }, RangeError);
102 assertThrows(function() { Atomics.add(si32a2, i, 0); }, RangeError);
103 assertThrows(function() { Atomics.sub(si32a2, i, 0); }, RangeError);
104 assertThrows(function() { Atomics.and(si32a2, i, 0); }, RangeError);
105 assertThrows(function() { Atomics.or(si32a2, i, 0); }, RangeError);
106 assertThrows(function() { Atomics.xor(si32a2, i, 0); }, RangeError);
107 assertThrows(function() { Atomics.exchange(si32a2, i, 0); }, RangeError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 });
109
Ben Murdochda12d292016-06-02 14:46:10 +0100110 // Monkey-patch length and make sure these functions still throw.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 Object.defineProperty(si32a, 'length', {get: function() { return 1000; }});
112 [2, 100].forEach(function(i) {
Ben Murdochda12d292016-06-02 14:46:10 +0100113 assertThrows(function() { Atomics.compareExchange(si32a, i, 0, 0); });
114 assertThrows(function() { Atomics.load(si32a, i); });
115 assertThrows(function() { Atomics.store(si32a, i, 0); });
116 assertThrows(function() { Atomics.add(si32a, i, 0); });
117 assertThrows(function() { Atomics.sub(si32a, i, 0); });
118 assertThrows(function() { Atomics.and(si32a, i, 0); });
119 assertThrows(function() { Atomics.or(si32a, i, 0); });
120 assertThrows(function() { Atomics.xor(si32a, i, 0); });
121 assertThrows(function() { Atomics.exchange(si32a, i, 0); });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 });
123})();
124
125(function TestGoodIndex() {
126 var sab = new SharedArrayBuffer(64);
127 var si32a = new Int32Array(sab);
128 var si32a2 = new Int32Array(sab, 32);
129
Ben Murdochda12d292016-06-02 14:46:10 +0100130 var testOp = function(op, ia, index, expectedIndex, name) {
131 for (var i = 0; i < ia.length; ++i)
132 ia[i] = 22;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133
Ben Murdochda12d292016-06-02 14:46:10 +0100134 ia[expectedIndex] = 0;
135 assertEquals(0, op(ia, index, 0, 0), name);
136 assertEquals(0, ia[expectedIndex], name);
137
138 for (var i = 0; i < ia.length; ++i) {
139 if (i == expectedIndex) continue;
140 assertEquals(22, ia[i], name);
141 }
142 };
143
144 // These values all map to index 0
145 [-0, 0, 0.0, null, false].forEach(function(i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 var name = String(i);
147 [si32a, si32a2].forEach(function(array) {
Ben Murdochda12d292016-06-02 14:46:10 +0100148 testOp(Atomics.compareExchange, array, i, 0, name);
149 testOp(Atomics.load, array, i, 0, name);
150 testOp(Atomics.store, array, i, 0, name);
151 testOp(Atomics.add, array, i, 0, name);
152 testOp(Atomics.sub, array, i, 0, name);
153 testOp(Atomics.and, array, i, 0, name);
154 testOp(Atomics.or, array, i, 0, name);
155 testOp(Atomics.xor, array, i, 0, name);
156 testOp(Atomics.exchange, array, i, 0, name);
157 });
158 });
159
160 // These values all map to index 3
161 var valueOf = {valueOf: function(){ return 3;}};
162 var toString = {toString: function(){ return '3';}};
163 [3, 3.0, '3', '3.0', valueOf, toString].forEach(function(i) {
164 var name = String(i);
165 [si32a, si32a2].forEach(function(array) {
166 testOp(Atomics.compareExchange, array, i, 3, name);
167 testOp(Atomics.load, array, i, 3, name);
168 testOp(Atomics.store, array, i, 3, name);
169 testOp(Atomics.add, array, i, 3, name);
170 testOp(Atomics.sub, array, i, 3, name);
171 testOp(Atomics.and, array, i, 3, name);
172 testOp(Atomics.or, array, i, 3, name);
173 testOp(Atomics.xor, array, i, 3, name);
174 testOp(Atomics.exchange, array, i, 3, name);
175 });
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 });
177})();
178
179function clearArray(sab) {
180 var ui8 = new Uint8Array(sab);
181 for (var i = 0; i < sab.byteLength; ++i) {
182 ui8[i] = 0;
183 }
184}
185
186(function TestCompareExchange() {
187 IntegerTypedArrayConstructors.forEach(function(t) {
188 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
189 var sta = new t.constr(sab);
190 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
191
192 [sta, sta2].forEach(function(array) {
193 clearArray(array.buffer);
194 var name = Object.prototype.toString.call(array);
195 for (var i = 0; i < array.length; ++i) {
196 // array[i] == 0, CAS will store
197 assertEquals(0, Atomics.compareExchange(array, i, 0, 50), name);
198 assertEquals(50, array[i], name);
199
200 // array[i] == 50, CAS will not store
201 assertEquals(50, Atomics.compareExchange(array, i, 0, 100), name);
202 assertEquals(50, array[i], name);
203 }
204 })
205 });
206})();
207
208(function TestLoad() {
209 IntegerTypedArrayConstructors.forEach(function(t) {
210 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
211 var sta = new t.constr(sab);
212 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
213
214 [sta, sta2].forEach(function(array) {
215 clearArray(array.buffer);
216 var name = Object.prototype.toString.call(array);
217 for (var i = 0; i < array.length; ++i) {
218 array[i] = 0;
219 assertEquals(0, Atomics.load(array, i), name);
220 array[i] = 50;
221 assertEquals(50, Atomics.load(array, i), name);
222 }
223 })
224 });
225})();
226
227(function TestStore() {
228 IntegerTypedArrayConstructors.forEach(function(t) {
229 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
230 var sta = new t.constr(sab);
231 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
232
233 [sta, sta2].forEach(function(array) {
234 clearArray(array.buffer);
235 var name = Object.prototype.toString.call(array);
236 for (var i = 0; i < array.length; ++i) {
237 assertEquals(50, Atomics.store(array, i, 50), name);
238 assertEquals(50, array[i], name);
239
240 assertEquals(100, Atomics.store(array, i, 100), name);
241 assertEquals(100, array[i], name);
242 }
243 })
244 });
245})();
246
247(function TestAdd() {
248 IntegerTypedArrayConstructors.forEach(function(t) {
249 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
250 var sta = new t.constr(sab);
251 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
252
253 [sta, sta2].forEach(function(array) {
254 clearArray(array.buffer);
255 var name = Object.prototype.toString.call(array);
256 for (var i = 0; i < array.length; ++i) {
257 assertEquals(0, Atomics.add(array, i, 50), name);
258 assertEquals(50, array[i], name);
259
260 assertEquals(50, Atomics.add(array, i, 70), name);
261 assertEquals(120, array[i], name);
262 }
263 })
264 });
265})();
266
267(function TestSub() {
268 IntegerTypedArrayConstructors.forEach(function(t) {
269 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
270 var sta = new t.constr(sab);
271 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
272
273 [sta, sta2].forEach(function(array) {
274 clearArray(array.buffer);
275 var name = Object.prototype.toString.call(array);
276 for (var i = 0; i < array.length; ++i) {
277 array[i] = 120;
278 assertEquals(120, Atomics.sub(array, i, 50), name);
279 assertEquals(70, array[i], name);
280
281 assertEquals(70, Atomics.sub(array, i, 70), name);
282 assertEquals(0, array[i], name);
283 }
284 })
285 });
286})();
287
288(function TestAnd() {
289 IntegerTypedArrayConstructors.forEach(function(t) {
290 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
291 var sta = new t.constr(sab);
292 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
293
294 [sta, sta2].forEach(function(array) {
295 clearArray(array.buffer);
296 var name = Object.prototype.toString.call(sta);
297 for (var i = 0; i < array.length; ++i) {
298 array[i] = 0x3f;
299 assertEquals(0x3f, Atomics.and(array, i, 0x30), name);
300 assertEquals(0x30, array[i], name);
301
302 assertEquals(0x30, Atomics.and(array, i, 0x20), name);
303 assertEquals(0x20, array[i], name);
304 }
305 })
306 });
307})();
308
309(function TestOr() {
310 IntegerTypedArrayConstructors.forEach(function(t) {
311 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
312 var sta = new t.constr(sab);
313 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
314
315 [sta, sta2].forEach(function(array) {
316 clearArray(array.buffer);
317 var name = Object.prototype.toString.call(array);
318 for (var i = 0; i < array.length; ++i) {
319 array[i] = 0x30;
320 assertEquals(0x30, Atomics.or(array, i, 0x1c), name);
321 assertEquals(0x3c, array[i], name);
322
323 assertEquals(0x3c, Atomics.or(array, i, 0x09), name);
324 assertEquals(0x3d, array[i], name);
325 }
326 })
327 });
328})();
329
330(function TestXor() {
331 IntegerTypedArrayConstructors.forEach(function(t) {
332 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
333 var sta = new t.constr(sab);
334 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
335
336 [sta, sta2].forEach(function(array) {
337 clearArray(array.buffer);
338 var name = Object.prototype.toString.call(array);
339 for (var i = 0; i < array.length; ++i) {
340 array[i] = 0x30;
341 assertEquals(0x30, Atomics.xor(array, i, 0x1c), name);
342 assertEquals(0x2c, array[i], name);
343
344 assertEquals(0x2c, Atomics.xor(array, i, 0x09), name);
345 assertEquals(0x25, array[i], name);
346 }
347 })
348 });
349})();
350
351(function TestExchange() {
352 IntegerTypedArrayConstructors.forEach(function(t) {
353 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
354 var sta = new t.constr(sab);
355 var sta2 = new t.constr(sab, 5 * t.constr.BYTES_PER_ELEMENT);
356
357 [sta, sta2].forEach(function(array) {
358 clearArray(array.buffer);
359 var name = Object.prototype.toString.call(array);
360 for (var i = 0; i < array.length; ++i) {
361 array[i] = 0x30;
362 assertEquals(0x30, Atomics.exchange(array, i, 0x1c), name);
363 assertEquals(0x1c, array[i], name);
364
365 assertEquals(0x1c, Atomics.exchange(array, i, 0x09), name);
366 assertEquals(0x09, array[i], name);
367 }
368 })
369 });
370})();
371
372(function TestIsLockFree() {
373 // For all platforms we support, 1, 2 and 4 bytes should be lock-free.
374 assertEquals(true, Atomics.isLockFree(1));
375 assertEquals(true, Atomics.isLockFree(2));
376 assertEquals(true, Atomics.isLockFree(4));
377
378 // Sizes that aren't equal to a typedarray BYTES_PER_ELEMENT always return
379 // false.
380 var validSizes = {};
381 IntegerTypedArrayConstructors.forEach(function(t) {
382 validSizes[t.constr.BYTES_PER_ELEMENT] = true;
383 });
384
385 for (var i = 0; i < 1000; ++i) {
386 if (!validSizes[i]) {
387 assertEquals(false, Atomics.isLockFree(i));
388 }
389 }
390})();
391
392(function TestToNumber() {
393 IntegerTypedArrayConstructors.forEach(function(t) {
394 var sab = new SharedArrayBuffer(1 * t.constr.BYTES_PER_ELEMENT);
395 var sta = new t.constr(sab);
396
397 var valueOf = {valueOf: function(){ return 3;}};
398 var toString = {toString: function(){ return '3';}};
399
400 [false, true, undefined, valueOf, toString].forEach(function(v) {
401 var name = Object.prototype.toString.call(sta) + ' - ' + v;
402
403 // CompareExchange
404 sta[0] = 50;
405 assertEquals(50, Atomics.compareExchange(sta, 0, v, v), name);
406
407 // Store
408 assertEquals(+v, Atomics.store(sta, 0, v), name);
409 assertEquals(v|0, sta[0], name);
410
411 // Add
412 sta[0] = 120;
413 assertEquals(120, Atomics.add(sta, 0, v), name);
414 assertEquals(120 + (v|0), sta[0], name);
415
416 // Sub
417 sta[0] = 70;
418 assertEquals(70, Atomics.sub(sta, 0, v), name);
419 assertEquals(70 - (v|0), sta[0]);
420
421 // And
422 sta[0] = 0x20;
423 assertEquals(0x20, Atomics.and(sta, 0, v), name);
424 assertEquals(0x20 & (v|0), sta[0]);
425
426 // Or
427 sta[0] = 0x3d;
428 assertEquals(0x3d, Atomics.or(sta, 0, v), name);
429 assertEquals(0x3d | (v|0), sta[0]);
430
431 // Xor
432 sta[0] = 0x25;
433 assertEquals(0x25, Atomics.xor(sta, 0, v), name);
434 assertEquals(0x25 ^ (v|0), sta[0]);
435
436 // Exchange
437 sta[0] = 0x09;
438 assertEquals(0x09, Atomics.exchange(sta, 0, v), name);
439 assertEquals(v|0, sta[0]);
440 });
441 });
442})();
443
444(function TestWrapping() {
445 IntegerTypedArrayConstructors.forEach(function(t) {
446 var sab = new SharedArrayBuffer(10 * t.constr.BYTES_PER_ELEMENT);
447 var sta = new t.constr(sab);
448 var name = Object.prototype.toString.call(sta);
449 var range = t.max - t.min + 1;
450 var offset;
451 var operand;
452 var val, newVal;
453 var valWrapped, newValWrapped;
454
455 for (offset = -range; offset <= range; offset += range) {
456 // CompareExchange
457 sta[0] = val = 0;
458 newVal = val + offset + 1;
459 newValWrapped = t.toRange(newVal);
460 assertEquals(val, Atomics.compareExchange(sta, 0, val, newVal), name);
461 assertEquals(newValWrapped, sta[0], name);
462
463 sta[0] = val = t.min;
464 newVal = val + offset - 1;
465 newValWrapped = t.toRange(newVal);
466 assertEquals(val, Atomics.compareExchange(sta, 0, val, newVal), name);
467 assertEquals(newValWrapped, sta[0], name);
468
469 // Store
470 sta[0] = 0;
471 val = t.max + offset + 1;
472 valWrapped = t.toRange(val);
473 assertEquals(val, Atomics.store(sta, 0, val), name);
474 assertEquals(valWrapped, sta[0], name);
475
476 sta[0] = val = t.min + offset - 1;
477 valWrapped = t.toRange(val);
478 assertEquals(val, Atomics.store(sta, 0, val), name);
479 assertEquals(valWrapped, sta[0], name);
480
481 // Add
482 sta[0] = val = t.max;
483 operand = offset + 1;
484 valWrapped = t.toRange(val + operand);
485 assertEquals(val, Atomics.add(sta, 0, operand), name);
486 assertEquals(valWrapped, sta[0], name);
487
488 sta[0] = val = t.min;
489 operand = offset - 1;
490 valWrapped = t.toRange(val + operand);
491 assertEquals(val, Atomics.add(sta, 0, operand), name);
492 assertEquals(valWrapped, sta[0], name);
493
494 // Sub
495 sta[0] = val = t.max;
496 operand = offset - 1;
497 valWrapped = t.toRange(val - operand);
498 assertEquals(val, Atomics.sub(sta, 0, operand), name);
499 assertEquals(valWrapped, sta[0], name);
500
501 sta[0] = val = t.min;
502 operand = offset + 1;
503 valWrapped = t.toRange(val - operand);
504 assertEquals(val, Atomics.sub(sta, 0, operand), name);
505 assertEquals(valWrapped, sta[0], name);
506
507 // There's no way to wrap results with logical operators, just test that
508 // using an out-of-range value is properly wrapped/clamped when written
509 // to memory.
510
511 // And
512 sta[0] = val = 0xf;
513 operand = 0x3 + offset;
514 valWrapped = t.toRange(val & operand);
515 assertEquals(val, Atomics.and(sta, 0, operand), name);
516 assertEquals(valWrapped, sta[0], name);
517
518 // Or
519 sta[0] = val = 0x12;
520 operand = 0x22 + offset;
521 valWrapped = t.toRange(val | operand);
522 assertEquals(val, Atomics.or(sta, 0, operand), name);
523 assertEquals(valWrapped, sta[0], name);
524
525 // Xor
526 sta[0] = val = 0x12;
527 operand = 0x22 + offset;
528 valWrapped = t.toRange(val ^ operand);
529 assertEquals(val, Atomics.xor(sta, 0, operand), name);
530 assertEquals(valWrapped, sta[0], name);
531
532 // Exchange
533 sta[0] = val = 0x12;
534 operand = 0x22 + offset;
535 valWrapped = t.toRange(operand);
536 assertEquals(val, Atomics.exchange(sta, 0, operand), name);
537 assertEquals(valWrapped, sta[0], name);
538 }
539
540 });
541})();