Line data Source code
1 : // Copyright 2012 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 : #include <stdlib.h>
29 :
30 : #include "src/v8.h"
31 :
32 : #include "src/api.h"
33 : #include "src/base/platform/platform.h"
34 : #include "src/compilation-cache.h"
35 : #include "src/debug/debug.h"
36 : #include "src/deoptimizer.h"
37 : #include "src/isolate.h"
38 : #include "src/objects-inl.h"
39 : #include "test/cctest/cctest.h"
40 :
41 : using ::v8::base::OS;
42 : using ::v8::internal::Deoptimizer;
43 : using ::v8::internal::EmbeddedVector;
44 : using ::v8::internal::Handle;
45 : using ::v8::internal::Isolate;
46 : using ::v8::internal::JSFunction;
47 : using ::v8::internal::Object;
48 :
49 : // Size of temp buffer for formatting small strings.
50 : #define SMALL_STRING_BUFFER_SIZE 80
51 :
52 : // Utility class to set the following runtime flags when constructed and return
53 : // to their default state when destroyed:
54 : // --allow-natives-syntax --always-opt --noturbo-inlining
55 : class AlwaysOptimizeAllowNativesSyntaxNoInlining {
56 : public:
57 : AlwaysOptimizeAllowNativesSyntaxNoInlining()
58 : : always_opt_(i::FLAG_always_opt),
59 : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
60 60 : turbo_inlining_(i::FLAG_turbo_inlining) {
61 60 : i::FLAG_always_opt = true;
62 60 : i::FLAG_allow_natives_syntax = true;
63 60 : i::FLAG_turbo_inlining = false;
64 : }
65 :
66 : ~AlwaysOptimizeAllowNativesSyntaxNoInlining() {
67 60 : i::FLAG_always_opt = always_opt_;
68 60 : i::FLAG_allow_natives_syntax = allow_natives_syntax_;
69 60 : i::FLAG_turbo_inlining = turbo_inlining_;
70 : }
71 :
72 : private:
73 : bool always_opt_;
74 : bool allow_natives_syntax_;
75 : bool turbo_inlining_;
76 : };
77 :
78 : // Utility class to set the following runtime flags when constructed and return
79 : // to their default state when destroyed:
80 : // --allow-natives-syntax --noturbo-inlining
81 : class AllowNativesSyntaxNoInlining {
82 : public:
83 : AllowNativesSyntaxNoInlining()
84 : : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
85 54 : turbo_inlining_(i::FLAG_turbo_inlining) {
86 54 : i::FLAG_allow_natives_syntax = true;
87 54 : i::FLAG_turbo_inlining = false;
88 : }
89 :
90 : ~AllowNativesSyntaxNoInlining() {
91 54 : i::FLAG_allow_natives_syntax = allow_natives_syntax_;
92 54 : i::FLAG_turbo_inlining = turbo_inlining_;
93 : }
94 :
95 : private:
96 : bool allow_natives_syntax_;
97 : bool turbo_inlining_;
98 : };
99 :
100 :
101 : // Abort any ongoing incremental marking to make sure that all weak global
102 : // handle callbacks are processed.
103 : static void NonIncrementalGC(i::Isolate* isolate) {
104 : isolate->heap()->CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask,
105 114 : i::GarbageCollectionReason::kTesting);
106 : }
107 :
108 :
109 195 : static Handle<JSFunction> GetJSFunction(v8::Local<v8::Context> context,
110 : const char* property_name) {
111 : v8::Local<v8::Function> fun = v8::Local<v8::Function>::Cast(
112 780 : context->Global()->Get(context, v8_str(property_name)).ToLocalChecked());
113 195 : return i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
114 : }
115 :
116 :
117 23724 : TEST(DeoptimizeSimple) {
118 : ManualGCScope manual_gc_scope;
119 12 : LocalContext env;
120 12 : v8::HandleScope scope(env->GetIsolate());
121 :
122 : // Test lazy deoptimization of a simple function.
123 : {
124 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
125 : CompileRun(
126 : "var count = 0;"
127 : "function h() { %DeoptimizeFunction(f); }"
128 : "function g() { count++; h(); }"
129 : "function f() { g(); };"
130 : "f();");
131 : }
132 : NonIncrementalGC(CcTest::i_isolate());
133 :
134 36 : CHECK_EQ(1, env->Global()
135 : ->Get(env.local(), v8_str("count"))
136 : .ToLocalChecked()
137 : ->Int32Value(env.local())
138 : .FromJust());
139 12 : CHECK(!GetJSFunction(env.local(), "f")->IsOptimized());
140 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
141 :
142 : // Test lazy deoptimization of a simple function. Call the function after the
143 : // deoptimization while it is still activated further down the stack.
144 : {
145 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
146 : CompileRun(
147 : "var count = 0;"
148 : "function g() { count++; %DeoptimizeFunction(f); f(false); }"
149 : "function f(x) { if (x) { g(); } else { return } };"
150 : "f(true);");
151 : }
152 : NonIncrementalGC(CcTest::i_isolate());
153 :
154 36 : CHECK_EQ(1, env->Global()
155 : ->Get(env.local(), v8_str("count"))
156 : .ToLocalChecked()
157 : ->Int32Value(env.local())
158 : .FromJust());
159 12 : CHECK(!GetJSFunction(env.local(), "f")->IsOptimized());
160 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
161 6 : }
162 :
163 :
164 23724 : TEST(DeoptimizeSimpleWithArguments) {
165 : ManualGCScope manual_gc_scope;
166 12 : LocalContext env;
167 12 : v8::HandleScope scope(env->GetIsolate());
168 :
169 : // Test lazy deoptimization of a simple function with some arguments.
170 : {
171 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
172 : CompileRun(
173 : "var count = 0;"
174 : "function h(x) { %DeoptimizeFunction(f); }"
175 : "function g(x, y) { count++; h(x); }"
176 : "function f(x, y, z) { g(1,x); y+z; };"
177 : "f(1, \"2\", false);");
178 : }
179 : NonIncrementalGC(CcTest::i_isolate());
180 :
181 36 : CHECK_EQ(1, env->Global()
182 : ->Get(env.local(), v8_str("count"))
183 : .ToLocalChecked()
184 : ->Int32Value(env.local())
185 : .FromJust());
186 12 : CHECK(!GetJSFunction(env.local(), "f")->IsOptimized());
187 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
188 :
189 : // Test lazy deoptimization of a simple function with some arguments. Call the
190 : // function after the deoptimization while it is still activated further down
191 : // the stack.
192 : {
193 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
194 : CompileRun(
195 : "var count = 0;"
196 : "function g(x, y) { count++; %DeoptimizeFunction(f); f(false, 1, y); }"
197 : "function f(x, y, z) { if (x) { g(x, y); } else { return y + z; } };"
198 : "f(true, 1, \"2\");");
199 : }
200 : NonIncrementalGC(CcTest::i_isolate());
201 :
202 36 : CHECK_EQ(1, env->Global()
203 : ->Get(env.local(), v8_str("count"))
204 : .ToLocalChecked()
205 : ->Int32Value(env.local())
206 : .FromJust());
207 12 : CHECK(!GetJSFunction(env.local(), "f")->IsOptimized());
208 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
209 6 : }
210 :
211 :
212 23724 : TEST(DeoptimizeSimpleNested) {
213 : ManualGCScope manual_gc_scope;
214 12 : LocalContext env;
215 12 : v8::HandleScope scope(env->GetIsolate());
216 :
217 : // Test lazy deoptimization of a simple function. Have a nested function call
218 : // do the deoptimization.
219 : {
220 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
221 : CompileRun(
222 : "var count = 0;"
223 : "var result = 0;"
224 : "function h(x, y, z) { return x + y + z; }"
225 : "function g(z) { count++; %DeoptimizeFunction(f); return z;}"
226 : "function f(x,y,z) { return h(x, y, g(z)); };"
227 : "result = f(1, 2, 3);");
228 : NonIncrementalGC(CcTest::i_isolate());
229 :
230 36 : CHECK_EQ(1, env->Global()
231 : ->Get(env.local(), v8_str("count"))
232 : .ToLocalChecked()
233 : ->Int32Value(env.local())
234 : .FromJust());
235 36 : CHECK_EQ(6, env->Global()
236 : ->Get(env.local(), v8_str("result"))
237 : .ToLocalChecked()
238 : ->Int32Value(env.local())
239 : .FromJust());
240 12 : CHECK(!GetJSFunction(env.local(), "f")->IsOptimized());
241 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
242 : }
243 6 : }
244 :
245 :
246 23724 : TEST(DeoptimizeRecursive) {
247 : ManualGCScope manual_gc_scope;
248 12 : LocalContext env;
249 12 : v8::HandleScope scope(env->GetIsolate());
250 :
251 : {
252 : // Test lazy deoptimization of a simple function called recursively. Call
253 : // the function recursively a number of times before deoptimizing it.
254 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
255 : CompileRun(
256 : "var count = 0;"
257 : "var calls = 0;"
258 : "function g() { count++; %DeoptimizeFunction(f); }"
259 : "function f(x) { calls++; if (x > 0) { f(x - 1); } else { g(); } };"
260 : "f(10);");
261 : }
262 : NonIncrementalGC(CcTest::i_isolate());
263 :
264 36 : CHECK_EQ(1, env->Global()
265 : ->Get(env.local(), v8_str("count"))
266 : .ToLocalChecked()
267 : ->Int32Value(env.local())
268 : .FromJust());
269 36 : CHECK_EQ(11, env->Global()
270 : ->Get(env.local(), v8_str("calls"))
271 : .ToLocalChecked()
272 : ->Int32Value(env.local())
273 : .FromJust());
274 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
275 :
276 : v8::Local<v8::Function> fun = v8::Local<v8::Function>::Cast(
277 : env->Global()
278 24 : ->Get(env.local(), v8_str(CcTest::isolate(), "f"))
279 6 : .ToLocalChecked());
280 6 : CHECK(!fun.IsEmpty());
281 6 : }
282 :
283 :
284 23724 : TEST(DeoptimizeMultiple) {
285 : ManualGCScope manual_gc_scope;
286 12 : LocalContext env;
287 12 : v8::HandleScope scope(env->GetIsolate());
288 :
289 : {
290 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
291 : CompileRun(
292 : "var count = 0;"
293 : "var result = 0;"
294 : "function g() { count++;"
295 : " %DeoptimizeFunction(f1);"
296 : " %DeoptimizeFunction(f2);"
297 : " %DeoptimizeFunction(f3);"
298 : " %DeoptimizeFunction(f4);}"
299 : "function f4(x) { g(); };"
300 : "function f3(x, y, z) { f4(); return x + y + z; };"
301 : "function f2(x, y) { return x + f3(y + 1, y + 1, y + 1) + y; };"
302 : "function f1(x) { return f2(x + 1, x + 1) + x; };"
303 : "result = f1(1);");
304 : }
305 : NonIncrementalGC(CcTest::i_isolate());
306 :
307 36 : CHECK_EQ(1, env->Global()
308 : ->Get(env.local(), v8_str("count"))
309 : .ToLocalChecked()
310 : ->Int32Value(env.local())
311 : .FromJust());
312 36 : CHECK_EQ(14, env->Global()
313 : ->Get(env.local(), v8_str("result"))
314 : .ToLocalChecked()
315 : ->Int32Value(env.local())
316 : .FromJust());
317 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
318 6 : }
319 :
320 :
321 23724 : TEST(DeoptimizeConstructor) {
322 : ManualGCScope manual_gc_scope;
323 12 : LocalContext env;
324 12 : v8::HandleScope scope(env->GetIsolate());
325 :
326 : {
327 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
328 : CompileRun(
329 : "var count = 0;"
330 : "function g() { count++;"
331 : " %DeoptimizeFunction(f); }"
332 : "function f() { g(); };"
333 : "result = new f() instanceof f;");
334 : }
335 : NonIncrementalGC(CcTest::i_isolate());
336 :
337 36 : CHECK_EQ(1, env->Global()
338 : ->Get(env.local(), v8_str("count"))
339 : .ToLocalChecked()
340 : ->Int32Value(env.local())
341 : .FromJust());
342 30 : CHECK(env->Global()
343 : ->Get(env.local(), v8_str("result"))
344 : .ToLocalChecked()
345 : ->IsTrue());
346 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
347 :
348 : {
349 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
350 : CompileRun(
351 : "var count = 0;"
352 : "var result = 0;"
353 : "function g() { count++;"
354 : " %DeoptimizeFunction(f); }"
355 : "function f(x, y) { this.x = x; g(); this.y = y; };"
356 : "result = new f(1, 2);"
357 : "result = result.x + result.y;");
358 : }
359 : NonIncrementalGC(CcTest::i_isolate());
360 :
361 36 : CHECK_EQ(1, env->Global()
362 : ->Get(env.local(), v8_str("count"))
363 : .ToLocalChecked()
364 : ->Int32Value(env.local())
365 : .FromJust());
366 36 : CHECK_EQ(3, env->Global()
367 : ->Get(env.local(), v8_str("result"))
368 : .ToLocalChecked()
369 : ->Int32Value(env.local())
370 : .FromJust());
371 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
372 6 : }
373 :
374 :
375 23724 : TEST(DeoptimizeConstructorMultiple) {
376 : ManualGCScope manual_gc_scope;
377 12 : LocalContext env;
378 12 : v8::HandleScope scope(env->GetIsolate());
379 :
380 : {
381 : AlwaysOptimizeAllowNativesSyntaxNoInlining options;
382 : CompileRun(
383 : "var count = 0;"
384 : "var result = 0;"
385 : "function g() { count++;"
386 : " %DeoptimizeFunction(f1);"
387 : " %DeoptimizeFunction(f2);"
388 : " %DeoptimizeFunction(f3);"
389 : " %DeoptimizeFunction(f4);}"
390 : "function f4(x) { this.result = x; g(); };"
391 : "function f3(x, y, z) { this.result = new f4(x + y + z).result; };"
392 : "function f2(x, y) {"
393 : " this.result = x + new f3(y + 1, y + 1, y + 1).result + y; };"
394 : "function f1(x) { this.result = new f2(x + 1, x + 1).result + x; };"
395 : "result = new f1(1).result;");
396 : }
397 : NonIncrementalGC(CcTest::i_isolate());
398 :
399 36 : CHECK_EQ(1, env->Global()
400 : ->Get(env.local(), v8_str("count"))
401 : .ToLocalChecked()
402 : ->Int32Value(env.local())
403 : .FromJust());
404 36 : CHECK_EQ(14, env->Global()
405 : ->Get(env.local(), v8_str("result"))
406 : .ToLocalChecked()
407 : ->Int32Value(env.local())
408 : .FromJust());
409 6 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(CcTest::i_isolate()));
410 6 : }
411 :
412 :
413 23724 : UNINITIALIZED_TEST(DeoptimizeBinaryOperationADDString) {
414 : ManualGCScope manual_gc_scope;
415 6 : i::FLAG_concurrent_recompilation = false;
416 : AllowNativesSyntaxNoInlining options;
417 : v8::Isolate::CreateParams create_params;
418 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
419 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
420 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
421 6 : isolate->Enter();
422 : {
423 : LocalContext env(isolate);
424 12 : v8::HandleScope scope(env->GetIsolate());
425 :
426 : const char* f_source = "function f(x, y) { return x + y; };";
427 :
428 : {
429 : // Compile function f and collect to type feedback to insert binary op
430 : // stub call in the optimized code.
431 6 : i::FLAG_prepare_always_opt = true;
432 : CompileRun(
433 : "var count = 0;"
434 : "var result = 0;"
435 : "var deopt = false;"
436 : "function X() { };"
437 : "X.prototype.toString = function () {"
438 : " if (deopt) { count++; %DeoptimizeFunction(f); } return 'an X'"
439 : "};");
440 : CompileRun(f_source);
441 : CompileRun(
442 : "for (var i = 0; i < 5; i++) {"
443 : " f('a+', new X());"
444 : "};");
445 :
446 : // Compile an optimized version of f.
447 6 : i::FLAG_always_opt = true;
448 : CompileRun(f_source);
449 : CompileRun("f('a+', new X());");
450 11 : CHECK(!i_isolate->use_optimizer() ||
451 : GetJSFunction(env.local(), "f")->IsOptimized());
452 :
453 : // Call f and force deoptimization while processing the binary operation.
454 : CompileRun(
455 : "deopt = true;"
456 : "var result = f('a+', new X());");
457 : }
458 : NonIncrementalGC(i_isolate);
459 :
460 12 : CHECK(!GetJSFunction(env.local(), "f")->IsOptimized());
461 36 : CHECK_EQ(1, env->Global()
462 : ->Get(env.local(), v8_str("count"))
463 : .ToLocalChecked()
464 : ->Int32Value(env.local())
465 : .FromJust());
466 : v8::Local<v8::Value> result =
467 30 : env->Global()->Get(env.local(), v8_str("result")).ToLocalChecked();
468 6 : CHECK(result->IsString());
469 12 : v8::String::Utf8Value utf8(isolate, result);
470 6 : CHECK_EQ(0, strcmp("a+an X", *utf8));
471 12 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate));
472 : }
473 6 : isolate->Exit();
474 6 : isolate->Dispose();
475 6 : }
476 :
477 :
478 30 : static void CompileConstructorWithDeoptimizingValueOf() {
479 : CompileRun("var count = 0;"
480 : "var result = 0;"
481 : "var deopt = false;"
482 : "function X() { };"
483 : "X.prototype.valueOf = function () {"
484 : " if (deopt) { count++; %DeoptimizeFunction(f); } return 8"
485 : "};");
486 30 : }
487 :
488 :
489 30 : static void TestDeoptimizeBinaryOpHelper(LocalContext* env,
490 : const char* binary_op) {
491 30 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>((*env)->GetIsolate());
492 : EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer;
493 : SNPrintF(f_source_buffer,
494 : "function f(x, y) { return x %s y; };",
495 30 : binary_op);
496 30 : char* f_source = f_source_buffer.start();
497 :
498 : AllowNativesSyntaxNoInlining options;
499 : // Compile function f and collect to type feedback to insert binary op stub
500 : // call in the optimized code.
501 30 : i::FLAG_prepare_always_opt = true;
502 30 : CompileConstructorWithDeoptimizingValueOf();
503 : CompileRun(f_source);
504 : CompileRun("for (var i = 0; i < 5; i++) {"
505 : " f(8, new X());"
506 : "};");
507 :
508 : // Compile an optimized version of f.
509 30 : i::FLAG_always_opt = true;
510 : CompileRun(f_source);
511 : CompileRun("f(7, new X());");
512 55 : CHECK(!i_isolate->use_optimizer() ||
513 : GetJSFunction((*env).local(), "f")->IsOptimized());
514 :
515 : // Call f and force deoptimization while processing the binary operation.
516 : CompileRun("deopt = true;"
517 : "var result = f(7, new X());");
518 : NonIncrementalGC(i_isolate);
519 60 : CHECK(!GetJSFunction((*env).local(), "f")->IsOptimized());
520 30 : }
521 :
522 :
523 23724 : UNINITIALIZED_TEST(DeoptimizeBinaryOperationADD) {
524 : ManualGCScope manual_gc_scope;
525 6 : i::FLAG_concurrent_recompilation = false;
526 : v8::Isolate::CreateParams create_params;
527 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
528 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
529 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
530 6 : isolate->Enter();
531 : {
532 : LocalContext env(isolate);
533 12 : v8::HandleScope scope(env->GetIsolate());
534 :
535 6 : TestDeoptimizeBinaryOpHelper(&env, "+");
536 :
537 36 : CHECK_EQ(1, env->Global()
538 : ->Get(env.local(), v8_str("count"))
539 : .ToLocalChecked()
540 : ->Int32Value(env.local())
541 : .FromJust());
542 36 : CHECK_EQ(15, env->Global()
543 : ->Get(env.local(), v8_str("result"))
544 : .ToLocalChecked()
545 : ->Int32Value(env.local())
546 : .FromJust());
547 12 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate));
548 : }
549 6 : isolate->Exit();
550 6 : isolate->Dispose();
551 6 : }
552 :
553 :
554 23724 : UNINITIALIZED_TEST(DeoptimizeBinaryOperationSUB) {
555 : ManualGCScope manual_gc_scope;
556 6 : i::FLAG_concurrent_recompilation = false;
557 : v8::Isolate::CreateParams create_params;
558 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
559 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
560 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
561 6 : isolate->Enter();
562 : {
563 : LocalContext env(isolate);
564 12 : v8::HandleScope scope(env->GetIsolate());
565 :
566 6 : TestDeoptimizeBinaryOpHelper(&env, "-");
567 :
568 36 : CHECK_EQ(1, env->Global()
569 : ->Get(env.local(), v8_str("count"))
570 : .ToLocalChecked()
571 : ->Int32Value(env.local())
572 : .FromJust());
573 36 : CHECK_EQ(-1, env->Global()
574 : ->Get(env.local(), v8_str("result"))
575 : .ToLocalChecked()
576 : ->Int32Value(env.local())
577 : .FromJust());
578 12 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate));
579 : }
580 6 : isolate->Exit();
581 6 : isolate->Dispose();
582 6 : }
583 :
584 :
585 23724 : UNINITIALIZED_TEST(DeoptimizeBinaryOperationMUL) {
586 : ManualGCScope manual_gc_scope;
587 6 : i::FLAG_concurrent_recompilation = false;
588 : v8::Isolate::CreateParams create_params;
589 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
590 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
591 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
592 6 : isolate->Enter();
593 : {
594 : LocalContext env(isolate);
595 12 : v8::HandleScope scope(env->GetIsolate());
596 :
597 6 : TestDeoptimizeBinaryOpHelper(&env, "*");
598 :
599 36 : CHECK_EQ(1, env->Global()
600 : ->Get(env.local(), v8_str("count"))
601 : .ToLocalChecked()
602 : ->Int32Value(env.local())
603 : .FromJust());
604 36 : CHECK_EQ(56, env->Global()
605 : ->Get(env.local(), v8_str("result"))
606 : .ToLocalChecked()
607 : ->Int32Value(env.local())
608 : .FromJust());
609 12 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate));
610 : }
611 6 : isolate->Exit();
612 6 : isolate->Dispose();
613 6 : }
614 :
615 :
616 23724 : UNINITIALIZED_TEST(DeoptimizeBinaryOperationDIV) {
617 : ManualGCScope manual_gc_scope;
618 6 : i::FLAG_concurrent_recompilation = false;
619 : v8::Isolate::CreateParams create_params;
620 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
621 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
622 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
623 6 : isolate->Enter();
624 : {
625 : LocalContext env(isolate);
626 12 : v8::HandleScope scope(env->GetIsolate());
627 :
628 6 : TestDeoptimizeBinaryOpHelper(&env, "/");
629 :
630 36 : CHECK_EQ(1, env->Global()
631 : ->Get(env.local(), v8_str("count"))
632 : .ToLocalChecked()
633 : ->Int32Value(env.local())
634 : .FromJust());
635 36 : CHECK_EQ(0, env->Global()
636 : ->Get(env.local(), v8_str("result"))
637 : .ToLocalChecked()
638 : ->Int32Value(env.local())
639 : .FromJust());
640 12 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate));
641 : }
642 6 : isolate->Exit();
643 6 : isolate->Dispose();
644 6 : }
645 :
646 :
647 23724 : UNINITIALIZED_TEST(DeoptimizeBinaryOperationMOD) {
648 : ManualGCScope manual_gc_scope;
649 6 : i::FLAG_concurrent_recompilation = false;
650 : v8::Isolate::CreateParams create_params;
651 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
652 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
653 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
654 6 : isolate->Enter();
655 : {
656 : LocalContext env(isolate);
657 12 : v8::HandleScope scope(env->GetIsolate());
658 :
659 6 : TestDeoptimizeBinaryOpHelper(&env, "%");
660 :
661 36 : CHECK_EQ(1, env->Global()
662 : ->Get(env.local(), v8_str("count"))
663 : .ToLocalChecked()
664 : ->Int32Value(env.local())
665 : .FromJust());
666 36 : CHECK_EQ(7, env->Global()
667 : ->Get(env.local(), v8_str("result"))
668 : .ToLocalChecked()
669 : ->Int32Value(env.local())
670 : .FromJust());
671 12 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate));
672 : }
673 6 : isolate->Exit();
674 6 : isolate->Dispose();
675 6 : }
676 :
677 :
678 23724 : UNINITIALIZED_TEST(DeoptimizeCompare) {
679 : ManualGCScope manual_gc_scope;
680 6 : i::FLAG_concurrent_recompilation = false;
681 : v8::Isolate::CreateParams create_params;
682 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
683 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
684 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
685 6 : isolate->Enter();
686 : {
687 : LocalContext env(isolate);
688 12 : v8::HandleScope scope(env->GetIsolate());
689 :
690 : const char* f_source = "function f(x, y) { return x < y; };";
691 :
692 : {
693 : AllowNativesSyntaxNoInlining options;
694 : // Compile function f and collect to type feedback to insert compare ic
695 : // call in the optimized code.
696 6 : i::FLAG_prepare_always_opt = true;
697 : CompileRun(
698 : "var count = 0;"
699 : "var result = 0;"
700 : "var deopt = false;"
701 : "function X() { };"
702 : "X.prototype.toString = function () {"
703 : " if (deopt) { count++; %DeoptimizeFunction(f); } return 'b'"
704 : "};");
705 : CompileRun(f_source);
706 : CompileRun(
707 : "for (var i = 0; i < 5; i++) {"
708 : " f('a', new X());"
709 : "};");
710 :
711 : // Compile an optimized version of f.
712 6 : i::FLAG_always_opt = true;
713 : CompileRun(f_source);
714 : CompileRun("f('a', new X());");
715 11 : CHECK(!i_isolate->use_optimizer() ||
716 : GetJSFunction(env.local(), "f")->IsOptimized());
717 :
718 : // Call f and force deoptimization while processing the comparison.
719 : CompileRun(
720 : "deopt = true;"
721 : "var result = f('a', new X());");
722 : }
723 : NonIncrementalGC(i_isolate);
724 :
725 12 : CHECK(!GetJSFunction(env.local(), "f")->IsOptimized());
726 36 : CHECK_EQ(1, env->Global()
727 : ->Get(env.local(), v8_str("count"))
728 : .ToLocalChecked()
729 : ->Int32Value(env.local())
730 : .FromJust());
731 36 : CHECK_EQ(true, env->Global()
732 : ->Get(env.local(), v8_str("result"))
733 : .ToLocalChecked()
734 : ->BooleanValue(env.local())
735 : .FromJust());
736 12 : CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount(i_isolate));
737 : }
738 6 : isolate->Exit();
739 6 : isolate->Dispose();
740 6 : }
741 :
742 :
743 23724 : UNINITIALIZED_TEST(DeoptimizeLoadICStoreIC) {
744 : ManualGCScope manual_gc_scope;
745 6 : i::FLAG_concurrent_recompilation = false;
746 : v8::Isolate::CreateParams create_params;
747 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
748 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
749 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
750 6 : isolate->Enter();
751 : {
752 : LocalContext env(isolate);
753 12 : v8::HandleScope scope(env->GetIsolate());
754 :
755 : // Functions to generate load/store/keyed load/keyed store IC calls.
756 : const char* f1_source = "function f1(x) { return x.y; };";
757 : const char* g1_source = "function g1(x) { x.y = 1; };";
758 : const char* f2_source = "function f2(x, y) { return x[y]; };";
759 : const char* g2_source = "function g2(x, y) { x[y] = 1; };";
760 :
761 : {
762 : AllowNativesSyntaxNoInlining options;
763 : // Compile functions and collect to type feedback to insert ic
764 : // calls in the optimized code.
765 6 : i::FLAG_prepare_always_opt = true;
766 : CompileRun(
767 : "var count = 0;"
768 : "var result = 0;"
769 : "var deopt = false;"
770 : "function X() { };"
771 : "X.prototype.__defineGetter__('y', function () {"
772 : " if (deopt) { count++; %DeoptimizeFunction(f1); };"
773 : " return 13;"
774 : "});"
775 : "X.prototype.__defineSetter__('y', function () {"
776 : " if (deopt) { count++; %DeoptimizeFunction(g1); };"
777 : "});"
778 : "X.prototype.__defineGetter__('z', function () {"
779 : " if (deopt) { count++; %DeoptimizeFunction(f2); };"
780 : " return 13;"
781 : "});"
782 : "X.prototype.__defineSetter__('z', function () {"
783 : " if (deopt) { count++; %DeoptimizeFunction(g2); };"
784 : "});");
785 : CompileRun(f1_source);
786 : CompileRun(g1_source);
787 : CompileRun(f2_source);
788 : CompileRun(g2_source);
789 : CompileRun(
790 : "for (var i = 0; i < 5; i++) {"
791 : " f1(new X());"
792 : " g1(new X());"
793 : " f2(new X(), 'z');"
794 : " g2(new X(), 'z');"
795 : "};");
796 :
797 : // Compile an optimized version of the functions.
798 6 : i::FLAG_always_opt = true;
799 : CompileRun(f1_source);
800 : CompileRun(g1_source);
801 : CompileRun(f2_source);
802 : CompileRun(g2_source);
803 : CompileRun("f1(new X());");
804 : CompileRun("g1(new X());");
805 : CompileRun("f2(new X(), 'z');");
806 : CompileRun("g2(new X(), 'z');");
807 6 : if (i_isolate->use_optimizer()) {
808 10 : CHECK(GetJSFunction(env.local(), "f1")->IsOptimized());
809 10 : CHECK(GetJSFunction(env.local(), "g1")->IsOptimized());
810 10 : CHECK(GetJSFunction(env.local(), "f2")->IsOptimized());
811 10 : CHECK(GetJSFunction(env.local(), "g2")->IsOptimized());
812 : }
813 :
814 : // Call functions and force deoptimization while processing the ics.
815 : CompileRun(
816 : "deopt = true;"
817 : "var result = f1(new X());"
818 : "g1(new X());"
819 : "f2(new X(), 'z');"
820 : "g2(new X(), 'z');");
821 : }
822 : NonIncrementalGC(i_isolate);
823 :
824 12 : CHECK(!GetJSFunction(env.local(), "f1")->IsOptimized());
825 12 : CHECK(!GetJSFunction(env.local(), "g1")->IsOptimized());
826 12 : CHECK(!GetJSFunction(env.local(), "f2")->IsOptimized());
827 12 : CHECK(!GetJSFunction(env.local(), "g2")->IsOptimized());
828 36 : CHECK_EQ(4, env->Global()
829 : ->Get(env.local(), v8_str("count"))
830 : .ToLocalChecked()
831 : ->Int32Value(env.local())
832 : .FromJust());
833 36 : CHECK_EQ(13, env->Global()
834 : ->Get(env.local(), v8_str("result"))
835 : .ToLocalChecked()
836 : ->Int32Value(env.local())
837 6 : .FromJust());
838 : }
839 6 : isolate->Exit();
840 6 : isolate->Dispose();
841 6 : }
842 :
843 :
844 23724 : UNINITIALIZED_TEST(DeoptimizeLoadICStoreICNested) {
845 : ManualGCScope manual_gc_scope;
846 6 : i::FLAG_concurrent_recompilation = false;
847 : v8::Isolate::CreateParams create_params;
848 6 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
849 6 : v8::Isolate* isolate = v8::Isolate::New(create_params);
850 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
851 6 : isolate->Enter();
852 : {
853 : LocalContext env(isolate);
854 12 : v8::HandleScope scope(env->GetIsolate());
855 :
856 : // Functions to generate load/store/keyed load/keyed store IC calls.
857 : const char* f1_source = "function f1(x) { return x.y; };";
858 : const char* g1_source = "function g1(x) { x.y = 1; };";
859 : const char* f2_source = "function f2(x, y) { return x[y]; };";
860 : const char* g2_source = "function g2(x, y) { x[y] = 1; };";
861 :
862 : {
863 : AllowNativesSyntaxNoInlining options;
864 : // Compile functions and collect to type feedback to insert ic
865 : // calls in the optimized code.
866 6 : i::FLAG_prepare_always_opt = true;
867 : CompileRun(
868 : "var count = 0;"
869 : "var result = 0;"
870 : "var deopt = false;"
871 : "function X() { };"
872 : "X.prototype.__defineGetter__('y', function () {"
873 : " g1(this);"
874 : " return 13;"
875 : "});"
876 : "X.prototype.__defineSetter__('y', function () {"
877 : " f2(this, 'z');"
878 : "});"
879 : "X.prototype.__defineGetter__('z', function () {"
880 : " g2(this, 'z');"
881 : "});"
882 : "X.prototype.__defineSetter__('z', function () {"
883 : " if (deopt) {"
884 : " count++;"
885 : " %DeoptimizeFunction(f1);"
886 : " %DeoptimizeFunction(g1);"
887 : " %DeoptimizeFunction(f2);"
888 : " %DeoptimizeFunction(g2); };"
889 : "});");
890 : CompileRun(f1_source);
891 : CompileRun(g1_source);
892 : CompileRun(f2_source);
893 : CompileRun(g2_source);
894 : CompileRun(
895 : "for (var i = 0; i < 5; i++) {"
896 : " f1(new X());"
897 : " g1(new X());"
898 : " f2(new X(), 'z');"
899 : " g2(new X(), 'z');"
900 : "};");
901 :
902 : // Compile an optimized version of the functions.
903 6 : i::FLAG_always_opt = true;
904 : CompileRun(f1_source);
905 : CompileRun(g1_source);
906 : CompileRun(f2_source);
907 : CompileRun(g2_source);
908 : CompileRun("f1(new X());");
909 : CompileRun("g1(new X());");
910 : CompileRun("f2(new X(), 'z');");
911 : CompileRun("g2(new X(), 'z');");
912 6 : if (i_isolate->use_optimizer()) {
913 10 : CHECK(GetJSFunction(env.local(), "f1")->IsOptimized());
914 10 : CHECK(GetJSFunction(env.local(), "g1")->IsOptimized());
915 10 : CHECK(GetJSFunction(env.local(), "f2")->IsOptimized());
916 10 : CHECK(GetJSFunction(env.local(), "g2")->IsOptimized());
917 : }
918 :
919 : // Call functions and force deoptimization while processing the ics.
920 : CompileRun(
921 : "deopt = true;"
922 : "var result = f1(new X());");
923 : }
924 : NonIncrementalGC(i_isolate);
925 :
926 12 : CHECK(!GetJSFunction(env.local(), "f1")->IsOptimized());
927 12 : CHECK(!GetJSFunction(env.local(), "g1")->IsOptimized());
928 12 : CHECK(!GetJSFunction(env.local(), "f2")->IsOptimized());
929 12 : CHECK(!GetJSFunction(env.local(), "g2")->IsOptimized());
930 36 : CHECK_EQ(1, env->Global()
931 : ->Get(env.local(), v8_str("count"))
932 : .ToLocalChecked()
933 : ->Int32Value(env.local())
934 : .FromJust());
935 36 : CHECK_EQ(13, env->Global()
936 : ->Get(env.local(), v8_str("result"))
937 : .ToLocalChecked()
938 : ->Int32Value(env.local())
939 6 : .FromJust());
940 : }
941 6 : isolate->Exit();
942 6 : isolate->Dispose();
943 71160 : }
|