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 3// found in the LICENSE file. 4 5// Flags: --harmony-simd 6// Flags: --allow-natives-syntax --expose-natives-as natives --noalways-opt 7 8function lanesForType(typeName) { 9 // The lane count follows the first 'x' in the type name, which begins with 10 // 'float', 'int', or 'bool'. 11 return Number.parseInt(typeName.substr(typeName.indexOf('x') + 1)); 12} 13 14 15// Creates an instance that has been zeroed, so it can be used for equality 16// testing. 17function createInstance(type) { 18 // Provide enough parameters for the longest type (currently 16). It's 19 // important that instances be consistent to better test that different SIMD 20 // types can't be compared and are never equal or the same in any sense. 21 return SIMD[type](0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); 22} 23 24 25function isValidSimdString(string, value, type, lanes) { 26 var simdFn = SIMD[type], 27 parseFn = 28 type.indexOf('Float') === 0 ? Number.parseFloat : Number.parseInt, 29 indexOfOpenParen = string.indexOf('('); 30 // Check prefix (e.g. SIMD.Float32x4.) 31 if (string.substr(0, indexOfOpenParen) !== 'SIMD.' + type) 32 return false; 33 // Remove type name (e.g. SIMD.Float32x4) and open parenthesis. 34 string = string.substr(indexOfOpenParen + 1); 35 var laneStrings = string.split(','); 36 if (laneStrings.length !== lanes) 37 return false; 38 for (var i = 0; i < lanes; i++) { 39 var fromString = parseFn(laneStrings[i]), 40 fromValue = simdFn.extractLane(value, i); 41 if (Math.abs(fromString - fromValue) > Number.EPSILON) 42 return false; 43 } 44 return true; 45} 46 47 48var simdTypeNames = ['Float32x4', 'Int32x4', 'Uint32x4', 'Bool32x4', 49 'Int16x8', 'Uint16x8', 'Bool16x8', 50 'Int8x16', 'Uint8x16', 'Bool8x16']; 51 52var nonSimdValues = [347, 1.275, NaN, "string", null, undefined, {}, 53 function() {}]; 54 55function checkTypeMatrix(type, fn) { 56 // Check against non-SIMD types. 57 nonSimdValues.forEach(fn); 58 // Check against SIMD values of a different type. 59 for (var i = 0; i < simdTypeNames.length; i++) { 60 var otherType = simdTypeNames[i]; 61 if (type != otherType) fn(createInstance(otherType)); 62 } 63} 64 65 66// Test different forms of constructor calls. 67function TestConstructor(type, lanes) { 68 var simdFn = SIMD[type]; 69 var instance = createInstance(type); 70 71 assertFalse(Object === simdFn.prototype.constructor) 72 assertFalse(simdFn === Object.prototype.constructor) 73 assertSame(simdFn, simdFn.prototype.constructor) 74 75 assertSame(simdFn, instance.__proto__.constructor) 76 assertSame(simdFn, Object(instance).__proto__.constructor) 77 assertSame(simdFn.prototype, instance.__proto__) 78 assertSame(simdFn.prototype, Object(instance).__proto__) 79} 80 81 82function TestType(type, lanes) { 83 var simdFn = SIMD[type]; 84 var instance = createInstance(type); 85 var typeofString = type.charAt(0).toLowerCase() + type.slice(1); 86 87 assertEquals(typeofString, typeof instance) 88 assertTrue(typeof instance === typeofString) 89 assertTrue(typeof Object(instance) === 'object') 90 assertEquals(null, %_ClassOf(instance)) 91 assertEquals(type, %_ClassOf(Object(instance))) 92} 93 94 95function TestPrototype(type, lanes) { 96 var simdFn = SIMD[type]; 97 var instance = createInstance(type); 98 99 assertSame(Object.prototype, simdFn.prototype.__proto__) 100 assertSame(simdFn.prototype, instance.__proto__) 101 assertSame(simdFn.prototype, Object(instance).__proto__) 102} 103 104 105function TestValueOf(type, lanes) { 106 var simdFn = SIMD[type]; 107 var instance = createInstance(type); 108 109 assertTrue(instance === Object(instance).valueOf()) 110 assertTrue(instance === instance.valueOf()) 111 assertTrue(simdFn.prototype.valueOf.call(Object(instance)) === instance) 112 assertTrue(simdFn.prototype.valueOf.call(instance) === instance) 113} 114 115 116function TestGet(type, lanes) { 117 var simdFn = SIMD[type]; 118 var instance = createInstance(type); 119 120 assertEquals(undefined, instance.a) 121 assertEquals(undefined, instance["a" + "b"]) 122 assertEquals(undefined, instance["" + "1"]) 123 assertEquals(undefined, instance[42]) 124} 125 126 127function TestToBoolean(type, lanes) { 128 var simdFn = SIMD[type]; 129 var instance = createInstance(type); 130 131 assertTrue(Boolean(Object(instance))) 132 assertFalse(!Object(instance)) 133 assertTrue(Boolean(instance).valueOf()) 134 assertFalse(!instance) 135 assertTrue(!!instance) 136 assertTrue(instance && true) 137 assertFalse(!instance && false) 138 assertTrue(!instance || true) 139 assertEquals(1, instance ? 1 : 2) 140 assertEquals(2, !instance ? 1 : 2) 141 if (!instance) assertUnreachable(); 142 if (instance) {} else assertUnreachable(); 143} 144 145 146function TestToString(type, lanes) { 147 var simdFn = SIMD[type]; 148 var instance = createInstance(type); 149 150 assertEquals(instance.toString(), String(instance)) 151 assertTrue(isValidSimdString(instance.toString(), instance, type, lanes)) 152 assertTrue( 153 isValidSimdString(Object(instance).toString(), instance, type, lanes)) 154 assertTrue(isValidSimdString( 155 simdFn.prototype.toString.call(instance), instance, type, lanes)) 156} 157 158 159function TestToNumber(type, lanes) { 160 var simdFn = SIMD[type]; 161 var instance = createInstance(type); 162 163 assertThrows(function() { Number(Object(instance)) }, TypeError) 164 assertThrows(function() { +Object(instance) }, TypeError) 165 assertThrows(function() { Number(instance) }, TypeError) 166 assertThrows(function() { instance + 0 }, TypeError) 167} 168 169 170function TestCoercions(type, lanes) { 171 var simdFn = SIMD[type]; 172 var instance = createInstance(type); 173 // Test that setting a lane to value 'a' results in a lane with value 'b'. 174 function test(a, b) { 175 for (var i = 0; i < lanes; i++) { 176 var ainstance = simdFn.replaceLane(instance, i, a); 177 var lane_value = simdFn.extractLane(ainstance, i); 178 assertSame(b, lane_value); 179 } 180 } 181 182 switch (type) { 183 case 'Float32x4': 184 test(0, 0); 185 test(-0, -0); 186 test(NaN, NaN); 187 test(null, 0); 188 test(undefined, NaN); 189 test("5.25", 5.25); 190 test(Number.MAX_VALUE, Infinity); 191 test(-Number.MAX_VALUE, -Infinity); 192 test(Number.MIN_VALUE, 0); 193 break; 194 case 'Int32x4': 195 test(Infinity, 0); 196 test(-Infinity, 0); 197 test(NaN, 0); 198 test(0, 0); 199 test(-0, 0); 200 test(Number.MIN_VALUE, 0); 201 test(-Number.MIN_VALUE, 0); 202 test(0.1, 0); 203 test(-0.1, 0); 204 test(1, 1); 205 test(1.1, 1); 206 test(-1, -1); 207 test(-1.6, -1); 208 test(2147483647, 2147483647); 209 test(2147483648, -2147483648); 210 test(2147483649, -2147483647); 211 test(4294967295, -1); 212 test(4294967296, 0); 213 test(4294967297, 1); 214 break; 215 case 'Uint32x4': 216 test(Infinity, 0); 217 test(-Infinity, 0); 218 test(NaN, 0); 219 test(0, 0); 220 test(-0, 0); 221 test(Number.MIN_VALUE, 0); 222 test(-Number.MIN_VALUE, 0); 223 test(0.1, 0); 224 test(-0.1, 0); 225 test(1, 1); 226 test(1.1, 1); 227 test(-1, 4294967295); 228 test(-1.6, 4294967295); 229 test(4294967295, 4294967295); 230 test(4294967296, 0); 231 test(4294967297, 1); 232 break; 233 case 'Int16x8': 234 test(Infinity, 0); 235 test(-Infinity, 0); 236 test(NaN, 0); 237 test(0, 0); 238 test(-0, 0); 239 test(Number.MIN_VALUE, 0); 240 test(-Number.MIN_VALUE, 0); 241 test(0.1, 0); 242 test(-0.1, 0); 243 test(1, 1); 244 test(1.1, 1); 245 test(-1, -1); 246 test(-1.6, -1); 247 test(32767, 32767); 248 test(32768, -32768); 249 test(32769, -32767); 250 test(65535, -1); 251 test(65536, 0); 252 test(65537, 1); 253 break; 254 case 'Uint16x8': 255 test(Infinity, 0); 256 test(-Infinity, 0); 257 test(NaN, 0); 258 test(0, 0); 259 test(-0, 0); 260 test(Number.MIN_VALUE, 0); 261 test(-Number.MIN_VALUE, 0); 262 test(0.1, 0); 263 test(-0.1, 0); 264 test(1, 1); 265 test(1.1, 1); 266 test(-1, 65535); 267 test(-1.6, 65535); 268 test(65535, 65535); 269 test(65536, 0); 270 test(65537, 1); 271 break; 272 case 'Int8x16': 273 test(Infinity, 0); 274 test(-Infinity, 0); 275 test(NaN, 0); 276 test(0, 0); 277 test(-0, 0); 278 test(Number.MIN_VALUE, 0); 279 test(-Number.MIN_VALUE, 0); 280 test(0.1, 0); 281 test(-0.1, 0); 282 test(1, 1); 283 test(1.1, 1); 284 test(-1, -1); 285 test(-1.6, -1); 286 test(127, 127); 287 test(128, -128); 288 test(129, -127); 289 test(255, -1); 290 test(256, 0); 291 test(257, 1); 292 break; 293 case 'Uint8x16': 294 test(Infinity, 0); 295 test(-Infinity, 0); 296 test(NaN, 0); 297 test(0, 0); 298 test(-0, 0); 299 test(Number.MIN_VALUE, 0); 300 test(-Number.MIN_VALUE, 0); 301 test(0.1, 0); 302 test(-0.1, 0); 303 test(1, 1); 304 test(1.1, 1); 305 test(-1, 255); 306 test(-1.6, 255); 307 test(255, 255); 308 test(256, 0); 309 test(257, 1); 310 break; 311 case 'Bool32x4': 312 case 'Bool16x8': 313 case 'Bool8x16': 314 test(true, true); 315 test(false, false); 316 test(0, false); 317 test(1, true); 318 test(0.1, true); 319 test(NaN, false); 320 test(null, false); 321 test("", false); 322 test("false", true); 323 break; 324 } 325} 326 327 328function TestEquality(type, lanes) { 329 var simdFn = SIMD[type]; 330 var instance = createInstance(type); 331 332 // Every SIMD value should equal itself, and non-strictly equal its wrapper. 333 assertSame(instance, instance) 334 assertEquals(instance, instance) 335 assertTrue(Object.is(instance, instance)) 336 assertTrue(instance === instance) 337 assertTrue(instance == instance) 338 assertFalse(instance === Object(instance)) 339 assertFalse(Object(instance) === instance) 340 assertTrue(instance == Object(instance)) 341 assertTrue(Object(instance) == instance) 342 assertTrue(instance === instance.valueOf()) 343 assertTrue(instance.valueOf() === instance) 344 assertTrue(instance == instance.valueOf()) 345 assertTrue(instance.valueOf() == instance) 346 assertFalse(Object(instance) === Object(instance)) 347 assertEquals(Object(instance).valueOf(), Object(instance).valueOf()) 348 349 function notEqual(other) { 350 assertFalse(instance === other) 351 assertFalse(other === instance) 352 assertFalse(instance == other) 353 assertFalse(other == instance) 354 } 355 356 // SIMD values should not be equal to instances of different types. 357 checkTypeMatrix(type, function(other) { 358 assertFalse(instance === other) 359 assertFalse(other === instance) 360 assertFalse(instance == other) 361 assertFalse(other == instance) 362 }); 363 364 // Test that f(a, b) is the same as f(SIMD(a), SIMD(b)) for equality and 365 // strict equality, at every lane. 366 function test(a, b) { 367 for (var i = 0; i < lanes; i++) { 368 var aval = simdFn.replaceLane(instance, i, a); 369 var bval = simdFn.replaceLane(instance, i, b); 370 assertSame(a == b, aval == bval); 371 assertSame(a === b, aval === bval); 372 } 373 } 374 375 switch (type) { 376 case 'Float32x4': 377 test(1, 2.5); 378 test(1, 1); 379 test(0, 0); 380 test(-0, +0); 381 test(+0, -0); 382 test(-0, -0); 383 test(0, NaN); 384 test(NaN, NaN); 385 break; 386 case 'Int32x4': 387 case 'Uint32x4': 388 case 'Int16x8': 389 case 'Uint16x8': 390 case 'Int8x16': 391 case 'Uint8x16': 392 test(1, 2); 393 test(1, 1); 394 test(1, -1); 395 break; 396 case 'Bool32x4': 397 case 'Bool16x8': 398 case 'Bool8x16': 399 test(true, false); 400 test(false, true); 401 break; 402 } 403} 404 405 406function TestSameValue(type, lanes) { 407 var simdFn = SIMD[type]; 408 var instance = createInstance(type); 409 var sameValue = Object.is 410 var sameValueZero = function(x, y) { return %SameValueZero(x, y); } 411 412 // SIMD values should not be the same as instances of different types. 413 checkTypeMatrix(type, function(other) { 414 assertFalse(sameValue(instance, other)); 415 assertFalse(sameValueZero(instance, other)); 416 }); 417 418 // Test that f(a, b) is the same as f(SIMD(a), SIMD(b)) for sameValue and 419 // sameValueZero, at every lane. 420 function test(a, b) { 421 for (var i = 0; i < lanes; i++) { 422 var aval = simdFn.replaceLane(instance, i, a); 423 var bval = simdFn.replaceLane(instance, i, b); 424 assertSame(sameValue(a, b), sameValue(aval, bval)); 425 assertSame(sameValueZero(a, b), sameValueZero(aval, bval)); 426 } 427 } 428 429 switch (type) { 430 case 'Float32x4': 431 test(1, 2.5); 432 test(1, 1); 433 test(0, 0); 434 test(-0, +0); 435 test(+0, -0); 436 test(-0, -0); 437 test(0, NaN); 438 test(NaN, NaN); 439 break; 440 case 'Int32x4': 441 case 'Uint32x4': 442 case 'Int16x8': 443 case 'Uint16x8': 444 case 'Int8x16': 445 case 'Uint8x16': 446 test(1, 2); 447 test(1, 1); 448 test(1, -1); 449 break; 450 case 'Bool32x4': 451 case 'Bool16x8': 452 case 'Bool8x16': 453 test(true, false); 454 test(false, true); 455 break; 456 } 457} 458 459 460function TestComparison(type, lanes) { 461 var simdFn = SIMD[type]; 462 var a = createInstance(type), b = createInstance(type); 463 464 function compare(other) { 465 var throwFuncs = [ 466 function lt() { a < b; }, 467 function gt() { a > b; }, 468 function le() { a <= b; }, 469 function ge() { a >= b; }, 470 function lt_same() { a < a; }, 471 function gt_same() { a > a; }, 472 function le_same() { a <= a; }, 473 function ge_same() { a >= a; }, 474 ]; 475 476 for (var f of throwFuncs) { 477 assertThrows(f, TypeError); 478 %OptimizeFunctionOnNextCall(f); 479 assertThrows(f, TypeError); 480 assertThrows(f, TypeError); 481 } 482 } 483 484 // Test comparison against the same SIMD type. 485 compare(b); 486 // Test comparison against other types. 487 checkTypeMatrix(type, compare); 488} 489 490 491// Test SIMD value wrapping/boxing over non-builtins. 492function TestCall(type, lanes) { 493 var simdFn = SIMD[type]; 494 var instance = createInstance(type); 495 simdFn.prototype.getThisProto = function () { 496 return Object.getPrototypeOf(this); 497 } 498 assertTrue(instance.getThisProto() === simdFn.prototype) 499} 500 501 502function TestAsSetKey(type, lanes, set) { 503 var simdFn = SIMD[type]; 504 var instance = createInstance(type); 505 506 function test(set, key) { 507 assertFalse(set.has(key)); 508 assertFalse(set.delete(key)); 509 if (!(set instanceof WeakSet)) { 510 assertSame(set, set.add(key)); 511 assertTrue(set.has(key)); 512 assertTrue(set.delete(key)); 513 } else { 514 // SIMD values can't be used as keys in WeakSets. 515 assertThrows(function() { set.add(key) }); 516 } 517 assertFalse(set.has(key)); 518 assertFalse(set.delete(key)); 519 assertFalse(set.has(key)); 520 } 521 522 test(set, instance); 523} 524 525 526function TestAsMapKey(type, lanes, map) { 527 var simdFn = SIMD[type]; 528 var instance = createInstance(type); 529 530 function test(map, key, value) { 531 assertFalse(map.has(key)); 532 assertSame(undefined, map.get(key)); 533 assertFalse(map.delete(key)); 534 if (!(map instanceof WeakMap)) { 535 assertSame(map, map.set(key, value)); 536 assertSame(value, map.get(key)); 537 assertTrue(map.has(key)); 538 assertTrue(map.delete(key)); 539 } else { 540 // SIMD values can't be used as keys in WeakMaps. 541 assertThrows(function() { map.set(key, value) }); 542 } 543 assertFalse(map.has(key)); 544 assertSame(undefined, map.get(key)); 545 assertFalse(map.delete(key)); 546 assertFalse(map.has(key)); 547 assertSame(undefined, map.get(key)); 548 } 549 550 test(map, instance, {}); 551} 552 553 554// Test SIMD type with Harmony reflect-apply. 555function TestReflectApply(type) { 556 var simdFn = SIMD[type]; 557 var instance = createInstance(type); 558 559 function returnThis() { return this; } 560 function returnThisStrict() { 'use strict'; return this; } 561 function noop() {} 562 function noopStrict() { 'use strict'; } 563 var R = void 0; 564 565 assertSame(SIMD[type].prototype, 566 Object.getPrototypeOf( 567 Reflect.apply(returnThis, instance, []))); 568 assertSame(instance, Reflect.apply(returnThisStrict, instance, [])); 569 570 assertThrows( 571 function() { 'use strict'; Reflect.apply(instance); }, TypeError); 572 assertThrows( 573 function() { Reflect.apply(instance); }, TypeError); 574 assertThrows( 575 function() { Reflect.apply(noopStrict, R, instance); }, TypeError); 576 assertThrows( 577 function() { Reflect.apply(noop, R, instance); }, TypeError); 578} 579 580 581function TestSIMDTypes() { 582 for (var i = 0; i < simdTypeNames.length; ++i) { 583 var type = simdTypeNames[i], 584 lanes = lanesForType(type); 585 TestConstructor(type, lanes); 586 TestType(type, lanes); 587 TestPrototype(type, lanes); 588 TestValueOf(type, lanes); 589 TestGet(type, lanes); 590 TestToBoolean(type, lanes); 591 TestToString(type, lanes); 592 TestToNumber(type, lanes); 593 TestCoercions(type, lanes); 594 TestEquality(type, lanes); 595 TestSameValue(type, lanes); 596 TestComparison(type, lanes); 597 TestCall(type, lanes); 598 TestAsSetKey(type, lanes, new Set); 599 TestAsSetKey(type, lanes, new WeakSet); 600 TestAsMapKey(type, lanes, new Map); 601 TestAsMapKey(type, lanes, new WeakMap); 602 TestReflectApply(type); 603 } 604} 605TestSIMDTypes(); 606 607// Tests for the global SIMD object. 608function TestSIMDObject() { 609 assertSame(typeof SIMD, 'object'); 610 assertSame(SIMD.constructor, Object); 611 assertSame(Object.getPrototypeOf(SIMD), Object.prototype); 612 assertSame(SIMD + "", "[object SIMD]"); 613 // The SIMD object is mutable. 614 SIMD.foo = "foo"; 615 assertSame(SIMD.foo, "foo"); 616 delete SIMD.foo; 617 delete SIMD.Bool8x16; 618 assertSame(SIMD.Bool8x16, undefined); 619} 620TestSIMDObject() 621 622 623function TestStringify(expected, input) { 624 assertEquals(expected, JSON.stringify(input)); 625 assertEquals(expected, JSON.stringify(input, (key, value) => value)); 626 assertEquals(JSON.stringify(input, null, "="), 627 JSON.stringify(input, (key, value) => value, "=")); 628} 629 630TestStringify(undefined, SIMD.Float32x4(1, 2, 3, 4)); 631TestStringify('[null]', [SIMD.Float32x4(1, 2, 3, 4)]); 632TestStringify('[{}]', [Object(SIMD.Float32x4(1, 2, 3, 4))]); 633var simd_wrapper = Object(SIMD.Float32x4(1, 2, 3, 4)); 634TestStringify('{}', simd_wrapper); 635simd_wrapper.a = 1; 636TestStringify('{"a":1}', simd_wrapper); 637