Index: test/mjsunit/harmony/atomics.js |
diff --git a/test/mjsunit/harmony/atomics.js b/test/mjsunit/harmony/atomics.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ca8fb20deb0a8eb4433e8b36083d71549d329434 |
--- /dev/null |
+++ b/test/mjsunit/harmony/atomics.js |
@@ -0,0 +1,476 @@ |
+// Copyright 2014 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// Flags: --harmony-atomics --harmony-shared-typed-arrays |
+// |
+(function TestBadArray() { |
+ var ab = new ArrayBuffer(16); |
+ var u32a = new Uint32Array(16); |
+ var sab = new SharedArrayBuffer(16); |
+ var sf32a = new SharedFloat32Array(16); |
+ var sf64a = new SharedFloat64Array(16); |
+ |
+ // Atomic ops required shared typed arrays |
+ [undefined, 1, 'hi', 3.4, ab, u32a, sab].forEach(function(o) { |
+ assertThrows(function() { Atomics.compareExchange(o, 0, 0, 0); }, |
+ TypeError); |
+ assertThrows(function() { Atomics.load(o, 0); }, TypeError); |
+ assertThrows(function() { Atomics.store(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.add(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.sub(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.and(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.or(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.xor(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.exchange(o, 0, 0); }, TypeError); |
+ }); |
+ |
+ // Arithmetic atomic ops require integer shared arrays |
+ [sab, sf32a, sf64a].forEach(function(o) { |
+ assertThrows(function() { Atomics.add(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.sub(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.and(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.or(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.xor(o, 0, 0); }, TypeError); |
+ assertThrows(function() { Atomics.exchange(o, 0, 0); }, TypeError); |
+ }); |
+})(); |
+ |
+(function TestBadIndex() { |
+ var si32a = new SharedInt32Array(16); |
+ |
+ // TODO(binji): shouldn't work for 0.5 either, currently busted |
+ [undefined, null, false, 'hi', {}, -100, 17].forEach(function(i) { |
+ assertEquals(undefined, Atomics.compareExchange(si32a, i, 0, 0), i); |
+ assertEquals(undefined, Atomics.load(si32a, i), i); |
+ assertEquals(undefined, Atomics.store(si32a, i, 0), i); |
+ assertEquals(undefined, Atomics.add(si32a, i, 0), i); |
+ assertEquals(undefined, Atomics.sub(si32a, i, 0), i); |
+ assertEquals(undefined, Atomics.and(si32a, i, 0), i); |
+ assertEquals(undefined, Atomics.or(si32a, i, 0), i); |
+ assertEquals(undefined, Atomics.xor(si32a, i, 0), i); |
+ assertEquals(undefined, Atomics.exchange(si32a, i, 0), i); |
+ }); |
+})(); |
+ |
+(function TestGoodIndex() { |
+ var si32a = new SharedInt32Array(16); |
+ |
+ // TODO(binji): should work for new Number(5) too, currently busted |
+ // TODO(binji): should work for {valueOf:function(){return 3;}} too |
+ [0, 15, '10'].forEach(function(i) { |
+ assertEquals(0, Atomics.compareExchange(si32a, i, 0, 0), i); |
+ assertEquals(0, Atomics.load(si32a, i), i); |
+ assertEquals(0, Atomics.store(si32a, i, 0), i); |
+ assertEquals(0, Atomics.add(si32a, i, 0), i); |
+ assertEquals(0, Atomics.sub(si32a, i, 0), i); |
+ assertEquals(0, Atomics.and(si32a, i, 0), i); |
+ assertEquals(0, Atomics.or(si32a, i, 0), i); |
+ assertEquals(0, Atomics.xor(si32a, i, 0), i); |
+ /* |
+ assertEquals(0, Atomics.exchange(si32a, i, 0), i); |
+ */ |
+ }); |
+})(); |
+ |
+(function TestCompareExchange() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ var sf32a = new SharedFloat32Array(10); |
+ var sf64a = new SharedFloat64Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a, sf32a, sf64a].forEach(function(sta) { |
+ var name = Object.prototype.toString.call(sta); |
+ for (var i = 0; i < 10; ++i) { |
+ // sta[i] == 0, CAS will store |
+ assertEquals(0, Atomics.compareExchange(sta, i, 0, 50), name); |
+ assertEquals(50, sta[i], name); |
+ |
+ // sta[i] == 50, CAS will not store |
+ assertEquals(50, Atomics.compareExchange(sta, i, 0, 100), name); |
+ assertEquals(50, sta[i], name); |
+ } |
+ }); |
+ |
+ // Check out-of-range values (should wrap) |
+ var integerTypes = [ |
+ {a: si8a, min: -128, max: 127}, |
+ {a: si16a, min: -32768, max: 32767}, |
+ {a: si32a, min: -0x80000000, max: 0x7fffffff}, |
+ {a: su8a, min: 0, max: 255}, |
+ {a: su16a, min: 0, max: 65535}, |
+ {a: su32a, min: 0, max: 0xffffffff}, |
+ ]; |
+ |
+ integerTypes.forEach(function(t) { |
+ var name = Object.prototype.toString.call(t.a); |
+ var range = t.max - t.min + 1; |
+ var add; |
+ var oldVal, oldValWrapped; |
+ var newVal, newValWrapped; |
+ |
+ for (add = -range; add <= range; add += range) { |
+ t.a[0] = oldVal = 0; |
+ newVal = t.max + add + 1; |
+ newValWrapped = t.min; |
+ assertEquals(oldVal, |
+ Atomics.compareExchange(t.a, 0, oldVal, newVal), name); |
+ assertEquals(newValWrapped, t.a[0], name); |
+ |
+ oldVal = newVal; |
+ oldValWrapped = newValWrapped; |
+ newVal = t.min + add - 1; |
+ newValWrapped = t.max; |
+ assertEquals(oldValWrapped, |
+ Atomics.compareExchange(t.a, 0, oldVal, newVal), name); |
+ assertEquals(newValWrapped, t.a[0], name); |
+ } |
+ }); |
+ |
+ // * Exact float values should be OK |
+ // * Infinity, -Infinity should be OK (has exact representation) |
+ // * NaN is not OK, it has many representations, cannot ensure successful CAS |
+ // because it does a bitwise compare |
+ [1.5, 4.25, -1e8, -Infinity, Infinity].forEach(function(v) { |
+ sf32a[0] = 0; |
+ assertEquals(0, Atomics.compareExchange(sf32a, 0, 0, v)); |
+ assertEquals(v, sf32a[0]); |
+ assertEquals(v, Atomics.compareExchange(sf32a, 0, v, 0)); |
+ assertEquals(0, sf32a[0]); |
+ |
+ sf64a[0] = 0; |
+ assertEquals(0, Atomics.compareExchange(sf64a, 0, 0, v)); |
+ assertEquals(v, sf64a[0]); |
+ assertEquals(v, Atomics.compareExchange(sf64a, 0, v, 0)); |
+ assertEquals(0, sf64a[0]); |
+ }); |
+})(); |
+ |
+(function TestLoad() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ var sf32a = new SharedFloat32Array(10); |
+ var sf64a = new SharedFloat64Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a, sf32a, sf64a].forEach(function(sta) { |
+ for (var i = 0; i < 10; ++i) { |
+ var name = Object.prototype.toString.call(sta); |
+ sta[i] = 0; |
+ assertEquals(0, Atomics.load(sta, i), name); |
+ sta[i] = 50; |
+ assertEquals(50, Atomics.load(sta, i), name); |
+ } |
+ }); |
+})(); |
+ |
+(function TestStore() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ var sf32a = new SharedFloat32Array(10); |
+ var sf64a = new SharedFloat64Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a, sf32a, sf64a].forEach(function(sta) { |
+ var name = Object.prototype.toString.call(sta); |
+ for (var i = 0; i < 10; ++i) { |
+ assertEquals(50, Atomics.store(sta, i, 50), name); |
+ assertEquals(50, sta[i], name); |
+ |
+ assertEquals(100, Atomics.store(sta, i, 100), name); |
+ assertEquals(100, sta[i], name); |
+ } |
+ }); |
+ |
+ // Check out-of-range values (should wrap stored value, but not wrap the |
+ // returned value) |
+ var integerTypes = [ |
+ {a: si8a, min: -128, max: 127}, |
+ {a: si16a, min: -32768, max: 32767}, |
+ {a: si32a, min: -0x80000000, max: 0x7fffffff}, |
+ {a: su8a, min: 0, max: 255}, |
+ {a: su16a, min: 0, max: 65535}, |
+ {a: su32a, min: 0, max: 0xffffffff}, |
+ ]; |
+ |
+ integerTypes.forEach(function(t) { |
+ var name = Object.prototype.toString.call(t.a); |
+ var range = t.max - t.min + 1; |
+ var add; |
+ var val, valWrapped; |
+ |
+ for (add = -range; add <= range; add += range) { |
+ t.a[0] = 0; |
+ val = t.max + add + 1; |
+ valWrapped = t.min; |
+ assertEquals(val, Atomics.store(t.a, 0, val), name); |
+ assertEquals(valWrapped, t.a[0], name); |
+ |
+ val = t.min + add - 1; |
+ valWrapped = t.max; |
+ assertEquals(val, Atomics.store(t.a, 0, val), name); |
+ assertEquals(valWrapped, t.a[0], name); |
+ } |
+ }); |
+ |
+ [1.5, 4.25, -1e8, -Infinity, Infinity, NaN].forEach(function(v) { |
+ sf32a[0] = 0; |
+ assertEquals(v, Atomics.store(sf32a, 0, v)); |
+ assertEquals(v, sf32a[0]); |
+ |
+ sf64a[0] = 0; |
+ assertEquals(v, Atomics.store(sf64a, 0, v)); |
+ assertEquals(v, sf64a[0]); |
+ }); |
+})(); |
+ |
+(function TestAdd() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a].forEach(function(sta) { |
+ var name = Object.prototype.toString.call(sta); |
+ for (var i = 0; i < 10; ++i) { |
+ assertEquals(0, Atomics.add(sta, i, 50), name); |
+ assertEquals(50, sta[i], name); |
+ |
+ assertEquals(50, Atomics.add(sta, i, 70), name); |
+ assertEquals(120, sta[i], name); |
+ } |
+ }); |
+ |
+ // Check out-of-range values (should wrap stored value, but not wrap the |
+ // returned value) |
+ var integerTypes = [ |
+ {a: si8a, min: -128, max: 127}, |
+ {a: si16a, min: -32768, max: 32767}, |
+ {a: si32a, min: -0x80000000, max: 0x7fffffff}, |
+ {a: su8a, min: 0, max: 255}, |
+ {a: su16a, min: 0, max: 65535}, |
+ {a: su32a, min: 0, max: 0xffffffff}, |
+ ]; |
+ |
+ integerTypes.forEach(function(t) { |
+ var name = Object.prototype.toString.call(t.a); |
+ var range = t.max - t.min + 1; |
+ var add; |
+ |
+ for (add = -range; add <= range; add += range) { |
+ t.a[0] = t.max; |
+ valWrapped = t.min; |
+ assertEquals(t.max, Atomics.add(t.a, 0, add + 1), name); |
+ assertEquals(t.min, t.a[0], name); |
+ |
+ assertEquals(t.min, Atomics.add(t.a, 0, add - 1), name); |
+ assertEquals(t.max, t.a[0], name); |
+ } |
+ }); |
+})(); |
+ |
+(function TestSub() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a].forEach(function(sta) { |
+ var name = Object.prototype.toString.call(sta); |
+ for (var i = 0; i < 10; ++i) { |
+ sta[i] = 120; |
+ assertEquals(120, Atomics.sub(sta, i, 50), name); |
+ assertEquals(70, sta[i], name); |
+ |
+ assertEquals(70, Atomics.sub(sta, i, 70), name); |
+ assertEquals(0, sta[i], name); |
+ } |
+ }); |
+ |
+ // Check out-of-range values (should wrap stored value, but not wrap the |
+ // returned value) |
+ var integerTypes = [ |
+ {a: si8a, min: -128, max: 127}, |
+ {a: si16a, min: -32768, max: 32767}, |
+ {a: si32a, min: -0x80000000, max: 0x7fffffff}, |
+ {a: su8a, min: 0, max: 255}, |
+ {a: su16a, min: 0, max: 65535}, |
+ {a: su32a, min: 0, max: 0xffffffff}, |
+ ]; |
+ |
+ integerTypes.forEach(function(t) { |
+ var name = Object.prototype.toString.call(t.a); |
+ var range = t.max - t.min + 1; |
+ var add; |
+ |
+ for (add = -range; add <= range; add += range) { |
+ t.a[0] = t.max; |
+ valWrapped = t.min; |
+ assertEquals(t.max, Atomics.sub(t.a, 0, add - 1), name); |
+ assertEquals(t.min, t.a[0], name); |
+ |
+ assertEquals(t.min, Atomics.sub(t.a, 0, add + 1), name); |
+ assertEquals(t.max, t.a[0], name); |
+ } |
+ }); |
+})(); |
+ |
+(function TestAnd() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a].forEach(function(sta) { |
+ var name = Object.prototype.toString.call(sta); |
+ for (var i = 0; i < 10; ++i) { |
+ sta[i] = 0x3f; |
+ assertEquals(0x3f, Atomics.and(sta, i, 0x30), name); |
+ assertEquals(0x30, sta[i], name); |
+ |
+ assertEquals(0x30, Atomics.and(sta, i, 0x20), name); |
+ assertEquals(0x20, sta[i], name); |
+ } |
+ }); |
+ |
+ // Check out-of-range values (should wrap stored value, but not wrap the |
+ // returned value) |
+ var integerTypes = [ |
+ {a: si8a, min: -128, max: 127}, |
+ {a: si16a, min: -32768, max: 32767}, |
+ {a: si32a, min: -0x80000000, max: 0x7fffffff}, |
+ {a: su8a, min: 0, max: 255}, |
+ {a: su16a, min: 0, max: 65535}, |
+ {a: su32a, min: 0, max: 0xffffffff}, |
+ ]; |
+ |
+ integerTypes.forEach(function(t) { |
+ var name = Object.prototype.toString.call(t.a); |
+ var range = t.max - t.min + 1; |
+ var add; |
+ |
+ // There's no way to wrap results with logical operators, just test that |
+ // using an out-of-range value is properly masked. |
+ for (add = -range; add <= range; add += range) { |
+ t.a[0] = 0xf; |
+ assertEquals(0xf, Atomics.and(t.a, 0, 0x3 + add), name); |
+ assertEquals(0x3, t.a[0], name); |
+ } |
+ }); |
+})(); |
+ |
+(function TestOr() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a].forEach(function(sta) { |
+ var name = Object.prototype.toString.call(sta); |
+ for (var i = 0; i < 10; ++i) { |
+ sta[i] = 0x30; |
+ assertEquals(0x30, Atomics.or(sta, i, 0x1c), name); |
+ assertEquals(0x3c, sta[i], name); |
+ |
+ assertEquals(0x3c, Atomics.or(sta, i, 0x09), name); |
+ assertEquals(0x3d, sta[i], name); |
+ } |
+ }); |
+ |
+ // Check out-of-range values (should wrap stored value, but not wrap the |
+ // returned value) |
+ var integerTypes = [ |
+ {a: si8a, min: -128, max: 127}, |
+ {a: si16a, min: -32768, max: 32767}, |
+ {a: si32a, min: -0x80000000, max: 0x7fffffff}, |
+ {a: su8a, min: 0, max: 255}, |
+ {a: su16a, min: 0, max: 65535}, |
+ {a: su32a, min: 0, max: 0xffffffff}, |
+ ]; |
+ |
+ integerTypes.forEach(function(t) { |
+ var name = Object.prototype.toString.call(t.a); |
+ var range = t.max - t.min + 1; |
+ var add; |
+ |
+ // There's no way to wrap results with logical operators, just test that |
+ // using an out-of-range value is properly masked. |
+ for (add = -range; add <= range; add += range) { |
+ t.a[0] = 0x12; |
+ assertEquals(0x12, Atomics.or(t.a, 0, 0x22 + add), name); |
+ assertEquals(0x32, t.a[0], name); |
+ } |
+ }); |
+})(); |
+ |
+(function TestXor() { |
+ var si8a = new SharedInt8Array(10); |
+ var si16a = new SharedInt16Array(10); |
+ var si32a = new SharedInt32Array(10); |
+ var su8a = new SharedUint8Array(10); |
+ var su16a = new SharedUint16Array(10); |
+ var su32a = new SharedUint32Array(10); |
+ // TODO(binji): SharedUint8ClampedArray? |
+ |
+ [si8a, si16a, si32a, su8a, su16a, su32a].forEach(function(sta) { |
+ var name = Object.prototype.toString.call(sta); |
+ for (var i = 0; i < 10; ++i) { |
+ sta[i] = 0x30; |
+ assertEquals(0x30, Atomics.xor(sta, i, 0x1c), name); |
+ assertEquals(0x2c, sta[i], name); |
+ |
+ assertEquals(0x2c, Atomics.xor(sta, i, 0x09), name); |
+ assertEquals(0x25, sta[i], name); |
+ } |
+ }); |
+ |
+ // Check out-of-range values (should wrap stored value, but not wrap the |
+ // returned value) |
+ var integerTypes = [ |
+ {a: si8a, min: -128, max: 127}, |
+ {a: si16a, min: -32768, max: 32767}, |
+ {a: si32a, min: -0x80000000, max: 0x7fffffff}, |
+ {a: su8a, min: 0, max: 255}, |
+ {a: su16a, min: 0, max: 65535}, |
+ {a: su32a, min: 0, max: 0xffffffff}, |
+ ]; |
+ |
+ integerTypes.forEach(function(t) { |
+ var name = Object.prototype.toString.call(t.a); |
+ var range = t.max - t.min + 1; |
+ var add; |
+ |
+ // There's no way to wrap results with logical operators, just test that |
+ // using an out-of-range value is properly masked. |
+ for (add = -range; add <= range; add += range) { |
+ t.a[0] = 0x12; |
+ assertEquals(0x12, Atomics.xor(t.a, 0, 0x22 + add), name); |
+ assertEquals(0x30, t.a[0], name); |
+ } |
+ }); |
+})(); |