LCOV - code coverage report
Current view: top level - test/cctest - test-deoptimization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 256 256 100.0 %
Date: 2019-04-17 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.10