danno@chromium.org | f005df6 | 2013-04-30 16:36:45 +0000 | [diff] [blame] | 1 | // Copyright 2013 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: --track-fields --track-double-fields --allow-natives-syntax |
| 29 | |
| 30 | // Test transitions caused by changes to field representations. |
| 31 | |
| 32 | function create_smi_object() { |
| 33 | var o = {}; |
| 34 | o.x = 1; |
| 35 | o.y = 2; |
| 36 | o.z = 3; |
| 37 | return o; |
| 38 | } |
| 39 | |
| 40 | var o1 = create_smi_object(); |
| 41 | var o2 = create_smi_object(); |
| 42 | |
| 43 | // o1,o2 are smi, smi, smi |
| 44 | assertTrue(%HaveSameMap(o1, o2)); |
| 45 | o1.y = 1.3; |
| 46 | // o1 is smi, double, smi |
| 47 | assertFalse(%HaveSameMap(o1, o2)); |
| 48 | o2.y = 1.5; |
| 49 | // o2 is smi, double, smi |
| 50 | assertTrue(%HaveSameMap(o1, o2)); |
| 51 | |
| 52 | // o3 is initialized as smi, double, smi |
| 53 | var o3 = create_smi_object(); |
| 54 | assertTrue(%HaveSameMap(o1, o3)); |
| 55 | |
| 56 | function set_large(o, v) { |
| 57 | o.x01 = v; o.x02 = v; o.x03 = v; o.x04 = v; o.x05 = v; o.x06 = v; o.x07 = v; |
| 58 | o.x08 = v; o.x09 = v; o.x10 = v; o.x11 = v; o.x12 = v; o.x13 = v; o.x14 = v; |
| 59 | o.x15 = v; o.x16 = v; o.x17 = v; o.x18 = v; o.x19 = v; o.x20 = v; o.x21 = v; |
| 60 | o.x22 = v; o.x23 = v; o.x24 = v; o.x25 = v; o.x26 = v; o.x27 = v; o.x28 = v; |
| 61 | o.x29 = v; o.x30 = v; o.x31 = v; o.x32 = v; o.x33 = v; o.x34 = v; o.x35 = v; |
| 62 | o.x36 = v; o.x37 = v; o.x38 = v; o.x39 = v; o.x40 = v; o.x41 = v; o.x42 = v; |
| 63 | o.y01 = v; o.y02 = v; o.y03 = v; o.y04 = v; o.y05 = v; o.y06 = v; o.y07 = v; |
| 64 | o.y08 = v; o.y09 = v; o.y10 = v; o.y11 = v; o.y12 = v; o.y13 = v; o.y14 = v; |
| 65 | o.y15 = v; o.y16 = v; o.y17 = v; o.y18 = v; o.y19 = v; o.y20 = v; o.y21 = v; |
| 66 | } |
| 67 | |
| 68 | // Check that large object migrations work. |
| 69 | var o4 = {}; |
| 70 | // All smi. |
| 71 | set_large(o4, 0); |
| 72 | assertTrue(%HasFastProperties(o4)); |
| 73 | // All double. |
| 74 | set_large(o4, 1.5); |
| 75 | // o5 is immediately allocated with doubles. |
| 76 | var o5 = {}; |
| 77 | set_large(o5, 0); |
| 78 | assertTrue(%HaveSameMap(o4, o5)); |
| 79 | |
| 80 | function create_smi_object2() { |
| 81 | var o = {}; |
| 82 | o.a = 1; |
| 83 | o.b = 2; |
| 84 | o.c = 3; |
| 85 | return o; |
| 86 | } |
| 87 | |
| 88 | // All smi |
| 89 | var o6 = create_smi_object2(); |
| 90 | var o7 = create_smi_object2(); |
| 91 | |
| 92 | assertTrue(%HaveSameMap(o6, o7)); |
| 93 | // Smi, double, smi. |
| 94 | o6.b = 1.5; |
| 95 | assertFalse(%HaveSameMap(o6, o7)); |
| 96 | // Smi, double, object. |
| 97 | o7.c = {}; |
| 98 | assertFalse(%HaveSameMap(o6, o7)); |
| 99 | // Smi, double, object. |
| 100 | o6.c = {}; |
| 101 | assertTrue(%HaveSameMap(o6, o7)); |
ulan@chromium.org | 57ff881 | 2013-05-10 08:16:55 +0000 | [diff] [blame^] | 102 | |
| 103 | function poly_load(o, b) { |
| 104 | var v = o.field; |
| 105 | if (b) { |
| 106 | return v + 10; |
| 107 | } |
| 108 | return o; |
| 109 | } |
| 110 | |
| 111 | var of1 = {a:0}; |
| 112 | of1.field = {}; |
| 113 | var of2 = {b:0}; |
| 114 | of2.field = 10; |
| 115 | |
| 116 | poly_load(of1, false); |
| 117 | poly_load(of1, false); |
| 118 | poly_load(of2, true); |
| 119 | %OptimizeFunctionOnNextCall(poly_load); |
| 120 | assertEquals("[object Object]10", poly_load(of1, true)); |
| 121 | |
| 122 | // Ensure small object literals with doubles do not share double storage. |
| 123 | function object_literal() { return {"a":1.5}; } |
| 124 | var o8 = object_literal(); |
| 125 | var o9 = object_literal(); |
| 126 | o8.a = 4.6 |
| 127 | assertEquals(1.5, o9.a); |
| 128 | |
| 129 | // Ensure double storage is not leaked in the case of polymorphic loads. |
| 130 | function load_poly(o) { |
| 131 | return o.a; |
| 132 | } |
| 133 | |
| 134 | var o10 = { "a": 1.6 }; |
| 135 | var o11 = { "b": 1, "a": 1.7 }; |
| 136 | load_poly(o10); |
| 137 | load_poly(o10); |
| 138 | load_poly(o11); |
| 139 | %OptimizeFunctionOnNextCall(load_poly); |
| 140 | var val = load_poly(o10); |
| 141 | o10.a = 19.5; |
| 142 | assertFalse(o10.a == val); |
| 143 | |
| 144 | // Ensure polymorphic loads only go monomorphic when the representations are |
| 145 | // compatible. |
| 146 | |
| 147 | // Check polymorphic load from double + object fields. |
| 148 | function load_mono(o) { |
| 149 | return o.a1; |
| 150 | } |
| 151 | |
| 152 | var object = {"x": 1}; |
| 153 | var o10 = { "a1": 1.6 }; |
| 154 | var o11 = { "a1": object, "b": 1 }; |
| 155 | load_mono(o10); |
| 156 | load_mono(o10); |
| 157 | load_mono(o11); |
| 158 | %OptimizeFunctionOnNextCall(load_mono); |
| 159 | assertEquals(object, load_mono(o11)); |
| 160 | |
| 161 | // Check polymorphic load from smi + object fields. |
| 162 | function load_mono2(o) { |
| 163 | return o.a2; |
| 164 | } |
| 165 | |
| 166 | var o12 = { "a2": 5 }; |
| 167 | var o13 = { "a2": object, "b": 1 }; |
| 168 | load_mono2(o12); |
| 169 | load_mono2(o12); |
| 170 | load_mono2(o13); |
| 171 | %OptimizeFunctionOnNextCall(load_mono2); |
| 172 | assertEquals(object, load_mono2(o13)); |
| 173 | |
| 174 | // Check polymorphic load from double + double fields. |
| 175 | function load_mono3(o) { |
| 176 | return o.a3; |
| 177 | } |
| 178 | |
| 179 | var o14 = { "a3": 1.6 }; |
| 180 | var o15 = { "a3": 1.8, "b": 1 }; |
| 181 | load_mono3(o14); |
| 182 | load_mono3(o14); |
| 183 | load_mono3(o15); |
| 184 | %OptimizeFunctionOnNextCall(load_mono3); |
| 185 | assertEquals(1.6, load_mono3(o14)); |
| 186 | assertEquals(1.8, load_mono3(o15)); |
| 187 | |
| 188 | // Check that JSON parsing respects existing representations. |
| 189 | var o16 = JSON.parse('{"a":1.5}'); |
| 190 | var o17 = JSON.parse('{"a":100}'); |
| 191 | assertTrue(%HaveSameMap(o16, o17)); |
| 192 | var o17_a = o17.a; |
| 193 | assertEquals(100, o17_a); |
| 194 | o17.a = 200; |
| 195 | assertEquals(100, o17_a); |
| 196 | assertEquals(200, o17.a); |
| 197 | |
| 198 | // Ensure normalizing results in ignored representations. |
| 199 | var o18 = {}; |
| 200 | o18.field1 = 100; |
| 201 | o18.field2 = 1; |
| 202 | o18.to_delete = 100; |
| 203 | |
| 204 | var o19 = {}; |
| 205 | o19.field1 = 100; |
| 206 | o19.field2 = 1.6; |
| 207 | o19.to_delete = 100; |
| 208 | |
| 209 | assertFalse(%HaveSameMap(o18, o19)); |
| 210 | |
| 211 | delete o18.to_delete; |
| 212 | delete o19.to_delete; |
| 213 | |
| 214 | assertTrue(%HaveSameMap(o18, o19)); |
| 215 | assertEquals(1, o18.field2); |
| 216 | assertEquals(1.6, o19.field2); |
| 217 | |
| 218 | // Test megamorphic keyed stub behaviour in combination with representations. |
| 219 | var some_object20 = {"a":1}; |
| 220 | var o20 = {}; |
| 221 | o20.smi = 1; |
| 222 | o20.dbl = 1.5; |
| 223 | o20.obj = some_object20; |
| 224 | |
| 225 | function keyed_load(o, k) { |
| 226 | return o[k]; |
| 227 | } |
| 228 | |
| 229 | function keyed_store(o, k, v) { |
| 230 | return o[k] = v; |
| 231 | } |
| 232 | |
| 233 | var smi20 = keyed_load(o20, "smi"); |
| 234 | var dbl20 = keyed_load(o20, "dbl"); |
| 235 | var obj20 = keyed_load(o20, "obj"); |
| 236 | keyed_load(o20, "smi"); |
| 237 | keyed_load(o20, "dbl"); |
| 238 | keyed_load(o20, "obj"); |
| 239 | keyed_load(o20, "smi"); |
| 240 | keyed_load(o20, "dbl"); |
| 241 | keyed_load(o20, "obj"); |
| 242 | |
| 243 | assertEquals(1, smi20); |
| 244 | assertEquals(1.5, dbl20); |
| 245 | assertEquals(some_object20, obj20); |
| 246 | |
| 247 | keyed_store(o20, "smi", 100); |
| 248 | keyed_store(o20, "dbl", 100); |
| 249 | keyed_store(o20, "obj", 100); |
| 250 | keyed_store(o20, "smi", 100); |
| 251 | keyed_store(o20, "dbl", 100); |
| 252 | keyed_store(o20, "obj", 100); |
| 253 | keyed_store(o20, "smi", 100); |
| 254 | keyed_store(o20, "dbl", 100); |
| 255 | keyed_store(o20, "obj", 100); |
| 256 | |
| 257 | assertEquals(1, smi20); |
| 258 | assertEquals(1.5, dbl20); |
| 259 | assertEquals(some_object20, obj20); |
| 260 | |
| 261 | assertEquals(100, o20.smi); |
| 262 | assertEquals(100, o20.dbl); |
| 263 | assertEquals(100, o20.dbl); |