1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 // Flags: --allow-natives-syntax --smi-only-arrays --expose-gc --nostress-opt --typed-array-max_size_in-heap=2048
30 // Test element kind of objects.
31 // Since --smi-only-arrays affects builtins, its default setting at compile
32 // time sticks if built with snapshot. If --smi-only-arrays is deactivated
33 // by default, only a no-snapshot build actually has smi-only arrays enabled
34 // in this test case. Depending on whether smi-only arrays are actually
35 // enabled, this test takes the appropriate code path to check smi-only arrays.
37 support_smi_only_arrays = %HasFastSmiElements(new Array(1,2,3,4,5,6,7,8));
39 if (support_smi_only_arrays) {
40 print("Tests include smi-only arrays.");
42 print("Tests do NOT include smi-only arrays.");
46 fast_smi_only : 'fast smi only elements',
47 fast : 'fast elements',
48 fast_double : 'fast double elements',
49 dictionary : 'dictionary elements',
50 external_int32 : 'external int8 elements',
51 external_uint8 : 'external uint8 elements',
52 external_int16 : 'external int16 elements',
53 external_uint16 : 'external uint16 elements',
54 external_int32 : 'external int32 elements',
55 external_uint32 : 'external uint32 elements',
56 external_float32 : 'external float32 elements',
57 external_float64 : 'external float64 elements',
58 external_uint8_clamped : 'external uint8_clamped elements',
59 fixed_int32 : 'fixed int8 elements',
60 fixed_uint8 : 'fixed uint8 elements',
61 fixed_int16 : 'fixed int16 elements',
62 fixed_uint16 : 'fixed uint16 elements',
63 fixed_int32 : 'fixed int32 elements',
64 fixed_uint32 : 'fixed uint32 elements',
65 fixed_float32 : 'fixed float32 elements',
66 fixed_float64 : 'fixed float64 elements',
67 fixed_uint8_clamped : 'fixed uint8_clamped elements'
70 function getKind(obj) {
71 if (%HasFastSmiElements(obj)) return elements_kind.fast_smi_only;
72 if (%HasFastObjectElements(obj)) return elements_kind.fast;
73 if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
74 if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
76 // Every external kind is also an external array.
77 if (%HasExternalInt8Elements(obj)) {
78 return elements_kind.external_int8;
80 if (%HasExternalUint8Elements(obj)) {
81 return elements_kind.external_uint8;
83 if (%HasExternalInt16Elements(obj)) {
84 return elements_kind.external_int16;
86 if (%HasExternalUint16Elements(obj)) {
87 return elements_kind.external_uint16;
89 if (%HasExternalInt32Elements(obj)) {
90 return elements_kind.external_int32;
92 if (%HasExternalUint32Elements(obj)) {
93 return elements_kind.external_uint32;
95 if (%HasExternalFloat32Elements(obj)) {
96 return elements_kind.external_float32;
98 if (%HasExternalFloat64Elements(obj)) {
99 return elements_kind.external_float64;
101 if (%HasExternalUint8ClampedElements(obj)) {
102 return elements_kind.external_uint8_clamped;
104 if (%HasFixedInt8Elements(obj)) {
105 return elements_kind.fixed_int8;
107 if (%HasFixedUint8Elements(obj)) {
108 return elements_kind.fixed_uint8;
110 if (%HasFixedInt16Elements(obj)) {
111 return elements_kind.fixed_int16;
113 if (%HasFixedUint16Elements(obj)) {
114 return elements_kind.fixed_uint16;
116 if (%HasFixedInt32Elements(obj)) {
117 return elements_kind.fixed_int32;
119 if (%HasFixedUint32Elements(obj)) {
120 return elements_kind.fixed_uint32;
122 if (%HasFixedFloat32Elements(obj)) {
123 return elements_kind.fixed_float32;
125 if (%HasFixedFloat64Elements(obj)) {
126 return elements_kind.fixed_float64;
128 if (%HasFixedUint8ClampedElements(obj)) {
129 return elements_kind.fixed_uint8_clamped;
133 function assertKind(expected, obj, name_opt) {
134 if (!support_smi_only_arrays &&
135 expected == elements_kind.fast_smi_only) {
136 expected = elements_kind.fast;
138 assertEquals(expected, getKind(obj), name_opt);
142 assertKind(elements_kind.fast, me);
145 assertKind(elements_kind.fast, me);
147 if (support_smi_only_arrays) {
149 assertKind(elements_kind.fast_smi_only, too);
152 assertKind(elements_kind.fast_smi_only, too);
155 // Make sure the element kind transitions from smi when a non-smi is stored.
156 function test_wrapper() {
157 var you = new Array();
158 assertKind(elements_kind.fast_smi_only, you);
159 for (var i = 0; i < 1337; i++) {
162 assertKind(elements_kind.fast_smi_only, you);
167 assertKind(elements_kind.fast, you);
169 assertKind(elements_kind.dictionary, new Array(0xDECAF));
171 var fast_double_array = new Array(0xDECAF);
172 for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
173 assertKind(elements_kind.fast_double, fast_double_array);
175 assertKind(elements_kind.fixed_int8, new Int8Array(007));
176 assertKind(elements_kind.fixed_uint8, new Uint8Array(007));
177 assertKind(elements_kind.fixed_int16, new Int16Array(666));
178 assertKind(elements_kind.fixed_uint16, new Uint16Array(42));
179 assertKind(elements_kind.fixed_int32, new Int32Array(0xF));
180 assertKind(elements_kind.fixed_uint32, new Uint32Array(23));
181 assertKind(elements_kind.fixed_float32, new Float32Array(7));
182 assertKind(elements_kind.fixed_float64, new Float64Array(0));
183 assertKind(elements_kind.fixed_uint8_clamped, new Uint8ClampedArray(512));
185 var ab = new ArrayBuffer(128);
186 assertKind(elements_kind.external_int8, new Int8Array(ab));
187 assertKind(elements_kind.external_uint8, new Uint8Array(ab));
188 assertKind(elements_kind.external_int16, new Int16Array(ab));
189 assertKind(elements_kind.external_uint16, new Uint16Array(ab));
190 assertKind(elements_kind.external_int32, new Int32Array(ab));
191 assertKind(elements_kind.external_uint32, new Uint32Array(ab));
192 assertKind(elements_kind.external_float32, new Float32Array(ab));
193 assertKind(elements_kind.external_float64, new Float64Array(ab));
194 assertKind(elements_kind.external_uint8_clamped, new Uint8ClampedArray(ab));
196 // Crankshaft support for smi-only array elements.
197 function monomorphic(array) {
198 assertKind(elements_kind.fast_smi_only, array);
199 for (var i = 0; i < 3; i++) {
202 assertKind(elements_kind.fast_smi_only, array);
203 for (var i = 0; i < 3; i++) {
205 assertEquals(i + 10, a);
208 var smi_only = new Array(1, 2, 3);
209 assertKind(elements_kind.fast_smi_only, smi_only);
210 for (var i = 0; i < 3; i++) monomorphic(smi_only);
211 %OptimizeFunctionOnNextCall(monomorphic);
212 monomorphic(smi_only);
215 // The test is called in a wrapper function to eliminate the transition learning
216 // feedback of AllocationSites.
218 %ClearFunctionTypeFeedback(test_wrapper);
220 if (support_smi_only_arrays) {
221 %NeverOptimizeFunction(construct_smis);
223 // This code exists to eliminate the learning influence of AllocationSites
224 // on the following tests.
226 function make_array_string() {
227 this.__sequence = this.__sequence + 1;
228 return "/* " + this.__sequence + " */ [0, 0, 0];"
230 function make_array() {
231 return eval(make_array_string());
234 function construct_smis() {
235 var a = make_array();
236 a[0] = 0; // Send the COW array map to the steak house.
237 assertKind(elements_kind.fast_smi_only, a);
240 %NeverOptimizeFunction(construct_doubles);
241 function construct_doubles() {
242 var a = construct_smis();
244 assertKind(elements_kind.fast_double, a);
247 %NeverOptimizeFunction(construct_objects);
248 function construct_objects() {
249 var a = construct_smis();
251 assertKind(elements_kind.fast, a);
255 // Test crankshafted transition SMI->DOUBLE.
256 %NeverOptimizeFunction(convert_to_double);
257 function convert_to_double(array) {
259 assertKind(elements_kind.fast_double, array);
260 assertEquals(2.5, array[1]);
262 var smis = construct_smis();
263 for (var i = 0; i < 3; i++) convert_to_double(smis);
264 %OptimizeFunctionOnNextCall(convert_to_double);
265 smis = construct_smis();
266 convert_to_double(smis);
267 // Test crankshafted transitions SMI->FAST and DOUBLE->FAST.
268 %NeverOptimizeFunction(convert_to_fast);
269 function convert_to_fast(array) {
271 assertKind(elements_kind.fast, array);
272 assertEquals("two", array[1]);
274 smis = construct_smis();
275 for (var i = 0; i < 3; i++) convert_to_fast(smis);
276 var doubles = construct_doubles();
277 for (var i = 0; i < 3; i++) convert_to_fast(doubles);
278 smis = construct_smis();
279 doubles = construct_doubles();
280 %OptimizeFunctionOnNextCall(convert_to_fast);
281 convert_to_fast(smis);
282 convert_to_fast(doubles);
283 // Test transition chain SMI->DOUBLE->FAST (crankshafted function will
284 // transition to FAST directly).
285 %NeverOptimizeFunction(convert_mixed);
286 function convert_mixed(array, value, kind) {
288 assertKind(kind, array);
289 assertEquals(value, array[1]);
291 smis = construct_smis();
292 for (var i = 0; i < 3; i++) {
293 convert_mixed(smis, 1.5, elements_kind.fast_double);
295 doubles = construct_doubles();
296 for (var i = 0; i < 3; i++) {
297 convert_mixed(doubles, "three", elements_kind.fast);
299 convert_mixed(construct_smis(), "three", elements_kind.fast);
300 convert_mixed(construct_doubles(), "three", elements_kind.fast);
301 %OptimizeFunctionOnNextCall(convert_mixed);
302 smis = construct_smis();
303 doubles = construct_doubles();
304 convert_mixed(smis, 1, elements_kind.fast);
305 convert_mixed(doubles, 1, elements_kind.fast);
306 assertTrue(%HaveSameMap(smis, doubles));
309 // Crankshaft support for smi-only elements in dynamic array literals.
310 function get(foo) { return foo; } // Used to generate dynamic values.
312 function crankshaft_test() {
313 if (support_smi_only_arrays) {
314 var a1 = [get(1), get(2), get(3)];
315 assertKind(elements_kind.fast_smi_only, a1);
317 var a2 = new Array(get(1), get(2), get(3));
318 assertKind(elements_kind.fast_smi_only, a2);
319 var b = [get(1), get(2), get("three")];
320 assertKind(elements_kind.fast, b);
321 var c = [get(1), get(2), get(3.5)];
322 if (support_smi_only_arrays) {
323 assertKind(elements_kind.fast_double, c);
326 for (var i = 0; i < 3; i++) {
329 %OptimizeFunctionOnNextCall(crankshaft_test);
332 // Elements_kind transitions for arrays.
334 // A map can have three different elements_kind transitions: SMI->DOUBLE,
335 // DOUBLE->OBJECT, and SMI->OBJECT. No matter in which order these three are
336 // created, they must always end up with the same FAST map.
338 // This test is meaningless without FAST_SMI_ONLY_ELEMENTS.
339 if (support_smi_only_arrays) {
340 // Preparation: create one pair of identical objects for each case.
343 assertTrue(%HaveSameMap(a, b));
344 assertKind(elements_kind.fast_smi_only, a);
349 assertTrue(%HaveSameMap(c, d));
350 assertFalse(%HaveSameMap(a, c));
351 assertKind(elements_kind.fast_smi_only, c);
356 assertTrue(%HaveSameMap(e, f));
357 assertFalse(%HaveSameMap(a, e));
358 assertFalse(%HaveSameMap(c, e));
359 assertKind(elements_kind.fast_smi_only, e);
360 // Case 1: SMI->DOUBLE, DOUBLE->OBJECT, SMI->OBJECT.
362 assertKind(elements_kind.fast_double, a);
364 assertKind(elements_kind.fast, a);
366 assertTrue(%HaveSameMap(a, b));
367 // Case 2: SMI->DOUBLE, SMI->OBJECT, DOUBLE->OBJECT.
369 assertKind(elements_kind.fast_double, c);
370 assertFalse(%HaveSameMap(c, d));
372 assertKind(elements_kind.fast, d);
373 assertFalse(%HaveSameMap(c, d));
375 assertTrue(%HaveSameMap(c, d));
376 // Case 3: SMI->OBJECT, SMI->DOUBLE, DOUBLE->OBJECT.
378 assertKind(elements_kind.fast, e);
379 assertFalse(%HaveSameMap(e, f));
381 assertKind(elements_kind.fast_double, f);
382 assertFalse(%HaveSameMap(e, f));
384 assertKind(elements_kind.fast, f);
385 assertTrue(%HaveSameMap(e, f));
388 // Test if Array.concat() works correctly with DOUBLE elements.
389 if (support_smi_only_arrays) {
391 assertKind(elements_kind.fast_smi_only, a);
393 assertKind(elements_kind.fast_double, b);
395 assertEquals([1, 2, 4.5, 5.5], c);
396 assertKind(elements_kind.fast_double, c);
399 // Test that Array.push() correctly handles SMI elements.
400 if (support_smi_only_arrays) {
402 assertKind(elements_kind.fast_smi_only, a);
404 assertKind(elements_kind.fast_smi_only, a);
405 assertEquals([1, 2, 3, 4, 5], a);
408 // Test that Array.splice() and Array.slice() return correct ElementsKinds.
409 if (support_smi_only_arrays) {
410 var a = ["foo", "bar"];
411 assertKind(elements_kind.fast, a);
412 var b = a.splice(0, 1);
413 assertKind(elements_kind.fast, b);
414 var c = a.slice(0, 1);
415 assertKind(elements_kind.fast, c);
418 // Throw away type information in the ICs for next stress run.