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