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