1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/v8.h"
6
7#include "test/cctest/compiler/function-tester.h"
8
9#if V8_TURBOFAN_TARGET
10
11using namespace v8::internal;
12using namespace v8::internal::compiler;
13
14// Helper to determine inline count via JavaScriptFrame::GetInlineCount.
15// Note that a count of 1 indicates that no inlining has occured.
16static void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
17  StackTraceFrameIterator it(CcTest::i_isolate());
18  int frames_seen = 0;
19  JavaScriptFrame* topmost = it.frame();
20  while (!it.done()) {
21    JavaScriptFrame* frame = it.frame();
22    PrintF("%d %s, inline count: %d\n", frames_seen,
23           frame->function()->shared()->DebugName()->ToCString().get(),
24           frame->GetInlineCount());
25    frames_seen++;
26    it.Advance();
27  }
28  CHECK_EQ(args[0]->ToInt32()->Value(), topmost->GetInlineCount());
29}
30
31
32static void InstallAssertInlineCountHelper(v8::Isolate* isolate) {
33  v8::Local<v8::Context> context = isolate->GetCurrentContext();
34  v8::Local<v8::FunctionTemplate> t =
35      v8::FunctionTemplate::New(isolate, AssertInlineCount);
36  context->Global()->Set(v8_str("AssertInlineCount"), t->GetFunction());
37}
38
39
40TEST(SimpleInlining) {
41  FLAG_turbo_deoptimization = true;
42  FunctionTester T(
43      "(function(){"
44      "function foo(s) { AssertInlineCount(2); return s; };"
45      "function bar(s, t) { return foo(s); };"
46      "return bar;})();",
47      CompilationInfo::kInliningEnabled |
48          CompilationInfo::kContextSpecializing |
49          CompilationInfo::kTypingEnabled);
50
51  InstallAssertInlineCountHelper(CcTest::isolate());
52  T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
53}
54
55
56TEST(SimpleInliningDeopt) {
57  FLAG_turbo_deoptimization = true;
58  FunctionTester T(
59      "(function(){"
60      "function foo(s) { %DeoptimizeFunction(bar); return "
61      "s; };"
62      "function bar(s, t) { return foo(s); };"
63      "return bar;})();",
64      CompilationInfo::kInliningEnabled |
65          CompilationInfo::kContextSpecializing |
66          CompilationInfo::kTypingEnabled);
67
68  InstallAssertInlineCountHelper(CcTest::isolate());
69  T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
70}
71
72
73TEST(SimpleInliningContext) {
74  FLAG_turbo_deoptimization = true;
75  FunctionTester T(
76      "(function () {"
77      "function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
78      "function bar(s, t) { return foo(s); };"
79      "return bar;"
80      "})();",
81      CompilationInfo::kInliningEnabled |
82          CompilationInfo::kContextSpecializing |
83          CompilationInfo::kTypingEnabled);
84
85  InstallAssertInlineCountHelper(CcTest::isolate());
86  T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
87}
88
89
90TEST(SimpleInliningContextDeopt) {
91  FLAG_turbo_deoptimization = true;
92  FunctionTester T(
93      "(function () {"
94      "function foo(s) { "
95      "  AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
96      "  return s + x;"
97      "};"
98      "function bar(s, t) { return foo(s); };"
99      "return bar;"
100      "})();",
101      CompilationInfo::kInliningEnabled |
102          CompilationInfo::kContextSpecializing |
103          CompilationInfo::kTypingEnabled);
104
105  InstallAssertInlineCountHelper(CcTest::isolate());
106  T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
107}
108
109
110TEST(CaptureContext) {
111  FLAG_turbo_deoptimization = true;
112  FunctionTester T(
113      "var f = (function () {"
114      "var x = 42;"
115      "function bar(s) { return x + s; };"
116      "return (function (s) { return bar(s); });"
117      "})();"
118      "(function (s) { return f(s)})",
119      CompilationInfo::kInliningEnabled |
120          CompilationInfo::kContextSpecializing |
121          CompilationInfo::kTypingEnabled);
122
123  InstallAssertInlineCountHelper(CcTest::isolate());
124  T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
125}
126
127
128// TODO(sigurds) For now we do not inline any native functions. If we do at
129// some point, change this test.
130TEST(DontInlineEval) {
131  FLAG_turbo_deoptimization = true;
132  FunctionTester T(
133      "var x = 42;"
134      "(function () {"
135      "function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
136      "return bar;"
137      "})();",
138      CompilationInfo::kInliningEnabled |
139          CompilationInfo::kContextSpecializing |
140          CompilationInfo::kTypingEnabled);
141
142  InstallAssertInlineCountHelper(CcTest::isolate());
143  T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
144}
145
146
147TEST(InlineOmitArguments) {
148  FLAG_turbo_deoptimization = true;
149  FunctionTester T(
150      "(function () {"
151      "var x = 42;"
152      "function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
153      "return (function (s,t) { return bar(s); });"
154      "})();",
155      CompilationInfo::kInliningEnabled |
156          CompilationInfo::kContextSpecializing |
157          CompilationInfo::kTypingEnabled);
158
159  InstallAssertInlineCountHelper(CcTest::isolate());
160  T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
161}
162
163
164TEST(InlineOmitArgumentsDeopt) {
165  FLAG_turbo_deoptimization = true;
166  FunctionTester T(
167      "(function () {"
168      "function foo(s,t,u,v) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
169      "return baz(); };"
170      "function bar() { return foo(11); };"
171      "function baz() { return foo.arguments.length == 1 && "
172      "                        foo.arguments[0] == 11 ; }"
173      "return bar;"
174      "})();",
175      CompilationInfo::kInliningEnabled |
176          CompilationInfo::kContextSpecializing |
177          CompilationInfo::kTypingEnabled);
178
179  InstallAssertInlineCountHelper(CcTest::isolate());
180  T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
181}
182
183
184TEST(InlineSurplusArguments) {
185  FLAG_turbo_deoptimization = true;
186  FunctionTester T(
187      "(function () {"
188      "var x = 42;"
189      "function foo(s) { AssertInlineCount(2); return x + s; };"
190      "function bar(s,t) { return foo(s,t,13); };"
191      "return bar;"
192      "})();",
193      CompilationInfo::kInliningEnabled |
194          CompilationInfo::kContextSpecializing |
195          CompilationInfo::kTypingEnabled);
196
197  InstallAssertInlineCountHelper(CcTest::isolate());
198  T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
199}
200
201
202TEST(InlineSurplusArgumentsDeopt) {
203  FLAG_turbo_deoptimization = true;
204  FunctionTester T(
205      "(function () {"
206      "function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
207      "return baz(); };"
208      "function bar() { return foo(13, 14, 15); };"
209      "function baz() { return foo.arguments.length == 3 && "
210      "                        foo.arguments[0] == 13 && "
211      "                        foo.arguments[1] == 14 && "
212      "                        foo.arguments[2] == 15; }"
213      "return bar;"
214      "})();",
215      CompilationInfo::kInliningEnabled |
216          CompilationInfo::kContextSpecializing |
217          CompilationInfo::kTypingEnabled);
218
219  InstallAssertInlineCountHelper(CcTest::isolate());
220  T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
221}
222
223
224TEST(InlineTwice) {
225  FLAG_turbo_deoptimization = true;
226  FunctionTester T(
227      "(function () {"
228      "var x = 42;"
229      "function bar(s) { AssertInlineCount(2); return x + s; };"
230      "return (function (s,t) { return bar(s) + bar(t); });"
231      "})();",
232      CompilationInfo::kInliningEnabled |
233          CompilationInfo::kContextSpecializing |
234          CompilationInfo::kTypingEnabled);
235
236  InstallAssertInlineCountHelper(CcTest::isolate());
237  T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4));
238}
239
240
241TEST(InlineTwiceDependent) {
242  FLAG_turbo_deoptimization = true;
243  FunctionTester T(
244      "(function () {"
245      "var x = 42;"
246      "function foo(s) { AssertInlineCount(2); return x + s; };"
247      "function bar(s,t) { return foo(foo(s)); };"
248      "return bar;"
249      "})();",
250      CompilationInfo::kInliningEnabled |
251          CompilationInfo::kContextSpecializing |
252          CompilationInfo::kTypingEnabled);
253
254  InstallAssertInlineCountHelper(CcTest::isolate());
255  T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4));
256}
257
258
259TEST(InlineTwiceDependentDiamond) {
260  FLAG_turbo_deoptimization = true;
261  FunctionTester T(
262      "(function () {"
263      "var x = 41;"
264      "function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
265      "                  return x - s } else { return x + s; } };"
266      "function bar(s,t) { return foo(foo(s)); };"
267      "return bar;"
268      "})();",
269      CompilationInfo::kInliningEnabled |
270          CompilationInfo::kContextSpecializing |
271          CompilationInfo::kTypingEnabled);
272
273  InstallAssertInlineCountHelper(CcTest::isolate());
274  T.CheckCall(T.Val(-11), T.Val(11), T.Val(4));
275}
276
277
278TEST(InlineTwiceDependentDiamondDifferent) {
279  FLAG_turbo_deoptimization = true;
280  FunctionTester T(
281      "(function () {"
282      "var x = 41;"
283      "function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
284      "                    return x - s * t } else { return x + s * t; } };"
285      "function bar(s,t) { return foo(foo(s, 3), 5); };"
286      "return bar;"
287      "})();",
288      CompilationInfo::kInliningEnabled |
289          CompilationInfo::kContextSpecializing |
290          CompilationInfo::kTypingEnabled);
291
292  InstallAssertInlineCountHelper(CcTest::isolate());
293  T.CheckCall(T.Val(-329), T.Val(11), T.Val(4));
294}
295
296
297TEST(InlineLoop) {
298  FLAG_turbo_deoptimization = true;
299  FunctionTester T(
300      "(function () {"
301      "var x = 41;"
302      "function foo(s) { AssertInlineCount(2); while (s > 0) {"
303      "                  s = s - 1; }; return s; };"
304      "function bar(s,t) { return foo(foo(s)); };"
305      "return bar;"
306      "})();",
307      CompilationInfo::kInliningEnabled |
308          CompilationInfo::kContextSpecializing |
309          CompilationInfo::kTypingEnabled);
310
311  InstallAssertInlineCountHelper(CcTest::isolate());
312  T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
313}
314
315
316TEST(InlineStrictIntoNonStrict) {
317  FLAG_turbo_deoptimization = true;
318  FunctionTester T(
319      "(function () {"
320      "var x = Object.create({}, { y: { value:42, writable:false } });"
321      "function foo(s) { 'use strict';"
322      "                   x.y = 9; };"
323      "function bar(s,t) { return foo(s); };"
324      "return bar;"
325      "})();",
326      CompilationInfo::kInliningEnabled |
327          CompilationInfo::kContextSpecializing |
328          CompilationInfo::kTypingEnabled);
329
330  InstallAssertInlineCountHelper(CcTest::isolate());
331  T.CheckThrows(T.undefined(), T.undefined());
332}
333
334
335TEST(InlineNonStrictIntoStrict) {
336  FLAG_turbo_deoptimization = true;
337  FunctionTester T(
338      "(function () {"
339      "var x = Object.create({}, { y: { value:42, writable:false } });"
340      "function foo(s) { x.y = 9; return x.y; };"
341      "function bar(s,t) { \'use strict\'; return foo(s); };"
342      "return bar;"
343      "})();",
344      CompilationInfo::kInliningEnabled |
345          CompilationInfo::kContextSpecializing |
346          CompilationInfo::kTypingEnabled);
347
348  InstallAssertInlineCountHelper(CcTest::isolate());
349  T.CheckCall(T.Val(42), T.undefined(), T.undefined());
350}
351
352
353#endif  // V8_TURBOFAN_TARGET
354