unbox-double-arrays.js revision 85b71799222b55eb5dd74ea26efe0c64ab655c8c
1// Copyright 2011 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
4// met:
5//
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.
15//
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.
27
28// Test dictionary -> double elements -> dictionary elements round trip
29
30// Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc
31var large_array_size = 100000;
32var approx_dict_to_elements_threshold = 70000;
33
34var name = 0;
35
36function expected_array_value(i) {
37  if ((i % 50) != 0) {
38    return i;
39  } else {
40    return i + 0.5;
41  }
42}
43
44function force_to_fast_double_array(a) {
45  a[large_array_size - 2] = 1;
46  for (var i= 0; i < approx_dict_to_elements_threshold; ++i ) {
47    a[i] = expected_array_value(i);
48  }
49  assertTrue(%HasFastDoubleElements(a));
50}
51
52function make_object_like_array(size) {
53  obj = new Object();
54  obj.length = size;
55  return obj;
56}
57
58function testOneArrayType(allocator) {
59  var large_array = new allocator(large_array_size);
60  force_to_fast_double_array(large_array);
61  var six = 6;
62
63  for (var i= 0; i < approx_dict_to_elements_threshold; i += 501 ) {
64    assertEquals(expected_array_value(i), large_array[i]);
65  }
66
67  // This function has a constant and won't get inlined.
68  function computed_6() {
69    return six;
70  }
71
72  // Multiple versions of the test function makes sure that IC/Crankshaft state
73  // doesn't get reused.
74  function test_various_loads(a, value_5, value_6, value_7) {
75    assertTrue(%HasFastDoubleElements(a));
76    assertEquals(value_5, a[5]);
77    assertEquals(value_6, a[6]);
78    assertEquals(value_6, a[computed_6()]); // Test non-constant key
79    assertEquals(value_7, a[7]);
80    assertEquals(undefined, a[large_array_size-1]);
81    assertEquals(undefined, a[-1]);
82    assertEquals(large_array_size, a.length);
83    assertTrue(%HasFastDoubleElements(a));
84  }
85
86  function test_various_loads2(a, value_5, value_6, value_7) {
87    assertTrue(%HasFastDoubleElements(a));
88    assertEquals(value_5, a[5]);
89    assertEquals(value_6, a[6]);
90    assertEquals(value_6, a[computed_6()]); // Test non-constant key
91    assertEquals(value_7, a[7]);
92    assertEquals(undefined, a[large_array_size-1]);
93    assertEquals(undefined, a[-1]);
94    assertEquals(large_array_size, a.length);
95    assertTrue(%HasFastDoubleElements(a));
96  }
97
98  function test_various_loads3(a, value_5, value_6, value_7) {
99    assertTrue(%HasFastDoubleElements(a));
100    assertEquals(value_5, a[5]);
101    assertEquals(value_6, a[6]);
102    assertEquals(value_6, a[computed_6()]); // Test non-constant key
103    assertEquals(value_7, a[7]);
104    assertEquals(undefined, a[large_array_size-1]);
105    assertEquals(undefined, a[-1]);
106    assertEquals(large_array_size, a.length);
107    assertTrue(%HasFastDoubleElements(a));
108  }
109
110  function test_various_loads4(a, value_5, value_6, value_7) {
111    assertTrue(%HasFastDoubleElements(a));
112    assertEquals(value_5, a[5]);
113    assertEquals(value_6, a[6]);
114    assertEquals(value_6, a[computed_6()]); // Test non-constant key
115    assertEquals(value_7, a[7]);
116    assertEquals(undefined, a[large_array_size-1]);
117    assertEquals(undefined, a[-1]);
118    assertEquals(large_array_size, a.length);
119    assertTrue(%HasFastDoubleElements(a));
120  }
121
122  function test_various_loads5(a, value_5, value_6, value_7) {
123    assertTrue(%HasFastDoubleElements(a));
124    assertEquals(value_5, a[5]);
125    assertEquals(value_6, a[6]);
126    assertEquals(value_6, a[computed_6()]); // Test non-constant key
127    assertEquals(value_7, a[7]);
128    assertEquals(undefined, a[large_array_size-1]);
129    assertEquals(undefined, a[-1]);
130    assertEquals(large_array_size, a.length);
131    assertTrue(%HasFastDoubleElements(a));
132  }
133
134  function test_various_loads6(a, value_5, value_6, value_7) {
135    assertTrue(%HasFastDoubleElements(a));
136    assertEquals(value_5, a[5]);
137    assertEquals(value_6, a[6]);
138    assertEquals(value_6, a[computed_6()]); // Test non-constant key
139    assertEquals(value_7, a[7]);
140    assertEquals(undefined, a[large_array_size-1]);
141    assertEquals(undefined, a[-1]);
142    assertEquals(large_array_size, a.length);
143    assertTrue(%HasFastDoubleElements(a));
144  }
145
146  function test_various_stores(a, value_5, value_6, value_7) {
147    assertTrue(%HasFastDoubleElements(a));
148    a[5] = value_5;
149    a[computed_6()] = value_6;
150    a[7] = value_7;
151    assertTrue(%HasFastDoubleElements(a));
152  }
153
154  // Test double and integer values
155  test_various_loads(large_array,
156                     expected_array_value(5),
157                     expected_array_value(6),
158                     expected_array_value(7));
159  test_various_loads(large_array,
160                     expected_array_value(5),
161                     expected_array_value(6),
162                     expected_array_value(7));
163  test_various_loads(large_array,
164                     expected_array_value(5),
165                     expected_array_value(6),
166                     expected_array_value(7));
167  %OptimizeFunctionOnNextCall(test_various_loads);
168  test_various_loads(large_array,
169                     expected_array_value(5),
170                     expected_array_value(6),
171                     expected_array_value(7));
172
173  // Test NaN values
174  test_various_stores(large_array, NaN, -NaN, expected_array_value(7));
175
176  test_various_loads2(large_array,
177                      NaN,
178                      -NaN,
179                      expected_array_value(7));
180  test_various_loads2(large_array,
181                      NaN,
182                      -NaN,
183                      expected_array_value(7));
184  test_various_loads2(large_array,
185                      NaN,
186                      -NaN,
187                      expected_array_value(7));
188  %OptimizeFunctionOnNextCall(test_various_loads2);
189  test_various_loads2(large_array,
190                      NaN,
191                      -NaN,
192                      expected_array_value(7));
193
194  // Test Infinity values
195  test_various_stores(large_array,
196                      Infinity,
197                      -Infinity,
198                      expected_array_value(7));
199
200  test_various_loads3(large_array,
201                      Infinity,
202                      -Infinity,
203                      expected_array_value(7));
204  test_various_loads3(large_array,
205                      Infinity,
206                      -Infinity,
207                      expected_array_value(7));
208  test_various_loads3(large_array,
209                      Infinity,
210                      -Infinity,
211                      expected_array_value(7));
212  %OptimizeFunctionOnNextCall(test_various_loads3);
213  test_various_loads3(large_array,
214                      Infinity,
215                      -Infinity,
216                      expected_array_value(7));
217
218  // Test the hole for the default runtime implementation.
219  delete large_array[5];
220  delete large_array[6];
221  test_various_loads4(large_array,
222                      undefined,
223                      undefined,
224                      expected_array_value(7));
225
226  // Test the keyed load IC implementation when the value is the hole.
227  test_various_stores(large_array,
228                      expected_array_value(5),
229                      expected_array_value(6),
230                      expected_array_value(7));
231  test_various_loads5(large_array,
232                      expected_array_value(5),
233                      expected_array_value(6),
234                      expected_array_value(7));
235  test_various_loads5(large_array,
236                      expected_array_value(5),
237                      expected_array_value(6),
238                      expected_array_value(7));
239  delete large_array[5];
240  delete large_array[6];
241  test_various_loads5(large_array,
242                      undefined,
243                      undefined,
244                      expected_array_value(7));
245  test_various_loads5(large_array,
246                      undefined,
247                      undefined,
248                      expected_array_value(7));
249
250  // Make sure Crankshaft code handles the hole correctly (bailout)
251  test_various_stores(large_array,
252                      expected_array_value(5),
253                      expected_array_value(6),
254                      expected_array_value(7));
255  test_various_loads6(large_array,
256                      expected_array_value(5),
257                      expected_array_value(6),
258                      expected_array_value(7));
259  test_various_loads6(large_array,
260                      expected_array_value(5),
261                      expected_array_value(6),
262                      expected_array_value(7));
263  %OptimizeFunctionOnNextCall(test_various_loads6);
264  test_various_loads6(large_array,
265                      expected_array_value(5),
266                      expected_array_value(6),
267                      expected_array_value(7));
268
269  delete large_array[5];
270  delete large_array[6];
271  test_various_loads6(large_array,
272                      undefined,
273                      undefined,
274                      expected_array_value(7));
275
276  // Test stores for non-NaN.
277  %OptimizeFunctionOnNextCall(test_various_stores);
278  test_various_stores(large_array,
279                      expected_array_value(5),
280                      expected_array_value(6),
281                      expected_array_value(7));
282
283  test_various_stores(large_array,
284                      expected_array_value(5),
285                      expected_array_value(6),
286                      expected_array_value(7));
287
288  test_various_loads6(large_array,
289                      expected_array_value(5),
290                      expected_array_value(6),
291                      expected_array_value(7));
292
293  // Test NaN behavior for stores.
294  test_various_stores(large_array,
295                      NaN,
296                      -NaN,
297                      expected_array_value(7));
298
299  test_various_stores(large_array,
300                      NaN,
301                      -NaN,
302                      expected_array_value(7));
303
304  test_various_loads6(large_array,
305                      NaN,
306                      -NaN,
307                      expected_array_value(7));
308
309  // Test Infinity behavior for stores.
310  test_various_stores(large_array,
311                      Infinity,
312                      -Infinity,
313                      expected_array_value(7));
314
315  test_various_stores(large_array,
316                      Infinity,
317                      -Infinity,
318                      expected_array_value(7));
319
320  test_various_loads6(large_array,
321                      Infinity,
322                      -Infinity,
323                      expected_array_value(7));
324
325  assertTrue(%GetOptimizationStatus(test_various_stores) != 2);
326
327  // Make sure that we haven't converted from fast double.
328  assertTrue(%HasFastDoubleElements(large_array));
329}
330
331testOneArrayType(make_object_like_array);
332testOneArrayType(Array);
333
334var large_array = new Array(large_array_size);
335force_to_fast_double_array(large_array);
336assertTrue(%HasFastDoubleElements(large_array));
337
338// Cause the array to grow beyond it's JSArray length. This will double the
339// size of the capacity and force the array into "slow" dictionary case.
340large_array[5] = Infinity;
341large_array[large_array_size+10001] = 50;
342assertTrue(%HasDictionaryElements(large_array));
343assertEquals(50, large_array[large_array_size+10001]);
344assertEquals(large_array_size+10002, large_array.length);
345assertEquals(Infinity, large_array[5]);
346assertEquals(undefined, large_array[large_array_size-1]);
347assertEquals(undefined, large_array[-1]);
348assertEquals(large_array_size+10002, large_array.length);
349
350// Test dictionary -> double elements -> fast elements.
351var large_array2 = new Array(large_array_size);
352force_to_fast_double_array(large_array2);
353delete large_array2[5];
354
355// Convert back to fast elements and make sure the contents of the array are
356// unchanged.
357large_array2[25] = new Object();
358assertTrue(%HasFastElements(large_array2));
359for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) {
360  if (i != 25 && i != 5) {
361    assertEquals(expected_array_value(i), large_array2[i]);
362  }
363}
364assertEquals(undefined, large_array2[5]);
365assertEquals(undefined, large_array2[large_array_size-1]);
366assertEquals(undefined, large_array2[-1]);
367assertEquals(large_array_size, large_array2.length);
368
369// Make sure it's possible to change the array's length and that array is still
370// intact after the resize.
371var large_array3 = new Array(large_array_size);
372force_to_fast_double_array(large_array3);
373large_array3.length = 60000;
374assertEquals(60000, large_array3.length);
375assertEquals(undefined, large_array3[60000]);
376assertTrue(%HasFastDoubleElements(large_array3));
377assertEquals(expected_array_value(5), large_array3[5]);
378assertEquals(expected_array_value(6), large_array3[6]);
379assertEquals(expected_array_value(7), large_array3[7]);
380assertEquals(expected_array_value(large_array3.length-1),
381             large_array3[large_array3.length-1]);
382assertEquals(undefined, large_array3[large_array_size-1]);
383assertEquals(undefined, large_array3[-1]);
384gc();
385
386for (var i= 0; i < large_array3.length; i += 501 ) {
387  assertEquals(expected_array_value(i), large_array3[i]);
388}
389
390large_array3.length = 25;
391assertEquals(25, large_array3.length);
392assertTrue(%HasFastDoubleElements(large_array3));
393assertEquals(undefined, large_array3[25]);
394assertEquals(expected_array_value(5), large_array3[5]);
395assertEquals(expected_array_value(6), large_array3[6]);
396assertEquals(expected_array_value(7), large_array3[7]);
397assertEquals(expected_array_value(large_array3.length-1),
398             large_array3[large_array3.length-1]);
399assertEquals(undefined, large_array3[large_array_size-1]);
400assertEquals(undefined, large_array3[-1]);
401gc();
402
403for (var i= 0; i < large_array3.length; ++i) {
404  assertEquals(expected_array_value(i), large_array3[i]);
405}
406
407large_array3.length = 100;
408assertEquals(100, large_array3.length);
409large_array3[95] = 95;
410assertTrue(%HasFastDoubleElements(large_array3));
411assertEquals(undefined, large_array3[100]);
412assertEquals(95, large_array3[95]);
413assertEquals(expected_array_value(5), large_array3[5]);
414assertEquals(expected_array_value(6), large_array3[6]);
415assertEquals(expected_array_value(7), large_array3[7]);
416assertEquals(undefined, large_array3[large_array3.length-1]);
417assertEquals(undefined, large_array3[large_array_size-1]);
418assertEquals(undefined, large_array3[-1]);
419gc();
420
421// Test apply on arrays backed by double elements.
422function called_by_apply(arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
423  assertEquals(expected_array_value(0), arg0);
424  assertEquals(NaN, arg1);
425  assertEquals(-NaN, arg2);
426  assertEquals(Infinity, arg3);
427  assertEquals(-Infinity, arg4);
428  assertEquals(expected_array_value(5), arg5);
429}
430
431large_array3[1] = NaN;
432large_array3[2] = -NaN;
433large_array3[3] = Infinity;
434large_array3[4] = -Infinity;
435
436function call_apply() {
437  assertTrue(%HasFastDoubleElements(large_array3));
438  called_by_apply.apply({}, large_array3);
439}
440
441call_apply();
442call_apply();
443call_apply();
444%OptimizeFunctionOnNextCall(call_apply);
445call_apply();
446call_apply();
447call_apply();
448
449function test_for_in() {
450  // Due to previous tests, keys 0..25 and 95 should be present.
451  next_expected = 0;
452  assertTrue(%HasFastDoubleElements(large_array3));
453  for (x in large_array3) {
454    assertTrue(next_expected++ == x);
455    if (next_expected == 25) {
456      next_expected = 95;
457    }
458  }
459  assertTrue(next_expected == 96);
460}
461
462test_for_in();
463test_for_in();
464test_for_in();
465%OptimizeFunctionOnNextCall(test_for_in);
466test_for_in();
467test_for_in();
468test_for_in();
469
470function test_get_property_names() {
471  names = %GetPropertyNames(large_array3);
472  property_name_count = 0;
473  for (x in names) { property_name_count++; };
474  assertEquals(26, property_name_count);
475}
476
477test_get_property_names();
478test_get_property_names();
479test_get_property_names();
480
481// Test elements getters.
482assertEquals(expected_array_value(10), large_array3[10]);
483assertEquals(expected_array_value(-NaN), large_array3[2]);
484large_array3.__defineGetter__("2", function(){
485    return expected_array_value(10);
486});
487
488function test_getter() {
489  assertEquals(expected_array_value(10), large_array3[10]);
490  assertEquals(expected_array_value(10), large_array3[2]);
491}
492
493test_getter();
494test_getter();
495test_getter();
496%OptimizeFunctionOnNextCall(test_getter);
497test_getter();
498test_getter();
499test_getter();
500
501// Test element setters.
502large_array4 = new Array(large_array_size);
503force_to_fast_double_array(large_array4);
504
505var setter_called = false;
506
507assertEquals(expected_array_value(10), large_array4[10]);
508assertEquals(expected_array_value(2), large_array4[2]);
509large_array4.__defineSetter__("10", function(value){
510    setter_called = true;
511  });
512
513function test_setter() {
514  setter_called = false;
515  large_array4[10] = 119;
516  assertTrue(setter_called);
517  assertEquals(undefined, large_array4[10]);
518  assertEquals(expected_array_value(2), large_array4[2]);
519}
520
521test_setter();
522test_setter();
523test_setter();
524%OptimizeFunctionOnNextCall(test_setter);
525test_setter();
526test_setter();
527test_setter();
528