| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame^] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. | 
| Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 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 |  | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame^] | 37 | support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6,7,8)); | 
| Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 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 |  | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame^] | 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 | } | 
| Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 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) { | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame^] | 150 |   assertKind(elements_kind.fast_smi_only, array); | 
| Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 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 | } | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame^] | 160 | var smi_only = new Array(1, 2, 3); | 
 | 161 | assertKind(elements_kind.fast_smi_only, smi_only); | 
| Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 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() { | 
| Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame^] | 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); | 
| Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 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); | 
| Ben Murdoch | 592a9fc | 2012-03-05 11:04:45 +0000 | [diff] [blame] | 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(); |