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 37support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6,7,8)); 38 39if (support_smi_only_arrays) { 40 print("Tests include smi-only arrays."); 41} else { 42 print("Tests do NOT include smi-only arrays."); 43} 44 45var 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 61function 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 97function 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 105var me = {}; 106assertKind(elements_kind.fast, me); 107me.dance = 0xD15C0; 108me.drink = 0xC0C0A; 109assertKind(elements_kind.fast, me); 110 111if (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. 120var you = new Array(); 121assertKind(elements_kind.fast_smi_only, you); 122for (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} 130assertKind(elements_kind.fast, you); 131 132assertKind(elements_kind.dictionary, new Array(0xDECAF)); 133 134var fast_double_array = new Array(0xDECAF); 135for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2; 136assertKind(elements_kind.fast_double, fast_double_array); 137 138assertKind(elements_kind.external_byte, new Int8Array(9001)); 139assertKind(elements_kind.external_unsigned_byte, new Uint8Array(007)); 140assertKind(elements_kind.external_short, new Int16Array(666)); 141assertKind(elements_kind.external_unsigned_short, new Uint16Array(42)); 142assertKind(elements_kind.external_int, new Int32Array(0xF)); 143assertKind(elements_kind.external_unsigned_int, new Uint32Array(23)); 144assertKind(elements_kind.external_float, new Float32Array(7)); 145assertKind(elements_kind.external_double, new Float64Array(0)); 146assertKind(elements_kind.external_pixel, new PixelArray(512)); 147 148// Crankshaft support for smi-only array elements. 149function 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} 160var smi_only = new Array(1, 2, 3); 161assertKind(elements_kind.fast_smi_only, smi_only); 162for (var i = 0; i < 3; i++) monomorphic(smi_only); 163%OptimizeFunctionOnNextCall(monomorphic); 164monomorphic(smi_only); 165 166if (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. 236function get(foo) { return foo; } // Used to generate dynamic values. 237 238function 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} 252for (var i = 0; i < 3; i++) { 253 crankshaft_test(); 254} 255%OptimizeFunctionOnNextCall(crankshaft_test); 256crankshaft_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. 265if (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. 315if (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. 327if (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. 336if (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. 346gc(); 347