blob: b12e7bfca0af1016dfa03cdebbb2924983f5f54f [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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 non-shallow nested graph of captured objects with duplicates
307(function testDeepDuplicate() {
308 function constructor1() {
309 this.x = 23;
310 }
311 function constructor2(nested) {
312 this.a = 17;
313 this.b = nested;
314 this.c = 42;
315 }
316 function deep(shouldDeopt) {
317 var o1 = new constructor1();
318 var o2 = new constructor2(o1);
319 var o3 = new constructor2(o1);
320 assertEquals(17, o2.a);
321 assertEquals(23, o2.b.x);
322 assertEquals(42, o2.c);
323 o3.c = 54;
324 o1.x = 99;
325 if (shouldDeopt) %DeoptimizeFunction(deep);
326 assertEquals(99, o1.x);
327 assertEquals(99, o2.b.x);
328 assertEquals(99, o3.b.x);
329 assertEquals(54, o3.c);
330 assertEquals(17, o3.a);
331 assertEquals(42, o2.c);
332 assertEquals(17, o2.a);
333 o3.b.x = 1;
334 assertEquals(1, o1.x);
335 }
336 deep(false); deep(false);
337 %OptimizeFunctionOnNextCall(deep);
338 deep(false); deep(false);
339 deep(true); deep(true);
340})();
341
342
343// Test non-shallow nested graph of captured objects with inline
344(function testDeepInline() {
345 function h() {
346 return { y : 3 };
347 }
348
349 function g(x) {
350 var u = { x : h() };
351 %DeoptimizeFunction(f);
352 return u;
353 }
354
355 function f() {
356 var l = { dummy : { } };
357 var r = g(l);
358 assertEquals(3, r.x.y);
359 }
360
361 f(); f(); f();
362 %OptimizeFunctionOnNextCall(f);
363 f();
364})();
365
366
367// Test two nested objects
368(function testTwoNestedObjects() {
369 function f() {
370 var l = { x : { y : 111 } };
371 var l2 = { x : { y : 111 } };
372 %DeoptimizeFunction(f);
373 assertEquals(111, l.x.y);
374 assertEquals(111, l2.x.y);
375 }
376
377 f(); f(); f();
378 %OptimizeFunctionOnNextCall(f);
379 f();
380})();
381
382
383// Test a nested object and a duplicate
384(function testTwoObjectsWithDuplicate() {
385 function f() {
386 var l = { x : { y : 111 } };
387 var dummy = { d : 0 };
388 var l2 = l.x;
389 %DeoptimizeFunction(f);
390 assertEquals(111, l.x.y);
391 assertEquals(111, l2.y);
392 assertEquals(0, dummy.d);
393 }
394
395 f(); f(); f();
396 %OptimizeFunctionOnNextCall(f);
397 f();
398})();
399
400
401// Test materialization of a field that requires a Smi value.
402(function testSmiField() {
403 var deopt = { deopt:false };
404 function constructor() {
405 this.x = 1;
406 }
407 function field(x) {
408 var o = new constructor();
409 o.x = x;
410 deopt.deopt
411 assertEquals(x, o.x);
412 }
413 field(1); field(2);
414 %OptimizeFunctionOnNextCall(field);
415 field(3); field(4);
416 delete deopt.deopt;
417 field(5.5); field(6.5);
418})();
419
420
421// Test materialization of a field that requires a heap object value.
422(function testHeapObjectField() {
423 var deopt = { deopt:false };
424 function constructor() {
425 this.x = {};
426 }
427 function field(x) {
428 var o = new constructor();
429 o.x = x;
430 deopt.deopt
431 assertEquals(x, o.x);
432 }
433 field({}); field({});
434 %OptimizeFunctionOnNextCall(field);
435 field({}); field({});
436 delete deopt.deopt;
437 field(1); field(2);
438})();