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