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 --smi-only-arrays --expose-gc 29 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. 36 37 support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6,7,8)); 38 39 if (support_smi_only_arrays) { 40 print("Tests include smi-only arrays."); 41 } else { 42 print("Tests do NOT include smi-only arrays."); 43 } 44 45 var elements_kind = { 46 fast_smi_only : 'fast smi only elements', 47 fast : 'fast elements', 48 fast_double : 'fast double elements', 49 dictionary : 'dictionary elements', 50 external_byte : 'external byte elements', 51 external_unsigned_byte : 'external unsigned byte elements', 52 external_short : 'external short elements', 53 external_unsigned_short : 'external unsigned short elements', 54 external_int : 'external int elements', 55 external_unsigned_int : 'external unsigned int elements', 56 external_float : 'external float elements', 57 external_double : 'external double elements', 58 external_pixel : 'external pixel elements' 59 } 60 61 function getKind(obj) { 62 if (%HasFastSmiOnlyElements(obj)) return elements_kind.fast_smi_only; 63 if (%HasFastElements(obj)) return elements_kind.fast; 64 if (%HasFastDoubleElements(obj)) return elements_kind.fast_double; 65 if (%HasDictionaryElements(obj)) return elements_kind.dictionary; 66 // Every external kind is also an external array. 67 assertTrue(%HasExternalArrayElements(obj)); 68 if (%HasExternalByteElements(obj)) { 69 return elements_kind.external_byte; 70 } 71 if (%HasExternalUnsignedByteElements(obj)) { 72 return elements_kind.external_unsigned_byte; 73 } 74 if (%HasExternalShortElements(obj)) { 75 return elements_kind.external_short; 76 } 77 if (%HasExternalUnsignedShortElements(obj)) { 78 return elements_kind.external_unsigned_short; 79 } 80 if (%HasExternalIntElements(obj)) { 81 return elements_kind.external_int; 82 } 83 if (%HasExternalUnsignedIntElements(obj)) { 84 return elements_kind.external_unsigned_int; 85 } 86 if (%HasExternalFloatElements(obj)) { 87 return elements_kind.external_float; 88 } 89 if (%HasExternalDoubleElements(obj)) { 90 return elements_kind.external_double; 91 } 92 if (%HasExternalPixelElements(obj)) { 93 return elements_kind.external_pixel; 94 } 95 } 96 97 function assertKind(expected, obj, name_opt) { 98 if (!support_smi_only_arrays && 99 expected == elements_kind.fast_smi_only) { 100 expected = elements_kind.fast; 101 } 102 assertEquals(expected, getKind(obj), name_opt); 103 } 104 105 var me = {}; 106 assertKind(elements_kind.fast, me); 107 me.dance = 0xD15C0; 108 me.drink = 0xC0C0A; 109 assertKind(elements_kind.fast, me); 110 111 if (support_smi_only_arrays) { 112 var too = [1,2,3]; 113 assertKind(elements_kind.fast_smi_only, too); 114 too.dance = 0xD15C0; 115 too.drink = 0xC0C0A; 116 assertKind(elements_kind.fast_smi_only, too); 117 } 118 119 // Make sure the element kind transitions from smionly when a non-smi is stored. 120 var you = new Array(); 121 assertKind(elements_kind.fast_smi_only, you); 122 for (var i = 0; i < 1337; i++) { 123 var val = i; 124 if (i == 1336) { 125 assertKind(elements_kind.fast_smi_only, you); 126 val = new Object(); 127 } 128 you[i] = val; 129 } 130 assertKind(elements_kind.fast, you); 131 132 assertKind(elements_kind.dictionary, new Array(0xDECAF)); 133 134 var fast_double_array = new Array(0xDECAF); 135 for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2; 136 assertKind(elements_kind.fast_double, fast_double_array); 137 138 assertKind(elements_kind.external_byte, new Int8Array(9001)); 139 assertKind(elements_kind.external_unsigned_byte, new Uint8Array(007)); 140 assertKind(elements_kind.external_short, new Int16Array(666)); 141 assertKind(elements_kind.external_unsigned_short, new Uint16Array(42)); 142 assertKind(elements_kind.external_int, new Int32Array(0xF)); 143 assertKind(elements_kind.external_unsigned_int, new Uint32Array(23)); 144 assertKind(elements_kind.external_float, new Float32Array(7)); 145 assertKind(elements_kind.external_double, new Float64Array(0)); 146 assertKind(elements_kind.external_pixel, new PixelArray(512)); 147 148 // Crankshaft support for smi-only array elements. 149 function monomorphic(array) { 150 assertKind(elements_kind.fast_smi_only, array); 151 for (var i = 0; i < 3; i++) { 152 array[i] = i + 10; 153 } 154 assertKind(elements_kind.fast_smi_only, array); 155 for (var i = 0; i < 3; i++) { 156 var a = array[i]; 157 assertEquals(i + 10, a); 158 } 159 } 160 var smi_only = new Array(1, 2, 3); 161 assertKind(elements_kind.fast_smi_only, smi_only); 162 for (var i = 0; i < 3; i++) monomorphic(smi_only); 163 %OptimizeFunctionOnNextCall(monomorphic); 164 monomorphic(smi_only); 165 166 if (support_smi_only_arrays) { 167 function construct_smis() { 168 var a = [0, 0, 0]; 169 a[0] = 0; // Send the COW array map to the steak house. 170 assertKind(elements_kind.fast_smi_only, a); 171 return a; 172 } 173 function construct_doubles() { 174 var a = construct_smis(); 175 a[0] = 1.5; 176 assertKind(elements_kind.fast_double, a); 177 return a; 178 } 179 function construct_objects() { 180 var a = construct_smis(); 181 a[0] = "one"; 182 assertKind(elements_kind.fast, a); 183 return a; 184 } 185 186 // Test crankshafted transition SMI->DOUBLE. 187 function convert_to_double(array) { 188 array[1] = 2.5; 189 assertKind(elements_kind.fast_double, array); 190 assertEquals(2.5, array[1]); 191 } 192 var smis = construct_smis(); 193 for (var i = 0; i < 3; i++) convert_to_double(smis); 194 %OptimizeFunctionOnNextCall(convert_to_double); 195 smis = construct_smis(); 196 convert_to_double(smis); 197 // Test crankshafted transitions SMI->FAST and DOUBLE->FAST. 198 function convert_to_fast(array) { 199 array[1] = "two"; 200 assertKind(elements_kind.fast, array); 201 assertEquals("two", array[1]); 202 } 203 smis = construct_smis(); 204 for (var i = 0; i < 3; i++) convert_to_fast(smis); 205 var doubles = construct_doubles(); 206 for (var i = 0; i < 3; i++) convert_to_fast(doubles); 207 smis = construct_smis(); 208 doubles = construct_doubles(); 209 %OptimizeFunctionOnNextCall(convert_to_fast); 210 convert_to_fast(smis); 211 convert_to_fast(doubles); 212 // Test transition chain SMI->DOUBLE->FAST (crankshafted function will 213 // transition to FAST directly). 214 function convert_mixed(array, value, kind) { 215 array[1] = value; 216 assertKind(kind, array); 217 assertEquals(value, array[1]); 218 } 219 smis = construct_smis(); 220 for (var i = 0; i < 3; i++) { 221 convert_mixed(smis, 1.5, elements_kind.fast_double); 222 } 223 doubles = construct_doubles(); 224 for (var i = 0; i < 3; i++) { 225 convert_mixed(doubles, "three", elements_kind.fast); 226 } 227 smis = construct_smis(); 228 doubles = construct_doubles(); 229 %OptimizeFunctionOnNextCall(convert_mixed); 230 convert_mixed(smis, 1, elements_kind.fast); 231 convert_mixed(doubles, 1, elements_kind.fast); 232 assertTrue(%HaveSameMap(smis, doubles)); 233 } 234 235 // Crankshaft support for smi-only elements in dynamic array literals. 236 function get(foo) { return foo; } // Used to generate dynamic values. 237 238 function crankshaft_test() { 239 if (support_smi_only_arrays) { 240 var a1 = [get(1), get(2), get(3)]; 241 assertKind(elements_kind.fast_smi_only, a1); 242 } 243 var a2 = new Array(get(1), get(2), get(3)); 244 assertKind(elements_kind.fast_smi_only, a2); 245 var b = [get(1), get(2), get("three")]; 246 assertKind(elements_kind.fast, b); 247 var c = [get(1), get(2), get(3.5)]; 248 if (support_smi_only_arrays) { 249 assertKind(elements_kind.fast_double, c); 250 } 251 } 252 for (var i = 0; i < 3; i++) { 253 crankshaft_test(); 254 } 255 %OptimizeFunctionOnNextCall(crankshaft_test); 256 crankshaft_test(); 257 258 // Elements_kind transitions for arrays. 259 260 // A map can have three different elements_kind transitions: SMI->DOUBLE, 261 // DOUBLE->OBJECT, and SMI->OBJECT. No matter in which order these three are 262 // created, they must always end up with the same FAST map. 263 264 // This test is meaningless without FAST_SMI_ONLY_ELEMENTS. 265 if (support_smi_only_arrays) { 266 // Preparation: create one pair of identical objects for each case. 267 var a = [1, 2, 3]; 268 var b = [1, 2, 3]; 269 assertTrue(%HaveSameMap(a, b)); 270 assertKind(elements_kind.fast_smi_only, a); 271 var c = [1, 2, 3]; 272 c["case2"] = true; 273 var d = [1, 2, 3]; 274 d["case2"] = true; 275 assertTrue(%HaveSameMap(c, d)); 276 assertFalse(%HaveSameMap(a, c)); 277 assertKind(elements_kind.fast_smi_only, c); 278 var e = [1, 2, 3]; 279 e["case3"] = true; 280 var f = [1, 2, 3]; 281 f["case3"] = true; 282 assertTrue(%HaveSameMap(e, f)); 283 assertFalse(%HaveSameMap(a, e)); 284 assertFalse(%HaveSameMap(c, e)); 285 assertKind(elements_kind.fast_smi_only, e); 286 // Case 1: SMI->DOUBLE, DOUBLE->OBJECT, SMI->OBJECT. 287 a[0] = 1.5; 288 assertKind(elements_kind.fast_double, a); 289 a[0] = "foo"; 290 assertKind(elements_kind.fast, a); 291 b[0] = "bar"; 292 assertTrue(%HaveSameMap(a, b)); 293 // Case 2: SMI->DOUBLE, SMI->OBJECT, DOUBLE->OBJECT. 294 c[0] = 1.5; 295 assertKind(elements_kind.fast_double, c); 296 assertFalse(%HaveSameMap(c, d)); 297 d[0] = "foo"; 298 assertKind(elements_kind.fast, d); 299 assertFalse(%HaveSameMap(c, d)); 300 c[0] = "bar"; 301 assertTrue(%HaveSameMap(c, d)); 302 // Case 3: SMI->OBJECT, SMI->DOUBLE, DOUBLE->OBJECT. 303 e[0] = "foo"; 304 assertKind(elements_kind.fast, e); 305 assertFalse(%HaveSameMap(e, f)); 306 f[0] = 1.5; 307 assertKind(elements_kind.fast_double, f); 308 assertFalse(%HaveSameMap(e, f)); 309 f[0] = "bar"; 310 assertKind(elements_kind.fast, f); 311 assertTrue(%HaveSameMap(e, f)); 312 } 313 314 // Test if Array.concat() works correctly with DOUBLE elements. 315 if (support_smi_only_arrays) { 316 var a = [1, 2]; 317 assertKind(elements_kind.fast_smi_only, a); 318 var b = [4.5, 5.5]; 319 assertKind(elements_kind.fast_double, b); 320 var c = a.concat(b); 321 assertEquals([1, 2, 4.5, 5.5], c); 322 // TODO(1810): Change implementation so that we get DOUBLE elements here? 323 assertKind(elements_kind.fast, c); 324 } 325 326 // Test that Array.push() correctly handles SMI elements. 327 if (support_smi_only_arrays) { 328 var a = [1, 2]; 329 assertKind(elements_kind.fast_smi_only, a); 330 a.push(3, 4, 5); 331 assertKind(elements_kind.fast_smi_only, a); 332 assertEquals([1, 2, 3, 4, 5], a); 333 } 334 335 // Test that Array.splice() and Array.slice() return correct ElementsKinds. 336 if (support_smi_only_arrays) { 337 var a = ["foo", "bar"]; 338 assertKind(elements_kind.fast, a); 339 var b = a.splice(0, 1); 340 assertKind(elements_kind.fast, b); 341 var c = a.slice(0, 1); 342 assertKind(elements_kind.fast, c); 343 } 344 345 // Throw away type information in the ICs for next stress run. 346 gc(); 347