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