51a04c7fdc9e39f535f76ccf39b2afeac5f0d56b
[platform/upstream/v8.git] / test / mjsunit / harmony / simd.js
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 --harmony-tostring  --harmony-reflect
6 // Flags: --allow-natives-syntax --expose-natives-as natives --noalways-opt
7
8 function 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[typeName.indexOf('x') + 1]);
12 }
13
14
15 function isValidSimdString(string, value, type, lanes) {
16   var simdFn = SIMD[type],
17       parseFn =
18           type.indexOf('float') === 0 ? Number.parseFloat : Number.parseInt,
19       indexOfOpenParen = string.indexOf('(');
20   // Check prefix for correct type name.
21   if (string.substr(0, indexOfOpenParen).toUpperCase() !== type.toUpperCase())
22     return false;
23   // Remove type name and open parenthesis.
24   string = string.substr(indexOfOpenParen + 1);
25   var laneStrings = string.split(',');
26   if (laneStrings.length !== lanes)
27     return false;
28   for (var i = 0; i < lanes; i++) {
29     var fromString = parseFn(laneStrings[i]),
30         fromValue = simdFn.extractLane(value, i);
31     if (Math.abs(fromString - fromValue) > Number.EPSILON)
32       return false;
33   }
34   return true;
35 }
36
37
38 // Test for structural equivalence.
39 function areEquivalent(type, lanes, a, b) {
40   var simdFn = SIMD[type];
41   for (var i = 0; i < lanes; i++) {
42     if (simdFn.extractLane(a, i) !== simdFn.extractLane(b, i))
43       return false;
44   }
45   return true;
46 }
47
48
49 var sameValue = natives.$sameValue;
50 var sameValueZero = natives.$sameValueZero;
51
52 // Calls SameValue and SameValueZero and checks that their results match. Also
53 // checks the internal SameValue checks using Object freeze and defineProperty.
54 function sameValueBoth(a, b) {
55   var result = sameValue(a, b);
56   assertTrue(result === sameValueZero(a, b));
57   return result;
58 }
59
60
61 // Calls SameValue and SameValueZero and checks that their results don't match.
62 function sameValueZeroOnly(a, b) {
63   var result = sameValueZero(a, b);
64   assertTrue(result && !sameValue(a, b));
65   return result;
66 }
67
68
69 // Tests for the global SIMD object.
70 function TestSIMDObject() {
71   assertSame(typeof SIMD, 'object');
72   assertSame(SIMD.constructor, Object);
73   assertSame(Object.getPrototypeOf(SIMD), Object.prototype);
74   assertSame(SIMD + "", "[object SIMD]");
75 }
76 TestSIMDObject()
77
78 // TestConstructor populates this with interesting values for the other tests.
79 var values;
80
81 // Test different forms of constructor calls. This test populates 'values' with
82 // a variety of SIMD values as a side effect, which are used by other tests.
83 function TestConstructor(type, lanes) {
84   var simdFn = SIMD[type];
85   assertFalse(Object === simdFn.prototype.constructor)
86   assertFalse(simdFn === Object.prototype.constructor)
87   assertSame(simdFn, simdFn.prototype.constructor)
88
89   values = []
90
91   // The constructor expects values for all lanes.
92   switch (type) {
93     case 'float32x4':
94       // The constructor expects values for all lanes.
95       assertThrows(function () { simdFn() }, TypeError)
96       assertThrows(function () { simdFn(0) }, TypeError)
97       assertThrows(function () { simdFn(0, 1) }, TypeError)
98       assertThrows(function () { simdFn(0, 1, 2) }, TypeError)
99
100       values.push(simdFn(1, 2, 3, 4))
101       values.push(simdFn(1, 2, 3, 4))       // test structural equivalence
102       values.push(simdFn(-0, NaN, 0, 0.5))
103       values.push(simdFn(-0, NaN, 0, 0.5))  // test structural equivalence
104       values.push(simdFn(3, 2, 1, 0))
105       values.push(simdFn(0, 0, 0, 0))
106       break
107   }
108   for (var i in values) {
109     assertSame(simdFn, values[i].__proto__.constructor)
110     assertSame(simdFn, Object(values[i]).__proto__.constructor)
111     assertSame(simdFn.prototype, values[i].__proto__)
112     assertSame(simdFn.prototype, Object(values[i]).__proto__)
113   }
114 }
115
116
117 function TestType(type, lanes) {
118   for (var i in values) {
119     assertEquals(type, typeof values[i])
120     assertTrue(typeof values[i] === type)
121     assertTrue(typeof Object(values[i]) === 'object')
122     assertEquals(null, %_ClassOf(values[i]))
123     assertEquals("Float32x4", %_ClassOf(Object(values[i])))
124   }
125 }
126
127
128 function TestPrototype(type, lanes) {
129   var simdFn = SIMD[type];
130   assertSame(Object.prototype, simdFn.prototype.__proto__)
131   for (var i in values) {
132     assertSame(simdFn.prototype, values[i].__proto__)
133     assertSame(simdFn.prototype, Object(values[i]).__proto__)
134   }
135 }
136
137
138 function TestValueOf(type, lanes) {
139   var simdFn = SIMD[type];
140   for (var i in values) {
141     assertTrue(values[i] === Object(values[i]).valueOf())
142     assertTrue(values[i] === values[i].valueOf())
143     assertTrue(simdFn.prototype.valueOf.call(Object(values[i])) === values[i])
144     assertTrue(simdFn.prototype.valueOf.call(values[i]) === values[i])
145   }
146 }
147
148
149 function TestGet(type, lanes) {
150   var simdFn = SIMD[type];
151   for (var i in values) {
152     assertEquals(undefined, values[i].a)
153     assertEquals(undefined, values[i]["a" + "b"])
154     assertEquals(undefined, values[i]["" + "1"])
155     assertEquals(undefined, values[i][42])
156   }
157 }
158
159
160 function TestToBoolean(type, lanes) {
161   for (var i in values) {
162     assertTrue(Boolean(Object(values[i])))
163     assertFalse(!Object(values[i]))
164     assertTrue(Boolean(values[i]).valueOf())
165     assertFalse(!values[i])
166     assertTrue(!!values[i])
167     assertTrue(values[i] && true)
168     assertFalse(!values[i] && false)
169     assertTrue(!values[i] || true)
170     assertEquals(1, values[i] ? 1 : 2)
171     assertEquals(2, !values[i] ? 1 : 2)
172     if (!values[i]) assertUnreachable();
173     if (values[i]) {} else assertUnreachable();
174   }
175 }
176
177
178 function TestToString(type, lanes) {
179   var simdFn = SIMD[type];
180   for (var i in values) {
181     assertEquals(values[i].toString(), String(values[i]))
182     assertTrue(isValidSimdString(values[i].toString(), values[i], type, lanes))
183     assertTrue(
184         isValidSimdString(Object(values[i]).toString(), values[i], type, lanes))
185     assertTrue(isValidSimdString(
186         simdFn.prototype.toString.call(values[i]), values[i], type, lanes))
187   }
188 }
189
190
191 function TestToNumber(type, lanes) {
192   for (var i in values) {
193     assertThrows(function() { Number(Object(values[i])) }, TypeError)
194     assertThrows(function() { +Object(values[i]) }, TypeError)
195     assertThrows(function() { Number(values[i]) }, TypeError)
196     assertThrows(function() { values[i] + 0 }, TypeError)
197   }
198 }
199
200
201 function TestEquality(type, lanes) {
202   // Every SIMD value should equal itself, and non-strictly equal its wrapper.
203   for (var i in values) {
204     assertSame(values[i], values[i])
205     assertEquals(values[i], values[i])
206     assertTrue(Object.is(values[i], values[i]))
207     assertTrue(values[i] === values[i])
208     assertTrue(values[i] == values[i])
209     assertFalse(values[i] === Object(values[i]))
210     assertFalse(Object(values[i]) === values[i])
211     assertFalse(values[i] == Object(values[i]))
212     assertFalse(Object(values[i]) == values[i])
213     assertTrue(values[i] === values[i].valueOf())
214     assertTrue(values[i].valueOf() === values[i])
215     assertTrue(values[i] == values[i].valueOf())
216     assertTrue(values[i].valueOf() == values[i])
217     assertFalse(Object(values[i]) === Object(values[i]))
218     assertEquals(Object(values[i]).valueOf(), Object(values[i]).valueOf())
219   }
220
221   // Test structural equivalence.
222   for (var i = 0; i < values.length; i++) {
223     for (var j = i + 1; j < values.length; j++) {
224       var a = values[i], b = values[j],
225           equivalent = areEquivalent(type, lanes, a, b);
226       assertSame(equivalent, a == b);
227       assertSame(equivalent, a === b);
228     }
229   }
230
231   // SIMD values should not be equal to any other kind of object.
232   var others = [347, 1.275, NaN, "string", null, undefined, {}, function() {}]
233   for (var i in values) {
234     for (var j in others) {
235       assertFalse(values[i] === others[j])
236       assertFalse(others[j] === values[i])
237       assertFalse(values[i] == others[j])
238       assertFalse(others[j] == values[i])
239     }
240   }
241 }
242
243
244 function TestSameValue(type, lanes) {
245   // SIMD value types.
246   // All lanes checked.
247   // TODO(bbudge): use loops to test lanes when replaceLane is defined.
248   assertTrue(sameValueBoth(SIMD.float32x4(1, 2, 3, 4),
249                            SIMD.float32x4(1, 2, 3, 4)));
250   assertFalse(sameValueBoth(SIMD.float32x4(1, 2, 3, 4),
251                             SIMD.float32x4(NaN, 2, 3, 4)));
252   assertFalse(sameValueBoth(SIMD.float32x4(1, 2, 3, 4),
253                             SIMD.float32x4(1, NaN, 3, 4)));
254   assertFalse(sameValueBoth(SIMD.float32x4(1, 2, 3, 4),
255                             SIMD.float32x4(1, 2, NaN, 4)));
256   assertFalse(sameValueBoth(SIMD.float32x4(1, 2, 3, 4),
257                             SIMD.float32x4(1, 2, 3, NaN)));
258   // Special values.
259   // TODO(bbudge): use loops to test lanes when replaceLane is defined.
260   assertTrue(sameValueBoth(SIMD.float32x4(NaN, 2, 3, 4),
261                            SIMD.float32x4(NaN, 2, 3, 4)));
262   assertTrue(sameValueBoth(SIMD.float32x4(+0, 2, 3, 4),
263                            SIMD.float32x4(+0, 2, 3, 4)));
264   assertTrue(sameValueBoth(SIMD.float32x4(-0, 2, 3, 4),
265                            SIMD.float32x4(-0, 2, 3, 4)));
266   assertTrue(sameValueZeroOnly(SIMD.float32x4(+0, 2, 3, 4),
267                                SIMD.float32x4(-0, 2, 3, 4)));
268   assertTrue(sameValueZeroOnly(SIMD.float32x4(-0, 2, 3, 4),
269                                SIMD.float32x4(+0, 2, 3, 4)));
270 }
271
272
273 function TestComparison(type, lanes) {
274   var a = values[0], b = values[1];
275
276   function lt() { a < b; }
277   function gt() { a > b; }
278   function le() { a <= b; }
279   function ge() { a >= b; }
280   function lt_same() { a < a; }
281   function gt_same() { a > a; }
282   function le_same() { a <= a; }
283   function ge_same() { a >= a; }
284
285   var throwFuncs = [lt, gt, le, ge, lt_same, gt_same, le_same, ge_same];
286
287   for (var f of throwFuncs) {
288     assertThrows(f, TypeError);
289     %OptimizeFunctionOnNextCall(f);
290     assertThrows(f, TypeError);
291     assertThrows(f, TypeError);
292   }
293 }
294
295
296 // Test SIMD value wrapping/boxing over non-builtins.
297 function TestCall(type, lanes) {
298   var simdFn = SIMD[type];
299   simdFn.prototype.getThisProto = function () {
300     return Object.getPrototypeOf(this);
301   }
302   for (var i in values) {
303     assertTrue(values[i].getThisProto() === simdFn.prototype)
304   }
305 }
306
307
308 function TestAsSetKey(type, lanes, set) {
309   function test(set, key) {
310     assertFalse(set.has(key));
311     assertFalse(set.delete(key));
312     if (!(set instanceof WeakSet)) {
313       assertSame(set, set.add(key));
314       assertTrue(set.has(key));
315       assertTrue(set.delete(key));
316     } else {
317       // SIMD values can't be used as keys in WeakSets.
318       assertThrows(function() { set.add(key) });
319     }
320     assertFalse(set.has(key));
321     assertFalse(set.delete(key));
322     assertFalse(set.has(key));
323   }
324
325   for (var i in values) {
326     test(set, values[i]);
327   }
328 }
329
330
331 function TestAsMapKey(type, lanes, map) {
332   function test(map, key, value) {
333     assertFalse(map.has(key));
334     assertSame(undefined, map.get(key));
335     assertFalse(map.delete(key));
336     if (!(map instanceof WeakMap)) {
337       assertSame(map, map.set(key, value));
338       assertSame(value, map.get(key));
339       assertTrue(map.has(key));
340       assertTrue(map.delete(key));
341     } else {
342       // SIMD values can't be used as keys in WeakMaps.
343       assertThrows(function() { map.set(key, value) });
344     }
345     assertFalse(map.has(key));
346     assertSame(undefined, map.get(key));
347     assertFalse(map.delete(key));
348     assertFalse(map.has(key));
349     assertSame(undefined, map.get(key));
350   }
351
352   for (var i in values) {
353     test(map, values[i], {});
354   }
355 }
356
357
358 // Test SIMD type with Harmony reflect-apply.
359 function TestReflectApply(type) {
360   function returnThis() { return this; }
361   function returnThisStrict() { 'use strict'; return this; }
362   function noop() {}
363   function noopStrict() { 'use strict'; }
364   var R = void 0;
365
366   for (var i in values) {
367     assertSame(SIMD[type].prototype,
368                Object.getPrototypeOf(
369                   Reflect.apply(returnThis, values[i], [])));
370     assertSame(values[i], Reflect.apply(returnThisStrict, values[i], []));
371
372     assertThrows(
373         function() { 'use strict'; Reflect.apply(values[i]); }, TypeError);
374     assertThrows(
375         function() { Reflect.apply(values[i]); }, TypeError);
376     assertThrows(
377         function() { Reflect.apply(noopStrict, R, values[i]); }, TypeError);
378     assertThrows(
379         function() { Reflect.apply(noop, R, values[i]); }, TypeError);
380   }
381 }
382
383
384 function TestSIMDTypes() {
385   var types = [ 'float32x4' ];
386   for (var i = 0; i < types.length; ++i) {
387     var type = types[i],
388         lanes = lanesForType(type);
389     TestConstructor(type, lanes);
390     TestType(type, lanes);
391     TestPrototype(type, lanes);
392     TestValueOf(type, lanes);
393     TestGet(type, lanes);
394     TestToBoolean(type, lanes);
395     TestToString(type, lanes);
396     TestToNumber(type, lanes);
397     TestEquality(type, lanes);
398     TestSameValue(type, lanes);
399     TestComparison(type, lanes);
400     TestCall(type, lanes);
401     TestAsSetKey(type, lanes, new Set);
402     TestAsSetKey(type, lanes, new WeakSet);
403     TestAsMapKey(type, lanes, new Map);
404     TestAsMapKey(type, lanes, new WeakMap);
405     TestReflectApply(type);
406   }
407 }
408 TestSIMDTypes();