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: --allow-natives-syntax --use-escape-analysis --expose-gc 29 30 31// Test stores on a join path. 32(function testJoin() { 33 function constructor() { 34 this.a = 0; 35 } 36 function join(mode, expected) { 37 var object = new constructor(); 38 if (mode) { 39 object.a = 1; 40 } else { 41 object.a = 2; 42 } 43 assertEquals(expected, object.a); 44 } 45 join(true, 1); join(true, 1); 46 join(false, 2); join(false, 2); 47 %OptimizeFunctionOnNextCall(join); 48 join(true, 1); join(false, 2); 49})(); 50 51 52// Test loads and stores inside a loop. 53(function testLoop() { 54 function constructor() { 55 this.a = 0; 56 this.b = 23; 57 } 58 function loop() { 59 var object = new constructor(); 60 for (var i = 1; i < 10; i++) { 61 object.a = object.a + i; 62 assertEquals(i*(i+1)/2, object.a); 63 assertEquals(23, object.b); 64 } 65 assertEquals(45, object.a); 66 assertEquals(23, object.b); 67 } 68 loop(); loop(); 69 %OptimizeFunctionOnNextCall(loop); 70 loop(); loop(); 71})(); 72 73 74// Test loads and stores inside nested loop. 75(function testNested() { 76 function constructor() { 77 this.a = 0; 78 this.b = 0; 79 this.c = 23; 80 } 81 function nested() { 82 var object = new constructor(); 83 for (var i = 1; i < 10; i++) { 84 object.a = object.a + i; 85 assertEquals(i*(i+1)/2, object.a); 86 assertEquals((i-1)*6, object.b); 87 assertEquals(23, object.c); 88 for (var j = 1; j < 4; j++) { 89 object.b = object.b + j; 90 assertEquals(i*(i+1)/2, object.a); 91 assertEquals((i-1)*6+j*(j+1)/2, object.b); 92 assertEquals(23, object.c); 93 } 94 assertEquals(i*(i+1)/2, object.a); 95 assertEquals(i*6, object.b); 96 assertEquals(23, object.c); 97 } 98 assertEquals(45, object.a); 99 assertEquals(54, object.b); 100 assertEquals(23, object.c); 101 } 102 nested(); nested(); 103 %OptimizeFunctionOnNextCall(nested); 104 nested(); nested(); 105})(); 106 107 108// Test deoptimization with captured objects in local variables. 109(function testDeoptLocal() { 110 var deopt = { deopt:false }; 111 function constructor1() { 112 this.a = 1.0; 113 this.b = 2.3; 114 this.c = 3.0; 115 } 116 function constructor2(o) { 117 this.d = o; 118 this.e = 4.5; 119 } 120 function func() { 121 var o1 = new constructor1(); 122 var o2 = new constructor2(o1); 123 deopt.deopt; 124 assertEquals(1.0, o1.a); 125 assertEquals(2.3, o2.d.b); 126 assertEquals(3.0, o2.d.c); 127 assertEquals(4.5, o2.e); 128 } 129 func(); func(); 130 %OptimizeFunctionOnNextCall(func); 131 func(); func(); 132 delete deopt.deopt; 133 func(); func(); 134})(); 135 136 137// Test deoptimization with captured objects on operand stack. 138(function testDeoptOperand() { 139 var deopt = { deopt:false }; 140 function constructor1() { 141 this.a = 1.0; 142 this.b = 2.3; 143 deopt.deopt; 144 assertEquals(1.0, this.a); 145 assertEquals(2.3, this.b); 146 this.b = 2.7; 147 this.c = 3.0; 148 this.d = 4.5; 149 } 150 function constructor2() { 151 this.e = 5.0; 152 this.f = new constructor1(); 153 assertEquals(1.0, this.f.a); 154 assertEquals(2.7, this.f.b); 155 assertEquals(3.0, this.f.c); 156 assertEquals(4.5, this.f.d); 157 assertEquals(5.0, this.e); 158 this.e = 5.9; 159 this.g = 6.7; 160 } 161 function func() { 162 var o = new constructor2(); 163 assertEquals(1.0, o.f.a); 164 assertEquals(2.7, o.f.b); 165 assertEquals(3.0, o.f.c); 166 assertEquals(4.5, o.f.d); 167 assertEquals(5.9, o.e); 168 assertEquals(6.7, o.g); 169 } 170 func(); func(); 171 %OptimizeFunctionOnNextCall(func); 172 func(); func(); 173 delete deopt.deopt; 174 func(); func(); 175})(); 176 177 178// Test map checks on captured objects. 179(function testMapCheck() { 180 var sum = 0; 181 function getter() { return 27; } 182 function setter(v) { sum += v; } 183 function constructor() { 184 this.x = 23; 185 this.y = 42; 186 } 187 function check(x, y) { 188 var o = new constructor(); 189 assertEquals(x, o.x); 190 assertEquals(y, o.y); 191 } 192 var monkey = Object.create(null, { 193 x: { get:getter, set:setter }, 194 y: { get:getter, set:setter } 195 }); 196 check(23, 42); check(23, 42); 197 %OptimizeFunctionOnNextCall(check); 198 check(23, 42); check(23, 42); 199 constructor.prototype = monkey; 200 check(27, 27); check(27, 27); 201 assertEquals(130, sum); 202})(); 203 204 205// Test OSR into a loop with captured objects. 206(function testOSR() { 207 function constructor() { 208 this.a = 23; 209 } 210 function osr1(length) { 211 assertEquals(23, (new constructor()).a); 212 var result = 0; 213 for (var i = 0; i < length; i++) { 214 result = (result + i) % 99; 215 } 216 return result; 217 } 218 function osr2(length) { 219 var result = 0; 220 for (var i = 0; i < length; i++) { 221 result = (result + i) % 99; 222 } 223 assertEquals(23, (new constructor()).a); 224 return result; 225 } 226 function osr3(length) { 227 var result = 0; 228 var o = new constructor(); 229 for (var i = 0; i < length; i++) { 230 result = (result + i) % 99; 231 } 232 assertEquals(23, o.a); 233 return result; 234 } 235 function test(closure) { 236 assertEquals(45, closure(10)); 237 assertEquals(45, closure(10)); 238 assertEquals(10, closure(50000)); 239 } 240 test(osr1); 241 test(osr2); 242 test(osr3); 243})(); 244 245 246// Test out-of-bounds access on captured objects. 247(function testOOB() { 248 function cons1() { 249 this.x = 1; 250 this.y = 2; 251 this.z = 3; 252 } 253 function cons2() { 254 this.a = 7; 255 } 256 function oob(constructor, branch) { 257 var o = new constructor(); 258 if (branch) { 259 return o.a; 260 } else { 261 return o.z; 262 } 263 } 264 assertEquals(3, oob(cons1, false)); 265 assertEquals(3, oob(cons1, false)); 266 assertEquals(7, oob(cons2, true)); 267 assertEquals(7, oob(cons2, true)); 268 gc(); // Clears type feedback of constructor call. 269 assertEquals(7, oob(cons2, true)); 270 assertEquals(7, oob(cons2, true)); 271 %OptimizeFunctionOnNextCall(oob); 272 assertEquals(7, oob(cons2, true)); 273})(); 274 275 276// Test non-shallow nested graph of captured objects. 277(function testDeep() { 278 var deopt = { deopt:false }; 279 function constructor1() { 280 this.x = 23; 281 } 282 function constructor2(nested) { 283 this.a = 17; 284 this.b = nested; 285 this.c = 42; 286 } 287 function deep() { 288 var o1 = new constructor1(); 289 var o2 = new constructor2(o1); 290 assertEquals(17, o2.a); 291 assertEquals(23, o2.b.x); 292 assertEquals(42, o2.c); 293 o1.x = 99; 294 deopt.deopt; 295 assertEquals(99, o1.x); 296 assertEquals(99, o2.b.x); 297 } 298 deep(); deep(); 299 %OptimizeFunctionOnNextCall(deep); 300 deep(); deep(); 301 delete deopt.deopt; 302 deep(); deep(); 303})(); 304 305 306// Test materialization of a field that requires a Smi value. 307(function testSmiField() { 308 var deopt = { deopt:false }; 309 function constructor() { 310 this.x = 1; 311 } 312 function field(x) { 313 var o = new constructor(); 314 o.x = x; 315 deopt.deopt 316 assertEquals(x, o.x); 317 } 318 field(1); field(2); 319 %OptimizeFunctionOnNextCall(field); 320 field(3); field(4); 321 delete deopt.deopt; 322 field(5.5); field(6.5); 323})(); 324 325 326// Test materialization of a field that requires a heap object value. 327(function testHeapObjectField() { 328 var deopt = { deopt:false }; 329 function constructor() { 330 this.x = {}; 331 } 332 function field(x) { 333 var o = new constructor(); 334 o.x = x; 335 deopt.deopt 336 assertEquals(x, o.x); 337 } 338 field({}); field({}); 339 %OptimizeFunctionOnNextCall(field); 340 field({}); field({}); 341 delete deopt.deopt; 342 field(1); field(2); 343})(); 344