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