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// Flags: --allow-natives-syntax --expose-gc 29 30// Test element kind of objects. 31 32var elements_kind = { 33 fast_smi_only : 'fast smi only elements', 34 fast : 'fast elements', 35 fast_double : 'fast double elements', 36 dictionary : 'dictionary elements', 37 external_byte : 'external byte elements', 38 external_unsigned_byte : 'external unsigned byte elements', 39 external_short : 'external short elements', 40 external_unsigned_short : 'external unsigned short elements', 41 external_int : 'external int elements', 42 external_unsigned_int : 'external unsigned int elements', 43 external_float : 'external float elements', 44 external_double : 'external double elements', 45 external_pixel : 'external pixel elements' 46} 47 48function getKind(obj) { 49 if (%HasFastSmiElements(obj)) return elements_kind.fast_smi_only; 50 if (%HasFastObjectElements(obj)) return elements_kind.fast; 51 if (%HasFastDoubleElements(obj)) return elements_kind.fast_double; 52 if (%HasDictionaryElements(obj)) return elements_kind.dictionary; 53} 54 55function isHoley(obj) { 56 if (%HasFastHoleyElements(obj)) return true; 57 return false; 58} 59 60function assertKind(expected, obj, name_opt) { 61 assertEquals(expected, getKind(obj), name_opt); 62} 63 64// Test: If a call site goes megamorphic, it retains the ability to 65// use allocation site feedback (if FLAG_allocation_site_pretenuring 66// is on). 67(function() { 68 function bar(t, len) { 69 return new t(len); 70 } 71 72 a = bar(Array, 10); 73 a[0] = 3.5; 74 b = bar(Array, 1); 75 assertKind(elements_kind.fast_double, b); 76 c = bar(Object, 3); 77 b = bar(Array, 10); 78 // TODO(mvstanton): re-enable when FLAG_allocation_site_pretenuring 79 // is on in the build. 80 // assertKind(elements_kind.fast_double, b); 81})(); 82 83 84// Test: ensure that crankshafted array constructor sites are deopted 85// if another function is used. 86(function() { 87 function bar0(t) { 88 return new t(); 89 } 90 a = bar0(Array); 91 a[0] = 3.5; 92 b = bar0(Array); 93 assertKind(elements_kind.fast_double, b); 94 %OptimizeFunctionOnNextCall(bar0); 95 b = bar0(Array); 96 assertKind(elements_kind.fast_double, b); 97 assertOptimized(bar0); 98 // bar0 should deopt 99 b = bar0(Object); 100 assertUnoptimized(bar0) 101 // When it's re-optimized, we should call through the full stub 102 bar0(Array); 103 %OptimizeFunctionOnNextCall(bar0); 104 b = bar0(Array); 105 // This only makes sense to test if we allow crankshafting 106 if (4 != %GetOptimizationStatus(bar0)) { 107 // We also lost our ability to record kind feedback, as the site 108 // is megamorphic now. 109 assertKind(elements_kind.fast_smi_only, b); 110 assertOptimized(bar0); 111 b[0] = 3.5; 112 c = bar0(Array); 113 assertKind(elements_kind.fast_smi_only, c); 114 } 115})(); 116 117 118// Test: Ensure that inlined array calls in crankshaft learn from deopts 119// based on the move to a dictionary for the array. 120(function() { 121 function bar(len) { 122 return new Array(len); 123 } 124 a = bar(10); 125 a[0] = "a string"; 126 a = bar(10); 127 assertKind(elements_kind.fast, a); 128 %OptimizeFunctionOnNextCall(bar); 129 a = bar(10); 130 assertKind(elements_kind.fast, a); 131 assertOptimized(bar); 132 bar(100000); 133 assertOptimized(bar); 134 135 // If the argument isn't a smi, things should still work. 136 a = bar("oops"); 137 assertOptimized(bar); 138 assertKind(elements_kind.fast, a); 139 140 function barn(one, two, three) { 141 return new Array(one, two, three); 142 } 143 144 barn(1, 2, 3); 145 barn(1, 2, 3); 146 %OptimizeFunctionOnNextCall(barn); 147 barn(1, 2, 3); 148 assertOptimized(barn); 149 a = barn(1, "oops", 3); 150 assertOptimized(barn); 151})(); 152 153 154// Test: When a method with array constructor is crankshafted, the type 155// feedback for elements kind is baked in. Verify that transitions don't 156// change it anymore 157(function() { 158 function bar() { 159 return new Array(); 160 } 161 a = bar(); 162 bar(); 163 %OptimizeFunctionOnNextCall(bar); 164 b = bar(); 165 // This only makes sense to test if we allow crankshafting 166 if (4 != %GetOptimizationStatus(bar)) { 167 assertOptimized(bar); 168 %DebugPrint(3); 169 b[0] = 3.5; 170 c = bar(); 171 assertKind(elements_kind.fast_smi_only, c); 172 assertOptimized(bar); 173 } 174})(); 175 176 177// Test: create arrays in two contexts, verifying that the correct 178// map for Array in that context will be used. 179(function() { 180 function bar() { return new Array(); } 181 bar(); 182 bar(); 183 %OptimizeFunctionOnNextCall(bar); 184 a = bar(); 185 assertTrue(a instanceof Array); 186 187 var contextB = Realm.create(); 188 Realm.eval(contextB, "function bar2() { return new Array(); };"); 189 Realm.eval(contextB, "bar2(); bar2();"); 190 Realm.eval(contextB, "%OptimizeFunctionOnNextCall(bar2);"); 191 Realm.eval(contextB, "bar2();"); 192 assertFalse(Realm.eval(contextB, "bar2();") instanceof Array); 193 assertTrue(Realm.eval(contextB, "bar2() instanceof Array")); 194})(); 195 196// Test: create array with packed feedback, then optimize function, which 197// should deal with arguments that create holey arrays. 198(function() { 199 function bar(len) { return new Array(len); } 200 bar(0); 201 bar(0); 202 %OptimizeFunctionOnNextCall(bar); 203 a = bar(0); 204 assertOptimized(bar); 205 assertFalse(isHoley(a)); 206 a = bar(1); // ouch! 207 assertOptimized(bar); 208 assertTrue(isHoley(a)); 209 a = bar(100); 210 assertTrue(isHoley(a)); 211 a = bar(0); 212 assertOptimized(bar); 213 // Crankshafted functions don't use mementos, so feedback still 214 // indicates a packed array is desired. (unless --nocrankshaft is in use). 215 if (4 != %GetOptimizationStatus(bar)) { 216 assertFalse(isHoley(a)); 217 } 218})(); 219 220// Test: Make sure that crankshaft continues with feedback for large arrays. 221(function() { 222 function bar(len) { return new Array(len); } 223 var size = 100001; 224 // Perform a gc, because we are allocating a very large array and if a gc 225 // happens during the allocation we could lose our memento. 226 gc(); 227 bar(size)[0] = 'string'; 228 var res = bar(size); 229 assertKind(elements_kind.fast, bar(size)); 230 %OptimizeFunctionOnNextCall(bar); 231 assertKind(elements_kind.fast, bar(size)); 232 // But there is a limit, based on the size of the old generation, currently 233 // 22937600, but double it to prevent the test being too brittle. 234 var large_size = 22937600 * 2; 235 assertKind(elements_kind.dictionary, bar(large_size)); 236})(); 237