1// Copyright 2011 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 --max-opt-count=100
29
30function A() {
31}
32
33A.prototype.X = function (a, b, c) {
34  assertTrue(this instanceof A);
35  assertEquals(1, a);
36  assertEquals(2, b);
37  assertEquals(3, c);
38};
39
40A.prototype.Y = function () {
41  this.X.apply(this, arguments);
42};
43
44A.prototype.Z = function () {
45  this.Y(1,2,3);
46};
47
48var a = new A();
49a.Z(4,5,6);
50a.Z(4,5,6);
51%OptimizeFunctionOnNextCall(a.Z);
52a.Z(4,5,6);
53A.prototype.X.apply = function (receiver, args) {
54  return Function.prototype.apply.call(this, receiver, args);
55};
56a.Z(4,5,6);
57
58
59// Ensure that HArgumentsObject is inserted in a correct place
60// and dominates all uses.
61function F1() { }
62function F2() { F1.apply(this, arguments); }
63function F3(x, y) {
64  if (x) {
65    F2(y);
66  }
67}
68
69function F31() {
70  return F1.apply(this, arguments);
71}
72
73function F4() {
74  F3(true, false);
75  return F31(1);
76}
77
78F4(1);
79F4(1);
80F4(1);
81%OptimizeFunctionOnNextCall(F4);
82F4(1);
83
84
85// Test correct adapation of arguments.
86// Strict mode prevents arguments object from shadowing parameters.
87(function () {
88  "use strict";
89
90  function G2() {
91    assertArrayEquals([1,2], arguments);
92  }
93
94  function G4() {
95    assertArrayEquals([1,2,3,4], arguments);
96  }
97
98  function adapt2to4(a, b, c, d) {
99    G2.apply(this, arguments);
100  }
101
102  function adapt4to2(a, b) {
103    G4.apply(this, arguments);
104  }
105
106  function test_adaptation() {
107    adapt2to4(1, 2);
108    adapt4to2(1, 2, 3, 4);
109  }
110
111  test_adaptation();
112  test_adaptation();
113  %OptimizeFunctionOnNextCall(test_adaptation);
114  test_adaptation();
115})();
116
117// Test arguments access from the inlined function.
118%NeverOptimizeFunction(uninlinable);
119function uninlinable(v) {
120  assertEquals(0, v);
121  return 0;
122}
123
124function toarr_inner() {
125  var a = arguments;
126  var marker = a[0];
127  uninlinable(uninlinable(0, 0), marker.x);
128
129  var r = new Array();
130  for (var i = a.length - 1; i >= 1; i--) {
131    r.push(a[i]);
132  }
133
134  return r;
135}
136
137function toarr1(marker, a, b, c) {
138  return toarr_inner(marker, a / 2, b / 2, c / 2);
139}
140
141function toarr2(marker, a, b, c) {
142  var x = 0;
143  return uninlinable(uninlinable(0, 0),
144                     x = toarr_inner(marker, a / 2, b / 2, c / 2)), x;
145}
146
147function test_toarr(toarr) {
148  var marker = { x: 0 };
149  assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
150  assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
151  %OptimizeFunctionOnNextCall(toarr);
152  assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
153  delete marker.x;
154  assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
155}
156
157test_toarr(toarr1);
158test_toarr(toarr2);
159
160
161// Test that arguments access from inlined function uses correct values.
162(function () {
163  function inner(x, y) {
164    "use strict";
165    x = 10;
166    y = 20;
167    for (var i = 0; i < 1; i++) {
168      for (var j = 1; j <= arguments.length; j++) {
169        return arguments[arguments.length - j];
170      }
171    }
172  }
173
174  function outer(x, y) {
175    return inner(x, y);
176  }
177
178  %OptimizeFunctionOnNextCall(outer);
179  %OptimizeFunctionOnNextCall(inner);
180  assertEquals(2, outer(1, 2));
181})();
182
183
184(function () {
185  function inner(x, y) {
186    "use strict";
187    x = 10;
188    y = 20;
189    for (var i = 0; i < 1; i++) {
190      for (var j = 1; j <= arguments.length; j++) {
191        return arguments[arguments.length - j];
192      }
193    }
194  }
195
196  function outer(x, y) {
197    return inner(x, y);
198  }
199
200  assertEquals(2, outer(1, 2));
201  assertEquals(2, outer(1, 2));
202  assertEquals(2, outer(1, 2));
203  %OptimizeFunctionOnNextCall(outer);
204  assertEquals(2, outer(1, 2));
205})();
206
207
208// Test inlining and deoptimization of functions accessing and modifying
209// the arguments object in strict mode with mismatched arguments count.
210(function () {
211  "use strict";
212  function test(outerCount, middleCount, innerCount) {
213    var forceDeopt = { deopt:false };
214    function inner(x,y) {
215      x = 0; y = 0;
216      forceDeopt.deopt;
217      assertSame(innerCount, arguments.length);
218      for (var i = 0; i < arguments.length; i++) {
219        assertSame(30 + i, arguments[i]);
220      }
221    }
222
223    function middle(x,y) {
224      x = 0; y = 0;
225      if (innerCount == 1) inner(30);
226      if (innerCount == 2) inner(30, 31);
227      if (innerCount == 3) inner(30, 31, 32);
228      assertSame(middleCount, arguments.length);
229      for (var i = 0; i < arguments.length; i++) {
230        assertSame(20 + i, arguments[i]);
231      }
232    }
233
234    function outer(x,y) {
235      x = 0; y = 0;
236      if (middleCount == 1) middle(20);
237      if (middleCount == 2) middle(20, 21);
238      if (middleCount == 3) middle(20, 21, 22);
239      assertSame(outerCount, arguments.length);
240      for (var i = 0; i < arguments.length; i++) {
241        assertSame(10 + i, arguments[i]);
242      }
243    }
244
245    for (var step = 0; step < 4; step++) {
246      if (outerCount == 1) outer(10);
247      if (outerCount == 2) outer(10, 11);
248      if (outerCount == 3) outer(10, 11, 12);
249      if (step == 1) %OptimizeFunctionOnNextCall(outer);
250      if (step == 2) delete forceDeopt.deopt;
251    }
252
253    %DeoptimizeFunction(outer);
254    %DeoptimizeFunction(middle);
255    %DeoptimizeFunction(inner);
256    %ClearFunctionTypeFeedback(outer);
257    %ClearFunctionTypeFeedback(middle);
258    %ClearFunctionTypeFeedback(inner);
259  }
260
261  for (var a = 1; a <= 3; a++) {
262    for (var b = 1; b <= 3; b++) {
263      for (var c = 1; c <= 3; c++) {
264        test(a,b,c);
265      }
266    }
267  }
268})();
269
270
271// Test materialization of arguments object with values in registers.
272(function () {
273  "use strict";
274  var forceDeopt = { deopt:false };
275  function inner(a,b,c,d,e,f,g,h,i,j) {
276    var args = arguments;
277    forceDeopt.deopt;
278    assertSame(10, args.length);
279    assertSame(a, args[0]);
280    assertSame(b, args[1]);
281    assertSame(c, args[2]);
282    assertSame(d, args[3]);
283    assertSame(e, args[4]);
284    assertSame(f, args[5]);
285    assertSame(g, args[6]);
286    assertSame(h, args[7]);
287    assertSame(i, args[8]);
288    assertSame(j, args[9]);
289  }
290
291  var a = 0.5;
292  var b = 1.7;
293  var c = 123;
294  function outer() {
295    inner(
296      a - 0.3,  // double in double register
297      b + 2.3,  // integer in double register
298      c + 321,  // integer in general register
299      c - 456,  // integer in stack slot
300      a + 0.1, a + 0.2, a + 0.3, a + 0.4, a + 0.5,
301      a + 0.6   // double in stack slot
302    );
303  }
304
305  outer();
306  outer();
307  %OptimizeFunctionOnNextCall(outer);
308  outer();
309  delete forceDeopt.deopt;
310  outer();
311})();
312
313
314// Test inlining of functions with %_Arguments and %_ArgumentsLength intrinsic.
315(function () {
316  function inner(len,a,b,c) {
317    assertSame(len, %_ArgumentsLength());
318    for (var i = 1; i < len; ++i) {
319      var c = String.fromCharCode(96 + i);
320      assertSame(c, %_Arguments(i));
321    }
322  }
323
324  function outer() {
325    inner(1);
326    inner(2, 'a');
327    inner(3, 'a', 'b');
328    inner(4, 'a', 'b', 'c');
329    inner(5, 'a', 'b', 'c', 'd');
330    inner(6, 'a', 'b', 'c', 'd', 'e');
331  }
332
333  outer();
334  outer();
335  %OptimizeFunctionOnNextCall(outer);
336  outer();
337})();
338