OLD | NEW |
| (Empty) |
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/compilation-info.h" | |
6 #include "src/frames-inl.h" | |
7 #include "test/cctest/compiler/function-tester.h" | |
8 | |
9 namespace v8 { | |
10 namespace internal { | |
11 namespace compiler { | |
12 | |
13 namespace { | |
14 | |
15 // Helper to determine inline count via JavaScriptFrame::GetFunctions. | |
16 // Note that a count of 1 indicates that no inlining has occured. | |
17 void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
18 JavaScriptFrameIterator it(CcTest::i_isolate()); | |
19 int frames_seen = 0; | |
20 JavaScriptFrame* topmost = it.frame(); | |
21 while (!it.done()) { | |
22 JavaScriptFrame* frame = it.frame(); | |
23 List<JSFunction*> functions(2); | |
24 frame->GetFunctions(&functions); | |
25 PrintF("%d %s, inline count: %d\n", frames_seen, | |
26 frame->function()->shared()->DebugName()->ToCString().get(), | |
27 functions.length()); | |
28 frames_seen++; | |
29 it.Advance(); | |
30 } | |
31 List<JSFunction*> functions(2); | |
32 topmost->GetFunctions(&functions); | |
33 CHECK_EQ(args[0] | |
34 ->ToInt32(args.GetIsolate()->GetCurrentContext()) | |
35 .ToLocalChecked() | |
36 ->Value(), | |
37 functions.length()); | |
38 } | |
39 | |
40 | |
41 void InstallAssertInlineCountHelper(v8::Isolate* isolate) { | |
42 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
43 v8::Local<v8::FunctionTemplate> t = | |
44 v8::FunctionTemplate::New(isolate, AssertInlineCount); | |
45 CHECK(context->Global() | |
46 ->Set(context, v8_str("AssertInlineCount"), | |
47 t->GetFunction(context).ToLocalChecked()) | |
48 .FromJust()); | |
49 } | |
50 | |
51 const uint32_t kRestrictedInliningFlags = 0; | |
52 | |
53 const uint32_t kInlineFlags = CompilationInfo::kInliningEnabled; | |
54 | |
55 } // namespace | |
56 | |
57 | |
58 TEST(SimpleInlining) { | |
59 FunctionTester T( | |
60 "function foo(s) { AssertInlineCount(2); return s; };" | |
61 "function bar(s, t) { return foo(s); };" | |
62 "bar;", | |
63 kInlineFlags); | |
64 | |
65 InstallAssertInlineCountHelper(CcTest::isolate()); | |
66 T.CheckCall(T.Val(1), T.Val(1), T.Val(2)); | |
67 } | |
68 | |
69 | |
70 TEST(SimpleInliningDeopt) { | |
71 FunctionTester T( | |
72 "function foo(s) { %DeoptimizeFunction(bar); return s; };" | |
73 "function bar(s, t) { return foo(s); };" | |
74 "bar;", | |
75 kInlineFlags); | |
76 | |
77 InstallAssertInlineCountHelper(CcTest::isolate()); | |
78 T.CheckCall(T.Val(1), T.Val(1), T.Val(2)); | |
79 } | |
80 | |
81 | |
82 TEST(SimpleInliningDeoptSelf) { | |
83 FunctionTester T( | |
84 "function foo(s) { %_DeoptimizeNow(); return s; };" | |
85 "function bar(s, t) { return foo(s); };" | |
86 "bar;", | |
87 kInlineFlags); | |
88 | |
89 InstallAssertInlineCountHelper(CcTest::isolate()); | |
90 T.CheckCall(T.Val(1), T.Val(1), T.Val(2)); | |
91 } | |
92 | |
93 | |
94 TEST(SimpleInliningContext) { | |
95 FunctionTester T( | |
96 "function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };" | |
97 "function bar(s, t) { return foo(s); };" | |
98 "bar;", | |
99 kInlineFlags); | |
100 | |
101 InstallAssertInlineCountHelper(CcTest::isolate()); | |
102 T.CheckCall(T.Val(13), T.Val(1), T.Val(2)); | |
103 } | |
104 | |
105 | |
106 TEST(SimpleInliningContextDeopt) { | |
107 FunctionTester T( | |
108 "function foo(s) {" | |
109 " AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;" | |
110 " return s + x;" | |
111 "};" | |
112 "function bar(s, t) { return foo(s); };" | |
113 "bar;", | |
114 kInlineFlags); | |
115 | |
116 InstallAssertInlineCountHelper(CcTest::isolate()); | |
117 T.CheckCall(T.Val(13), T.Val(1), T.Val(2)); | |
118 } | |
119 | |
120 | |
121 TEST(CaptureContext) { | |
122 FunctionTester T( | |
123 "var f = (function () {" | |
124 " var x = 42;" | |
125 " function bar(s) { return x + s; };" | |
126 " return (function (s) { return bar(s); });" | |
127 "})();" | |
128 "(function (s) { return f(s) })", | |
129 kInlineFlags); | |
130 | |
131 InstallAssertInlineCountHelper(CcTest::isolate()); | |
132 T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined()); | |
133 } | |
134 | |
135 | |
136 // TODO(sigurds) For now we do not inline any native functions. If we do at | |
137 // some point, change this test. | |
138 TEST(DontInlineEval) { | |
139 FunctionTester T( | |
140 "var x = 42;" | |
141 "function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };" | |
142 "bar;", | |
143 kInlineFlags); | |
144 | |
145 InstallAssertInlineCountHelper(CcTest::isolate()); | |
146 T.CheckCall(T.Val(42), T.Val("x"), T.undefined()); | |
147 } | |
148 | |
149 | |
150 TEST(InlineOmitArguments) { | |
151 FunctionTester T( | |
152 "var x = 42;" | |
153 "function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };" | |
154 "function foo(s, t) { return bar(s); };" | |
155 "foo;", | |
156 kInlineFlags); | |
157 | |
158 InstallAssertInlineCountHelper(CcTest::isolate()); | |
159 T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined()); | |
160 } | |
161 | |
162 | |
163 TEST(InlineOmitArgumentsObject) { | |
164 FunctionTester T( | |
165 "function bar(s, t, u, v) { AssertInlineCount(2); return arguments; };" | |
166 "function foo(s, t) { var args = bar(s);" | |
167 " return args.length == 1 &&" | |
168 " args[0] == 11; };" | |
169 "foo;", | |
170 kInlineFlags); | |
171 | |
172 InstallAssertInlineCountHelper(CcTest::isolate()); | |
173 T.CheckCall(T.true_value(), T.Val(11), T.undefined()); | |
174 } | |
175 | |
176 | |
177 TEST(InlineOmitArgumentsDeopt) { | |
178 FunctionTester T( | |
179 "function foo(s,t,u,v) { AssertInlineCount(2);" | |
180 " %DeoptimizeFunction(bar); return baz(); };" | |
181 "function bar() { return foo(11); };" | |
182 "function baz() { return foo.arguments.length == 1 &&" | |
183 " foo.arguments[0] == 11; }" | |
184 "bar;", | |
185 kInlineFlags); | |
186 | |
187 InstallAssertInlineCountHelper(CcTest::isolate()); | |
188 T.CheckCall(T.true_value(), T.Val(12), T.Val(14)); | |
189 } | |
190 | |
191 | |
192 TEST(InlineSurplusArguments) { | |
193 FunctionTester T( | |
194 "var x = 42;" | |
195 "function foo(s) { AssertInlineCount(2); return x + s; };" | |
196 "function bar(s, t) { return foo(s, t, 13); };" | |
197 "bar;", | |
198 kInlineFlags); | |
199 | |
200 InstallAssertInlineCountHelper(CcTest::isolate()); | |
201 T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined()); | |
202 } | |
203 | |
204 | |
205 TEST(InlineSurplusArgumentsObject) { | |
206 FunctionTester T( | |
207 "function foo(s) { AssertInlineCount(2); return arguments; };" | |
208 "function bar(s, t) { var args = foo(s, t, 13);" | |
209 " return args.length == 3 &&" | |
210 " args[0] == 11 &&" | |
211 " args[1] == 12 &&" | |
212 " args[2] == 13; };" | |
213 "bar;", | |
214 kInlineFlags); | |
215 | |
216 InstallAssertInlineCountHelper(CcTest::isolate()); | |
217 T.CheckCall(T.true_value(), T.Val(11), T.Val(12)); | |
218 } | |
219 | |
220 | |
221 TEST(InlineSurplusArgumentsDeopt) { | |
222 FunctionTester T( | |
223 "function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar);" | |
224 " return baz(); };" | |
225 "function bar() { return foo(13, 14, 15); };" | |
226 "function baz() { return foo.arguments.length == 3 &&" | |
227 " foo.arguments[0] == 13 &&" | |
228 " foo.arguments[1] == 14 &&" | |
229 " foo.arguments[2] == 15; }" | |
230 "bar;", | |
231 kInlineFlags); | |
232 | |
233 InstallAssertInlineCountHelper(CcTest::isolate()); | |
234 T.CheckCall(T.true_value(), T.Val(12), T.Val(14)); | |
235 } | |
236 | |
237 | |
238 TEST(InlineTwice) { | |
239 FunctionTester T( | |
240 "var x = 42;" | |
241 "function bar(s) { AssertInlineCount(2); return x + s; };" | |
242 "function foo(s, t) { return bar(s) + bar(t); };" | |
243 "foo;", | |
244 kInlineFlags); | |
245 | |
246 InstallAssertInlineCountHelper(CcTest::isolate()); | |
247 T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4)); | |
248 } | |
249 | |
250 | |
251 TEST(InlineTwiceDependent) { | |
252 FunctionTester T( | |
253 "var x = 42;" | |
254 "function foo(s) { AssertInlineCount(2); return x + s; };" | |
255 "function bar(s,t) { return foo(foo(s)); };" | |
256 "bar;", | |
257 kInlineFlags); | |
258 | |
259 InstallAssertInlineCountHelper(CcTest::isolate()); | |
260 T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4)); | |
261 } | |
262 | |
263 | |
264 TEST(InlineTwiceDependentDiamond) { | |
265 FunctionTester T( | |
266 "var x = 41;" | |
267 "function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {" | |
268 " return x - s } else { return x + s; } };" | |
269 "function bar(s,t) { return foo(foo(s)); };" | |
270 "bar;", | |
271 kInlineFlags); | |
272 | |
273 InstallAssertInlineCountHelper(CcTest::isolate()); | |
274 T.CheckCall(T.Val(-11), T.Val(11), T.Val(4)); | |
275 } | |
276 | |
277 | |
278 TEST(InlineTwiceDependentDiamondDifferent) { | |
279 FunctionTester T( | |
280 "var x = 41;" | |
281 "function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {" | |
282 " return x - s * t } else { return x + s * t; } };" | |
283 "function bar(s,t) { return foo(foo(s, 3), 5); };" | |
284 "bar;", | |
285 kInlineFlags); | |
286 | |
287 InstallAssertInlineCountHelper(CcTest::isolate()); | |
288 T.CheckCall(T.Val(-329), T.Val(11), T.Val(4)); | |
289 } | |
290 | |
291 | |
292 TEST(InlineLoopGuardedEmpty) { | |
293 FunctionTester T( | |
294 "function foo(s) { AssertInlineCount(2); if (s) while (s); return s; };" | |
295 "function bar(s,t) { return foo(s); };" | |
296 "bar;", | |
297 kInlineFlags); | |
298 | |
299 InstallAssertInlineCountHelper(CcTest::isolate()); | |
300 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4)); | |
301 } | |
302 | |
303 | |
304 TEST(InlineLoopGuardedOnce) { | |
305 FunctionTester T( | |
306 "function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {" | |
307 " s = s - 1; }; return s; };" | |
308 "function bar(s,t) { return foo(s,t); };" | |
309 "bar;", | |
310 kInlineFlags); | |
311 | |
312 InstallAssertInlineCountHelper(CcTest::isolate()); | |
313 T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4)); | |
314 } | |
315 | |
316 | |
317 TEST(InlineLoopGuardedTwice) { | |
318 FunctionTester T( | |
319 "function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {" | |
320 " s = s - 1; }; return s; };" | |
321 "function bar(s,t) { return foo(foo(s,t),t); };" | |
322 "bar;", | |
323 kInlineFlags); | |
324 | |
325 InstallAssertInlineCountHelper(CcTest::isolate()); | |
326 T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4)); | |
327 } | |
328 | |
329 | |
330 TEST(InlineLoopUnguardedEmpty) { | |
331 FunctionTester T( | |
332 "function foo(s) { AssertInlineCount(2); while (s); return s; };" | |
333 "function bar(s, t) { return foo(s); };" | |
334 "bar;", | |
335 kInlineFlags); | |
336 | |
337 InstallAssertInlineCountHelper(CcTest::isolate()); | |
338 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4)); | |
339 } | |
340 | |
341 | |
342 TEST(InlineLoopUnguardedOnce) { | |
343 FunctionTester T( | |
344 "function foo(s) { AssertInlineCount(2); while (s) {" | |
345 " s = s - 1; }; return s; };" | |
346 "function bar(s, t) { return foo(s); };" | |
347 "bar;", | |
348 kInlineFlags); | |
349 | |
350 InstallAssertInlineCountHelper(CcTest::isolate()); | |
351 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4)); | |
352 } | |
353 | |
354 | |
355 TEST(InlineLoopUnguardedTwice) { | |
356 FunctionTester T( | |
357 "function foo(s) { AssertInlineCount(2); while (s > 0) {" | |
358 " s = s - 1; }; return s; };" | |
359 "function bar(s,t) { return foo(foo(s,t),t); };" | |
360 "bar;", | |
361 kInlineFlags); | |
362 | |
363 InstallAssertInlineCountHelper(CcTest::isolate()); | |
364 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4)); | |
365 } | |
366 | |
367 | |
368 TEST(InlineStrictIntoNonStrict) { | |
369 FunctionTester T( | |
370 "var x = Object.create({}, { y: { value:42, writable:false } });" | |
371 "function foo(s) { 'use strict';" | |
372 " x.y = 9; };" | |
373 "function bar(s,t) { return foo(s); };" | |
374 "bar;", | |
375 kInlineFlags); | |
376 | |
377 InstallAssertInlineCountHelper(CcTest::isolate()); | |
378 T.CheckThrows(T.undefined(), T.undefined()); | |
379 } | |
380 | |
381 | |
382 TEST(InlineNonStrictIntoStrict) { | |
383 FunctionTester T( | |
384 "var x = Object.create({}, { y: { value:42, writable:false } });" | |
385 "function foo(s) { x.y = 9; return x.y; };" | |
386 "function bar(s,t) { \'use strict\'; return foo(s); };" | |
387 "bar;", | |
388 kInlineFlags); | |
389 | |
390 InstallAssertInlineCountHelper(CcTest::isolate()); | |
391 T.CheckCall(T.Val(42), T.undefined(), T.undefined()); | |
392 } | |
393 | |
394 | |
395 TEST(InlineWithArguments) { | |
396 FunctionTester T( | |
397 "function foo(s,t,u) { AssertInlineCount(2);" | |
398 " return foo.arguments.length == 3 &&" | |
399 " foo.arguments[0] == 13 &&" | |
400 " foo.arguments[1] == 14 &&" | |
401 " foo.arguments[2] == 15;" | |
402 "}" | |
403 "function bar() { return foo(13, 14, 15); };" | |
404 "bar;", | |
405 kInlineFlags); | |
406 | |
407 InstallAssertInlineCountHelper(CcTest::isolate()); | |
408 T.CheckCall(T.true_value(), T.Val(12), T.Val(14)); | |
409 } | |
410 | |
411 | |
412 TEST(InlineBuiltin) { | |
413 FunctionTester T( | |
414 "function foo(s,t,u) { AssertInlineCount(2); return true; }" | |
415 "function bar() { return foo(); };" | |
416 "%SetForceInlineFlag(foo);" | |
417 "bar;", | |
418 kRestrictedInliningFlags); | |
419 | |
420 InstallAssertInlineCountHelper(CcTest::isolate()); | |
421 T.CheckCall(T.true_value()); | |
422 } | |
423 | |
424 | |
425 TEST(InlineNestedBuiltin) { | |
426 FunctionTester T( | |
427 "function foo(s,t,u) { AssertInlineCount(3); return true; }" | |
428 "function baz(s,t,u) { return foo(s,t,u); }" | |
429 "function bar() { return baz(); };" | |
430 "%SetForceInlineFlag(foo);" | |
431 "%SetForceInlineFlag(baz);" | |
432 "bar;", | |
433 kRestrictedInliningFlags); | |
434 | |
435 InstallAssertInlineCountHelper(CcTest::isolate()); | |
436 T.CheckCall(T.true_value()); | |
437 } | |
438 | |
439 | |
440 TEST(InlineSelfRecursive) { | |
441 FunctionTester T( | |
442 "function foo(x) { " | |
443 " AssertInlineCount(1);" | |
444 " if (x == 1) return foo(12);" | |
445 " return x;" | |
446 "}" | |
447 "foo;", | |
448 kInlineFlags); | |
449 | |
450 InstallAssertInlineCountHelper(CcTest::isolate()); | |
451 T.CheckCall(T.Val(12), T.Val(1)); | |
452 } | |
453 | |
454 | |
455 TEST(InlineMutuallyRecursive) { | |
456 FunctionTester T( | |
457 "function bar(x) { AssertInlineCount(2); return foo(x); }" | |
458 "function foo(x) { " | |
459 " if (x == 1) return bar(42);" | |
460 " return x;" | |
461 "}" | |
462 "foo;", | |
463 kInlineFlags); | |
464 | |
465 InstallAssertInlineCountHelper(CcTest::isolate()); | |
466 T.CheckCall(T.Val(42), T.Val(1)); | |
467 } | |
468 | |
469 } // namespace compiler | |
470 } // namespace internal | |
471 } // namespace v8 | |
OLD | NEW |