Home | History | Annotate | Download | only in cctest
      1 // Copyright 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 // Tests of profiles generator and utilities.
     29 
     30 #include "src/v8.h"
     31 
     32 #include "include/v8-profiler.h"
     33 #include "src/cpu-profiler-inl.h"
     34 #include "src/platform.h"
     35 #include "src/smart-pointers.h"
     36 #include "src/utils.h"
     37 #include "test/cctest/cctest.h"
     38 #include "test/cctest/profiler-extension.h"
     39 using i::CodeEntry;
     40 using i::CpuProfile;
     41 using i::CpuProfiler;
     42 using i::CpuProfilesCollection;
     43 using i::Heap;
     44 using i::ProfileGenerator;
     45 using i::ProfileNode;
     46 using i::ProfilerEventsProcessor;
     47 using i::ScopedVector;
     48 using i::SmartPointer;
     49 using i::TimeDelta;
     50 using i::Vector;
     51 
     52 
     53 TEST(StartStop) {
     54   i::Isolate* isolate = CcTest::i_isolate();
     55   CpuProfilesCollection profiles(isolate->heap());
     56   ProfileGenerator generator(&profiles);
     57   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
     58           &generator, NULL, TimeDelta::FromMicroseconds(100)));
     59   processor->Start();
     60   processor->StopSynchronously();
     61 }
     62 
     63 
     64 static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
     65                                    i::Address frame1,
     66                                    i::Address frame2 = NULL,
     67                                    i::Address frame3 = NULL) {
     68   i::TickSample* sample = proc->StartTickSample();
     69   sample->pc = frame1;
     70   sample->tos = frame1;
     71   sample->frames_count = 0;
     72   if (frame2 != NULL) {
     73     sample->stack[0] = frame2;
     74     sample->frames_count = 1;
     75   }
     76   if (frame3 != NULL) {
     77     sample->stack[1] = frame3;
     78     sample->frames_count = 2;
     79   }
     80   proc->FinishTickSample();
     81 }
     82 
     83 namespace {
     84 
     85 class TestSetup {
     86  public:
     87   TestSetup()
     88       : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
     89     i::FLAG_prof_browser_mode = false;
     90   }
     91 
     92   ~TestSetup() {
     93     i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
     94   }
     95 
     96  private:
     97   bool old_flag_prof_browser_mode_;
     98 };
     99 
    100 }  // namespace
    101 
    102 
    103 i::Code* CreateCode(LocalContext* env) {
    104   static int counter = 0;
    105   i::EmbeddedVector<char, 256> script;
    106   i::EmbeddedVector<char, 32> name;
    107 
    108   i::SNPrintF(name, "function_%d", ++counter);
    109   const char* name_start = name.start();
    110   i::SNPrintF(script,
    111       "function %s() {\n"
    112            "var counter = 0;\n"
    113            "for (var i = 0; i < %d; ++i) counter += i;\n"
    114            "return '%s_' + counter;\n"
    115        "}\n"
    116        "%s();\n", name_start, counter, name_start, name_start);
    117   CompileRun(script.start());
    118   i::Handle<i::JSFunction> fun = v8::Utils::OpenHandle(
    119       *v8::Local<v8::Function>::Cast(
    120           (*env)->Global()->Get(v8_str(name_start))));
    121   return fun->code();
    122 }
    123 
    124 
    125 TEST(CodeEvents) {
    126   CcTest::InitializeVM();
    127   LocalContext env;
    128   i::Isolate* isolate = CcTest::i_isolate();
    129   i::Factory* factory = isolate->factory();
    130   TestSetup test_setup;
    131 
    132   i::HandleScope scope(isolate);
    133 
    134   i::Code* aaa_code = CreateCode(&env);
    135   i::Code* comment_code = CreateCode(&env);
    136   i::Code* args5_code = CreateCode(&env);
    137   i::Code* comment2_code = CreateCode(&env);
    138   i::Code* moved_code = CreateCode(&env);
    139   i::Code* args3_code = CreateCode(&env);
    140   i::Code* args4_code = CreateCode(&env);
    141 
    142   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
    143   profiles->StartProfiling("", false);
    144   ProfileGenerator generator(profiles);
    145   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
    146           &generator, NULL, TimeDelta::FromMicroseconds(100)));
    147   processor->Start();
    148   CpuProfiler profiler(isolate, profiles, &generator, processor.get());
    149 
    150   // Enqueue code creation events.
    151   const char* aaa_str = "aaa";
    152   i::Handle<i::String> aaa_name = factory->NewStringFromAsciiChecked(aaa_str);
    153   profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code, *aaa_name);
    154   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code, "comment");
    155   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args5_code, 5);
    156   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code, "comment2");
    157   profiler.CodeMoveEvent(comment2_code->address(), moved_code->address());
    158   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args3_code, 3);
    159   profiler.CodeCreateEvent(i::Logger::STUB_TAG, args4_code, 4);
    160 
    161   // Enqueue a tick event to enable code events processing.
    162   EnqueueTickSampleEvent(processor.get(), aaa_code->address());
    163 
    164   processor->StopSynchronously();
    165 
    166   // Check the state of profile generator.
    167   CodeEntry* aaa = generator.code_map()->FindEntry(aaa_code->address());
    168   CHECK_NE(NULL, aaa);
    169   CHECK_EQ(aaa_str, aaa->name());
    170 
    171   CodeEntry* comment = generator.code_map()->FindEntry(comment_code->address());
    172   CHECK_NE(NULL, comment);
    173   CHECK_EQ("comment", comment->name());
    174 
    175   CodeEntry* args5 = generator.code_map()->FindEntry(args5_code->address());
    176   CHECK_NE(NULL, args5);
    177   CHECK_EQ("5", args5->name());
    178 
    179   CHECK_EQ(NULL, generator.code_map()->FindEntry(comment2_code->address()));
    180 
    181   CodeEntry* comment2 = generator.code_map()->FindEntry(moved_code->address());
    182   CHECK_NE(NULL, comment2);
    183   CHECK_EQ("comment2", comment2->name());
    184 }
    185 
    186 
    187 template<typename T>
    188 static int CompareProfileNodes(const T* p1, const T* p2) {
    189   return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
    190 }
    191 
    192 
    193 TEST(TickEvents) {
    194   TestSetup test_setup;
    195   LocalContext env;
    196   i::Isolate* isolate = CcTest::i_isolate();
    197   i::HandleScope scope(isolate);
    198 
    199   i::Code* frame1_code = CreateCode(&env);
    200   i::Code* frame2_code = CreateCode(&env);
    201   i::Code* frame3_code = CreateCode(&env);
    202 
    203   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
    204   profiles->StartProfiling("", false);
    205   ProfileGenerator generator(profiles);
    206   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
    207           &generator, NULL, TimeDelta::FromMicroseconds(100)));
    208   processor->Start();
    209   CpuProfiler profiler(isolate, profiles, &generator, processor.get());
    210 
    211   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
    212   profiler.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, 5);
    213   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
    214 
    215   EnqueueTickSampleEvent(processor.get(), frame1_code->instruction_start());
    216   EnqueueTickSampleEvent(
    217       processor.get(),
    218       frame2_code->instruction_start() + frame2_code->ExecutableSize() / 2,
    219       frame1_code->instruction_start() + frame2_code->ExecutableSize() / 2);
    220   EnqueueTickSampleEvent(
    221       processor.get(),
    222       frame3_code->instruction_end() - 1,
    223       frame2_code->instruction_end() - 1,
    224       frame1_code->instruction_end() - 1);
    225 
    226   processor->StopSynchronously();
    227   CpuProfile* profile = profiles->StopProfiling("");
    228   CHECK_NE(NULL, profile);
    229 
    230   // Check call trees.
    231   const i::List<ProfileNode*>* top_down_root_children =
    232       profile->top_down()->root()->children();
    233   CHECK_EQ(1, top_down_root_children->length());
    234   CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
    235   const i::List<ProfileNode*>* top_down_bbb_children =
    236       top_down_root_children->last()->children();
    237   CHECK_EQ(1, top_down_bbb_children->length());
    238   CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
    239   const i::List<ProfileNode*>* top_down_stub_children =
    240       top_down_bbb_children->last()->children();
    241   CHECK_EQ(1, top_down_stub_children->length());
    242   CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
    243   const i::List<ProfileNode*>* top_down_ddd_children =
    244       top_down_stub_children->last()->children();
    245   CHECK_EQ(0, top_down_ddd_children->length());
    246 }
    247 
    248 
    249 // http://crbug/51594
    250 // This test must not crash.
    251 TEST(CrashIfStoppingLastNonExistentProfile) {
    252   CcTest::InitializeVM();
    253   TestSetup test_setup;
    254   CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
    255   profiler->StartProfiling("1");
    256   profiler->StopProfiling("2");
    257   profiler->StartProfiling("1");
    258   profiler->StopProfiling("");
    259 }
    260 
    261 
    262 // http://code.google.com/p/v8/issues/detail?id=1398
    263 // Long stacks (exceeding max frames limit) must not be erased.
    264 TEST(Issue1398) {
    265   TestSetup test_setup;
    266   LocalContext env;
    267   i::Isolate* isolate = CcTest::i_isolate();
    268   i::HandleScope scope(isolate);
    269 
    270   i::Code* code = CreateCode(&env);
    271 
    272   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
    273   profiles->StartProfiling("", false);
    274   ProfileGenerator generator(profiles);
    275   SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
    276           &generator, NULL, TimeDelta::FromMicroseconds(100)));
    277   processor->Start();
    278   CpuProfiler profiler(isolate, profiles, &generator, processor.get());
    279 
    280   profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
    281 
    282   i::TickSample* sample = processor->StartTickSample();
    283   sample->pc = code->address();
    284   sample->tos = 0;
    285   sample->frames_count = i::TickSample::kMaxFramesCount;
    286   for (int i = 0; i < sample->frames_count; ++i) {
    287     sample->stack[i] = code->address();
    288   }
    289   processor->FinishTickSample();
    290 
    291   processor->StopSynchronously();
    292   CpuProfile* profile = profiles->StopProfiling("");
    293   CHECK_NE(NULL, profile);
    294 
    295   int actual_depth = 0;
    296   const ProfileNode* node = profile->top_down()->root();
    297   while (node->children()->length() > 0) {
    298     node = node->children()->last();
    299     ++actual_depth;
    300   }
    301 
    302   CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth);  // +1 for PC.
    303 }
    304 
    305 
    306 TEST(DeleteAllCpuProfiles) {
    307   CcTest::InitializeVM();
    308   TestSetup test_setup;
    309   CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
    310   CHECK_EQ(0, profiler->GetProfilesCount());
    311   profiler->DeleteAllProfiles();
    312   CHECK_EQ(0, profiler->GetProfilesCount());
    313 
    314   profiler->StartProfiling("1");
    315   profiler->StopProfiling("1");
    316   CHECK_EQ(1, profiler->GetProfilesCount());
    317   profiler->DeleteAllProfiles();
    318   CHECK_EQ(0, profiler->GetProfilesCount());
    319   profiler->StartProfiling("1");
    320   profiler->StartProfiling("2");
    321   profiler->StopProfiling("2");
    322   profiler->StopProfiling("1");
    323   CHECK_EQ(2, profiler->GetProfilesCount());
    324   profiler->DeleteAllProfiles();
    325   CHECK_EQ(0, profiler->GetProfilesCount());
    326 
    327   // Test profiling cancellation by the 'delete' command.
    328   profiler->StartProfiling("1");
    329   profiler->StartProfiling("2");
    330   CHECK_EQ(0, profiler->GetProfilesCount());
    331   profiler->DeleteAllProfiles();
    332   CHECK_EQ(0, profiler->GetProfilesCount());
    333 }
    334 
    335 
    336 static bool FindCpuProfile(v8::CpuProfiler* v8profiler,
    337                            const v8::CpuProfile* v8profile) {
    338   i::CpuProfiler* profiler = reinterpret_cast<i::CpuProfiler*>(v8profiler);
    339   const i::CpuProfile* profile =
    340       reinterpret_cast<const i::CpuProfile*>(v8profile);
    341   int length = profiler->GetProfilesCount();
    342   for (int i = 0; i < length; i++) {
    343     if (profile == profiler->GetProfile(i))
    344       return true;
    345   }
    346   return false;
    347 }
    348 
    349 
    350 TEST(DeleteCpuProfile) {
    351   LocalContext env;
    352   v8::HandleScope scope(env->GetIsolate());
    353   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    354   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(cpu_profiler);
    355 
    356   CHECK_EQ(0, iprofiler->GetProfilesCount());
    357   v8::Local<v8::String> name1 = v8::String::NewFromUtf8(env->GetIsolate(), "1");
    358   cpu_profiler->StartProfiling(name1);
    359   v8::CpuProfile* p1 = cpu_profiler->StopProfiling(name1);
    360   CHECK_NE(NULL, p1);
    361   CHECK_EQ(1, iprofiler->GetProfilesCount());
    362   CHECK(FindCpuProfile(cpu_profiler, p1));
    363   p1->Delete();
    364   CHECK_EQ(0, iprofiler->GetProfilesCount());
    365 
    366   v8::Local<v8::String> name2 = v8::String::NewFromUtf8(env->GetIsolate(), "2");
    367   cpu_profiler->StartProfiling(name2);
    368   v8::CpuProfile* p2 = cpu_profiler->StopProfiling(name2);
    369   CHECK_NE(NULL, p2);
    370   CHECK_EQ(1, iprofiler->GetProfilesCount());
    371   CHECK(FindCpuProfile(cpu_profiler, p2));
    372   v8::Local<v8::String> name3 = v8::String::NewFromUtf8(env->GetIsolate(), "3");
    373   cpu_profiler->StartProfiling(name3);
    374   v8::CpuProfile* p3 = cpu_profiler->StopProfiling(name3);
    375   CHECK_NE(NULL, p3);
    376   CHECK_EQ(2, iprofiler->GetProfilesCount());
    377   CHECK_NE(p2, p3);
    378   CHECK(FindCpuProfile(cpu_profiler, p3));
    379   CHECK(FindCpuProfile(cpu_profiler, p2));
    380   p2->Delete();
    381   CHECK_EQ(1, iprofiler->GetProfilesCount());
    382   CHECK(!FindCpuProfile(cpu_profiler, p2));
    383   CHECK(FindCpuProfile(cpu_profiler, p3));
    384   p3->Delete();
    385   CHECK_EQ(0, iprofiler->GetProfilesCount());
    386 }
    387 
    388 
    389 TEST(ProfileStartEndTime) {
    390   LocalContext env;
    391   v8::HandleScope scope(env->GetIsolate());
    392   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    393 
    394   v8::Local<v8::String> profile_name =
    395       v8::String::NewFromUtf8(env->GetIsolate(), "test");
    396   cpu_profiler->StartProfiling(profile_name);
    397   const v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
    398   CHECK(profile->GetStartTime() <= profile->GetEndTime());
    399 }
    400 
    401 
    402 static v8::CpuProfile* RunProfiler(
    403     v8::Handle<v8::Context> env, v8::Handle<v8::Function> function,
    404     v8::Handle<v8::Value> argv[], int argc,
    405     unsigned min_js_samples, bool collect_samples = false) {
    406   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    407   v8::Local<v8::String> profile_name =
    408       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile");
    409 
    410   cpu_profiler->StartProfiling(profile_name, collect_samples);
    411 
    412   i::Sampler* sampler =
    413       reinterpret_cast<i::Isolate*>(env->GetIsolate())->logger()->sampler();
    414   sampler->StartCountingSamples();
    415   do {
    416     function->Call(env->Global(), argc, argv);
    417   } while (sampler->js_and_external_sample_count() < min_js_samples);
    418 
    419   v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
    420 
    421   CHECK_NE(NULL, profile);
    422   // Dump collected profile to have a better diagnostic in case of failure.
    423   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    424 
    425   return profile;
    426 }
    427 
    428 
    429 static bool ContainsString(v8::Handle<v8::String> string,
    430                            const Vector<v8::Handle<v8::String> >& vector) {
    431   for (int i = 0; i < vector.length(); i++) {
    432     if (string->Equals(vector[i]))
    433       return true;
    434   }
    435   return false;
    436 }
    437 
    438 
    439 static void CheckChildrenNames(const v8::CpuProfileNode* node,
    440                                const Vector<v8::Handle<v8::String> >& names) {
    441   int count = node->GetChildrenCount();
    442   for (int i = 0; i < count; i++) {
    443     v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName();
    444     CHECK(ContainsString(name, names));
    445     // Check that there are no duplicates.
    446     for (int j = 0; j < count; j++) {
    447       if (j == i) continue;
    448       CHECK_NE(name, node->GetChild(j)->GetFunctionName());
    449     }
    450   }
    451 }
    452 
    453 
    454 static const v8::CpuProfileNode* FindChild(v8::Isolate* isolate,
    455                                            const v8::CpuProfileNode* node,
    456                                            const char* name) {
    457   int count = node->GetChildrenCount();
    458   v8::Handle<v8::String> nameHandle = v8::String::NewFromUtf8(isolate, name);
    459   for (int i = 0; i < count; i++) {
    460     const v8::CpuProfileNode* child = node->GetChild(i);
    461     if (nameHandle->Equals(child->GetFunctionName())) return child;
    462   }
    463   return NULL;
    464 }
    465 
    466 
    467 static const v8::CpuProfileNode* GetChild(v8::Isolate* isolate,
    468                                           const v8::CpuProfileNode* node,
    469                                           const char* name) {
    470   const v8::CpuProfileNode* result = FindChild(isolate, node, name);
    471   if (!result) {
    472     char buffer[100];
    473     i::SNPrintF(Vector<char>(buffer, ARRAY_SIZE(buffer)),
    474                 "Failed to GetChild: %s", name);
    475     FATAL(buffer);
    476   }
    477   return result;
    478 }
    479 
    480 
    481 static void CheckSimpleBranch(v8::Isolate* isolate,
    482                               const v8::CpuProfileNode* node,
    483                               const char* names[], int length) {
    484   for (int i = 0; i < length; i++) {
    485     const char* name = names[i];
    486     node = GetChild(isolate, node, name);
    487     int expectedChildrenCount = (i == length - 1) ? 0 : 1;
    488     CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
    489   }
    490 }
    491 
    492 
    493 static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
    494 "  this.mmm = 0;\n"
    495 "  var start = Date.now();\n"
    496 "  while (Date.now() - start < timeout) {\n"
    497 "    var n = 100*1000;\n"
    498 "    while(n > 1) {\n"
    499 "      n--;\n"
    500 "      this.mmm += n * n * n;\n"
    501 "    }\n"
    502 "  }\n"
    503 "}\n"
    504 "function delay() { try { loop(10); } catch(e) { } }\n"
    505 "function bar() { delay(); }\n"
    506 "function baz() { delay(); }\n"
    507 "function foo() {\n"
    508 "    try {\n"
    509 "       delay();\n"
    510 "       bar();\n"
    511 "       delay();\n"
    512 "       baz();\n"
    513 "    } catch (e) { }\n"
    514 "}\n"
    515 "function start(timeout) {\n"
    516 "  var start = Date.now();\n"
    517 "  do {\n"
    518 "    foo();\n"
    519 "    var duration = Date.now() - start;\n"
    520 "  } while (duration < timeout);\n"
    521 "  return duration;\n"
    522 "}\n";
    523 
    524 
    525 // Check that the profile tree for the script above will look like the
    526 // following:
    527 //
    528 // [Top down]:
    529 //  1062     0   (root) [-1]
    530 //  1054     0    start [-1]
    531 //  1054     1      foo [-1]
    532 //   265     0        baz [-1]
    533 //   265     1          delay [-1]
    534 //   264   264            loop [-1]
    535 //   525     3        delay [-1]
    536 //   522   522          loop [-1]
    537 //   263     0        bar [-1]
    538 //   263     1          delay [-1]
    539 //   262   262            loop [-1]
    540 //     2     2    (program) [-1]
    541 //     6     6    (garbage collector) [-1]
    542 TEST(CollectCpuProfile) {
    543   LocalContext env;
    544   v8::HandleScope scope(env->GetIsolate());
    545 
    546   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
    547                                               cpu_profiler_test_source))->Run();
    548   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    549       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
    550 
    551   int32_t profiling_interval_ms = 200;
    552   v8::Handle<v8::Value> args[] = {
    553     v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
    554   };
    555   v8::CpuProfile* profile =
    556       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
    557   function->Call(env->Global(), ARRAY_SIZE(args), args);
    558 
    559   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    560 
    561   ScopedVector<v8::Handle<v8::String> > names(3);
    562   names[0] = v8::String::NewFromUtf8(
    563       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
    564   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
    565                                      ProfileGenerator::kProgramEntryName);
    566   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
    567   CheckChildrenNames(root, names);
    568 
    569   const v8::CpuProfileNode* startNode =
    570       GetChild(env->GetIsolate(), root, "start");
    571   CHECK_EQ(1, startNode->GetChildrenCount());
    572 
    573   const v8::CpuProfileNode* fooNode =
    574       GetChild(env->GetIsolate(), startNode, "foo");
    575   CHECK_EQ(3, fooNode->GetChildrenCount());
    576 
    577   const char* barBranch[] = { "bar", "delay", "loop" };
    578   CheckSimpleBranch(env->GetIsolate(), fooNode, barBranch,
    579                     ARRAY_SIZE(barBranch));
    580   const char* bazBranch[] = { "baz", "delay", "loop" };
    581   CheckSimpleBranch(env->GetIsolate(), fooNode, bazBranch,
    582                     ARRAY_SIZE(bazBranch));
    583   const char* delayBranch[] = { "delay", "loop" };
    584   CheckSimpleBranch(env->GetIsolate(), fooNode, delayBranch,
    585                     ARRAY_SIZE(delayBranch));
    586 
    587   profile->Delete();
    588 }
    589 
    590 
    591 static const char* hot_deopt_no_frame_entry_test_source =
    592 "function foo(a, b) {\n"
    593 "    try {\n"
    594 "      return a + b;\n"
    595 "    } catch (e) { }\n"
    596 "}\n"
    597 "function start(timeout) {\n"
    598 "  var start = Date.now();\n"
    599 "  do {\n"
    600 "    for (var i = 1; i < 1000; ++i) foo(1, i);\n"
    601 "    var duration = Date.now() - start;\n"
    602 "  } while (duration < timeout);\n"
    603 "  return duration;\n"
    604 "}\n";
    605 
    606 // Check that the profile tree for the script above will look like the
    607 // following:
    608 //
    609 // [Top down]:
    610 //  1062     0  (root) [-1]
    611 //  1054     0    start [-1]
    612 //  1054     1      foo [-1]
    613 //     2     2    (program) [-1]
    614 //     6     6    (garbage collector) [-1]
    615 //
    616 // The test checks no FP ranges are present in a deoptimized funcion.
    617 // If 'foo' has no ranges the samples falling into the prologue will miss the
    618 // 'start' function on the stack, so 'foo' will be attached to the (root).
    619 TEST(HotDeoptNoFrameEntry) {
    620   LocalContext env;
    621   v8::HandleScope scope(env->GetIsolate());
    622 
    623   v8::Script::Compile(v8::String::NewFromUtf8(
    624       env->GetIsolate(),
    625       hot_deopt_no_frame_entry_test_source))->Run();
    626   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    627       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
    628 
    629   int32_t profiling_interval_ms = 200;
    630   v8::Handle<v8::Value> args[] = {
    631     v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
    632   };
    633   v8::CpuProfile* profile =
    634       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
    635   function->Call(env->Global(), ARRAY_SIZE(args), args);
    636 
    637   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    638 
    639   ScopedVector<v8::Handle<v8::String> > names(3);
    640   names[0] = v8::String::NewFromUtf8(
    641       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
    642   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
    643                                      ProfileGenerator::kProgramEntryName);
    644   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
    645   CheckChildrenNames(root, names);
    646 
    647   const v8::CpuProfileNode* startNode =
    648       GetChild(env->GetIsolate(), root, "start");
    649   CHECK_EQ(1, startNode->GetChildrenCount());
    650 
    651   GetChild(env->GetIsolate(), startNode, "foo");
    652 
    653   profile->Delete();
    654 }
    655 
    656 
    657 TEST(CollectCpuProfileSamples) {
    658   LocalContext env;
    659   v8::HandleScope scope(env->GetIsolate());
    660 
    661   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
    662                                               cpu_profiler_test_source))->Run();
    663   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    664       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
    665 
    666   int32_t profiling_interval_ms = 200;
    667   v8::Handle<v8::Value> args[] = {
    668     v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
    669   };
    670   v8::CpuProfile* profile =
    671       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200, true);
    672 
    673   CHECK_LE(200, profile->GetSamplesCount());
    674   uint64_t end_time = profile->GetEndTime();
    675   uint64_t current_time = profile->GetStartTime();
    676   CHECK_LE(current_time, end_time);
    677   for (int i = 0; i < profile->GetSamplesCount(); i++) {
    678     CHECK_NE(NULL, profile->GetSample(i));
    679     uint64_t timestamp = profile->GetSampleTimestamp(i);
    680     CHECK_LE(current_time, timestamp);
    681     CHECK_LE(timestamp, end_time);
    682     current_time = timestamp;
    683   }
    684 
    685   profile->Delete();
    686 }
    687 
    688 
    689 static const char* cpu_profiler_test_source2 = "function loop() {}\n"
    690 "function delay() { loop(); }\n"
    691 "function start(count) {\n"
    692 "  var k = 0;\n"
    693 "  do {\n"
    694 "    delay();\n"
    695 "  } while (++k < count*100*1000);\n"
    696 "}\n";
    697 
    698 // Check that the profile tree doesn't contain unexpected traces:
    699 //  - 'loop' can be called only by 'delay'
    700 //  - 'delay' may be called only by 'start'
    701 // The profile will look like the following:
    702 //
    703 // [Top down]:
    704 //   135     0   (root) [-1] #1
    705 //   121    72    start [-1] #3
    706 //    49    33      delay [-1] #4
    707 //    16    16        loop [-1] #5
    708 //    14    14    (program) [-1] #2
    709 TEST(SampleWhenFrameIsNotSetup) {
    710   LocalContext env;
    711   v8::HandleScope scope(env->GetIsolate());
    712 
    713   v8::Script::Compile(v8::String::NewFromUtf8(
    714                           env->GetIsolate(), cpu_profiler_test_source2))->Run();
    715   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    716       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
    717 
    718   int32_t repeat_count = 100;
    719 #if defined(USE_SIMULATOR)
    720   // Simulators are much slower.
    721   repeat_count = 1;
    722 #endif
    723   v8::Handle<v8::Value> args[] = {
    724     v8::Integer::New(env->GetIsolate(), repeat_count)
    725   };
    726   v8::CpuProfile* profile =
    727       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
    728 
    729   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    730 
    731   ScopedVector<v8::Handle<v8::String> > names(3);
    732   names[0] = v8::String::NewFromUtf8(
    733       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
    734   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
    735                                      ProfileGenerator::kProgramEntryName);
    736   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
    737   CheckChildrenNames(root, names);
    738 
    739   const v8::CpuProfileNode* startNode =
    740       FindChild(env->GetIsolate(), root, "start");
    741   // On slow machines there may be no meaningfull samples at all, skip the
    742   // check there.
    743   if (startNode && startNode->GetChildrenCount() > 0) {
    744     CHECK_EQ(1, startNode->GetChildrenCount());
    745     const v8::CpuProfileNode* delayNode =
    746         GetChild(env->GetIsolate(), startNode, "delay");
    747     if (delayNode->GetChildrenCount() > 0) {
    748       CHECK_EQ(1, delayNode->GetChildrenCount());
    749       GetChild(env->GetIsolate(), delayNode, "loop");
    750     }
    751   }
    752 
    753   profile->Delete();
    754 }
    755 
    756 
    757 static const char* native_accessor_test_source = "function start(count) {\n"
    758 "  for (var i = 0; i < count; i++) {\n"
    759 "    var o = instance.foo;\n"
    760 "    instance.foo = o + 1;\n"
    761 "  }\n"
    762 "}\n";
    763 
    764 
    765 class TestApiCallbacks {
    766  public:
    767   explicit TestApiCallbacks(int min_duration_ms)
    768       : min_duration_ms_(min_duration_ms),
    769         is_warming_up_(false) {}
    770 
    771   static void Getter(v8::Local<v8::String> name,
    772                      const v8::PropertyCallbackInfo<v8::Value>& info) {
    773     TestApiCallbacks* data = fromInfo(info);
    774     data->Wait();
    775   }
    776 
    777   static void Setter(v8::Local<v8::String> name,
    778                      v8::Local<v8::Value> value,
    779                      const v8::PropertyCallbackInfo<void>& info) {
    780     TestApiCallbacks* data = fromInfo(info);
    781     data->Wait();
    782   }
    783 
    784   static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) {
    785     TestApiCallbacks* data = fromInfo(info);
    786     data->Wait();
    787   }
    788 
    789   void set_warming_up(bool value) { is_warming_up_ = value; }
    790 
    791  private:
    792   void Wait() {
    793     if (is_warming_up_) return;
    794     double start = i::OS::TimeCurrentMillis();
    795     double duration = 0;
    796     while (duration < min_duration_ms_) {
    797       i::OS::Sleep(1);
    798       duration = i::OS::TimeCurrentMillis() - start;
    799     }
    800   }
    801 
    802   template<typename T>
    803   static TestApiCallbacks* fromInfo(const T& info) {
    804     void* data = v8::External::Cast(*info.Data())->Value();
    805     return reinterpret_cast<TestApiCallbacks*>(data);
    806   }
    807 
    808   int min_duration_ms_;
    809   bool is_warming_up_;
    810 };
    811 
    812 
    813 // Test that native accessors are properly reported in the CPU profile.
    814 // This test checks the case when the long-running accessors are called
    815 // only once and the optimizer doesn't have chance to change the invocation
    816 // code.
    817 TEST(NativeAccessorUninitializedIC) {
    818   LocalContext env;
    819   v8::Isolate* isolate = env->GetIsolate();
    820   v8::HandleScope scope(isolate);
    821 
    822   v8::Local<v8::FunctionTemplate> func_template =
    823       v8::FunctionTemplate::New(isolate);
    824   v8::Local<v8::ObjectTemplate> instance_template =
    825       func_template->InstanceTemplate();
    826 
    827   TestApiCallbacks accessors(100);
    828   v8::Local<v8::External> data =
    829       v8::External::New(isolate, &accessors);
    830   instance_template->SetAccessor(
    831       v8::String::NewFromUtf8(isolate, "foo"),
    832       &TestApiCallbacks::Getter, &TestApiCallbacks::Setter, data);
    833   v8::Local<v8::Function> func = func_template->GetFunction();
    834   v8::Local<v8::Object> instance = func->NewInstance();
    835   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
    836                      instance);
    837 
    838   v8::Script::Compile(
    839       v8::String::NewFromUtf8(isolate, native_accessor_test_source))
    840       ->Run();
    841   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    842       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
    843 
    844   int32_t repeat_count = 1;
    845   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
    846   v8::CpuProfile* profile =
    847       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 180);
    848 
    849   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    850   const v8::CpuProfileNode* startNode =
    851       GetChild(isolate, root, "start");
    852   GetChild(isolate, startNode, "get foo");
    853   GetChild(isolate, startNode, "set foo");
    854 
    855   profile->Delete();
    856 }
    857 
    858 
    859 // Test that native accessors are properly reported in the CPU profile.
    860 // This test makes sure that the accessors are called enough times to become
    861 // hot and to trigger optimizations.
    862 TEST(NativeAccessorMonomorphicIC) {
    863   LocalContext env;
    864   v8::Isolate* isolate = env->GetIsolate();
    865   v8::HandleScope scope(isolate);
    866 
    867   v8::Local<v8::FunctionTemplate> func_template =
    868       v8::FunctionTemplate::New(isolate);
    869   v8::Local<v8::ObjectTemplate> instance_template =
    870       func_template->InstanceTemplate();
    871 
    872   TestApiCallbacks accessors(1);
    873   v8::Local<v8::External> data =
    874       v8::External::New(isolate, &accessors);
    875   instance_template->SetAccessor(
    876       v8::String::NewFromUtf8(isolate, "foo"),
    877       &TestApiCallbacks::Getter, &TestApiCallbacks::Setter, data);
    878   v8::Local<v8::Function> func = func_template->GetFunction();
    879   v8::Local<v8::Object> instance = func->NewInstance();
    880   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
    881                      instance);
    882 
    883   v8::Script::Compile(
    884       v8::String::NewFromUtf8(isolate, native_accessor_test_source))
    885       ->Run();
    886   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    887       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
    888 
    889   {
    890     // Make sure accessors ICs are in monomorphic state before starting
    891     // profiling.
    892     accessors.set_warming_up(true);
    893     int32_t warm_up_iterations = 3;
    894     v8::Handle<v8::Value> args[] = {
    895       v8::Integer::New(isolate, warm_up_iterations)
    896     };
    897     function->Call(env->Global(), ARRAY_SIZE(args), args);
    898     accessors.set_warming_up(false);
    899   }
    900 
    901   int32_t repeat_count = 100;
    902   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
    903   v8::CpuProfile* profile =
    904       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200);
    905 
    906   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    907   const v8::CpuProfileNode* startNode =
    908       GetChild(isolate, root, "start");
    909   GetChild(isolate, startNode, "get foo");
    910   GetChild(isolate, startNode, "set foo");
    911 
    912   profile->Delete();
    913 }
    914 
    915 
    916 static const char* native_method_test_source = "function start(count) {\n"
    917 "  for (var i = 0; i < count; i++) {\n"
    918 "    instance.fooMethod();\n"
    919 "  }\n"
    920 "}\n";
    921 
    922 
    923 TEST(NativeMethodUninitializedIC) {
    924   LocalContext env;
    925   v8::Isolate* isolate = env->GetIsolate();
    926   v8::HandleScope scope(isolate);
    927 
    928   TestApiCallbacks callbacks(100);
    929   v8::Local<v8::External> data =
    930       v8::External::New(isolate, &callbacks);
    931 
    932   v8::Local<v8::FunctionTemplate> func_template =
    933       v8::FunctionTemplate::New(isolate);
    934   func_template->SetClassName(
    935       v8::String::NewFromUtf8(isolate, "Test_InstanceCostructor"));
    936   v8::Local<v8::ObjectTemplate> proto_template =
    937       func_template->PrototypeTemplate();
    938   v8::Local<v8::Signature> signature =
    939       v8::Signature::New(isolate, func_template);
    940   proto_template->Set(v8::String::NewFromUtf8(isolate, "fooMethod"),
    941                       v8::FunctionTemplate::New(isolate,
    942                                                 &TestApiCallbacks::Callback,
    943                                                 data, signature, 0));
    944 
    945   v8::Local<v8::Function> func = func_template->GetFunction();
    946   v8::Local<v8::Object> instance = func->NewInstance();
    947   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
    948                      instance);
    949 
    950   v8::Script::Compile(v8::String::NewFromUtf8(
    951                           isolate, native_method_test_source))->Run();
    952   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    953       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
    954 
    955   int32_t repeat_count = 1;
    956   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
    957   v8::CpuProfile* profile =
    958       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
    959 
    960   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    961   const v8::CpuProfileNode* startNode =
    962       GetChild(isolate, root, "start");
    963   GetChild(isolate, startNode, "fooMethod");
    964 
    965   profile->Delete();
    966 }
    967 
    968 
    969 TEST(NativeMethodMonomorphicIC) {
    970   LocalContext env;
    971   v8::Isolate* isolate = env->GetIsolate();
    972   v8::HandleScope scope(isolate);
    973 
    974   TestApiCallbacks callbacks(1);
    975   v8::Local<v8::External> data =
    976       v8::External::New(isolate, &callbacks);
    977 
    978   v8::Local<v8::FunctionTemplate> func_template =
    979       v8::FunctionTemplate::New(isolate);
    980   func_template->SetClassName(
    981       v8::String::NewFromUtf8(isolate, "Test_InstanceCostructor"));
    982   v8::Local<v8::ObjectTemplate> proto_template =
    983       func_template->PrototypeTemplate();
    984   v8::Local<v8::Signature> signature =
    985       v8::Signature::New(isolate, func_template);
    986   proto_template->Set(v8::String::NewFromUtf8(isolate, "fooMethod"),
    987                       v8::FunctionTemplate::New(isolate,
    988                                                 &TestApiCallbacks::Callback,
    989                                                 data, signature, 0));
    990 
    991   v8::Local<v8::Function> func = func_template->GetFunction();
    992   v8::Local<v8::Object> instance = func->NewInstance();
    993   env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
    994                      instance);
    995 
    996   v8::Script::Compile(v8::String::NewFromUtf8(
    997                           isolate, native_method_test_source))->Run();
    998   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
    999       env->Global()->Get(v8::String::NewFromUtf8(isolate, "start")));
   1000   {
   1001     // Make sure method ICs are in monomorphic state before starting
   1002     // profiling.
   1003     callbacks.set_warming_up(true);
   1004     int32_t warm_up_iterations = 3;
   1005     v8::Handle<v8::Value> args[] = {
   1006       v8::Integer::New(isolate, warm_up_iterations)
   1007     };
   1008     function->Call(env->Global(), ARRAY_SIZE(args), args);
   1009     callbacks.set_warming_up(false);
   1010   }
   1011 
   1012   int32_t repeat_count = 100;
   1013   v8::Handle<v8::Value> args[] = { v8::Integer::New(isolate, repeat_count) };
   1014   v8::CpuProfile* profile =
   1015       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
   1016 
   1017   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1018   GetChild(isolate, root, "start");
   1019   const v8::CpuProfileNode* startNode =
   1020       GetChild(isolate, root, "start");
   1021   GetChild(isolate, startNode, "fooMethod");
   1022 
   1023   profile->Delete();
   1024 }
   1025 
   1026 
   1027 static const char* bound_function_test_source = "function foo(iterations) {\n"
   1028 "  var r = 0;\n"
   1029 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
   1030 "  return r;\n"
   1031 "}\n"
   1032 "function start(duration) {\n"
   1033 "  var callback = foo.bind(this);\n"
   1034 "  var start = Date.now();\n"
   1035 "  while (Date.now() - start < duration) {\n"
   1036 "    callback(10 * 1000);\n"
   1037 "  }\n"
   1038 "}";
   1039 
   1040 
   1041 TEST(BoundFunctionCall) {
   1042   LocalContext env;
   1043   v8::HandleScope scope(env->GetIsolate());
   1044 
   1045   v8::Script::Compile(
   1046       v8::String::NewFromUtf8(env->GetIsolate(), bound_function_test_source))
   1047       ->Run();
   1048   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1049       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
   1050 
   1051   int32_t duration_ms = 100;
   1052   v8::Handle<v8::Value> args[] = {
   1053     v8::Integer::New(env->GetIsolate(), duration_ms)
   1054   };
   1055   v8::CpuProfile* profile =
   1056       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
   1057 
   1058   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1059   ScopedVector<v8::Handle<v8::String> > names(3);
   1060   names[0] = v8::String::NewFromUtf8(
   1061       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
   1062   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
   1063                                      ProfileGenerator::kProgramEntryName);
   1064   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
   1065   // Don't allow |foo| node to be at the top level.
   1066   CheckChildrenNames(root, names);
   1067 
   1068   const v8::CpuProfileNode* startNode =
   1069       GetChild(env->GetIsolate(), root, "start");
   1070   GetChild(env->GetIsolate(), startNode, "foo");
   1071 
   1072   profile->Delete();
   1073 }
   1074 
   1075 
   1076 static const char* call_function_test_source = "function bar(iterations) {\n"
   1077 "}\n"
   1078 "function start(duration) {\n"
   1079 "  var start = Date.now();\n"
   1080 "  while (Date.now() - start < duration) {\n"
   1081 "    try {\n"
   1082 "      bar.call(this, 10 * 1000);\n"
   1083 "    } catch(e) {}\n"
   1084 "  }\n"
   1085 "}";
   1086 
   1087 
   1088 // Test that if we sampled thread when it was inside FunctionCall buitin then
   1089 // its caller frame will be '(unresolved function)' as we have no reliable way
   1090 // to resolve it.
   1091 //
   1092 // [Top down]:
   1093 //    96     0   (root) [-1] #1
   1094 //     1     1    (garbage collector) [-1] #4
   1095 //     5     0    (unresolved function) [-1] #5
   1096 //     5     5      call [-1] #6
   1097 //    71    70    start [-1] #3
   1098 //     1     1      bar [-1] #7
   1099 //    19    19    (program) [-1] #2
   1100 TEST(FunctionCallSample) {
   1101   LocalContext env;
   1102   v8::HandleScope scope(env->GetIsolate());
   1103 
   1104   // Collect garbage that might have be generated while installing extensions.
   1105   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
   1106 
   1107   v8::Script::Compile(v8::String::NewFromUtf8(
   1108                           env->GetIsolate(), call_function_test_source))->Run();
   1109   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1110       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
   1111 
   1112   int32_t duration_ms = 100;
   1113   v8::Handle<v8::Value> args[] = {
   1114     v8::Integer::New(env->GetIsolate(), duration_ms)
   1115   };
   1116   v8::CpuProfile* profile =
   1117       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
   1118 
   1119   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1120   {
   1121     ScopedVector<v8::Handle<v8::String> > names(4);
   1122     names[0] = v8::String::NewFromUtf8(
   1123         env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
   1124     names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
   1125                                        ProfileGenerator::kProgramEntryName);
   1126     names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
   1127     names[3] = v8::String::NewFromUtf8(
   1128         env->GetIsolate(), i::ProfileGenerator::kUnresolvedFunctionName);
   1129     // Don't allow |bar| and |call| nodes to be at the top level.
   1130     CheckChildrenNames(root, names);
   1131   }
   1132 
   1133   // In case of GC stress tests all samples may be in GC phase and there
   1134   // won't be |start| node in the profiles.
   1135   bool is_gc_stress_testing =
   1136       (i::FLAG_gc_interval != -1) || i::FLAG_stress_compaction;
   1137   const v8::CpuProfileNode* startNode =
   1138       FindChild(env->GetIsolate(), root, "start");
   1139   CHECK(is_gc_stress_testing || startNode);
   1140   if (startNode) {
   1141     ScopedVector<v8::Handle<v8::String> > names(2);
   1142     names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "bar");
   1143     names[1] = v8::String::NewFromUtf8(env->GetIsolate(), "call");
   1144     CheckChildrenNames(startNode, names);
   1145   }
   1146 
   1147   const v8::CpuProfileNode* unresolvedNode = FindChild(
   1148       env->GetIsolate(), root, i::ProfileGenerator::kUnresolvedFunctionName);
   1149   if (unresolvedNode) {
   1150     ScopedVector<v8::Handle<v8::String> > names(1);
   1151     names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "call");
   1152     CheckChildrenNames(unresolvedNode, names);
   1153   }
   1154 
   1155   profile->Delete();
   1156 }
   1157 
   1158 
   1159 static const char* function_apply_test_source = "function bar(iterations) {\n"
   1160 "}\n"
   1161 "function test() {\n"
   1162 "  bar.apply(this, [10 * 1000]);\n"
   1163 "}\n"
   1164 "function start(duration) {\n"
   1165 "  var start = Date.now();\n"
   1166 "  while (Date.now() - start < duration) {\n"
   1167 "    try {\n"
   1168 "      test();\n"
   1169 "    } catch(e) {}\n"
   1170 "  }\n"
   1171 "}";
   1172 
   1173 
   1174 // [Top down]:
   1175 //    94     0   (root) [-1] #0 1
   1176 //     2     2    (garbage collector) [-1] #0 7
   1177 //    82    49    start [-1] #16 3
   1178 //     1     0      (unresolved function) [-1] #0 8
   1179 //     1     1        apply [-1] #0 9
   1180 //    32    21      test [-1] #16 4
   1181 //     2     2        bar [-1] #16 6
   1182 //     9     9        apply [-1] #0 5
   1183 //    10    10    (program) [-1] #0 2
   1184 TEST(FunctionApplySample) {
   1185   LocalContext env;
   1186   v8::HandleScope scope(env->GetIsolate());
   1187 
   1188   v8::Script::Compile(
   1189       v8::String::NewFromUtf8(env->GetIsolate(), function_apply_test_source))
   1190       ->Run();
   1191   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1192       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
   1193 
   1194   int32_t duration_ms = 100;
   1195   v8::Handle<v8::Value> args[] = {
   1196     v8::Integer::New(env->GetIsolate(), duration_ms)
   1197   };
   1198 
   1199   v8::CpuProfile* profile =
   1200       RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100);
   1201 
   1202   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1203   {
   1204     ScopedVector<v8::Handle<v8::String> > names(3);
   1205     names[0] = v8::String::NewFromUtf8(
   1206         env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
   1207     names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
   1208                                        ProfileGenerator::kProgramEntryName);
   1209     names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
   1210     // Don't allow |test|, |bar| and |apply| nodes to be at the top level.
   1211     CheckChildrenNames(root, names);
   1212   }
   1213 
   1214   const v8::CpuProfileNode* startNode =
   1215       FindChild(env->GetIsolate(), root, "start");
   1216   if (startNode) {
   1217     {
   1218       ScopedVector<v8::Handle<v8::String> > names(2);
   1219       names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "test");
   1220       names[1] = v8::String::NewFromUtf8(
   1221           env->GetIsolate(), ProfileGenerator::kUnresolvedFunctionName);
   1222       CheckChildrenNames(startNode, names);
   1223     }
   1224 
   1225     const v8::CpuProfileNode* testNode =
   1226         FindChild(env->GetIsolate(), startNode, "test");
   1227     if (testNode) {
   1228       ScopedVector<v8::Handle<v8::String> > names(3);
   1229       names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "bar");
   1230       names[1] = v8::String::NewFromUtf8(env->GetIsolate(), "apply");
   1231       // apply calls "get length" before invoking the function itself
   1232       // and we may get hit into it.
   1233       names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "get length");
   1234       CheckChildrenNames(testNode, names);
   1235     }
   1236 
   1237     if (const v8::CpuProfileNode* unresolvedNode =
   1238             FindChild(env->GetIsolate(), startNode,
   1239                       ProfileGenerator::kUnresolvedFunctionName)) {
   1240       ScopedVector<v8::Handle<v8::String> > names(1);
   1241       names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "apply");
   1242       CheckChildrenNames(unresolvedNode, names);
   1243       GetChild(env->GetIsolate(), unresolvedNode, "apply");
   1244     }
   1245   }
   1246 
   1247   profile->Delete();
   1248 }
   1249 
   1250 
   1251 static const char* js_native_js_test_source =
   1252 "var is_profiling = false;\n"
   1253 "function foo(iterations) {\n"
   1254 "  if (!is_profiling) {\n"
   1255 "    is_profiling = true;\n"
   1256 "    startProfiling('my_profile');\n"
   1257 "  }\n"
   1258 "  var r = 0;\n"
   1259 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
   1260 "  return r;\n"
   1261 "}\n"
   1262 "function bar(iterations) {\n"
   1263 "  try { foo(iterations); } catch(e) {}\n"
   1264 "}\n"
   1265 "function start(duration) {\n"
   1266 "  var start = Date.now();\n"
   1267 "  while (Date.now() - start < duration) {\n"
   1268 "    try {\n"
   1269 "      CallJsFunction(bar, 10 * 1000);\n"
   1270 "    } catch(e) {}\n"
   1271 "  }\n"
   1272 "}";
   1273 
   1274 static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
   1275   v8::Handle<v8::Function> function = info[0].As<v8::Function>();
   1276   v8::Handle<v8::Value> argv[] = { info[1] };
   1277   function->Call(info.This(), ARRAY_SIZE(argv), argv);
   1278 }
   1279 
   1280 
   1281 // [Top down]:
   1282 //    58     0   (root) #0 1
   1283 //     2     2    (program) #0 2
   1284 //    56     1    start #16 3
   1285 //    55     0      CallJsFunction #0 4
   1286 //    55     1        bar #16 5
   1287 //    54    54          foo #16 6
   1288 TEST(JsNativeJsSample) {
   1289   v8::HandleScope scope(CcTest::isolate());
   1290   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
   1291   v8::Context::Scope context_scope(env);
   1292 
   1293   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
   1294       env->GetIsolate(), CallJsFunction);
   1295   v8::Local<v8::Function> func = func_template->GetFunction();
   1296   func->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"));
   1297   env->Global()->Set(
   1298       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"), func);
   1299 
   1300   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
   1301                                               js_native_js_test_source))->Run();
   1302   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1303       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
   1304 
   1305   int32_t duration_ms = 20;
   1306   v8::Handle<v8::Value> args[] = {
   1307     v8::Integer::New(env->GetIsolate(), duration_ms)
   1308   };
   1309   v8::CpuProfile* profile =
   1310       RunProfiler(env, function, args, ARRAY_SIZE(args), 10);
   1311 
   1312   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1313   {
   1314     ScopedVector<v8::Handle<v8::String> > names(3);
   1315     names[0] = v8::String::NewFromUtf8(
   1316         env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
   1317     names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
   1318                                        ProfileGenerator::kProgramEntryName);
   1319     names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
   1320     CheckChildrenNames(root, names);
   1321   }
   1322 
   1323   const v8::CpuProfileNode* startNode =
   1324       GetChild(env->GetIsolate(), root, "start");
   1325   CHECK_EQ(1, startNode->GetChildrenCount());
   1326   const v8::CpuProfileNode* nativeFunctionNode =
   1327       GetChild(env->GetIsolate(), startNode, "CallJsFunction");
   1328 
   1329   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
   1330   const v8::CpuProfileNode* barNode =
   1331       GetChild(env->GetIsolate(), nativeFunctionNode, "bar");
   1332 
   1333   CHECK_EQ(1, barNode->GetChildrenCount());
   1334   GetChild(env->GetIsolate(), barNode, "foo");
   1335 
   1336   profile->Delete();
   1337 }
   1338 
   1339 
   1340 static const char* js_native_js_runtime_js_test_source =
   1341 "var is_profiling = false;\n"
   1342 "function foo(iterations) {\n"
   1343 "  if (!is_profiling) {\n"
   1344 "    is_profiling = true;\n"
   1345 "    startProfiling('my_profile');\n"
   1346 "  }\n"
   1347 "  var r = 0;\n"
   1348 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
   1349 "  return r;\n"
   1350 "}\n"
   1351 "var bound = foo.bind(this);\n"
   1352 "function bar(iterations) {\n"
   1353 "  try { bound(iterations); } catch(e) {}\n"
   1354 "}\n"
   1355 "function start(duration) {\n"
   1356 "  var start = Date.now();\n"
   1357 "  while (Date.now() - start < duration) {\n"
   1358 "    try {\n"
   1359 "      CallJsFunction(bar, 10 * 1000);\n"
   1360 "    } catch(e) {}\n"
   1361 "  }\n"
   1362 "}";
   1363 
   1364 
   1365 // [Top down]:
   1366 //    57     0   (root) #0 1
   1367 //    55     1    start #16 3
   1368 //    54     0      CallJsFunction #0 4
   1369 //    54     3        bar #16 5
   1370 //    51    51          foo #16 6
   1371 //     2     2    (program) #0 2
   1372 TEST(JsNativeJsRuntimeJsSample) {
   1373   v8::HandleScope scope(CcTest::isolate());
   1374   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
   1375   v8::Context::Scope context_scope(env);
   1376 
   1377   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
   1378       env->GetIsolate(), CallJsFunction);
   1379   v8::Local<v8::Function> func = func_template->GetFunction();
   1380   func->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"));
   1381   env->Global()->Set(
   1382       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction"), func);
   1383 
   1384   v8::Script::Compile(
   1385       v8::String::NewFromUtf8(env->GetIsolate(),
   1386                               js_native_js_runtime_js_test_source))->Run();
   1387   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1388       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
   1389 
   1390   int32_t duration_ms = 20;
   1391   v8::Handle<v8::Value> args[] = {
   1392     v8::Integer::New(env->GetIsolate(), duration_ms)
   1393   };
   1394   v8::CpuProfile* profile =
   1395       RunProfiler(env, function, args, ARRAY_SIZE(args), 10);
   1396 
   1397   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1398   ScopedVector<v8::Handle<v8::String> > names(3);
   1399   names[0] = v8::String::NewFromUtf8(
   1400       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
   1401   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
   1402                                      ProfileGenerator::kProgramEntryName);
   1403   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
   1404   CheckChildrenNames(root, names);
   1405 
   1406   const v8::CpuProfileNode* startNode =
   1407       GetChild(env->GetIsolate(), root, "start");
   1408   CHECK_EQ(1, startNode->GetChildrenCount());
   1409   const v8::CpuProfileNode* nativeFunctionNode =
   1410       GetChild(env->GetIsolate(), startNode, "CallJsFunction");
   1411 
   1412   CHECK_EQ(1, nativeFunctionNode->GetChildrenCount());
   1413   const v8::CpuProfileNode* barNode =
   1414       GetChild(env->GetIsolate(), nativeFunctionNode, "bar");
   1415 
   1416   // The child is in fact a bound foo.
   1417   // A bound function has a wrapper that may make calls to
   1418   // other functions e.g. "get length".
   1419   CHECK_LE(1, barNode->GetChildrenCount());
   1420   CHECK_GE(2, barNode->GetChildrenCount());
   1421   GetChild(env->GetIsolate(), barNode, "foo");
   1422 
   1423   profile->Delete();
   1424 }
   1425 
   1426 
   1427 static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) {
   1428   CallJsFunction(info);
   1429 }
   1430 
   1431 
   1432 static const char* js_native1_js_native2_js_test_source =
   1433 "var is_profiling = false;\n"
   1434 "function foo(iterations) {\n"
   1435 "  if (!is_profiling) {\n"
   1436 "    is_profiling = true;\n"
   1437 "    startProfiling('my_profile');\n"
   1438 "  }\n"
   1439 "  var r = 0;\n"
   1440 "  for (var i = 0; i < iterations; i++) { r += i; }\n"
   1441 "  return r;\n"
   1442 "}\n"
   1443 "function bar(iterations) {\n"
   1444 "  CallJsFunction2(foo, iterations);\n"
   1445 "}\n"
   1446 "function start(duration) {\n"
   1447 "  var start = Date.now();\n"
   1448 "  while (Date.now() - start < duration) {\n"
   1449 "    try {\n"
   1450 "      CallJsFunction1(bar, 10 * 1000);\n"
   1451 "    } catch(e) {}\n"
   1452 "  }\n"
   1453 "}";
   1454 
   1455 
   1456 // [Top down]:
   1457 //    57     0   (root) #0 1
   1458 //    55     1    start #16 3
   1459 //    54     0      CallJsFunction1 #0 4
   1460 //    54     0        bar #16 5
   1461 //    54     0          CallJsFunction2 #0 6
   1462 //    54    54            foo #16 7
   1463 //     2     2    (program) #0 2
   1464 TEST(JsNative1JsNative2JsSample) {
   1465   v8::HandleScope scope(CcTest::isolate());
   1466   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
   1467   v8::Context::Scope context_scope(env);
   1468 
   1469   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
   1470       env->GetIsolate(), CallJsFunction);
   1471   v8::Local<v8::Function> func1 = func_template->GetFunction();
   1472   func1->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction1"));
   1473   env->Global()->Set(
   1474       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction1"), func1);
   1475 
   1476   v8::Local<v8::Function> func2 = v8::FunctionTemplate::New(
   1477       env->GetIsolate(), CallJsFunction2)->GetFunction();
   1478   func2->SetName(v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction2"));
   1479   env->Global()->Set(
   1480       v8::String::NewFromUtf8(env->GetIsolate(), "CallJsFunction2"), func2);
   1481 
   1482   v8::Script::Compile(
   1483       v8::String::NewFromUtf8(env->GetIsolate(),
   1484                               js_native1_js_native2_js_test_source))->Run();
   1485   v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
   1486       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
   1487 
   1488   int32_t duration_ms = 20;
   1489   v8::Handle<v8::Value> args[] = {
   1490     v8::Integer::New(env->GetIsolate(), duration_ms)
   1491   };
   1492   v8::CpuProfile* profile =
   1493       RunProfiler(env, function, args, ARRAY_SIZE(args), 10);
   1494 
   1495   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1496   ScopedVector<v8::Handle<v8::String> > names(3);
   1497   names[0] = v8::String::NewFromUtf8(
   1498       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
   1499   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
   1500                                      ProfileGenerator::kProgramEntryName);
   1501   names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start");
   1502   CheckChildrenNames(root, names);
   1503 
   1504   const v8::CpuProfileNode* startNode =
   1505       GetChild(env->GetIsolate(), root, "start");
   1506   CHECK_EQ(1, startNode->GetChildrenCount());
   1507   const v8::CpuProfileNode* nativeNode1 =
   1508       GetChild(env->GetIsolate(), startNode, "CallJsFunction1");
   1509 
   1510   CHECK_EQ(1, nativeNode1->GetChildrenCount());
   1511   const v8::CpuProfileNode* barNode =
   1512       GetChild(env->GetIsolate(), nativeNode1, "bar");
   1513 
   1514   CHECK_EQ(1, barNode->GetChildrenCount());
   1515   const v8::CpuProfileNode* nativeNode2 =
   1516       GetChild(env->GetIsolate(), barNode, "CallJsFunction2");
   1517 
   1518   CHECK_EQ(1, nativeNode2->GetChildrenCount());
   1519   GetChild(env->GetIsolate(), nativeNode2, "foo");
   1520 
   1521   profile->Delete();
   1522 }
   1523 
   1524 
   1525 // [Top down]:
   1526 //     6     0   (root) #0 1
   1527 //     3     3    (program) #0 2
   1528 //     3     3    (idle) #0 3
   1529 TEST(IdleTime) {
   1530   LocalContext env;
   1531   v8::HandleScope scope(env->GetIsolate());
   1532   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   1533 
   1534   v8::Local<v8::String> profile_name =
   1535       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile");
   1536   cpu_profiler->StartProfiling(profile_name);
   1537 
   1538   i::Isolate* isolate = CcTest::i_isolate();
   1539   i::ProfilerEventsProcessor* processor = isolate->cpu_profiler()->processor();
   1540   processor->AddCurrentStack(isolate);
   1541 
   1542   cpu_profiler->SetIdle(true);
   1543 
   1544   for (int i = 0; i < 3; i++) {
   1545     processor->AddCurrentStack(isolate);
   1546   }
   1547 
   1548   cpu_profiler->SetIdle(false);
   1549   processor->AddCurrentStack(isolate);
   1550 
   1551 
   1552   v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
   1553   CHECK_NE(NULL, profile);
   1554   // Dump collected profile to have a better diagnostic in case of failure.
   1555   reinterpret_cast<i::CpuProfile*>(profile)->Print();
   1556 
   1557   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1558   ScopedVector<v8::Handle<v8::String> > names(3);
   1559   names[0] = v8::String::NewFromUtf8(
   1560       env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName);
   1561   names[1] = v8::String::NewFromUtf8(env->GetIsolate(),
   1562                                      ProfileGenerator::kProgramEntryName);
   1563   names[2] = v8::String::NewFromUtf8(env->GetIsolate(),
   1564                                      ProfileGenerator::kIdleEntryName);
   1565   CheckChildrenNames(root, names);
   1566 
   1567   const v8::CpuProfileNode* programNode =
   1568       GetChild(env->GetIsolate(), root, ProfileGenerator::kProgramEntryName);
   1569   CHECK_EQ(0, programNode->GetChildrenCount());
   1570   CHECK_GE(programNode->GetHitCount(), 3);
   1571 
   1572   const v8::CpuProfileNode* idleNode =
   1573       GetChild(env->GetIsolate(), root, ProfileGenerator::kIdleEntryName);
   1574   CHECK_EQ(0, idleNode->GetChildrenCount());
   1575   CHECK_GE(idleNode->GetHitCount(), 3);
   1576 
   1577   profile->Delete();
   1578 }
   1579 
   1580 
   1581 static void CheckFunctionDetails(v8::Isolate* isolate,
   1582                                  const v8::CpuProfileNode* node,
   1583                                  const char* name, const char* script_name,
   1584                                  int script_id, int line, int column) {
   1585   CHECK_EQ(v8::String::NewFromUtf8(isolate, name),
   1586            node->GetFunctionName());
   1587   CHECK_EQ(v8::String::NewFromUtf8(isolate, script_name),
   1588            node->GetScriptResourceName());
   1589   CHECK_EQ(script_id, node->GetScriptId());
   1590   CHECK_EQ(line, node->GetLineNumber());
   1591   CHECK_EQ(column, node->GetColumnNumber());
   1592 }
   1593 
   1594 
   1595 TEST(FunctionDetails) {
   1596   v8::HandleScope scope(CcTest::isolate());
   1597   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
   1598   v8::Context::Scope context_scope(env);
   1599 
   1600   v8::Handle<v8::Script> script_a = CompileWithOrigin(
   1601           "    function foo\n() { try { bar(); } catch(e) {} }\n"
   1602           " function bar() { startProfiling(); }\n",
   1603           "script_a");
   1604   script_a->Run();
   1605   v8::Handle<v8::Script> script_b = CompileWithOrigin(
   1606           "\n\n   function baz() { try { foo(); } catch(e) {} }\n"
   1607           "\n\nbaz();\n"
   1608           "stopProfiling();\n",
   1609           "script_b");
   1610   script_b->Run();
   1611   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
   1612   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
   1613   reinterpret_cast<ProfileNode*>(
   1614       const_cast<v8::CpuProfileNode*>(current))->Print(0);
   1615   // The tree should look like this:
   1616   //  0   (root) 0 #1
   1617   //  0    (anonymous function) 19 #2 no reason script_b:1
   1618   //  0      baz 19 #3 TryCatchStatement script_b:3
   1619   //  0        foo 18 #4 TryCatchStatement script_a:2
   1620   //  1          bar 18 #5 no reason script_a:3
   1621   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   1622   const v8::CpuProfileNode* script = GetChild(env->GetIsolate(), root,
   1623       ProfileGenerator::kAnonymousFunctionName);
   1624   CheckFunctionDetails(env->GetIsolate(), script,
   1625                        ProfileGenerator::kAnonymousFunctionName, "script_b",
   1626                        script_b->GetUnboundScript()->GetId(), 1, 1);
   1627   const v8::CpuProfileNode* baz = GetChild(env->GetIsolate(), script, "baz");
   1628   CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b",
   1629                        script_b->GetUnboundScript()->GetId(), 3, 16);
   1630   const v8::CpuProfileNode* foo = GetChild(env->GetIsolate(), baz, "foo");
   1631   CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a",
   1632                        script_a->GetUnboundScript()->GetId(), 2, 1);
   1633   const v8::CpuProfileNode* bar = GetChild(env->GetIsolate(), foo, "bar");
   1634   CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a",
   1635                        script_a->GetUnboundScript()->GetId(), 3, 14);
   1636 }
   1637 
   1638 
   1639 TEST(DontStopOnFinishedProfileDelete) {
   1640   v8::HandleScope scope(CcTest::isolate());
   1641   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
   1642   v8::Context::Scope context_scope(env);
   1643   v8::Isolate* isolate = env->GetIsolate();
   1644 
   1645   v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
   1646   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
   1647 
   1648   CHECK_EQ(0, iprofiler->GetProfilesCount());
   1649   v8::Handle<v8::String> outer = v8::String::NewFromUtf8(isolate, "outer");
   1650   profiler->StartProfiling(outer);
   1651   CHECK_EQ(0, iprofiler->GetProfilesCount());
   1652 
   1653   v8::Handle<v8::String> inner = v8::String::NewFromUtf8(isolate, "inner");
   1654   profiler->StartProfiling(inner);
   1655   CHECK_EQ(0, iprofiler->GetProfilesCount());
   1656 
   1657   v8::CpuProfile* inner_profile = profiler->StopProfiling(inner);
   1658   CHECK(inner_profile);
   1659   CHECK_EQ(1, iprofiler->GetProfilesCount());
   1660   inner_profile->Delete();
   1661   inner_profile = NULL;
   1662   CHECK_EQ(0, iprofiler->GetProfilesCount());
   1663 
   1664   v8::CpuProfile* outer_profile = profiler->StopProfiling(outer);
   1665   CHECK(outer_profile);
   1666   CHECK_EQ(1, iprofiler->GetProfilesCount());
   1667   outer_profile->Delete();
   1668   outer_profile = NULL;
   1669   CHECK_EQ(0, iprofiler->GetProfilesCount());
   1670 }
   1671