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}, |
| 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 |