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