LCOV - code coverage report
Current view: top level - test/cctest - test-cpu-profiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 737 946 77.9 %
Date: 2017-10-20 Functions: 50 65 76.9 %

          Line data    Source code
       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/api.h"
      34             : #include "src/base/platform/platform.h"
      35             : #include "src/deoptimizer.h"
      36             : #include "src/libplatform/default-platform.h"
      37             : #include "src/objects-inl.h"
      38             : #include "src/profiler/cpu-profiler-inl.h"
      39             : #include "src/profiler/profiler-listener.h"
      40             : #include "src/utils.h"
      41             : #include "test/cctest/cctest.h"
      42             : #include "test/cctest/profiler-extension.h"
      43             : 
      44             : #include "include/libplatform/v8-tracing.h"
      45             : #include "src/tracing/trace-event.h"
      46             : 
      47             : namespace v8 {
      48             : namespace internal {
      49             : namespace test_cpu_profiler {
      50             : 
      51             : // Helper methods
      52          95 : static v8::Local<v8::Function> GetFunction(v8::Local<v8::Context> env,
      53             :                                            const char* name) {
      54             :   return v8::Local<v8::Function>::Cast(
      55         380 :       env->Global()->Get(env, v8_str(name)).ToLocalChecked());
      56             : }
      57             : 
      58          15 : static size_t offset(const char* src, const char* substring) {
      59             :   const char* it = strstr(src, substring);
      60          15 :   CHECK(it);
      61          15 :   return static_cast<size_t>(it - src);
      62             : }
      63             : 
      64             : template <typename A, typename B>
      65             : static int dist(A a, B b) {
      66           6 :   return abs(static_cast<int>(a) - static_cast<int>(b));
      67             : }
      68             : 
      69             : static const char* reason(const i::DeoptimizeReason reason) {
      70           6 :   return i::DeoptimizeReasonToString(reason);
      71             : }
      72             : 
      73       23723 : TEST(StartStop) {
      74             :   i::Isolate* isolate = CcTest::i_isolate();
      75           5 :   CpuProfilesCollection profiles(isolate);
      76           5 :   ProfileGenerator generator(&profiles);
      77             :   std::unique_ptr<ProfilerEventsProcessor> processor(
      78             :       new ProfilerEventsProcessor(isolate, &generator,
      79           5 :                                   v8::base::TimeDelta::FromMicroseconds(100)));
      80           5 :   processor->Start();
      81          10 :   processor->StopSynchronously();
      82           5 : }
      83             : 
      84          30 : static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
      85             :                                    i::Address frame1,
      86             :                                    i::Address frame2 = nullptr,
      87             :                                    i::Address frame3 = nullptr) {
      88          30 :   v8::TickSample* sample = proc->StartTickSample();
      89          30 :   sample->pc = frame1;
      90          30 :   sample->tos = frame1;
      91          30 :   sample->frames_count = 0;
      92          30 :   if (frame2 != nullptr) {
      93          10 :     sample->stack[0] = frame2;
      94          10 :     sample->frames_count = 1;
      95             :   }
      96          30 :   if (frame3 != nullptr) {
      97           5 :     sample->stack[1] = frame3;
      98           5 :     sample->frames_count = 2;
      99             :   }
     100             :   proc->FinishTickSample();
     101          30 : }
     102             : 
     103             : namespace {
     104             : 
     105             : class TestSetup {
     106             :  public:
     107             :   TestSetup()
     108          25 :       : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
     109          25 :     i::FLAG_prof_browser_mode = false;
     110             :   }
     111             : 
     112             :   ~TestSetup() {
     113          25 :     i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
     114             :   }
     115             : 
     116             :  private:
     117             :   bool old_flag_prof_browser_mode_;
     118             : };
     119             : 
     120             : }  // namespace
     121             : 
     122          40 : i::AbstractCode* CreateCode(LocalContext* env) {
     123             :   static int counter = 0;
     124             :   i::EmbeddedVector<char, 256> script;
     125             :   i::EmbeddedVector<char, 32> name;
     126             : 
     127          40 :   i::SNPrintF(name, "function_%d", ++counter);
     128          40 :   const char* name_start = name.start();
     129             :   i::SNPrintF(script,
     130             :       "function %s() {\n"
     131             :            "var counter = 0;\n"
     132             :            "for (var i = 0; i < %d; ++i) counter += i;\n"
     133             :            "return '%s_' + counter;\n"
     134             :        "}\n"
     135          40 :        "%s();\n", name_start, counter, name_start, name_start);
     136          40 :   CompileRun(script.start());
     137             : 
     138             :   i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(
     139          80 :       v8::Utils::OpenHandle(*GetFunction(env->local(), name_start)));
     140          40 :   return fun->abstract_code();
     141             : }
     142             : 
     143       23723 : TEST(CodeEvents) {
     144           5 :   CcTest::InitializeVM();
     145           5 :   LocalContext env;
     146             :   i::Isolate* isolate = CcTest::i_isolate();
     147             :   i::Factory* factory = isolate->factory();
     148             :   TestSetup test_setup;
     149             : 
     150             :   i::HandleScope scope(isolate);
     151             : 
     152           5 :   i::AbstractCode* aaa_code = CreateCode(&env);
     153           5 :   i::AbstractCode* comment_code = CreateCode(&env);
     154           5 :   i::AbstractCode* comment2_code = CreateCode(&env);
     155           5 :   i::AbstractCode* moved_code = CreateCode(&env);
     156             : 
     157           5 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
     158           5 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
     159             :   ProfilerEventsProcessor* processor = new ProfilerEventsProcessor(
     160           5 :       isolate, generator, v8::base::TimeDelta::FromMicroseconds(100));
     161          10 :   CpuProfiler profiler(isolate, profiles, generator, processor);
     162           5 :   profiles->StartProfiling("", false);
     163           5 :   processor->Start();
     164          10 :   ProfilerListener profiler_listener(isolate);
     165           5 :   isolate->code_event_dispatcher()->AddListener(&profiler_listener);
     166           5 :   profiler_listener.AddObserver(&profiler);
     167             : 
     168             :   // Enqueue code creation events.
     169             :   const char* aaa_str = "aaa";
     170           5 :   i::Handle<i::String> aaa_name = factory->NewStringFromAsciiChecked(aaa_str);
     171             :   profiler_listener.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code,
     172           5 :                                     *aaa_name);
     173             :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code,
     174           5 :                                     "comment");
     175             :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code,
     176           5 :                                     "comment2");
     177           5 :   profiler_listener.CodeMoveEvent(comment2_code, moved_code->address());
     178             : 
     179             :   // Enqueue a tick event to enable code events processing.
     180           5 :   EnqueueTickSampleEvent(processor, aaa_code->address());
     181             : 
     182           5 :   profiler_listener.RemoveObserver(&profiler);
     183           5 :   isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
     184           5 :   processor->StopSynchronously();
     185             : 
     186             :   // Check the state of profile generator.
     187          10 :   CodeEntry* aaa = generator->code_map()->FindEntry(aaa_code->address());
     188           5 :   CHECK(aaa);
     189           5 :   CHECK_EQ(0, strcmp(aaa_str, aaa->name()));
     190             : 
     191           5 :   CodeEntry* comment =
     192           5 :       generator->code_map()->FindEntry(comment_code->address());
     193           5 :   CHECK(comment);
     194           5 :   CHECK_EQ(0, strcmp("comment", comment->name()));
     195             : 
     196           5 :   CHECK(!generator->code_map()->FindEntry(comment2_code->address()));
     197             : 
     198          10 :   CodeEntry* comment2 = generator->code_map()->FindEntry(moved_code->address());
     199           5 :   CHECK(comment2);
     200          10 :   CHECK_EQ(0, strcmp("comment2", comment2->name()));
     201           5 : }
     202             : 
     203             : template<typename T>
     204             : static int CompareProfileNodes(const T* p1, const T* p2) {
     205             :   return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
     206             : }
     207             : 
     208       23723 : TEST(TickEvents) {
     209             :   TestSetup test_setup;
     210          10 :   LocalContext env;
     211             :   i::Isolate* isolate = CcTest::i_isolate();
     212             :   i::HandleScope scope(isolate);
     213             : 
     214           5 :   i::AbstractCode* frame1_code = CreateCode(&env);
     215           5 :   i::AbstractCode* frame2_code = CreateCode(&env);
     216           5 :   i::AbstractCode* frame3_code = CreateCode(&env);
     217             : 
     218           5 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
     219           5 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
     220             :   ProfilerEventsProcessor* processor =
     221             :       new ProfilerEventsProcessor(CcTest::i_isolate(), generator,
     222           5 :                                   v8::base::TimeDelta::FromMicroseconds(100));
     223          10 :   CpuProfiler profiler(isolate, profiles, generator, processor);
     224           5 :   profiles->StartProfiling("", false);
     225           5 :   processor->Start();
     226          10 :   ProfilerListener profiler_listener(isolate);
     227           5 :   isolate->code_event_dispatcher()->AddListener(&profiler_listener);
     228           5 :   profiler_listener.AddObserver(&profiler);
     229             : 
     230           5 :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
     231           5 :   profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, "ccc");
     232           5 :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
     233             : 
     234           5 :   EnqueueTickSampleEvent(processor, frame1_code->instruction_start());
     235             :   EnqueueTickSampleEvent(
     236             :       processor,
     237           5 :       frame2_code->instruction_start() + frame2_code->ExecutableSize() / 2,
     238          10 :       frame1_code->instruction_start() + frame1_code->ExecutableSize() / 2);
     239           5 :   EnqueueTickSampleEvent(processor, frame3_code->instruction_end() - 1,
     240           5 :                          frame2_code->instruction_end() - 1,
     241          15 :                          frame1_code->instruction_end() - 1);
     242             : 
     243           5 :   profiler_listener.RemoveObserver(&profiler);
     244           5 :   isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
     245           5 :   processor->StopSynchronously();
     246           5 :   CpuProfile* profile = profiles->StopProfiling("");
     247           5 :   CHECK(profile);
     248             : 
     249             :   // Check call trees.
     250           5 :   const std::vector<ProfileNode*>* top_down_root_children =
     251           5 :       profile->top_down()->root()->children();
     252           5 :   CHECK_EQ(1, top_down_root_children->size());
     253           5 :   CHECK_EQ(0, strcmp("bbb", top_down_root_children->back()->entry()->name()));
     254           5 :   const std::vector<ProfileNode*>* top_down_bbb_children =
     255             :       top_down_root_children->back()->children();
     256           5 :   CHECK_EQ(1, top_down_bbb_children->size());
     257           5 :   CHECK_EQ(0, strcmp("ccc", top_down_bbb_children->back()->entry()->name()));
     258           5 :   const std::vector<ProfileNode*>* top_down_stub_children =
     259             :       top_down_bbb_children->back()->children();
     260           5 :   CHECK_EQ(1, top_down_stub_children->size());
     261           5 :   CHECK_EQ(0, strcmp("ddd", top_down_stub_children->back()->entry()->name()));
     262             :   const std::vector<ProfileNode*>* top_down_ddd_children =
     263             :       top_down_stub_children->back()->children();
     264           5 :   CHECK(top_down_ddd_children->empty());
     265             : 
     266           5 :   isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
     267           5 : }
     268             : 
     269             : // http://crbug/51594
     270             : // This test must not crash.
     271       23723 : TEST(CrashIfStoppingLastNonExistentProfile) {
     272           5 :   CcTest::InitializeVM();
     273             :   TestSetup test_setup;
     274           5 :   std::unique_ptr<CpuProfiler> profiler(new CpuProfiler(CcTest::i_isolate()));
     275           5 :   profiler->StartProfiling("1");
     276           5 :   profiler->StopProfiling("2");
     277           5 :   profiler->StartProfiling("1");
     278           5 :   profiler->StopProfiling("");
     279           5 : }
     280             : 
     281             : // http://code.google.com/p/v8/issues/detail?id=1398
     282             : // Long stacks (exceeding max frames limit) must not be erased.
     283       23723 : TEST(Issue1398) {
     284             :   TestSetup test_setup;
     285          10 :   LocalContext env;
     286             :   i::Isolate* isolate = CcTest::i_isolate();
     287             :   i::HandleScope scope(isolate);
     288             : 
     289           5 :   i::AbstractCode* code = CreateCode(&env);
     290             : 
     291           5 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
     292           5 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
     293             :   ProfilerEventsProcessor* processor =
     294             :       new ProfilerEventsProcessor(CcTest::i_isolate(), generator,
     295           5 :                                   v8::base::TimeDelta::FromMicroseconds(100));
     296          10 :   CpuProfiler profiler(isolate, profiles, generator, processor);
     297           5 :   profiles->StartProfiling("", false);
     298           5 :   processor->Start();
     299          10 :   ProfilerListener profiler_listener(isolate);
     300           5 :   isolate->code_event_dispatcher()->AddListener(&profiler_listener);
     301           5 :   profiler_listener.AddObserver(&profiler);
     302             : 
     303           5 :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
     304             : 
     305           5 :   v8::TickSample* sample = processor->StartTickSample();
     306           5 :   sample->pc = code->address();
     307           5 :   sample->tos = 0;
     308           5 :   sample->frames_count = v8::TickSample::kMaxFramesCount;
     309        1280 :   for (unsigned i = 0; i < sample->frames_count; ++i) {
     310        1275 :     sample->stack[i] = code->address();
     311             :   }
     312             :   processor->FinishTickSample();
     313             : 
     314           5 :   profiler_listener.RemoveObserver(&profiler);
     315           5 :   isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
     316           5 :   processor->StopSynchronously();
     317           5 :   CpuProfile* profile = profiles->StopProfiling("");
     318           5 :   CHECK(profile);
     319             : 
     320             :   unsigned actual_depth = 0;
     321           5 :   const ProfileNode* node = profile->top_down()->root();
     322        1290 :   while (!node->children()->empty()) {
     323        1280 :     node = node->children()->back();
     324        1280 :     ++actual_depth;
     325             :   }
     326             : 
     327           5 :   CHECK_EQ(1 + v8::TickSample::kMaxFramesCount, actual_depth);  // +1 for PC.
     328           5 : }
     329             : 
     330       23723 : TEST(DeleteAllCpuProfiles) {
     331           5 :   CcTest::InitializeVM();
     332             :   TestSetup test_setup;
     333           5 :   std::unique_ptr<CpuProfiler> profiler(new CpuProfiler(CcTest::i_isolate()));
     334           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     335           5 :   profiler->DeleteAllProfiles();
     336           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     337             : 
     338           5 :   profiler->StartProfiling("1");
     339           5 :   profiler->StopProfiling("1");
     340           5 :   CHECK_EQ(1, profiler->GetProfilesCount());
     341           5 :   profiler->DeleteAllProfiles();
     342           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     343           5 :   profiler->StartProfiling("1");
     344           5 :   profiler->StartProfiling("2");
     345           5 :   profiler->StopProfiling("2");
     346           5 :   profiler->StopProfiling("1");
     347           5 :   CHECK_EQ(2, profiler->GetProfilesCount());
     348           5 :   profiler->DeleteAllProfiles();
     349           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     350             : 
     351             :   // Test profiling cancellation by the 'delete' command.
     352           5 :   profiler->StartProfiling("1");
     353           5 :   profiler->StartProfiling("2");
     354           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     355           5 :   profiler->DeleteAllProfiles();
     356           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     357           5 : }
     358             : 
     359             : 
     360          30 : static bool FindCpuProfile(v8::CpuProfiler* v8profiler,
     361             :                            const v8::CpuProfile* v8profile) {
     362             :   i::CpuProfiler* profiler = reinterpret_cast<i::CpuProfiler*>(v8profiler);
     363             :   const i::CpuProfile* profile =
     364             :       reinterpret_cast<const i::CpuProfile*>(v8profile);
     365          30 :   int length = profiler->GetProfilesCount();
     366          40 :   for (int i = 0; i < length; i++) {
     367          35 :     if (profile == profiler->GetProfile(i))
     368             :       return true;
     369             :   }
     370             :   return false;
     371             : }
     372             : 
     373             : 
     374       23723 : TEST(DeleteCpuProfile) {
     375           5 :   LocalContext env;
     376          10 :   v8::HandleScope scope(env->GetIsolate());
     377           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
     378             :   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(cpu_profiler);
     379             : 
     380           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
     381           5 :   v8::Local<v8::String> name1 = v8_str("1");
     382           5 :   cpu_profiler->StartProfiling(name1);
     383           5 :   v8::CpuProfile* p1 = cpu_profiler->StopProfiling(name1);
     384           5 :   CHECK(p1);
     385           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
     386           5 :   CHECK(FindCpuProfile(cpu_profiler, p1));
     387           5 :   p1->Delete();
     388           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
     389             : 
     390           5 :   v8::Local<v8::String> name2 = v8_str("2");
     391           5 :   cpu_profiler->StartProfiling(name2);
     392           5 :   v8::CpuProfile* p2 = cpu_profiler->StopProfiling(name2);
     393           5 :   CHECK(p2);
     394           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
     395           5 :   CHECK(FindCpuProfile(cpu_profiler, p2));
     396           5 :   v8::Local<v8::String> name3 = v8_str("3");
     397           5 :   cpu_profiler->StartProfiling(name3);
     398           5 :   v8::CpuProfile* p3 = cpu_profiler->StopProfiling(name3);
     399           5 :   CHECK(p3);
     400           5 :   CHECK_EQ(2, iprofiler->GetProfilesCount());
     401           5 :   CHECK_NE(p2, p3);
     402           5 :   CHECK(FindCpuProfile(cpu_profiler, p3));
     403           5 :   CHECK(FindCpuProfile(cpu_profiler, p2));
     404           5 :   p2->Delete();
     405           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
     406           5 :   CHECK(!FindCpuProfile(cpu_profiler, p2));
     407           5 :   CHECK(FindCpuProfile(cpu_profiler, p3));
     408           5 :   p3->Delete();
     409           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
     410          10 :   cpu_profiler->Dispose();
     411           5 : }
     412             : 
     413             : 
     414       23723 : TEST(ProfileStartEndTime) {
     415           5 :   LocalContext env;
     416          10 :   v8::HandleScope scope(env->GetIsolate());
     417           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
     418             : 
     419           5 :   v8::Local<v8::String> profile_name = v8_str("test");
     420           5 :   cpu_profiler->StartProfiling(profile_name);
     421           5 :   const v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
     422           5 :   CHECK(profile->GetStartTime() <= profile->GetEndTime());
     423          10 :   cpu_profiler->Dispose();
     424           5 : }
     425             : 
     426             : class ProfilerHelper {
     427             :  public:
     428          59 :   explicit ProfilerHelper(const v8::Local<v8::Context>& context)
     429             :       : context_(context),
     430         118 :         profiler_(v8::CpuProfiler::New(context->GetIsolate())) {
     431             :     i::ProfilerExtension::set_profiler(profiler_);
     432          59 :   }
     433             :   ~ProfilerHelper() {
     434             :     i::ProfilerExtension::set_profiler(static_cast<CpuProfiler*>(nullptr));
     435          59 :     profiler_->Dispose();
     436             :   }
     437             : 
     438             :   v8::CpuProfile* Run(v8::Local<v8::Function> function,
     439             :                       v8::Local<v8::Value> argv[], int argc,
     440             :                       unsigned min_js_samples = 0,
     441             :                       unsigned min_external_samples = 0,
     442             :                       bool collect_samples = false);
     443             : 
     444             :   v8::CpuProfiler* profiler() { return profiler_; }
     445             : 
     446             :  private:
     447             :   v8::Local<v8::Context> context_;
     448             :   v8::CpuProfiler* profiler_;
     449             : };
     450             : 
     451          40 : v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function,
     452             :                                     v8::Local<v8::Value> argv[], int argc,
     453             :                                     unsigned min_js_samples,
     454             :                                     unsigned min_external_samples,
     455             :                                     bool collect_samples) {
     456          40 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
     457             : 
     458          40 :   profiler_->SetSamplingInterval(100);
     459          40 :   profiler_->StartProfiling(profile_name, collect_samples);
     460             : 
     461             :   v8::internal::CpuProfiler* iprofiler =
     462          40 :       reinterpret_cast<v8::internal::CpuProfiler*>(profiler_);
     463          90 :   v8::sampler::Sampler* sampler = iprofiler->processor()->sampler();
     464             :   sampler->StartCountingSamples();
     465          50 :   do {
     466         150 :     function->Call(context_, context_->Global(), argc, argv).ToLocalChecked();
     467          90 :   } while (sampler->js_sample_count() < min_js_samples ||
     468             :            sampler->external_sample_count() < min_external_samples);
     469             : 
     470          40 :   v8::CpuProfile* profile = profiler_->StopProfiling(profile_name);
     471             : 
     472          40 :   CHECK(profile);
     473             :   // Dump collected profile to have a better diagnostic in case of failure.
     474          40 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
     475             : 
     476          40 :   return profile;
     477             : }
     478             : 
     479         163 : static const v8::CpuProfileNode* FindChild(v8::Local<v8::Context> context,
     480             :                                            const v8::CpuProfileNode* node,
     481             :                                            const char* name) {
     482         163 :   int count = node->GetChildrenCount();
     483         163 :   v8::Local<v8::String> name_handle = v8_str(name);
     484         244 :   for (int i = 0; i < count; i++) {
     485         239 :     const v8::CpuProfileNode* child = node->GetChild(i);
     486         717 :     if (name_handle->Equals(context, child->GetFunctionName()).FromJust()) {
     487             :       return child;
     488             :     }
     489             :   }
     490             :   return nullptr;
     491             : }
     492             : 
     493             : 
     494         158 : static const v8::CpuProfileNode* GetChild(v8::Local<v8::Context> context,
     495             :                                           const v8::CpuProfileNode* node,
     496             :                                           const char* name) {
     497         158 :   const v8::CpuProfileNode* result = FindChild(context, node, name);
     498         158 :   if (!result) {
     499             :     char buffer[100];
     500           0 :     i::SNPrintF(i::ArrayVector(buffer), "Failed to GetChild: %s", name);
     501           0 :     FATAL(buffer);
     502             :   }
     503         158 :   return result;
     504             : }
     505             : 
     506             : 
     507           0 : static void CheckSimpleBranch(v8::Local<v8::Context> context,
     508             :                               const v8::CpuProfileNode* node,
     509             :                               const char* names[], int length) {
     510           0 :   for (int i = 0; i < length; i++) {
     511           0 :     const char* name = names[i];
     512           0 :     node = GetChild(context, node, name);
     513             :   }
     514           0 : }
     515             : 
     516             : 
     517           9 : static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context,
     518             :                                           v8::CpuProfile* profile,
     519             :                                           const char* names[], int length) {
     520           9 :   const v8::CpuProfileNode* node = profile->GetTopDownRoot();
     521          27 :   for (int i = 0; i < length; i++) {
     522          18 :     node = GetChild(context, node, names[i]);
     523             :   }
     524           9 :   return reinterpret_cast<const ProfileNode*>(node);
     525             : }
     526             : 
     527             : static const char* cpu_profiler_test_source =
     528             :     "%NeverOptimizeFunction(loop);\n"
     529             :     "%NeverOptimizeFunction(delay);\n"
     530             :     "%NeverOptimizeFunction(bar);\n"
     531             :     "%NeverOptimizeFunction(baz);\n"
     532             :     "%NeverOptimizeFunction(foo);\n"
     533             :     "%NeverOptimizeFunction(start);\n"
     534             :     "function loop(timeout) {\n"
     535             :     "  this.mmm = 0;\n"
     536             :     "  var start = Date.now();\n"
     537             :     "  do {\n"
     538             :     "    var n = 1000;\n"
     539             :     "    while(n > 1) {\n"
     540             :     "      n--;\n"
     541             :     "      this.mmm += n * n * n;\n"
     542             :     "    }\n"
     543             :     "  } while (Date.now() - start < timeout);\n"
     544             :     "}\n"
     545             :     "function delay() { loop(10); }\n"
     546             :     "function bar() { delay(); }\n"
     547             :     "function baz() { delay(); }\n"
     548             :     "function foo() {\n"
     549             :     "  delay();\n"
     550             :     "  bar();\n"
     551             :     "  delay();\n"
     552             :     "  baz();\n"
     553             :     "}\n"
     554             :     "function start(duration) {\n"
     555             :     "  var start = Date.now();\n"
     556             :     "  do {\n"
     557             :     "    foo();\n"
     558             :     "  } while (Date.now() - start < duration);\n"
     559             :     "}\n";
     560             : 
     561             : // Check that the profile tree for the script above will look like the
     562             : // following:
     563             : //
     564             : // [Top down]:
     565             : //  1062     0   (root) [-1]
     566             : //  1054     0    start [-1]
     567             : //  1054     1      foo [-1]
     568             : //   265     0        baz [-1]
     569             : //   265     1          delay [-1]
     570             : //   264   264            loop [-1]
     571             : //   525     3        delay [-1]
     572             : //   522   522          loop [-1]
     573             : //   263     0        bar [-1]
     574             : //   263     1          delay [-1]
     575             : //   262   262            loop [-1]
     576             : //     2     2    (program) [-1]
     577             : //     6     6    (garbage collector) [-1]
     578       23718 : TEST(CollectCpuProfile) {
     579           0 :   i::FLAG_allow_natives_syntax = true;
     580           0 :   LocalContext env;
     581           0 :   v8::HandleScope scope(env->GetIsolate());
     582             : 
     583           0 :   CompileRun(cpu_profiler_test_source);
     584           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     585             : 
     586             :   int32_t profiling_interval_ms = 200;
     587             :   v8::Local<v8::Value> args[] = {
     588           0 :       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
     589           0 :   ProfilerHelper helper(env.local());
     590           0 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
     591             : 
     592           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     593           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     594           0 :   const v8::CpuProfileNode* foo_node = GetChild(env.local(), start_node, "foo");
     595             : 
     596           0 :   const char* bar_branch[] = {"bar", "delay", "loop"};
     597           0 :   CheckSimpleBranch(env.local(), foo_node, bar_branch, arraysize(bar_branch));
     598           0 :   const char* baz_branch[] = {"baz", "delay", "loop"};
     599           0 :   CheckSimpleBranch(env.local(), foo_node, baz_branch, arraysize(baz_branch));
     600           0 :   const char* delay_branch[] = {"delay", "loop"};
     601             :   CheckSimpleBranch(env.local(), foo_node, delay_branch,
     602           0 :                     arraysize(delay_branch));
     603             : 
     604           0 :   profile->Delete();
     605           0 : }
     606             : 
     607             : static const char* hot_deopt_no_frame_entry_test_source =
     608             :     "%NeverOptimizeFunction(foo);\n"
     609             :     "%NeverOptimizeFunction(start);\n"
     610             :     "function foo(a, b) {\n"
     611             :     "  return a + b;\n"
     612             :     "}\n"
     613             :     "function start(timeout) {\n"
     614             :     "  var start = Date.now();\n"
     615             :     "  do {\n"
     616             :     "    for (var i = 1; i < 1000; ++i) foo(1, i);\n"
     617             :     "    var duration = Date.now() - start;\n"
     618             :     "  } while (duration < timeout);\n"
     619             :     "  return duration;\n"
     620             :     "}\n";
     621             : 
     622             : // Check that the profile tree for the script above will look like the
     623             : // following:
     624             : //
     625             : // [Top down]:
     626             : //  1062     0  (root) [-1]
     627             : //  1054     0    start [-1]
     628             : //  1054     1      foo [-1]
     629             : //     2     2    (program) [-1]
     630             : //     6     6    (garbage collector) [-1]
     631             : //
     632             : // The test checks no FP ranges are present in a deoptimized function.
     633             : // If 'foo' has no ranges the samples falling into the prologue will miss the
     634             : // 'start' function on the stack, so 'foo' will be attached to the (root).
     635       23718 : TEST(HotDeoptNoFrameEntry) {
     636           0 :   i::FLAG_allow_natives_syntax = true;
     637           0 :   LocalContext env;
     638           0 :   v8::HandleScope scope(env->GetIsolate());
     639             : 
     640           0 :   CompileRun(hot_deopt_no_frame_entry_test_source);
     641           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     642             : 
     643             :   int32_t profiling_interval_ms = 200;
     644             :   v8::Local<v8::Value> args[] = {
     645           0 :       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
     646           0 :   ProfilerHelper helper(env.local());
     647           0 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
     648           0 :   function->Call(env.local(), env->Global(), arraysize(args), args)
     649           0 :       .ToLocalChecked();
     650             : 
     651           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     652           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     653           0 :   GetChild(env.local(), start_node, "foo");
     654             : 
     655           0 :   profile->Delete();
     656           0 : }
     657             : 
     658       23723 : TEST(CollectCpuProfileSamples) {
     659           5 :   i::FLAG_allow_natives_syntax = true;
     660           5 :   LocalContext env;
     661          10 :   v8::HandleScope scope(env->GetIsolate());
     662             : 
     663           5 :   CompileRun(cpu_profiler_test_source);
     664           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     665             : 
     666             :   int32_t profiling_interval_ms = 200;
     667             :   v8::Local<v8::Value> args[] = {
     668           5 :       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
     669           5 :   ProfilerHelper helper(env.local());
     670             :   v8::CpuProfile* profile =
     671           5 :       helper.Run(function, args, arraysize(args), 1000, 0, true);
     672             : 
     673           5 :   CHECK_LE(200, profile->GetSamplesCount());
     674           5 :   uint64_t end_time = profile->GetEndTime();
     675           5 :   uint64_t current_time = profile->GetStartTime();
     676           5 :   CHECK_LE(current_time, end_time);
     677        7922 :   for (int i = 0; i < profile->GetSamplesCount(); i++) {
     678        7922 :     CHECK(profile->GetSample(i));
     679        7922 :     uint64_t timestamp = profile->GetSampleTimestamp(i);
     680        7922 :     CHECK_LE(current_time, timestamp);
     681        7922 :     CHECK_LE(timestamp, end_time);
     682             :     current_time = timestamp;
     683             :   }
     684             : 
     685          10 :   profile->Delete();
     686           5 : }
     687             : 
     688             : static const char* cpu_profiler_test_source2 =
     689             :     "%NeverOptimizeFunction(loop);\n"
     690             :     "%NeverOptimizeFunction(delay);\n"
     691             :     "%NeverOptimizeFunction(start);\n"
     692             :     "function loop() {}\n"
     693             :     "function delay() { loop(); }\n"
     694             :     "function start(duration) {\n"
     695             :     "  var start = Date.now();\n"
     696             :     "  do {\n"
     697             :     "    for (var i = 0; i < 10000; ++i) delay();\n"
     698             :     "  } while (Date.now() - start < duration);\n"
     699             :     "}";
     700             : 
     701             : // Check that the profile tree doesn't contain unexpected traces:
     702             : //  - 'loop' can be called only by 'delay'
     703             : //  - 'delay' may be called only by 'start'
     704             : // The profile will look like the following:
     705             : //
     706             : // [Top down]:
     707             : //   135     0   (root) [-1] #1
     708             : //   121    72    start [-1] #3
     709             : //    49    33      delay [-1] #4
     710             : //    16    16        loop [-1] #5
     711             : //    14    14    (program) [-1] #2
     712       23718 : TEST(SampleWhenFrameIsNotSetup) {
     713           0 :   i::FLAG_allow_natives_syntax = true;
     714           0 :   LocalContext env;
     715           0 :   v8::HandleScope scope(env->GetIsolate());
     716             : 
     717           0 :   CompileRun(cpu_profiler_test_source2);
     718           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     719             : 
     720             :   int32_t duration_ms = 100;
     721             :   v8::Local<v8::Value> args[] = {
     722           0 :       v8::Integer::New(env->GetIsolate(), duration_ms)};
     723           0 :   ProfilerHelper helper(env.local());
     724           0 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
     725             : 
     726           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     727           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     728             :   const v8::CpuProfileNode* delay_node =
     729           0 :       GetChild(env.local(), start_node, "delay");
     730           0 :   GetChild(env.local(), delay_node, "loop");
     731             : 
     732           0 :   profile->Delete();
     733           0 : }
     734             : 
     735             : static const char* native_accessor_test_source = "function start(count) {\n"
     736             : "  for (var i = 0; i < count; i++) {\n"
     737             : "    var o = instance.foo;\n"
     738             : "    instance.foo = o + 1;\n"
     739             : "  }\n"
     740             : "}\n";
     741             : 
     742             : class TestApiCallbacks {
     743             :  public:
     744             :   explicit TestApiCallbacks(int min_duration_ms)
     745             :       : min_duration_ms_(min_duration_ms),
     746          20 :         is_warming_up_(false) {}
     747             : 
     748         520 :   static void Getter(v8::Local<v8::String> name,
     749             :                      const v8::PropertyCallbackInfo<v8::Value>& info) {
     750             :     TestApiCallbacks* data = FromInfo(info);
     751         520 :     data->Wait();
     752         520 :   }
     753             : 
     754         520 :   static void Setter(v8::Local<v8::String> name,
     755             :                      v8::Local<v8::Value> value,
     756             :                      const v8::PropertyCallbackInfo<void>& info) {
     757             :     TestApiCallbacks* data = FromInfo(info);
     758         520 :     data->Wait();
     759         520 :   }
     760             : 
     761         520 :   static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     762             :     TestApiCallbacks* data = FromInfo(info);
     763         520 :     data->Wait();
     764         520 :   }
     765             : 
     766          20 :   void set_warming_up(bool value) { is_warming_up_ = value; }
     767             : 
     768             :  private:
     769        1560 :   void Wait() {
     770        3120 :     if (is_warming_up_) return;
     771        1515 :     v8::Platform* platform = v8::internal::V8::GetCurrentPlatform();
     772        1515 :     double start = platform->CurrentClockTimeMillis();
     773             :     double duration = 0;
     774       20041 :     while (duration < min_duration_ms_) {
     775       17011 :       v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1));
     776       17011 :       duration = platform->CurrentClockTimeMillis() - start;
     777             :     }
     778             :   }
     779             : 
     780             :   template <typename T>
     781         520 :   static TestApiCallbacks* FromInfo(const T& info) {
     782        1560 :     void* data = v8::External::Cast(*info.Data())->Value();
     783             :     return reinterpret_cast<TestApiCallbacks*>(data);
     784             :   }
     785             : 
     786             :   int min_duration_ms_;
     787             :   bool is_warming_up_;
     788             : };
     789             : 
     790             : 
     791             : // Test that native accessors are properly reported in the CPU profile.
     792             : // This test checks the case when the long-running accessors are called
     793             : // only once and the optimizer doesn't have chance to change the invocation
     794             : // code.
     795       23723 : TEST(NativeAccessorUninitializedIC) {
     796           5 :   LocalContext env;
     797           5 :   v8::Isolate* isolate = env->GetIsolate();
     798          10 :   v8::HandleScope scope(isolate);
     799             : 
     800             :   v8::Local<v8::FunctionTemplate> func_template =
     801           5 :       v8::FunctionTemplate::New(isolate);
     802             :   v8::Local<v8::ObjectTemplate> instance_template =
     803           5 :       func_template->InstanceTemplate();
     804             : 
     805             :   TestApiCallbacks accessors(100);
     806           5 :   v8::Local<v8::External> data = v8::External::New(isolate, &accessors);
     807             :   instance_template->SetAccessor(v8_str("foo"), &TestApiCallbacks::Getter,
     808          10 :                                  &TestApiCallbacks::Setter, data);
     809             :   v8::Local<v8::Function> func =
     810           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
     811             :   v8::Local<v8::Object> instance =
     812           5 :       func->NewInstance(env.local()).ToLocalChecked();
     813          25 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
     814             : 
     815           5 :   CompileRun(native_accessor_test_source);
     816           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     817             : 
     818           5 :   ProfilerHelper helper(env.local());
     819             :   int32_t repeat_count = 1;
     820           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
     821           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 100);
     822             : 
     823           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     824           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     825           5 :   GetChild(env.local(), start_node, "get foo");
     826           5 :   GetChild(env.local(), start_node, "set foo");
     827             : 
     828          10 :   profile->Delete();
     829           5 : }
     830             : 
     831             : 
     832             : // Test that native accessors are properly reported in the CPU profile.
     833             : // This test makes sure that the accessors are called enough times to become
     834             : // hot and to trigger optimizations.
     835       23723 : TEST(NativeAccessorMonomorphicIC) {
     836           5 :   LocalContext env;
     837           5 :   v8::Isolate* isolate = env->GetIsolate();
     838          10 :   v8::HandleScope scope(isolate);
     839             : 
     840             :   v8::Local<v8::FunctionTemplate> func_template =
     841           5 :       v8::FunctionTemplate::New(isolate);
     842             :   v8::Local<v8::ObjectTemplate> instance_template =
     843           5 :       func_template->InstanceTemplate();
     844             : 
     845             :   TestApiCallbacks accessors(1);
     846             :   v8::Local<v8::External> data =
     847           5 :       v8::External::New(isolate, &accessors);
     848             :   instance_template->SetAccessor(v8_str("foo"), &TestApiCallbacks::Getter,
     849          10 :                                  &TestApiCallbacks::Setter, data);
     850             :   v8::Local<v8::Function> func =
     851           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
     852             :   v8::Local<v8::Object> instance =
     853           5 :       func->NewInstance(env.local()).ToLocalChecked();
     854          25 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
     855             : 
     856           5 :   CompileRun(native_accessor_test_source);
     857           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     858             : 
     859             :   {
     860             :     // Make sure accessors ICs are in monomorphic state before starting
     861             :     // profiling.
     862             :     accessors.set_warming_up(true);
     863             :     int32_t warm_up_iterations = 3;
     864             :     v8::Local<v8::Value> args[] = {
     865           5 :         v8::Integer::New(isolate, warm_up_iterations)};
     866          15 :     function->Call(env.local(), env->Global(), arraysize(args), args)
     867           5 :         .ToLocalChecked();
     868             :     accessors.set_warming_up(false);
     869             :   }
     870             : 
     871             :   int32_t repeat_count = 100;
     872           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
     873           5 :   ProfilerHelper helper(env.local());
     874           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 100);
     875             : 
     876           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     877           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     878           5 :   GetChild(env.local(), start_node, "get foo");
     879           5 :   GetChild(env.local(), start_node, "set foo");
     880             : 
     881          10 :   profile->Delete();
     882           5 : }
     883             : 
     884             : 
     885             : static const char* native_method_test_source = "function start(count) {\n"
     886             : "  for (var i = 0; i < count; i++) {\n"
     887             : "    instance.fooMethod();\n"
     888             : "  }\n"
     889             : "}\n";
     890             : 
     891             : 
     892       23723 : TEST(NativeMethodUninitializedIC) {
     893           5 :   LocalContext env;
     894           5 :   v8::Isolate* isolate = env->GetIsolate();
     895          10 :   v8::HandleScope scope(isolate);
     896             : 
     897             :   TestApiCallbacks callbacks(100);
     898           5 :   v8::Local<v8::External> data = v8::External::New(isolate, &callbacks);
     899             : 
     900             :   v8::Local<v8::FunctionTemplate> func_template =
     901           5 :       v8::FunctionTemplate::New(isolate);
     902           5 :   func_template->SetClassName(v8_str("Test_InstanceConstructor"));
     903             :   v8::Local<v8::ObjectTemplate> proto_template =
     904           5 :       func_template->PrototypeTemplate();
     905             :   v8::Local<v8::Signature> signature =
     906           5 :       v8::Signature::New(isolate, func_template);
     907             :   proto_template->Set(
     908             :       v8_str("fooMethod"),
     909             :       v8::FunctionTemplate::New(isolate, &TestApiCallbacks::Callback, data,
     910          15 :                                 signature, 0));
     911             : 
     912             :   v8::Local<v8::Function> func =
     913           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
     914             :   v8::Local<v8::Object> instance =
     915           5 :       func->NewInstance(env.local()).ToLocalChecked();
     916          25 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
     917             : 
     918           5 :   CompileRun(native_method_test_source);
     919           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     920             : 
     921           5 :   ProfilerHelper helper(env.local());
     922             :   int32_t repeat_count = 1;
     923           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
     924           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 100);
     925             : 
     926           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     927           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     928           5 :   GetChild(env.local(), start_node, "fooMethod");
     929             : 
     930          10 :   profile->Delete();
     931           5 : }
     932             : 
     933             : 
     934       23723 : TEST(NativeMethodMonomorphicIC) {
     935           5 :   LocalContext env;
     936           5 :   v8::Isolate* isolate = env->GetIsolate();
     937          10 :   v8::HandleScope scope(isolate);
     938             : 
     939             :   TestApiCallbacks callbacks(1);
     940             :   v8::Local<v8::External> data =
     941           5 :       v8::External::New(isolate, &callbacks);
     942             : 
     943             :   v8::Local<v8::FunctionTemplate> func_template =
     944           5 :       v8::FunctionTemplate::New(isolate);
     945           5 :   func_template->SetClassName(v8_str("Test_InstanceCostructor"));
     946             :   v8::Local<v8::ObjectTemplate> proto_template =
     947           5 :       func_template->PrototypeTemplate();
     948             :   v8::Local<v8::Signature> signature =
     949           5 :       v8::Signature::New(isolate, func_template);
     950             :   proto_template->Set(
     951             :       v8_str("fooMethod"),
     952             :       v8::FunctionTemplate::New(isolate, &TestApiCallbacks::Callback, data,
     953          15 :                                 signature, 0));
     954             : 
     955             :   v8::Local<v8::Function> func =
     956           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
     957             :   v8::Local<v8::Object> instance =
     958           5 :       func->NewInstance(env.local()).ToLocalChecked();
     959          25 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
     960             : 
     961           5 :   CompileRun(native_method_test_source);
     962           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     963             :   {
     964             :     // Make sure method ICs are in monomorphic state before starting
     965             :     // profiling.
     966             :     callbacks.set_warming_up(true);
     967             :     int32_t warm_up_iterations = 3;
     968             :     v8::Local<v8::Value> args[] = {
     969           5 :         v8::Integer::New(isolate, warm_up_iterations)};
     970          15 :     function->Call(env.local(), env->Global(), arraysize(args), args)
     971           5 :         .ToLocalChecked();
     972             :     callbacks.set_warming_up(false);
     973             :   }
     974             : 
     975           5 :   ProfilerHelper helper(env.local());
     976             :   int32_t repeat_count = 100;
     977           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
     978           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 200);
     979             : 
     980           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     981           5 :   GetChild(env.local(), root, "start");
     982           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     983           5 :   GetChild(env.local(), start_node, "fooMethod");
     984             : 
     985          10 :   profile->Delete();
     986           5 : }
     987             : 
     988             : 
     989             : static const char* bound_function_test_source =
     990             :     "function foo() {\n"
     991             :     "  startProfiling('my_profile');\n"
     992             :     "}\n"
     993             :     "function start() {\n"
     994             :     "  var callback = foo.bind(this);\n"
     995             :     "  callback();\n"
     996             :     "}";
     997             : 
     998             : 
     999       23723 : TEST(BoundFunctionCall) {
    1000           5 :   v8::HandleScope scope(CcTest::isolate());
    1001           5 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1002             :   v8::Context::Scope context_scope(env);
    1003             : 
    1004           5 :   CompileRun(bound_function_test_source);
    1005           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1006             : 
    1007           5 :   ProfilerHelper helper(env);
    1008           5 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0);
    1009             : 
    1010           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1011             : 
    1012           5 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1013           5 :   GetChild(env, start_node, "foo");
    1014             : 
    1015          10 :   profile->Delete();
    1016           5 : }
    1017             : 
    1018             : // This tests checks distribution of the samples through the source lines.
    1019          10 : static void TickLines(bool optimize) {
    1020          10 :   if (!optimize) i::FLAG_opt = false;
    1021          10 :   CcTest::InitializeVM();
    1022          10 :   LocalContext env;
    1023          10 :   i::FLAG_allow_natives_syntax = true;
    1024             :   i::Isolate* isolate = CcTest::i_isolate();
    1025             :   i::Factory* factory = isolate->factory();
    1026             :   i::HandleScope scope(isolate);
    1027             : 
    1028             :   i::EmbeddedVector<char, 512> script;
    1029             :   i::EmbeddedVector<char, 64> optimize_call;
    1030             : 
    1031             :   const char* func_name = "func";
    1032          10 :   if (optimize) {
    1033             :     i::SNPrintF(optimize_call, "%%OptimizeFunctionOnNextCall(%s);\n",
    1034           5 :                 func_name);
    1035             :   } else {
    1036           5 :     optimize_call[0] = '\0';
    1037             :   }
    1038             :   i::SNPrintF(script,
    1039             :               "function %s() {\n"
    1040             :               "  var n = 0;\n"
    1041             :               "  var m = 100*100;\n"
    1042             :               "  while (m > 1) {\n"
    1043             :               "    m--;\n"
    1044             :               "    n += m * m * m;\n"
    1045             :               "  }\n"
    1046             :               "}\n"
    1047             :               "%s();\n"
    1048             :               "%s"
    1049             :               "%s();\n",
    1050          10 :               func_name, func_name, optimize_call.start(), func_name);
    1051             : 
    1052          10 :   CompileRun(script.start());
    1053             : 
    1054             :   i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
    1055          20 :       v8::Utils::OpenHandle(*GetFunction(env.local(), func_name)));
    1056          10 :   CHECK(func->shared());
    1057          10 :   CHECK(func->shared()->abstract_code());
    1058          16 :   CHECK(!optimize || func->IsOptimized() ||
    1059             :         !CcTest::i_isolate()->use_optimizer());
    1060          10 :   i::AbstractCode* code = func->abstract_code();
    1061          10 :   CHECK(code);
    1062          10 :   i::Address code_address = code->instruction_start();
    1063          10 :   CHECK(code_address);
    1064             : 
    1065          10 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
    1066          10 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
    1067             :   ProfilerEventsProcessor* processor =
    1068             :       new ProfilerEventsProcessor(CcTest::i_isolate(), generator,
    1069          10 :                                   v8::base::TimeDelta::FromMicroseconds(100));
    1070          20 :   CpuProfiler profiler(isolate, profiles, generator, processor);
    1071          10 :   profiles->StartProfiling("", false);
    1072          10 :   processor->Start();
    1073          20 :   ProfilerListener profiler_listener(isolate);
    1074          10 :   isolate->code_event_dispatcher()->AddListener(&profiler_listener);
    1075          10 :   profiler_listener.AddObserver(&profiler);
    1076             : 
    1077             :   // Enqueue code creation events.
    1078          10 :   i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
    1079             :   int line = 1;
    1080             :   int column = 1;
    1081             :   profiler_listener.CodeCreateEvent(i::Logger::FUNCTION_TAG, code,
    1082          10 :                                     func->shared(), *str, line, column);
    1083             : 
    1084             :   // Enqueue a tick event to enable code events processing.
    1085          10 :   EnqueueTickSampleEvent(processor, code_address);
    1086             : 
    1087          10 :   profiler_listener.RemoveObserver(&profiler);
    1088          10 :   isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
    1089          10 :   processor->StopSynchronously();
    1090             : 
    1091          10 :   CpuProfile* profile = profiles->StopProfiling("");
    1092          10 :   CHECK(profile);
    1093             : 
    1094             :   // Check the state of profile generator.
    1095          30 :   CodeEntry* func_entry = generator->code_map()->FindEntry(code_address);
    1096          10 :   CHECK(func_entry);
    1097          10 :   CHECK_EQ(0, strcmp(func_name, func_entry->name()));
    1098             :   const i::JITLineInfoTable* line_info = func_entry->line_info();
    1099          10 :   CHECK(line_info);
    1100          10 :   CHECK(!line_info->empty());
    1101             : 
    1102             :   // Check the hit source lines using V8 Public APIs.
    1103          10 :   const i::ProfileTree* tree = profile->top_down();
    1104             :   ProfileNode* root = tree->root();
    1105          10 :   CHECK(root);
    1106          10 :   ProfileNode* func_node = root->FindChild(func_entry);
    1107          10 :   CHECK(func_node);
    1108             : 
    1109             :   // Add 10 faked ticks to source line #5.
    1110             :   int hit_line = 5;
    1111             :   int hit_count = 10;
    1112         100 :   for (int i = 0; i < hit_count; i++) func_node->IncrementLineTicks(hit_line);
    1113             : 
    1114             :   unsigned int line_count = func_node->GetHitLineCount();
    1115          10 :   CHECK_EQ(2u, line_count);  // Expect two hit source lines - #1 and #5.
    1116          10 :   ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count);
    1117          10 :   CHECK(func_node->GetLineTicks(&entries[0], line_count));
    1118             :   int value = 0;
    1119          10 :   for (int i = 0; i < entries.length(); i++)
    1120          40 :     if (entries[i].line == hit_line) {
    1121          10 :       value = entries[i].hit_count;
    1122          10 :       break;
    1123             :     }
    1124          20 :   CHECK_EQ(hit_count, value);
    1125          10 : }
    1126             : 
    1127       23723 : TEST(TickLinesBaseline) { TickLines(false); }
    1128             : 
    1129       23723 : TEST(TickLinesOptimized) { TickLines(true); }
    1130             : 
    1131             : static const char* call_function_test_source =
    1132             :     "%NeverOptimizeFunction(bar);\n"
    1133             :     "%NeverOptimizeFunction(start);\n"
    1134             :     "function bar(n) {\n"
    1135             :     "  var s = 0;\n"
    1136             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1137             :     "  return s;\n"
    1138             :     "}\n"
    1139             :     "function start(duration) {\n"
    1140             :     "  var start = Date.now();\n"
    1141             :     "  do {\n"
    1142             :     "    for (var i = 0; i < 100; ++i)\n"
    1143             :     "      bar.call(this, 1000);\n"
    1144             :     "  } while (Date.now() - start < duration);\n"
    1145             :     "}";
    1146             : 
    1147             : // Test that if we sampled thread when it was inside FunctionCall buitin then
    1148             : // its caller frame will be '(unresolved function)' as we have no reliable way
    1149             : // to resolve it.
    1150             : //
    1151             : // [Top down]:
    1152             : //    96     0   (root) [-1] #1
    1153             : //     1     1    (garbage collector) [-1] #4
    1154             : //     5     0    (unresolved function) [-1] #5
    1155             : //     5     5      call [-1] #6
    1156             : //    71    70    start [-1] #3
    1157             : //     1     1      bar [-1] #7
    1158             : //    19    19    (program) [-1] #2
    1159       23723 : TEST(FunctionCallSample) {
    1160           5 :   i::FLAG_allow_natives_syntax = true;
    1161           5 :   LocalContext env;
    1162          10 :   v8::HandleScope scope(env->GetIsolate());
    1163             : 
    1164             :   // Collect garbage that might have be generated while installing
    1165             :   // extensions.
    1166           5 :   CcTest::CollectAllGarbage();
    1167             : 
    1168           5 :   CompileRun(call_function_test_source);
    1169           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    1170             : 
    1171           5 :   ProfilerHelper helper(env.local());
    1172             :   int32_t duration_ms = 100;
    1173             :   v8::Local<v8::Value> args[] = {
    1174           5 :       v8::Integer::New(env->GetIsolate(), duration_ms)};
    1175           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
    1176             : 
    1177           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1178           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
    1179           5 :   GetChild(env.local(), start_node, "bar");
    1180             : 
    1181             :   const v8::CpuProfileNode* unresolved_node =
    1182           5 :       FindChild(env.local(), root, i::CodeEntry::kUnresolvedFunctionName);
    1183           5 :   CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "call"));
    1184             : 
    1185          10 :   profile->Delete();
    1186           5 : }
    1187             : 
    1188             : static const char* function_apply_test_source =
    1189             :     "%NeverOptimizeFunction(bar);\n"
    1190             :     "%NeverOptimizeFunction(test);\n"
    1191             :     "%NeverOptimizeFunction(start);\n"
    1192             :     "function bar(n) {\n"
    1193             :     "  var s = 0;\n"
    1194             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1195             :     "  return s;\n"
    1196             :     "}\n"
    1197             :     "function test() {\n"
    1198             :     "  bar.apply(this, [1000]);\n"
    1199             :     "}\n"
    1200             :     "function start(duration) {\n"
    1201             :     "  var start = Date.now();\n"
    1202             :     "  do {\n"
    1203             :     "    for (var i = 0; i < 100; ++i) test();\n"
    1204             :     "  } while (Date.now() - start < duration);\n"
    1205             :     "}";
    1206             : 
    1207             : // [Top down]:
    1208             : //    94     0   (root) [-1] #0 1
    1209             : //     2     2    (garbage collector) [-1] #0 7
    1210             : //    82    49    start [-1] #16 3
    1211             : //     1     0      (unresolved function) [-1] #0 8
    1212             : //     1     1        apply [-1] #0 9
    1213             : //    32    21      test [-1] #16 4
    1214             : //     2     2        bar [-1] #16 6
    1215             : //    10    10    (program) [-1] #0 2
    1216       23718 : TEST(FunctionApplySample) {
    1217           0 :   i::FLAG_allow_natives_syntax = true;
    1218           0 :   LocalContext env;
    1219           0 :   v8::HandleScope scope(env->GetIsolate());
    1220             : 
    1221           0 :   CompileRun(function_apply_test_source);
    1222           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    1223             : 
    1224           0 :   ProfilerHelper helper(env.local());
    1225             :   int32_t duration_ms = 100;
    1226             :   v8::Local<v8::Value> args[] = {
    1227           0 :       v8::Integer::New(env->GetIsolate(), duration_ms)};
    1228           0 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
    1229             : 
    1230           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1231           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
    1232             :   const v8::CpuProfileNode* test_node =
    1233           0 :       GetChild(env.local(), start_node, "test");
    1234           0 :   GetChild(env.local(), test_node, "bar");
    1235             : 
    1236             :   const v8::CpuProfileNode* unresolved_node =
    1237           0 :       FindChild(env.local(), start_node, CodeEntry::kUnresolvedFunctionName);
    1238           0 :   CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "apply"));
    1239             : 
    1240           0 :   profile->Delete();
    1241           0 : }
    1242             : 
    1243             : static const char* cpu_profiler_deep_stack_test_source =
    1244             :     "function foo(n) {\n"
    1245             :     "  if (n)\n"
    1246             :     "    foo(n - 1);\n"
    1247             :     "  else\n"
    1248             :     "    collectSample();\n"
    1249             :     "}\n"
    1250             :     "function start() {\n"
    1251             :     "  startProfiling('my_profile');\n"
    1252             :     "  foo(250);\n"
    1253             :     "}\n";
    1254             : 
    1255             : // Check a deep stack
    1256             : //
    1257             : // [Top down]:
    1258             : //    0  (root) 0 #1
    1259             : //    2    (program) 0 #2
    1260             : //    0    start 21 #3 no reason
    1261             : //    0      foo 21 #4 no reason
    1262             : //    0        foo 21 #5 no reason
    1263             : //                ....
    1264             : //    0          foo 21 #254 no reason
    1265       23718 : TEST(CpuProfileDeepStack) {
    1266           0 :   v8::HandleScope scope(CcTest::isolate());
    1267           0 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1268             :   v8::Context::Scope context_scope(env);
    1269           0 :   ProfilerHelper helper(env);
    1270             : 
    1271           0 :   CompileRun(cpu_profiler_deep_stack_test_source);
    1272           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1273             : 
    1274           0 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
    1275           0 :   function->Call(env, env->Global(), 0, nullptr).ToLocalChecked();
    1276           0 :   v8::CpuProfile* profile = helper.profiler()->StopProfiling(profile_name);
    1277           0 :   CHECK(profile);
    1278             :   // Dump collected profile to have a better diagnostic in case of failure.
    1279           0 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    1280             : 
    1281           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1282           0 :   const v8::CpuProfileNode* node = GetChild(env, root, "start");
    1283           0 :   for (int i = 0; i <= 250; ++i) {
    1284           0 :     node = GetChild(env, node, "foo");
    1285             :   }
    1286           0 :   CHECK(!FindChild(env, node, "foo"));
    1287             : 
    1288           0 :   profile->Delete();
    1289           0 : }
    1290             : 
    1291             : static const char* js_native_js_test_source =
    1292             :     "%NeverOptimizeFunction(foo);\n"
    1293             :     "%NeverOptimizeFunction(bar);\n"
    1294             :     "%NeverOptimizeFunction(start);\n"
    1295             :     "function foo(n) {\n"
    1296             :     "  var s = 0;\n"
    1297             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1298             :     "  return s;\n"
    1299             :     "}\n"
    1300             :     "function bar() {\n"
    1301             :     "  foo(1000);\n"
    1302             :     "}\n"
    1303             :     "function start() {\n"
    1304             :     "  CallJsFunction(bar);\n"
    1305             :     "}";
    1306             : 
    1307           0 : static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
    1308             :   v8::Local<v8::Function> function = info[0].As<v8::Function>();
    1309           0 :   v8::Local<v8::Value> argv[] = {info[1]};
    1310             :   function->Call(info.GetIsolate()->GetCurrentContext(), info.This(),
    1311           0 :                  arraysize(argv), argv)
    1312           0 :       .ToLocalChecked();
    1313           0 : }
    1314             : 
    1315             : // [Top down]:
    1316             : //    58     0   (root) #0 1
    1317             : //     2     2    (program) #0 2
    1318             : //    56     1    start #16 3
    1319             : //    55     0      CallJsFunction #0 4
    1320             : //    55     1        bar #16 5
    1321             : //    54    54          foo #16 6
    1322       23718 : TEST(JsNativeJsSample) {
    1323           0 :   i::FLAG_allow_natives_syntax = true;
    1324           0 :   v8::HandleScope scope(CcTest::isolate());
    1325           0 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1326             :   v8::Context::Scope context_scope(env);
    1327             : 
    1328             :   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
    1329           0 :       env->GetIsolate(), CallJsFunction);
    1330             :   v8::Local<v8::Function> func =
    1331           0 :       func_template->GetFunction(env).ToLocalChecked();
    1332           0 :   func->SetName(v8_str("CallJsFunction"));
    1333           0 :   env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
    1334             : 
    1335           0 :   CompileRun(js_native_js_test_source);
    1336           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1337             : 
    1338           0 :   ProfilerHelper helper(env);
    1339           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 1000);
    1340             : 
    1341           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1342           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1343             :   const v8::CpuProfileNode* native_node =
    1344           0 :       GetChild(env, start_node, "CallJsFunction");
    1345           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
    1346           0 :   GetChild(env, bar_node, "foo");
    1347             : 
    1348           0 :   profile->Delete();
    1349           0 : }
    1350             : 
    1351             : static const char* js_native_js_runtime_js_test_source =
    1352             :     "%NeverOptimizeFunction(foo);\n"
    1353             :     "%NeverOptimizeFunction(bar);\n"
    1354             :     "%NeverOptimizeFunction(start);\n"
    1355             :     "function foo(n) {\n"
    1356             :     "  var s = 0;\n"
    1357             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1358             :     "  return s;\n"
    1359             :     "}\n"
    1360             :     "var bound = foo.bind(this);\n"
    1361             :     "function bar() {\n"
    1362             :     "  bound(1000);\n"
    1363             :     "}\n"
    1364             :     "function start() {\n"
    1365             :     "  CallJsFunction(bar);\n"
    1366             :     "}";
    1367             : 
    1368             : // [Top down]:
    1369             : //    57     0   (root) #0 1
    1370             : //    55     1    start #16 3
    1371             : //    54     0      CallJsFunction #0 4
    1372             : //    54     3        bar #16 5
    1373             : //    51    51          foo #16 6
    1374             : //     2     2    (program) #0 2
    1375       23718 : TEST(JsNativeJsRuntimeJsSample) {
    1376           0 :   i::FLAG_allow_natives_syntax = true;
    1377           0 :   v8::HandleScope scope(CcTest::isolate());
    1378           0 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1379             :   v8::Context::Scope context_scope(env);
    1380             : 
    1381             :   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
    1382           0 :       env->GetIsolate(), CallJsFunction);
    1383             :   v8::Local<v8::Function> func =
    1384           0 :       func_template->GetFunction(env).ToLocalChecked();
    1385           0 :   func->SetName(v8_str("CallJsFunction"));
    1386           0 :   env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
    1387             : 
    1388           0 :   CompileRun(js_native_js_runtime_js_test_source);
    1389           0 :   ProfilerHelper helper(env);
    1390           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1391           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 1000);
    1392             : 
    1393           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1394           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1395             :   const v8::CpuProfileNode* native_node =
    1396           0 :       GetChild(env, start_node, "CallJsFunction");
    1397           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
    1398           0 :   GetChild(env, bar_node, "foo");
    1399             : 
    1400           0 :   profile->Delete();
    1401           0 : }
    1402             : 
    1403           0 : static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) {
    1404           0 :   v8::base::OS::Print("In CallJsFunction2\n");
    1405           0 :   CallJsFunction(info);
    1406           0 : }
    1407             : 
    1408             : static const char* js_native1_js_native2_js_test_source =
    1409             :     "%NeverOptimizeFunction(foo);\n"
    1410             :     "%NeverOptimizeFunction(bar);\n"
    1411             :     "%NeverOptimizeFunction(start);\n"
    1412             :     "function foo() {\n"
    1413             :     "  var s = 0;\n"
    1414             :     "  for (var i = 0; i < 1000; i++) s += i * i * i;\n"
    1415             :     "  return s;\n"
    1416             :     "}\n"
    1417             :     "function bar() {\n"
    1418             :     "  CallJsFunction2(foo);\n"
    1419             :     "}\n"
    1420             :     "function start() {\n"
    1421             :     "  CallJsFunction1(bar);\n"
    1422             :     "}";
    1423             : 
    1424             : // [Top down]:
    1425             : //    57     0   (root) #0 1
    1426             : //    55     1    start #16 3
    1427             : //    54     0      CallJsFunction1 #0 4
    1428             : //    54     0        bar #16 5
    1429             : //    54     0          CallJsFunction2 #0 6
    1430             : //    54    54            foo #16 7
    1431             : //     2     2    (program) #0 2
    1432       23718 : TEST(JsNative1JsNative2JsSample) {
    1433           0 :   i::FLAG_allow_natives_syntax = true;
    1434           0 :   v8::HandleScope scope(CcTest::isolate());
    1435           0 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1436             :   v8::Context::Scope context_scope(env);
    1437             : 
    1438             :   v8::Local<v8::Function> func1 =
    1439           0 :       v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction)
    1440           0 :           ->GetFunction(env)
    1441           0 :           .ToLocalChecked();
    1442           0 :   func1->SetName(v8_str("CallJsFunction1"));
    1443           0 :   env->Global()->Set(env, v8_str("CallJsFunction1"), func1).FromJust();
    1444             : 
    1445             :   v8::Local<v8::Function> func2 =
    1446           0 :       v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction2)
    1447           0 :           ->GetFunction(env)
    1448           0 :           .ToLocalChecked();
    1449           0 :   func2->SetName(v8_str("CallJsFunction2"));
    1450           0 :   env->Global()->Set(env, v8_str("CallJsFunction2"), func2).FromJust();
    1451             : 
    1452           0 :   CompileRun(js_native1_js_native2_js_test_source);
    1453             : 
    1454           0 :   ProfilerHelper helper(env);
    1455           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1456           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 1000);
    1457             : 
    1458           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1459           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1460             :   const v8::CpuProfileNode* native_node1 =
    1461           0 :       GetChild(env, start_node, "CallJsFunction1");
    1462           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node1, "bar");
    1463             :   const v8::CpuProfileNode* native_node2 =
    1464           0 :       GetChild(env, bar_node, "CallJsFunction2");
    1465           0 :   GetChild(env, native_node2, "foo");
    1466             : 
    1467           0 :   profile->Delete();
    1468           0 : }
    1469             : 
    1470             : static const char* js_force_collect_sample_source =
    1471             :     "function start() {\n"
    1472             :     "  CallCollectSample();\n"
    1473             :     "}";
    1474             : 
    1475           5 : static void CallCollectSample(const v8::FunctionCallbackInfo<v8::Value>& info) {
    1476           5 :   i::ProfilerExtension::profiler()->CollectSample();
    1477           5 : }
    1478             : 
    1479       23723 : TEST(CollectSampleAPI) {
    1480           5 :   v8::HandleScope scope(CcTest::isolate());
    1481           5 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1482             :   v8::Context::Scope context_scope(env);
    1483             : 
    1484             :   v8::Local<v8::FunctionTemplate> func_template =
    1485           5 :       v8::FunctionTemplate::New(env->GetIsolate(), CallCollectSample);
    1486             :   v8::Local<v8::Function> func =
    1487           5 :       func_template->GetFunction(env).ToLocalChecked();
    1488           5 :   func->SetName(v8_str("CallCollectSample"));
    1489          20 :   env->Global()->Set(env, v8_str("CallCollectSample"), func).FromJust();
    1490             : 
    1491           5 :   CompileRun(js_force_collect_sample_source);
    1492           5 :   ProfilerHelper helper(env);
    1493           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1494           5 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 0);
    1495             : 
    1496           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1497           5 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1498           5 :   CHECK_LE(1, start_node->GetChildrenCount());
    1499           5 :   GetChild(env, start_node, "CallCollectSample");
    1500             : 
    1501          10 :   profile->Delete();
    1502           5 : }
    1503             : 
    1504             : static const char* js_native_js_runtime_multiple_test_source =
    1505             :     "%NeverOptimizeFunction(foo);\n"
    1506             :     "%NeverOptimizeFunction(bar);\n"
    1507             :     "%NeverOptimizeFunction(start);\n"
    1508             :     "function foo() {\n"
    1509             :     "  return Math.sin(Math.random());\n"
    1510             :     "}\n"
    1511             :     "var bound = foo.bind(this);\n"
    1512             :     "function bar() {\n"
    1513             :     "  return bound();\n"
    1514             :     "}\n"
    1515             :     "function start() {\n"
    1516             :     "  startProfiling('my_profile');\n"
    1517             :     "  var startTime = Date.now();\n"
    1518             :     "  do {\n"
    1519             :     "    CallJsFunction(bar);\n"
    1520             :     "  } while (Date.now() - startTime < 200);\n"
    1521             :     "}";
    1522             : 
    1523             : // The test check multiple entrances/exits between JS and native code.
    1524             : //
    1525             : // [Top down]:
    1526             : //    (root) #0 1
    1527             : //      start #16 3
    1528             : //        CallJsFunction #0 4
    1529             : //          bar #16 5
    1530             : //            foo #16 6
    1531             : //      (program) #0 2
    1532       23718 : TEST(JsNativeJsRuntimeJsSampleMultiple) {
    1533           0 :   i::FLAG_allow_natives_syntax = true;
    1534           0 :   v8::HandleScope scope(CcTest::isolate());
    1535           0 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1536             :   v8::Context::Scope context_scope(env);
    1537             : 
    1538             :   v8::Local<v8::FunctionTemplate> func_template =
    1539           0 :       v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction);
    1540             :   v8::Local<v8::Function> func =
    1541           0 :       func_template->GetFunction(env).ToLocalChecked();
    1542           0 :   func->SetName(v8_str("CallJsFunction"));
    1543           0 :   env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
    1544             : 
    1545           0 :   CompileRun(js_native_js_runtime_multiple_test_source);
    1546             : 
    1547           0 :   ProfilerHelper helper(env);
    1548           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1549           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 500, 500);
    1550             : 
    1551           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1552           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1553             :   const v8::CpuProfileNode* native_node =
    1554           0 :       GetChild(env, start_node, "CallJsFunction");
    1555           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
    1556           0 :   GetChild(env, bar_node, "foo");
    1557             : 
    1558           0 :   profile->Delete();
    1559           0 : }
    1560             : 
    1561             : static const char* inlining_test_source =
    1562             :     "%NeverOptimizeFunction(action);\n"
    1563             :     "%NeverOptimizeFunction(start);\n"
    1564             :     "level1()\n"
    1565             :     "%OptimizeFunctionOnNextCall(level1);\n"
    1566             :     "%OptimizeFunctionOnNextCall(level2);\n"
    1567             :     "%OptimizeFunctionOnNextCall(level3);\n"
    1568             :     "var finish = false;\n"
    1569             :     "function action(n) {\n"
    1570             :     "  var s = 0;\n"
    1571             :     "  for (var i = 0; i < n; ++i) s += i*i*i;\n"
    1572             :     "  if (finish)\n"
    1573             :     "    startProfiling('my_profile');\n"
    1574             :     "  return s;\n"
    1575             :     "}\n"
    1576             :     "function level3() { return action(100); }\n"
    1577             :     "function level2() { return level3() * 2; }\n"
    1578             :     "function level1() { return level2(); }\n"
    1579             :     "function start() {\n"
    1580             :     "  var n = 100;\n"
    1581             :     "  while (--n)\n"
    1582             :     "    level1();\n"
    1583             :     "  finish = true;\n"
    1584             :     "  level1();\n"
    1585             :     "}";
    1586             : 
    1587             : // The test check multiple entrances/exits between JS and native code.
    1588             : //
    1589             : // [Top down]:
    1590             : //    (root) #0 1
    1591             : //      start #16 3
    1592             : //        level1 #0 4
    1593             : //          level2 #16 5
    1594             : //            level3 #16 6
    1595             : //              action #16 7
    1596             : //      (program) #0 2
    1597       23723 : TEST(Inlining) {
    1598           5 :   i::FLAG_allow_natives_syntax = true;
    1599           5 :   v8::HandleScope scope(CcTest::isolate());
    1600           5 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1601             :   v8::Context::Scope context_scope(env);
    1602           5 :   ProfilerHelper helper(env);
    1603             : 
    1604           5 :   CompileRun(inlining_test_source);
    1605           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1606             : 
    1607           5 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
    1608          15 :   function->Call(env, env->Global(), 0, nullptr).ToLocalChecked();
    1609           5 :   v8::CpuProfile* profile = helper.profiler()->StopProfiling(profile_name);
    1610           5 :   CHECK(profile);
    1611             :   // Dump collected profile to have a better diagnostic in case of failure.
    1612           5 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    1613             : 
    1614           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1615           5 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1616           5 :   const v8::CpuProfileNode* level1_node = GetChild(env, start_node, "level1");
    1617           5 :   const v8::CpuProfileNode* level2_node = GetChild(env, level1_node, "level2");
    1618           5 :   const v8::CpuProfileNode* level3_node = GetChild(env, level2_node, "level3");
    1619           5 :   GetChild(env, level3_node, "action");
    1620             : 
    1621          10 :   profile->Delete();
    1622           5 : }
    1623             : 
    1624             : // [Top down]:
    1625             : //     0   (root) #0 1
    1626             : //     2    (program) #0 2
    1627             : //     3    (idle) #0 3
    1628       23723 : TEST(IdleTime) {
    1629           5 :   LocalContext env;
    1630          10 :   v8::HandleScope scope(env->GetIsolate());
    1631           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
    1632             : 
    1633           5 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
    1634           5 :   cpu_profiler->StartProfiling(profile_name);
    1635             : 
    1636             :   i::Isolate* isolate = CcTest::i_isolate();
    1637             :   i::ProfilerEventsProcessor* processor =
    1638             :       reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->processor();
    1639             : 
    1640           5 :   processor->AddCurrentStack(isolate, true);
    1641           5 :   cpu_profiler->SetIdle(true);
    1642          20 :   for (int i = 0; i < 3; i++) {
    1643          15 :     processor->AddCurrentStack(isolate, true);
    1644             :   }
    1645           5 :   cpu_profiler->SetIdle(false);
    1646           5 :   processor->AddCurrentStack(isolate, true);
    1647             : 
    1648           5 :   v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
    1649           5 :   CHECK(profile);
    1650             :   // Dump collected profile to have a better diagnostic in case of failure.
    1651           5 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    1652             : 
    1653           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1654             :   const v8::CpuProfileNode* program_node =
    1655           5 :       GetChild(env.local(), root, CodeEntry::kProgramEntryName);
    1656           5 :   CHECK_EQ(0, program_node->GetChildrenCount());
    1657           5 :   CHECK_GE(program_node->GetHitCount(), 2u);
    1658             : 
    1659             :   const v8::CpuProfileNode* idle_node =
    1660           5 :       GetChild(env.local(), root, CodeEntry::kIdleEntryName);
    1661           5 :   CHECK_EQ(0, idle_node->GetChildrenCount());
    1662           5 :   CHECK_GE(idle_node->GetHitCount(), 3u);
    1663             : 
    1664           5 :   profile->Delete();
    1665          10 :   cpu_profiler->Dispose();
    1666           5 : }
    1667             : 
    1668          20 : static void CheckFunctionDetails(v8::Isolate* isolate,
    1669             :                                  const v8::CpuProfileNode* node,
    1670             :                                  const char* name, const char* script_name,
    1671             :                                  int script_id, int line, int column) {
    1672          20 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
    1673          80 :   CHECK(v8_str(name)->Equals(context, node->GetFunctionName()).FromJust());
    1674          20 :   CHECK_EQ(0, strcmp(name, node->GetFunctionNameStr()));
    1675          80 :   CHECK(v8_str(script_name)
    1676             :             ->Equals(context, node->GetScriptResourceName())
    1677             :             .FromJust());
    1678          20 :   CHECK_EQ(0, strcmp(script_name, node->GetScriptResourceNameStr()));
    1679          20 :   CHECK_EQ(script_id, node->GetScriptId());
    1680          20 :   CHECK_EQ(line, node->GetLineNumber());
    1681          20 :   CHECK_EQ(column, node->GetColumnNumber());
    1682          20 : }
    1683             : 
    1684             : 
    1685       23723 : TEST(FunctionDetails) {
    1686           5 :   i::FLAG_allow_natives_syntax = true;
    1687           5 :   v8::HandleScope scope(CcTest::isolate());
    1688           5 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1689             :   v8::Context::Scope context_scope(env);
    1690           5 :   ProfilerHelper helper(env);
    1691             : 
    1692             :   v8::Local<v8::Script> script_a = CompileWithOrigin(
    1693             :       "%NeverOptimizeFunction(foo);\n"
    1694             :       "%NeverOptimizeFunction(bar);\n"
    1695             :       "    function foo\n() { bar(); }\n"
    1696             :       " function bar() { startProfiling(); }\n",
    1697           5 :       "script_a");
    1698           5 :   script_a->Run(env).ToLocalChecked();
    1699             :   v8::Local<v8::Script> script_b = CompileWithOrigin(
    1700             :       "%NeverOptimizeFunction(baz);"
    1701             :       "\n\n   function baz() { foo(); }\n"
    1702             :       "\n\nbaz();\n"
    1703             :       "stopProfiling();\n",
    1704           5 :       "script_b");
    1705           5 :   script_b->Run(env).ToLocalChecked();
    1706           5 :   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
    1707           5 :   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
    1708             :   reinterpret_cast<ProfileNode*>(
    1709           5 :       const_cast<v8::CpuProfileNode*>(current))->Print(0);
    1710             :   // The tree should look like this:
    1711             :   //  0   (root) 0 #1
    1712             :   //  0    "" 19 #2 no reason script_b:1
    1713             :   //  0      baz 19 #3 TryCatchStatement script_b:3
    1714             :   //  0        foo 18 #4 TryCatchStatement script_a:2
    1715             :   //  1          bar 18 #5 no reason script_a:3
    1716           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1717           5 :   const v8::CpuProfileNode* script = GetChild(env, root, "");
    1718             :   CheckFunctionDetails(env->GetIsolate(), script, "", "script_b",
    1719          15 :                        script_b->GetUnboundScript()->GetId(), 1, 1);
    1720           5 :   const v8::CpuProfileNode* baz = GetChild(env, script, "baz");
    1721             :   CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b",
    1722          15 :                        script_b->GetUnboundScript()->GetId(), 3, 16);
    1723           5 :   const v8::CpuProfileNode* foo = GetChild(env, baz, "foo");
    1724             :   CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a",
    1725          15 :                        script_a->GetUnboundScript()->GetId(), 4, 1);
    1726           5 :   const v8::CpuProfileNode* bar = GetChild(env, foo, "bar");
    1727             :   CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a",
    1728          20 :                        script_a->GetUnboundScript()->GetId(), 5, 14);
    1729           5 : }
    1730             : 
    1731             : 
    1732       23723 : TEST(DontStopOnFinishedProfileDelete) {
    1733           5 :   v8::HandleScope scope(CcTest::isolate());
    1734           5 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1735             :   v8::Context::Scope context_scope(env);
    1736             : 
    1737           5 :   v8::CpuProfiler* profiler = v8::CpuProfiler::New(env->GetIsolate());
    1738             :   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
    1739             : 
    1740           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    1741           5 :   v8::Local<v8::String> outer = v8_str("outer");
    1742           5 :   profiler->StartProfiling(outer);
    1743           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    1744             : 
    1745           5 :   v8::Local<v8::String> inner = v8_str("inner");
    1746           5 :   profiler->StartProfiling(inner);
    1747           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    1748             : 
    1749           5 :   v8::CpuProfile* inner_profile = profiler->StopProfiling(inner);
    1750           5 :   CHECK(inner_profile);
    1751           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
    1752           5 :   inner_profile->Delete();
    1753             :   inner_profile = nullptr;
    1754           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    1755             : 
    1756           5 :   v8::CpuProfile* outer_profile = profiler->StopProfiling(outer);
    1757           5 :   CHECK(outer_profile);
    1758           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
    1759           5 :   outer_profile->Delete();
    1760             :   outer_profile = nullptr;
    1761           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    1762          10 :   profiler->Dispose();
    1763           5 : }
    1764             : 
    1765             : 
    1766           0 : const char* GetBranchDeoptReason(v8::Local<v8::Context> context,
    1767             :                                  i::CpuProfile* iprofile, const char* branch[],
    1768             :                                  int length) {
    1769             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    1770             :   const ProfileNode* iopt_function = nullptr;
    1771           0 :   iopt_function = GetSimpleBranch(context, profile, branch, length);
    1772           0 :   CHECK_EQ(1U, iopt_function->deopt_infos().size());
    1773           0 :   return iopt_function->deopt_infos()[0].deopt_reason;
    1774             : }
    1775             : 
    1776             : 
    1777             : // deopt at top function
    1778       23718 : TEST(CollectDeoptEvents) {
    1779           0 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    1780           0 :   i::FLAG_allow_natives_syntax = true;
    1781           0 :   v8::HandleScope scope(CcTest::isolate());
    1782           0 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1783             :   v8::Context::Scope context_scope(env);
    1784           0 :   ProfilerHelper helper(env);
    1785             :   i::CpuProfiler* iprofiler =
    1786           0 :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    1787             : 
    1788             :   const char opt_source[] =
    1789             :       "function opt_function%d(value, depth) {\n"
    1790             :       "  if (depth) return opt_function%d(value, depth - 1);\n"
    1791             :       "\n"
    1792             :       "  return  10 / value;\n"
    1793             :       "}\n"
    1794           0 :       "\n";
    1795             : 
    1796           0 :   for (int i = 0; i < 3; ++i) {
    1797             :     i::EmbeddedVector<char, sizeof(opt_source) + 100> buffer;
    1798           0 :     i::SNPrintF(buffer, opt_source, i, i);
    1799           0 :     v8::Script::Compile(env, v8_str(buffer.start()))
    1800           0 :         .ToLocalChecked()
    1801             :         ->Run(env)
    1802           0 :         .ToLocalChecked();
    1803             :   }
    1804             : 
    1805             :   const char* source =
    1806             :       "startProfiling();\n"
    1807             :       "\n"
    1808             :       "opt_function0(1, 1);\n"
    1809             :       "\n"
    1810             :       "%OptimizeFunctionOnNextCall(opt_function0)\n"
    1811             :       "\n"
    1812             :       "opt_function0(1, 1);\n"
    1813             :       "\n"
    1814             :       "opt_function0(undefined, 1);\n"
    1815             :       "\n"
    1816             :       "opt_function1(1, 1);\n"
    1817             :       "\n"
    1818             :       "%OptimizeFunctionOnNextCall(opt_function1)\n"
    1819             :       "\n"
    1820             :       "opt_function1(1, 1);\n"
    1821             :       "\n"
    1822             :       "opt_function1(NaN, 1);\n"
    1823             :       "\n"
    1824             :       "opt_function2(1, 1);\n"
    1825             :       "\n"
    1826             :       "%OptimizeFunctionOnNextCall(opt_function2)\n"
    1827             :       "\n"
    1828             :       "opt_function2(1, 1);\n"
    1829             :       "\n"
    1830             :       "opt_function2(0, 1);\n"
    1831             :       "\n"
    1832             :       "stopProfiling();\n"
    1833             :       "\n";
    1834             : 
    1835           0 :   v8::Script::Compile(env, v8_str(source))
    1836           0 :       .ToLocalChecked()
    1837             :       ->Run(env)
    1838           0 :       .ToLocalChecked();
    1839           0 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    1840           0 :   iprofile->Print();
    1841             :   /* The expected profile
    1842             :   [Top down]:
    1843             :       0  (root) 0 #1
    1844             :      23     32 #2
    1845             :       1      opt_function2 31 #7
    1846             :       1        opt_function2 31 #8
    1847             :                   ;;; deopted at script_id: 31 position: 106 with reason
    1848             :   'division by zero'.
    1849             :       2      opt_function0 29 #3
    1850             :       4        opt_function0 29 #4
    1851             :                   ;;; deopted at script_id: 29 position: 108 with reason 'not a
    1852             :   heap number'.
    1853             :       0      opt_function1 30 #5
    1854             :       1        opt_function1 30 #6
    1855             :                   ;;; deopted at script_id: 30 position: 108 with reason 'lost
    1856             :   precision or NaN'.
    1857             :   */
    1858             : 
    1859             :   {
    1860           0 :     const char* branch[] = {"", "opt_function0", "opt_function0"};
    1861             :     const char* deopt_reason =
    1862           0 :         GetBranchDeoptReason(env, iprofile, branch, arraysize(branch));
    1863           0 :     if (deopt_reason != reason(i::DeoptimizeReason::kNotAHeapNumber) &&
    1864             :         deopt_reason != reason(i::DeoptimizeReason::kNotASmi)) {
    1865           0 :       FATAL(deopt_reason);
    1866             :     }
    1867             :   }
    1868             :   {
    1869           0 :     const char* branch[] = {"", "opt_function1", "opt_function1"};
    1870             :     const char* deopt_reason =
    1871           0 :         GetBranchDeoptReason(env, iprofile, branch, arraysize(branch));
    1872           0 :     if (deopt_reason != reason(i::DeoptimizeReason::kNaN) &&
    1873           0 :         deopt_reason != reason(i::DeoptimizeReason::kLostPrecisionOrNaN) &&
    1874             :         deopt_reason != reason(i::DeoptimizeReason::kNotASmi)) {
    1875           0 :       FATAL(deopt_reason);
    1876             :     }
    1877             :   }
    1878             :   {
    1879           0 :     const char* branch[] = {"", "opt_function2", "opt_function2"};
    1880           0 :     CHECK_EQ(reason(i::DeoptimizeReason::kDivisionByZero),
    1881             :              GetBranchDeoptReason(env, iprofile, branch, arraysize(branch)));
    1882             :   }
    1883           0 :   iprofiler->DeleteProfile(iprofile);
    1884             : }
    1885             : 
    1886             : 
    1887       23723 : TEST(SourceLocation) {
    1888           5 :   i::FLAG_always_opt = true;
    1889           5 :   LocalContext env;
    1890          10 :   v8::HandleScope scope(CcTest::isolate());
    1891             : 
    1892             :   const char* source =
    1893             :       "function CompareStatementWithThis() {\n"
    1894             :       "  if (this === 1) {}\n"
    1895             :       "}\n"
    1896             :       "CompareStatementWithThis();\n";
    1897             : 
    1898           5 :   v8::Script::Compile(env.local(), v8_str(source))
    1899           5 :       .ToLocalChecked()
    1900           5 :       ->Run(env.local())
    1901          10 :       .ToLocalChecked();
    1902           5 : }
    1903             : 
    1904             : static const char* inlined_source =
    1905             :     "function opt_function(left, right) { var k = left*right; return k + 1; "
    1906             :     "}\n";
    1907             : //   0.........1.........2.........3.........4....*....5.........6......*..7
    1908             : 
    1909             : 
    1910             : // deopt at the first level inlined function
    1911       23723 : TEST(DeoptAtFirstLevelInlinedSource) {
    1912           7 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    1913           3 :   i::FLAG_allow_natives_syntax = true;
    1914           3 :   v8::HandleScope scope(CcTest::isolate());
    1915           3 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1916             :   v8::Context::Scope context_scope(env);
    1917           3 :   ProfilerHelper helper(env);
    1918             :   i::CpuProfiler* iprofiler =
    1919           3 :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    1920             : 
    1921             :   //   0.........1.........2.........3.........4.........5.........6.........7
    1922             :   const char* source =
    1923             :       "function test(left, right) { return opt_function(left, right); }\n"
    1924             :       "\n"
    1925             :       "startProfiling();\n"
    1926             :       "\n"
    1927             :       "test(10, 10);\n"
    1928             :       "\n"
    1929             :       "%OptimizeFunctionOnNextCall(test)\n"
    1930             :       "\n"
    1931             :       "test(10, 10);\n"
    1932             :       "\n"
    1933             :       "test(undefined, 1e9);\n"
    1934             :       "\n"
    1935             :       "stopProfiling();\n"
    1936             :       "\n";
    1937             : 
    1938           3 :   v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
    1939           3 :   inlined_script->Run(env).ToLocalChecked();
    1940           6 :   int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
    1941             : 
    1942             :   v8::Local<v8::Script> script = v8_compile(source);
    1943           3 :   script->Run(env).ToLocalChecked();
    1944           6 :   int script_id = script->GetUnboundScript()->GetId();
    1945             : 
    1946           3 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    1947           3 :   iprofile->Print();
    1948             :   /* The expected profile output
    1949             :   [Top down]:
    1950             :       0  (root) 0 #1
    1951             :      10     30 #2
    1952             :       1      test 30 #3
    1953             :                 ;;; deopted at script_id: 29 position: 45 with reason 'not a
    1954             :   heap number'.
    1955             :                 ;;;     Inline point: script_id 30 position: 36.
    1956             :       4        opt_function 29 #4
    1957             :   */
    1958             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    1959             : 
    1960           3 :   const char* branch[] = {"", "test"};
    1961             :   const ProfileNode* itest_node =
    1962           3 :       GetSimpleBranch(env, profile, branch, arraysize(branch));
    1963           3 :   const std::vector<v8::CpuProfileDeoptInfo>& deopt_infos =
    1964             :       itest_node->deopt_infos();
    1965           3 :   CHECK_EQ(1U, deopt_infos.size());
    1966             : 
    1967             :   const v8::CpuProfileDeoptInfo& info = deopt_infos[0];
    1968           3 :   CHECK(reason(i::DeoptimizeReason::kNotASmi) == info.deopt_reason ||
    1969             :         reason(i::DeoptimizeReason::kNotAHeapNumber) == info.deopt_reason);
    1970           6 :   CHECK_EQ(2U, info.stack.size());
    1971           3 :   CHECK_EQ(inlined_script_id, info.stack[0].script_id);
    1972           6 :   CHECK_LE(dist(offset(inlined_source, "*right"), info.stack[0].position), 1);
    1973           3 :   CHECK_EQ(script_id, info.stack[1].script_id);
    1974           3 :   CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
    1975             : 
    1976           6 :   iprofiler->DeleteProfile(iprofile);
    1977             : }
    1978             : 
    1979             : 
    1980             : // deopt at the second level inlined function
    1981       23723 : TEST(DeoptAtSecondLevelInlinedSource) {
    1982           7 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    1983           3 :   i::FLAG_allow_natives_syntax = true;
    1984           3 :   v8::HandleScope scope(CcTest::isolate());
    1985           3 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    1986             :   v8::Context::Scope context_scope(env);
    1987           3 :   ProfilerHelper helper(env);
    1988             :   i::CpuProfiler* iprofiler =
    1989           3 :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    1990             : 
    1991             :   //   0.........1.........2.........3.........4.........5.........6.........7
    1992             :   const char* source =
    1993             :       "function test2(left, right) { return opt_function(left, right); }\n"
    1994             :       "function test1(left, right) { return test2(left, right); } \n"
    1995             :       "\n"
    1996             :       "startProfiling();\n"
    1997             :       "\n"
    1998             :       "test1(10, 10);\n"
    1999             :       "\n"
    2000             :       "%OptimizeFunctionOnNextCall(test1)\n"
    2001             :       "\n"
    2002             :       "test1(10, 10);\n"
    2003             :       "\n"
    2004             :       "test1(undefined, 1e9);\n"
    2005             :       "\n"
    2006             :       "stopProfiling();\n"
    2007             :       "\n";
    2008             : 
    2009           3 :   v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
    2010           3 :   inlined_script->Run(env).ToLocalChecked();
    2011           6 :   int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
    2012             : 
    2013             :   v8::Local<v8::Script> script = v8_compile(source);
    2014           3 :   script->Run(env).ToLocalChecked();
    2015           6 :   int script_id = script->GetUnboundScript()->GetId();
    2016             : 
    2017           3 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    2018           3 :   iprofile->Print();
    2019             :   /* The expected profile output
    2020             :   [Top down]:
    2021             :       0  (root) 0 #1
    2022             :      11     30 #2
    2023             :       1      test1 30 #3
    2024             :                 ;;; deopted at script_id: 29 position: 45 with reason 'not a
    2025             :   heap number'.
    2026             :                 ;;;     Inline point: script_id 30 position: 37.
    2027             :                 ;;;     Inline point: script_id 30 position: 103.
    2028             :       1        test2 30 #4
    2029             :       3          opt_function 29 #5
    2030             :   */
    2031             : 
    2032             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    2033             : 
    2034           3 :   const char* branch[] = {"", "test1"};
    2035             :   const ProfileNode* itest_node =
    2036           3 :       GetSimpleBranch(env, profile, branch, arraysize(branch));
    2037           3 :   const std::vector<v8::CpuProfileDeoptInfo>& deopt_infos =
    2038             :       itest_node->deopt_infos();
    2039           3 :   CHECK_EQ(1U, deopt_infos.size());
    2040             : 
    2041             :   const v8::CpuProfileDeoptInfo info = deopt_infos[0];
    2042           3 :   CHECK(reason(i::DeoptimizeReason::kNotASmi) == info.deopt_reason ||
    2043             :         reason(i::DeoptimizeReason::kNotAHeapNumber) == info.deopt_reason);
    2044           6 :   CHECK_EQ(3U, info.stack.size());
    2045           3 :   CHECK_EQ(inlined_script_id, info.stack[0].script_id);
    2046           6 :   CHECK_LE(dist(offset(inlined_source, "*right"), info.stack[0].position), 1);
    2047           3 :   CHECK_EQ(script_id, info.stack[1].script_id);
    2048           3 :   CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
    2049           3 :   CHECK_EQ(offset(source, "test2(left, right);"), info.stack[2].position);
    2050             : 
    2051           6 :   iprofiler->DeleteProfile(iprofile);
    2052             : }
    2053             : 
    2054             : 
    2055             : // deopt in untracked function
    2056       23723 : TEST(DeoptUntrackedFunction) {
    2057           7 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    2058           3 :   i::FLAG_allow_natives_syntax = true;
    2059           3 :   v8::HandleScope scope(CcTest::isolate());
    2060           3 :   v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
    2061             :   v8::Context::Scope context_scope(env);
    2062           3 :   ProfilerHelper helper(env);
    2063             :   i::CpuProfiler* iprofiler =
    2064           3 :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    2065             : 
    2066             :   //   0.........1.........2.........3.........4.........5.........6.........7
    2067             :   const char* source =
    2068             :       "function test(left, right) { return opt_function(left, right); }\n"
    2069             :       "\n"
    2070             :       "test(10, 10);\n"
    2071             :       "\n"
    2072             :       "%OptimizeFunctionOnNextCall(test)\n"
    2073             :       "\n"
    2074             :       "test(10, 10);\n"
    2075             :       "\n"
    2076             :       "startProfiling();\n"  // profiler started after compilation.
    2077             :       "\n"
    2078             :       "test(undefined, 10);\n"
    2079             :       "\n"
    2080             :       "stopProfiling();\n"
    2081             :       "\n";
    2082             : 
    2083           3 :   v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
    2084           3 :   inlined_script->Run(env).ToLocalChecked();
    2085             : 
    2086             :   v8::Local<v8::Script> script = v8_compile(source);
    2087           3 :   script->Run(env).ToLocalChecked();
    2088             : 
    2089           3 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    2090           3 :   iprofile->Print();
    2091             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    2092             : 
    2093           3 :   const char* branch[] = {"", "test"};
    2094             :   const ProfileNode* itest_node =
    2095           3 :       GetSimpleBranch(env, profile, branch, arraysize(branch));
    2096           6 :   CHECK_EQ(0U, itest_node->deopt_infos().size());
    2097             : 
    2098           6 :   iprofiler->DeleteProfile(iprofile);
    2099             : }
    2100             : 
    2101             : using v8::platform::tracing::TraceBuffer;
    2102             : using v8::platform::tracing::TraceConfig;
    2103             : using v8::platform::tracing::TraceObject;
    2104             : 
    2105             : namespace {
    2106             : 
    2107          15 : class CpuProfileEventChecker : public v8::platform::tracing::TraceWriter {
    2108             :  public:
    2109          20 :   void AppendTraceEvent(TraceObject* trace_event) override {
    2110          15 :     if (trace_event->name() != std::string("Profile") &&
    2111           5 :         trace_event->name() != std::string("ProfileChunk"))
    2112           5 :       return;
    2113           5 :     CHECK(!profile_id_ || trace_event->id() == profile_id_);
    2114           5 :     CHECK_EQ(1, trace_event->num_args());
    2115           5 :     CHECK_EQ(TRACE_VALUE_TYPE_CONVERTABLE, trace_event->arg_types()[0]);
    2116           5 :     profile_id_ = trace_event->id();
    2117             :     v8::ConvertableToTraceFormat* arg =
    2118             :         trace_event->arg_convertables()[0].get();
    2119           5 :     arg->AppendAsTraceFormat(&result_json_);
    2120             :   }
    2121           5 :   void Flush() override {}
    2122             : 
    2123           5 :   std::string result_json() const { return result_json_; }
    2124             : 
    2125             :  private:
    2126             :   std::string result_json_;
    2127             :   uint64_t profile_id_ = 0;
    2128             : };
    2129             : 
    2130             : }  // namespace
    2131             : 
    2132       23723 : TEST(TracingCpuProfiler) {
    2133           5 :   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
    2134           5 :   v8::Platform* default_platform = v8::platform::CreateDefaultPlatform();
    2135           5 :   i::V8::SetPlatformForTesting(default_platform);
    2136             : 
    2137           5 :   v8::platform::tracing::TracingController tracing_controller;
    2138             :   static_cast<v8::platform::DefaultPlatform*>(default_platform)
    2139           5 :       ->SetTracingController(&tracing_controller);
    2140             : 
    2141           5 :   CpuProfileEventChecker* event_checker = new CpuProfileEventChecker();
    2142             :   TraceBuffer* ring_buffer =
    2143           5 :       TraceBuffer::CreateTraceBufferRingBuffer(1, event_checker);
    2144           5 :   tracing_controller.Initialize(ring_buffer);
    2145           5 :   TraceConfig* trace_config = new TraceConfig();
    2146             :   trace_config->AddIncludedCategory(
    2147           5 :       TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"));
    2148             : 
    2149          10 :   LocalContext env;
    2150          10 :   v8::HandleScope scope(env->GetIsolate());
    2151             :   {
    2152           5 :     tracing_controller.StartTracing(trace_config);
    2153           5 :     auto profiler = v8::TracingCpuProfiler::Create(env->GetIsolate());
    2154             :     CompileRun("function foo() { } foo();");
    2155           5 :     tracing_controller.StopTracing();
    2156             :     CompileRun("function bar() { } bar();");
    2157             :   }
    2158             : 
    2159             :   const char* profile_checker =
    2160             :       "function checkProfile(profile) {\n"
    2161             :       "  if (typeof profile['startTime'] !== 'number') return 'startTime';\n"
    2162             :       "  return '';\n"
    2163             :       "}\n"
    2164             :       "checkProfile(";
    2165             :   std::string profile_json = event_checker->result_json();
    2166           5 :   CHECK_LT(0u, profile_json.length());
    2167             :   printf("Profile JSON: %s\n", profile_json.c_str());
    2168          10 :   std::string code = profile_checker + profile_json + ")";
    2169             :   v8::Local<v8::Value> result =
    2170           5 :       CompileRunChecked(CcTest::isolate(), code.c_str());
    2171          10 :   v8::String::Utf8Value value(CcTest::isolate(), result);
    2172           5 :   printf("Check result: %*s\n", value.length(), *value);
    2173           5 :   CHECK_EQ(0, value.length());
    2174             : 
    2175          10 :   i::V8::SetPlatformForTesting(old_platform);
    2176           5 : }
    2177             : 
    2178       23723 : TEST(Issue763073) {
    2179             :   class AllowNativesSyntax {
    2180             :    public:
    2181             :     AllowNativesSyntax()
    2182             :         : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
    2183           5 :           trace_deopt_(i::FLAG_trace_deopt) {
    2184           5 :       i::FLAG_allow_natives_syntax = true;
    2185           5 :       i::FLAG_trace_deopt = true;
    2186             :     }
    2187             : 
    2188             :     ~AllowNativesSyntax() {
    2189           5 :       i::FLAG_allow_natives_syntax = allow_natives_syntax_;
    2190           5 :       i::FLAG_trace_deopt = trace_deopt_;
    2191             :     }
    2192             : 
    2193             :    private:
    2194             :     bool allow_natives_syntax_;
    2195             :     bool trace_deopt_;
    2196             :   };
    2197             : 
    2198             :   AllowNativesSyntax allow_natives_syntax_scope;
    2199          10 :   LocalContext env;
    2200          10 :   v8::HandleScope scope(env->GetIsolate());
    2201             : 
    2202             :   CompileRun(
    2203             :       "function f() { return function g(x) { }; }"
    2204             :       // Create first closure, optimize it, and deoptimize it.
    2205             :       "var g = f();"
    2206             :       "g(1);"
    2207             :       "%OptimizeFunctionOnNextCall(g);"
    2208             :       "g(1);"
    2209             :       "%DeoptimizeFunction(g);"
    2210             :       // Create second closure, and optimize it. This will create another
    2211             :       // optimized code object and put in the (shared) type feedback vector.
    2212             :       "var h = f();"
    2213             :       "h(1);"
    2214             :       "%OptimizeFunctionOnNextCall(h);"
    2215             :       "h(1);");
    2216             : 
    2217             :   // Start profiling.
    2218           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
    2219           5 :   v8::Local<v8::String> profile_name = v8_str("test");
    2220             : 
    2221             :   // Here we test that the heap iteration upon profiling start is not
    2222             :   // confused by having a deoptimized code object for a closure while
    2223             :   // having a different optimized code object in the type feedback vector.
    2224           5 :   cpu_profiler->StartProfiling(profile_name);
    2225           5 :   v8::CpuProfile* p = cpu_profiler->StopProfiling(profile_name);
    2226           5 :   p->Delete();
    2227           5 :   cpu_profiler->Dispose();
    2228           5 : }
    2229             : 
    2230             : }  // namespace test_cpu_profiler
    2231             : }  // namespace internal
    2232       71154 : }  // namespace v8

Generated by: LCOV version 1.10