LCOV - code coverage report
Current view: top level - test/cctest - test-deoptimization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 236 236 100.0 %
Date: 2017-10-20 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.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 : }

Generated by: LCOV version 1.10