LCOV - code coverage report
Current view: top level - test/cctest - test-cpu-profiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 994 1224 81.2 %
Date: 2019-04-17 Functions: 71 91 78.0 %

          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 <limits>
      31             : #include <memory>
      32             : 
      33             : #include "src/v8.h"
      34             : 
      35             : #include "include/v8-profiler.h"
      36             : #include "src/api-inl.h"
      37             : #include "src/base/platform/platform.h"
      38             : #include "src/deoptimizer.h"
      39             : #include "src/libplatform/default-platform.h"
      40             : #include "src/log.h"
      41             : #include "src/objects-inl.h"
      42             : #include "src/profiler/cpu-profiler-inl.h"
      43             : #include "src/profiler/profiler-listener.h"
      44             : #include "src/profiler/tracing-cpu-profiler.h"
      45             : #include "src/source-position-table.h"
      46             : #include "src/utils.h"
      47             : #include "test/cctest/cctest.h"
      48             : #include "test/cctest/profiler-extension.h"
      49             : 
      50             : #include "include/libplatform/v8-tracing.h"
      51             : #include "src/tracing/trace-event.h"
      52             : 
      53             : namespace v8 {
      54             : namespace internal {
      55             : namespace test_cpu_profiler {
      56             : 
      57             : // Helper methods
      58         129 : static v8::Local<v8::Function> GetFunction(v8::Local<v8::Context> env,
      59             :                                            const char* name) {
      60             :   return v8::Local<v8::Function>::Cast(
      61         516 :       env->Global()->Get(env, v8_str(name)).ToLocalChecked());
      62             : }
      63             : 
      64           9 : static size_t offset(const char* src, const char* substring) {
      65             :   const char* it = strstr(src, substring);
      66           9 :   CHECK(it);
      67           9 :   return static_cast<size_t>(it - src);
      68             : }
      69             : 
      70             : template <typename A, typename B>
      71             : static int dist(A a, B b) {
      72           3 :   return abs(static_cast<int>(a) - static_cast<int>(b));
      73             : }
      74             : 
      75             : static const char* reason(const i::DeoptimizeReason reason) {
      76           3 :   return i::DeoptimizeReasonToString(reason);
      77             : }
      78             : 
      79       26644 : TEST(StartStop) {
      80             :   i::Isolate* isolate = CcTest::i_isolate();
      81          10 :   CpuProfilesCollection profiles(isolate);
      82           5 :   ProfileGenerator generator(&profiles);
      83             :   std::unique_ptr<ProfilerEventsProcessor> processor(
      84             :       new SamplingEventsProcessor(isolate, &generator,
      85          10 :                                   v8::base::TimeDelta::FromMicroseconds(100),
      86           5 :                                   true));
      87           5 :   processor->Start();
      88           5 :   processor->StopSynchronously();
      89           5 : }
      90             : 
      91          29 : static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
      92             :                                    i::Address frame1,
      93             :                                    i::Address frame2 = kNullAddress,
      94             :                                    i::Address frame3 = kNullAddress) {
      95             :   v8::internal::TickSample sample;
      96          29 :   sample.pc = reinterpret_cast<void*>(frame1);
      97          29 :   sample.tos = reinterpret_cast<void*>(frame1);
      98             :   sample.frames_count = 0;
      99          29 :   if (frame2 != kNullAddress) {
     100          10 :     sample.stack[0] = reinterpret_cast<void*>(frame2);
     101          10 :     sample.frames_count = 1;
     102             :   }
     103          29 :   if (frame3 != kNullAddress) {
     104           5 :     sample.stack[1] = reinterpret_cast<void*>(frame3);
     105           5 :     sample.frames_count = 2;
     106             :   }
     107          29 :   sample.timestamp = base::TimeTicks::HighResolutionNow();
     108          29 :   proc->AddSample(sample);
     109          29 : }
     110             : 
     111             : namespace {
     112             : 
     113             : class TestSetup {
     114             :  public:
     115             :   TestSetup()
     116          25 :       : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
     117          25 :     i::FLAG_prof_browser_mode = false;
     118             :   }
     119             : 
     120             :   ~TestSetup() {
     121          25 :     i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
     122             :   }
     123             : 
     124             :  private:
     125             :   bool old_flag_prof_browser_mode_;
     126             : };
     127             : 
     128             : }  // namespace
     129             : 
     130          45 : i::AbstractCode CreateCode(LocalContext* env) {
     131             :   static int counter = 0;
     132             :   i::EmbeddedVector<char, 256> script;
     133             :   i::EmbeddedVector<char, 32> name;
     134             : 
     135          45 :   i::SNPrintF(name, "function_%d", ++counter);
     136             :   const char* name_start = name.start();
     137             :   i::SNPrintF(script,
     138             :       "function %s() {\n"
     139             :            "var counter = 0;\n"
     140             :            "for (var i = 0; i < %d; ++i) counter += i;\n"
     141             :            "return '%s_' + counter;\n"
     142             :        "}\n"
     143          45 :        "%s();\n", name_start, counter, name_start, name_start);
     144             :   CompileRun(script.start());
     145             : 
     146             :   i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(
     147          90 :       v8::Utils::OpenHandle(*GetFunction(env->local(), name_start)));
     148          45 :   return fun->abstract_code();
     149             : }
     150             : 
     151       26644 : TEST(CodeEvents) {
     152           5 :   CcTest::InitializeVM();
     153           5 :   LocalContext env;
     154             :   i::Isolate* isolate = CcTest::i_isolate();
     155             :   i::Factory* factory = isolate->factory();
     156             :   TestSetup test_setup;
     157             : 
     158             :   i::HandleScope scope(isolate);
     159             : 
     160           5 :   i::AbstractCode aaa_code = CreateCode(&env);
     161           5 :   i::AbstractCode comment_code = CreateCode(&env);
     162           5 :   i::AbstractCode comment2_code = CreateCode(&env);
     163           5 :   i::AbstractCode moved_code = CreateCode(&env);
     164             : 
     165           5 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
     166           5 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
     167             :   ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
     168           5 :       isolate, generator, v8::base::TimeDelta::FromMicroseconds(100), true);
     169           5 :   processor->Start();
     170          10 :   ProfilerListener profiler_listener(isolate, processor);
     171           5 :   isolate->logger()->AddCodeEventListener(&profiler_listener);
     172             : 
     173             :   // Enqueue code creation events.
     174             :   const char* aaa_str = "aaa";
     175           5 :   i::Handle<i::String> aaa_name = factory->NewStringFromAsciiChecked(aaa_str);
     176          10 :   profiler_listener.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code,
     177           5 :                                     *aaa_name);
     178             :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code,
     179           5 :                                     "comment");
     180             :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code,
     181           5 :                                     "comment2");
     182           5 :   profiler_listener.CodeMoveEvent(comment2_code, moved_code);
     183             : 
     184             :   // Enqueue a tick event to enable code events processing.
     185           5 :   EnqueueTickSampleEvent(processor, aaa_code->InstructionStart());
     186             : 
     187           5 :   isolate->logger()->RemoveCodeEventListener(&profiler_listener);
     188           5 :   processor->StopSynchronously();
     189             : 
     190             :   // Check the state of profile generator.
     191             :   CodeEntry* aaa =
     192          10 :       generator->code_map()->FindEntry(aaa_code->InstructionStart());
     193           5 :   CHECK(aaa);
     194           5 :   CHECK_EQ(0, strcmp(aaa_str, aaa->name()));
     195             : 
     196             :   CodeEntry* comment =
     197           5 :       generator->code_map()->FindEntry(comment_code->InstructionStart());
     198           5 :   CHECK(comment);
     199           5 :   CHECK_EQ(0, strcmp("comment", comment->name()));
     200             : 
     201           5 :   CHECK(!generator->code_map()->FindEntry(comment2_code->InstructionStart()));
     202             : 
     203             :   CodeEntry* comment2 =
     204           5 :       generator->code_map()->FindEntry(moved_code->InstructionStart());
     205           5 :   CHECK(comment2);
     206           5 :   CHECK_EQ(0, strcmp("comment2", comment2->name()));
     207           5 : }
     208             : 
     209             : template<typename T>
     210             : static int CompareProfileNodes(const T* p1, const T* p2) {
     211             :   return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
     212             : }
     213             : 
     214       26644 : TEST(TickEvents) {
     215             :   TestSetup test_setup;
     216           5 :   LocalContext env;
     217             :   i::Isolate* isolate = CcTest::i_isolate();
     218             :   i::HandleScope scope(isolate);
     219             : 
     220           5 :   i::AbstractCode frame1_code = CreateCode(&env);
     221           5 :   i::AbstractCode frame2_code = CreateCode(&env);
     222           5 :   i::AbstractCode frame3_code = CreateCode(&env);
     223             : 
     224           5 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
     225           5 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
     226             :   ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
     227             :       CcTest::i_isolate(), generator,
     228           5 :       v8::base::TimeDelta::FromMicroseconds(100), true);
     229          10 :   CpuProfiler profiler(isolate, profiles, generator, processor);
     230           5 :   profiles->StartProfiling("", false);
     231           5 :   processor->Start();
     232          10 :   ProfilerListener profiler_listener(isolate, processor);
     233           5 :   isolate->logger()->AddCodeEventListener(&profiler_listener);
     234             : 
     235           5 :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
     236           5 :   profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, "ccc");
     237           5 :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
     238             : 
     239           5 :   EnqueueTickSampleEvent(processor, frame1_code->raw_instruction_start());
     240          10 :   EnqueueTickSampleEvent(
     241             :       processor,
     242           5 :       frame2_code->raw_instruction_start() + frame2_code->ExecutableSize() / 2,
     243          10 :       frame1_code->raw_instruction_start() + frame1_code->ExecutableSize() / 2);
     244          10 :   EnqueueTickSampleEvent(processor, frame3_code->raw_instruction_end() - 1,
     245           5 :                          frame2_code->raw_instruction_end() - 1,
     246          10 :                          frame1_code->raw_instruction_end() - 1);
     247             : 
     248           5 :   isolate->logger()->RemoveCodeEventListener(&profiler_listener);
     249           5 :   processor->StopSynchronously();
     250           5 :   CpuProfile* profile = profiles->StopProfiling("");
     251           5 :   CHECK(profile);
     252             : 
     253             :   // Check call trees.
     254             :   const std::vector<ProfileNode*>* top_down_root_children =
     255             :       profile->top_down()->root()->children();
     256           5 :   CHECK_EQ(1, top_down_root_children->size());
     257           5 :   CHECK_EQ(0, strcmp("bbb", top_down_root_children->back()->entry()->name()));
     258             :   const std::vector<ProfileNode*>* top_down_bbb_children =
     259             :       top_down_root_children->back()->children();
     260           5 :   CHECK_EQ(1, top_down_bbb_children->size());
     261           5 :   CHECK_EQ(0, strcmp("ccc", top_down_bbb_children->back()->entry()->name()));
     262             :   const std::vector<ProfileNode*>* top_down_stub_children =
     263             :       top_down_bbb_children->back()->children();
     264           5 :   CHECK_EQ(1, top_down_stub_children->size());
     265           5 :   CHECK_EQ(0, strcmp("ddd", top_down_stub_children->back()->entry()->name()));
     266             :   const std::vector<ProfileNode*>* top_down_ddd_children =
     267             :       top_down_stub_children->back()->children();
     268           5 :   CHECK(top_down_ddd_children->empty());
     269           5 : }
     270             : 
     271             : // http://crbug/51594
     272             : // This test must not crash.
     273       26644 : TEST(CrashIfStoppingLastNonExistentProfile) {
     274           5 :   CcTest::InitializeVM();
     275             :   TestSetup test_setup;
     276          10 :   std::unique_ptr<CpuProfiler> profiler(new CpuProfiler(CcTest::i_isolate()));
     277           5 :   profiler->StartProfiling("1");
     278           5 :   profiler->StopProfiling("2");
     279           5 :   profiler->StartProfiling("1");
     280           5 :   profiler->StopProfiling("");
     281           5 : }
     282             : 
     283             : // http://code.google.com/p/v8/issues/detail?id=1398
     284             : // Long stacks (exceeding max frames limit) must not be erased.
     285       26644 : TEST(Issue1398) {
     286             :   TestSetup test_setup;
     287           5 :   LocalContext env;
     288             :   i::Isolate* isolate = CcTest::i_isolate();
     289             :   i::HandleScope scope(isolate);
     290             : 
     291           5 :   i::AbstractCode code = CreateCode(&env);
     292             : 
     293           5 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
     294           5 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
     295             :   ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
     296             :       CcTest::i_isolate(), generator,
     297           5 :       v8::base::TimeDelta::FromMicroseconds(100), true);
     298          10 :   CpuProfiler profiler(isolate, profiles, generator, processor);
     299           5 :   profiles->StartProfiling("", false);
     300           5 :   processor->Start();
     301          10 :   ProfilerListener profiler_listener(isolate, processor);
     302             : 
     303           5 :   profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
     304             : 
     305             :   v8::internal::TickSample sample;
     306           5 :   sample.pc = reinterpret_cast<void*>(code->InstructionStart());
     307             :   sample.tos = nullptr;
     308             :   sample.frames_count = v8::TickSample::kMaxFramesCount;
     309        2555 :   for (unsigned i = 0; i < sample.frames_count; ++i) {
     310        1275 :     sample.stack[i] = reinterpret_cast<void*>(code->InstructionStart());
     311             :   }
     312           5 :   sample.timestamp = base::TimeTicks::HighResolutionNow();
     313           5 :   processor->AddSample(sample);
     314             : 
     315           5 :   processor->StopSynchronously();
     316           5 :   CpuProfile* profile = profiles->StopProfiling("");
     317           5 :   CHECK(profile);
     318             : 
     319             :   unsigned actual_depth = 0;
     320             :   const ProfileNode* node = profile->top_down()->root();
     321        2565 :   while (!node->children()->empty()) {
     322        1280 :     node = node->children()->back();
     323        1280 :     ++actual_depth;
     324             :   }
     325             : 
     326           5 :   CHECK_EQ(1 + v8::TickSample::kMaxFramesCount, actual_depth);  // +1 for PC.
     327           5 : }
     328             : 
     329       26644 : TEST(DeleteAllCpuProfiles) {
     330           5 :   CcTest::InitializeVM();
     331             :   TestSetup test_setup;
     332          10 :   std::unique_ptr<CpuProfiler> profiler(new CpuProfiler(CcTest::i_isolate()));
     333           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     334           5 :   profiler->DeleteAllProfiles();
     335           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     336             : 
     337           5 :   profiler->StartProfiling("1");
     338           5 :   profiler->StopProfiling("1");
     339           5 :   CHECK_EQ(1, profiler->GetProfilesCount());
     340           5 :   profiler->DeleteAllProfiles();
     341           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     342           5 :   profiler->StartProfiling("1");
     343           5 :   profiler->StartProfiling("2");
     344           5 :   profiler->StopProfiling("2");
     345           5 :   profiler->StopProfiling("1");
     346           5 :   CHECK_EQ(2, profiler->GetProfilesCount());
     347           5 :   profiler->DeleteAllProfiles();
     348           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     349             : 
     350             :   // Test profiling cancellation by the 'delete' command.
     351           5 :   profiler->StartProfiling("1");
     352           5 :   profiler->StartProfiling("2");
     353           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     354           5 :   profiler->DeleteAllProfiles();
     355           5 :   CHECK_EQ(0, profiler->GetProfilesCount());
     356           5 : }
     357             : 
     358             : 
     359          30 : static bool FindCpuProfile(v8::CpuProfiler* v8profiler,
     360             :                            const v8::CpuProfile* v8profile) {
     361             :   i::CpuProfiler* profiler = reinterpret_cast<i::CpuProfiler*>(v8profiler);
     362             :   const i::CpuProfile* profile =
     363             :       reinterpret_cast<const i::CpuProfile*>(v8profile);
     364          30 :   int length = profiler->GetProfilesCount();
     365          50 :   for (int i = 0; i < length; i++) {
     366          35 :     if (profile == profiler->GetProfile(i))
     367             :       return true;
     368             :   }
     369             :   return false;
     370             : }
     371             : 
     372             : 
     373       26644 : TEST(DeleteCpuProfile) {
     374           5 :   LocalContext env;
     375          10 :   v8::HandleScope scope(env->GetIsolate());
     376           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
     377             :   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(cpu_profiler);
     378             : 
     379           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
     380           5 :   v8::Local<v8::String> name1 = v8_str("1");
     381           5 :   cpu_profiler->StartProfiling(name1);
     382           5 :   v8::CpuProfile* p1 = cpu_profiler->StopProfiling(name1);
     383           5 :   CHECK(p1);
     384           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
     385           5 :   CHECK(FindCpuProfile(cpu_profiler, p1));
     386           5 :   p1->Delete();
     387           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
     388             : 
     389           5 :   v8::Local<v8::String> name2 = v8_str("2");
     390           5 :   cpu_profiler->StartProfiling(name2);
     391           5 :   v8::CpuProfile* p2 = cpu_profiler->StopProfiling(name2);
     392           5 :   CHECK(p2);
     393           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
     394           5 :   CHECK(FindCpuProfile(cpu_profiler, p2));
     395           5 :   v8::Local<v8::String> name3 = v8_str("3");
     396           5 :   cpu_profiler->StartProfiling(name3);
     397           5 :   v8::CpuProfile* p3 = cpu_profiler->StopProfiling(name3);
     398           5 :   CHECK(p3);
     399           5 :   CHECK_EQ(2, iprofiler->GetProfilesCount());
     400           5 :   CHECK_NE(p2, p3);
     401           5 :   CHECK(FindCpuProfile(cpu_profiler, p3));
     402           5 :   CHECK(FindCpuProfile(cpu_profiler, p2));
     403           5 :   p2->Delete();
     404           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
     405           5 :   CHECK(!FindCpuProfile(cpu_profiler, p2));
     406           5 :   CHECK(FindCpuProfile(cpu_profiler, p3));
     407           5 :   p3->Delete();
     408           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
     409           5 :   cpu_profiler->Dispose();
     410           5 : }
     411             : 
     412             : 
     413       26644 : TEST(ProfileStartEndTime) {
     414           5 :   LocalContext env;
     415          10 :   v8::HandleScope scope(env->GetIsolate());
     416           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
     417             : 
     418           5 :   v8::Local<v8::String> profile_name = v8_str("test");
     419           5 :   cpu_profiler->StartProfiling(profile_name);
     420           5 :   const v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
     421           5 :   CHECK(profile->GetStartTime() <= profile->GetEndTime());
     422           5 :   cpu_profiler->Dispose();
     423           5 : }
     424             : 
     425             : class ProfilerHelper {
     426             :  public:
     427          84 :   explicit ProfilerHelper(const v8::Local<v8::Context>& context)
     428             :       : context_(context),
     429         168 :         profiler_(v8::CpuProfiler::New(context->GetIsolate())) {
     430             :     i::ProfilerExtension::set_profiler(profiler_);
     431          84 :   }
     432          84 :   ~ProfilerHelper() {
     433             :     i::ProfilerExtension::set_profiler(static_cast<CpuProfiler*>(nullptr));
     434          84 :     profiler_->Dispose();
     435             :   }
     436             : 
     437             :   typedef v8::CpuProfilingMode ProfilingMode;
     438             : 
     439             :   v8::CpuProfile* Run(v8::Local<v8::Function> function,
     440             :                       v8::Local<v8::Value> argv[], int argc,
     441             :                       unsigned min_js_samples = 0,
     442             :                       unsigned min_external_samples = 0,
     443             :                       bool collect_samples = false,
     444             :                       ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
     445             : 
     446             :   v8::CpuProfiler* profiler() { return profiler_; }
     447             : 
     448             :  private:
     449             :   v8::Local<v8::Context> context_;
     450             :   v8::CpuProfiler* profiler_;
     451             : };
     452             : 
     453         560 : v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function,
     454             :                                     v8::Local<v8::Value> argv[], int argc,
     455             :                                     unsigned min_js_samples,
     456             :                                     unsigned min_external_samples,
     457             :                                     bool collect_samples, ProfilingMode mode) {
     458         560 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
     459             : 
     460         560 :   profiler_->SetSamplingInterval(100);
     461         560 :   profiler_->StartProfiling(profile_name, mode, collect_samples);
     462             : 
     463             :   v8::internal::CpuProfiler* iprofiler =
     464         560 :       reinterpret_cast<v8::internal::CpuProfiler*>(profiler_);
     465             :   v8::sampler::Sampler* sampler =
     466             :       reinterpret_cast<i::SamplingEventsProcessor*>(iprofiler->processor())
     467             :           ->sampler();
     468             :   sampler->StartCountingSamples();
     469        3270 :   do {
     470        9810 :     function->Call(context_, context_->Global(), argc, argv).ToLocalChecked();
     471        3270 :   } while (sampler->js_sample_count() < min_js_samples ||
     472             :            sampler->external_sample_count() < min_external_samples);
     473             : 
     474         560 :   v8::CpuProfile* profile = profiler_->StopProfiling(profile_name);
     475             : 
     476         560 :   CHECK(profile);
     477             :   // Dump collected profile to have a better diagnostic in case of failure.
     478         560 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
     479             : 
     480         560 :   return profile;
     481             : }
     482             : 
     483           0 : static unsigned TotalHitCount(const v8::CpuProfileNode* node) {
     484           0 :   unsigned hit_count = node->GetHitCount();
     485           0 :   for (int i = 0, count = node->GetChildrenCount(); i < count; ++i)
     486           0 :     hit_count += TotalHitCount(node->GetChild(i));
     487           0 :   return hit_count;
     488             : }
     489             : 
     490        1455 : static const v8::CpuProfileNode* FindChild(v8::Local<v8::Context> context,
     491             :                                            const v8::CpuProfileNode* node,
     492             :                                            const char* name) {
     493        1455 :   int count = node->GetChildrenCount();
     494        1455 :   v8::Local<v8::String> name_handle = v8_str(name);
     495        1665 :   for (int i = 0; i < count; i++) {
     496        1544 :     const v8::CpuProfileNode* child = node->GetChild(i);
     497        4632 :     if (name_handle->Equals(context, child->GetFunctionName()).FromJust()) {
     498             :       return child;
     499             :     }
     500             :   }
     501             :   return nullptr;
     502             : }
     503             : 
     504           0 : static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
     505             :                                            const char* name) {
     506           0 :   for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
     507           0 :     const v8::CpuProfileNode* child = node->GetChild(i);
     508           0 :     if (strcmp(child->GetFunctionNameStr(), name) == 0) {
     509             :       return child;
     510             :     }
     511             :   }
     512             :   return nullptr;
     513             : }
     514             : 
     515        1435 : static const v8::CpuProfileNode* GetChild(v8::Local<v8::Context> context,
     516             :                                           const v8::CpuProfileNode* node,
     517             :                                           const char* name) {
     518        1435 :   const v8::CpuProfileNode* result = FindChild(context, node, name);
     519        1435 :   if (!result) FATAL("Failed to GetChild: %s", name);
     520        1435 :   return result;
     521             : }
     522             : 
     523             : static void CheckSimpleBranch(v8::Local<v8::Context> context,
     524             :                               const v8::CpuProfileNode* node,
     525             :                               const char* names[], int length) {
     526           0 :   for (int i = 0; i < length; i++) {
     527           0 :     const char* name = names[i];
     528           0 :     node = GetChild(context, node, name);
     529             :   }
     530             : }
     531             : 
     532           6 : static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context,
     533             :                                           v8::CpuProfile* profile,
     534             :                                           const char* names[], int length) {
     535           6 :   const v8::CpuProfileNode* node = profile->GetTopDownRoot();
     536          30 :   for (int i = 0; i < length; i++) {
     537          12 :     node = GetChild(context, node, names[i]);
     538             :   }
     539           6 :   return reinterpret_cast<const ProfileNode*>(node);
     540             : }
     541             : 
     542             : struct NameLinePair {
     543             :   const char* name;
     544             :   int line_number;
     545             : };
     546             : 
     547         170 : static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
     548             :                                            NameLinePair pair) {
     549         233 :   for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
     550         233 :     const v8::CpuProfileNode* child = node->GetChild(i);
     551             :     // The name and line number must match, or if the requested line number was
     552             :     // -1, then match any function of the same name.
     553         661 :     if (strcmp(child->GetFunctionNameStr(), pair.name) == 0 &&
     554         220 :         (child->GetLineNumber() == pair.line_number ||
     555             :          pair.line_number == -1)) {
     556             :       return child;
     557             :     }
     558             :   }
     559             :   return nullptr;
     560             : }
     561             : 
     562         170 : static const v8::CpuProfileNode* GetChild(const v8::CpuProfileNode* node,
     563             :                                           NameLinePair pair) {
     564         170 :   const v8::CpuProfileNode* result = FindChild(node, pair);
     565         170 :   if (!result) FATAL("Failed to GetChild: %s:%d", pair.name, pair.line_number);
     566         170 :   return result;
     567             : }
     568             : 
     569          45 : static void CheckBranch(const v8::CpuProfileNode* node, NameLinePair path[],
     570             :                         int length) {
     571         365 :   for (int i = 0; i < length; i++) {
     572         160 :     NameLinePair pair = path[i];
     573         160 :     node = GetChild(node, pair);
     574             :   }
     575          45 : }
     576             : 
     577             : static const char* cpu_profiler_test_source =
     578             :     "%NeverOptimizeFunction(loop);\n"
     579             :     "%NeverOptimizeFunction(delay);\n"
     580             :     "%NeverOptimizeFunction(bar);\n"
     581             :     "%NeverOptimizeFunction(baz);\n"
     582             :     "%NeverOptimizeFunction(foo);\n"
     583             :     "%NeverOptimizeFunction(start);\n"
     584             :     "function loop(timeout) {\n"
     585             :     "  this.mmm = 0;\n"
     586             :     "  var start = Date.now();\n"
     587             :     "  do {\n"
     588             :     "    var n = 1000;\n"
     589             :     "    while(n > 1) {\n"
     590             :     "      n--;\n"
     591             :     "      this.mmm += n * n * n;\n"
     592             :     "    }\n"
     593             :     "  } while (Date.now() - start < timeout);\n"
     594             :     "}\n"
     595             :     "function delay() { loop(10); }\n"
     596             :     "function bar() { delay(); }\n"
     597             :     "function baz() { delay(); }\n"
     598             :     "function foo() {\n"
     599             :     "  delay();\n"
     600             :     "  bar();\n"
     601             :     "  delay();\n"
     602             :     "  baz();\n"
     603             :     "}\n"
     604             :     "function start(duration) {\n"
     605             :     "  var start = Date.now();\n"
     606             :     "  do {\n"
     607             :     "    foo();\n"
     608             :     "  } while (Date.now() - start < duration);\n"
     609             :     "}\n";
     610             : 
     611             : // Check that the profile tree for the script above will look like the
     612             : // following:
     613             : //
     614             : // [Top down]:
     615             : //  1062     0   (root) [-1]
     616             : //  1054     0    start [-1]
     617             : //  1054     1      foo [-1]
     618             : //   265     0        baz [-1]
     619             : //   265     1          delay [-1]
     620             : //   264   264            loop [-1]
     621             : //   525     3        delay [-1]
     622             : //   522   522          loop [-1]
     623             : //   263     0        bar [-1]
     624             : //   263     1          delay [-1]
     625             : //   262   262            loop [-1]
     626             : //     2     2    (program) [-1]
     627             : //     6     6    (garbage collector) [-1]
     628       26639 : TEST(CollectCpuProfile) {
     629           0 :   i::FLAG_allow_natives_syntax = true;
     630           0 :   LocalContext env;
     631           0 :   v8::HandleScope scope(env->GetIsolate());
     632             : 
     633           0 :   CompileRun(cpu_profiler_test_source);
     634           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     635             : 
     636             :   int32_t profiling_interval_ms = 200;
     637             :   v8::Local<v8::Value> args[] = {
     638           0 :       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
     639           0 :   ProfilerHelper helper(env.local());
     640           0 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
     641             : 
     642           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     643           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     644           0 :   const v8::CpuProfileNode* foo_node = GetChild(env.local(), start_node, "foo");
     645             : 
     646           0 :   const char* bar_branch[] = {"bar", "delay", "loop"};
     647             :   CheckSimpleBranch(env.local(), foo_node, bar_branch, arraysize(bar_branch));
     648           0 :   const char* baz_branch[] = {"baz", "delay", "loop"};
     649             :   CheckSimpleBranch(env.local(), foo_node, baz_branch, arraysize(baz_branch));
     650           0 :   const char* delay_branch[] = {"delay", "loop"};
     651             :   CheckSimpleBranch(env.local(), foo_node, delay_branch,
     652             :                     arraysize(delay_branch));
     653             : 
     654           0 :   profile->Delete();
     655           0 : }
     656             : 
     657       26644 : TEST(CollectCpuProfileCallerLineNumbers) {
     658           5 :   i::FLAG_allow_natives_syntax = true;
     659           5 :   LocalContext env;
     660          10 :   v8::HandleScope scope(env->GetIsolate());
     661             : 
     662           5 :   CompileRun(cpu_profiler_test_source);
     663           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     664             : 
     665             :   int32_t profiling_interval_ms = 200;
     666             :   v8::Local<v8::Value> args[] = {
     667           5 :       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
     668           5 :   ProfilerHelper helper(env.local());
     669             :   helper.Run(function, args, arraysize(args), 1000, 0, false,
     670           5 :              v8::CpuProfilingMode::kCallerLineNumbers);
     671             :   v8::CpuProfile* profile =
     672             :       helper.Run(function, args, arraysize(args), 1000, 0, false,
     673           5 :                  v8::CpuProfilingMode::kCallerLineNumbers);
     674             : 
     675           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     676           5 :   const v8::CpuProfileNode* start_node = GetChild(root, {"start", 27});
     677           5 :   const v8::CpuProfileNode* foo_node = GetChild(start_node, {"foo", 30});
     678             : 
     679           5 :   NameLinePair bar_branch[] = {{"bar", 23}, {"delay", 19}, {"loop", 18}};
     680           5 :   CheckBranch(foo_node, bar_branch, arraysize(bar_branch));
     681           5 :   NameLinePair baz_branch[] = {{"baz", 25}, {"delay", 20}, {"loop", 18}};
     682           5 :   CheckBranch(foo_node, baz_branch, arraysize(baz_branch));
     683           5 :   NameLinePair delay_at22_branch[] = {{"delay", 22}, {"loop", 18}};
     684           5 :   CheckBranch(foo_node, delay_at22_branch, arraysize(delay_at22_branch));
     685           5 :   NameLinePair delay_at24_branch[] = {{"delay", 24}, {"loop", 18}};
     686           5 :   CheckBranch(foo_node, delay_at24_branch, arraysize(delay_at24_branch));
     687             : 
     688           5 :   profile->Delete();
     689           5 : }
     690             : 
     691             : static const char* hot_deopt_no_frame_entry_test_source =
     692             :     "%NeverOptimizeFunction(foo);\n"
     693             :     "%NeverOptimizeFunction(start);\n"
     694             :     "function foo(a, b) {\n"
     695             :     "  return a + b;\n"
     696             :     "}\n"
     697             :     "function start(timeout) {\n"
     698             :     "  var start = Date.now();\n"
     699             :     "  do {\n"
     700             :     "    for (var i = 1; i < 1000; ++i) foo(1, i);\n"
     701             :     "    var duration = Date.now() - start;\n"
     702             :     "  } while (duration < timeout);\n"
     703             :     "  return duration;\n"
     704             :     "}\n";
     705             : 
     706             : // Check that the profile tree for the script above will look like the
     707             : // following:
     708             : //
     709             : // [Top down]:
     710             : //  1062     0  (root) [-1]
     711             : //  1054     0    start [-1]
     712             : //  1054     1      foo [-1]
     713             : //     2     2    (program) [-1]
     714             : //     6     6    (garbage collector) [-1]
     715             : //
     716             : // The test checks no FP ranges are present in a deoptimized function.
     717             : // If 'foo' has no ranges the samples falling into the prologue will miss the
     718             : // 'start' function on the stack, so 'foo' will be attached to the (root).
     719       26639 : TEST(HotDeoptNoFrameEntry) {
     720           0 :   i::FLAG_allow_natives_syntax = true;
     721           0 :   LocalContext env;
     722           0 :   v8::HandleScope scope(env->GetIsolate());
     723             : 
     724           0 :   CompileRun(hot_deopt_no_frame_entry_test_source);
     725           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     726             : 
     727             :   int32_t profiling_interval_ms = 200;
     728             :   v8::Local<v8::Value> args[] = {
     729           0 :       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
     730           0 :   ProfilerHelper helper(env.local());
     731           0 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
     732           0 :   function->Call(env.local(), env->Global(), arraysize(args), args)
     733             :       .ToLocalChecked();
     734             : 
     735           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     736           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     737           0 :   GetChild(env.local(), start_node, "foo");
     738             : 
     739           0 :   profile->Delete();
     740           0 : }
     741             : 
     742       26644 : TEST(CollectCpuProfileSamples) {
     743           5 :   i::FLAG_allow_natives_syntax = true;
     744           5 :   LocalContext env;
     745          10 :   v8::HandleScope scope(env->GetIsolate());
     746             : 
     747           5 :   CompileRun(cpu_profiler_test_source);
     748           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     749             : 
     750             :   int32_t profiling_interval_ms = 200;
     751             :   v8::Local<v8::Value> args[] = {
     752           5 :       v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
     753           5 :   ProfilerHelper helper(env.local());
     754             :   v8::CpuProfile* profile =
     755           5 :       helper.Run(function, args, arraysize(args), 1000, 0, true);
     756             : 
     757           5 :   CHECK_LE(200, profile->GetSamplesCount());
     758           5 :   uint64_t end_time = profile->GetEndTime();
     759           5 :   uint64_t current_time = profile->GetStartTime();
     760           5 :   CHECK_LE(current_time, end_time);
     761       18861 :   for (int i = 0; i < profile->GetSamplesCount(); i++) {
     762        9428 :     CHECK(profile->GetSample(i));
     763        9428 :     uint64_t timestamp = profile->GetSampleTimestamp(i);
     764        9428 :     CHECK_LE(current_time, timestamp);
     765        9428 :     CHECK_LE(timestamp, end_time);
     766             :     current_time = timestamp;
     767             :   }
     768             : 
     769           5 :   profile->Delete();
     770           5 : }
     771             : 
     772             : static const char* cpu_profiler_test_source2 =
     773             :     "%NeverOptimizeFunction(loop);\n"
     774             :     "%NeverOptimizeFunction(delay);\n"
     775             :     "%NeverOptimizeFunction(start);\n"
     776             :     "function loop() {}\n"
     777             :     "function delay() { loop(); }\n"
     778             :     "function start(duration) {\n"
     779             :     "  var start = Date.now();\n"
     780             :     "  do {\n"
     781             :     "    for (var i = 0; i < 10000; ++i) delay();\n"
     782             :     "  } while (Date.now() - start < duration);\n"
     783             :     "}";
     784             : 
     785             : // Check that the profile tree doesn't contain unexpected traces:
     786             : //  - 'loop' can be called only by 'delay'
     787             : //  - 'delay' may be called only by 'start'
     788             : // The profile will look like the following:
     789             : //
     790             : // [Top down]:
     791             : //   135     0   (root) [-1] #1
     792             : //   121    72    start [-1] #3
     793             : //    49    33      delay [-1] #4
     794             : //    16    16        loop [-1] #5
     795             : //    14    14    (program) [-1] #2
     796       26639 : TEST(SampleWhenFrameIsNotSetup) {
     797           0 :   i::FLAG_allow_natives_syntax = true;
     798           0 :   LocalContext env;
     799           0 :   v8::HandleScope scope(env->GetIsolate());
     800             : 
     801           0 :   CompileRun(cpu_profiler_test_source2);
     802           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     803             : 
     804             :   int32_t duration_ms = 100;
     805             :   v8::Local<v8::Value> args[] = {
     806           0 :       v8::Integer::New(env->GetIsolate(), duration_ms)};
     807           0 :   ProfilerHelper helper(env.local());
     808           0 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
     809             : 
     810           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     811           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     812             :   const v8::CpuProfileNode* delay_node =
     813           0 :       GetChild(env.local(), start_node, "delay");
     814           0 :   GetChild(env.local(), delay_node, "loop");
     815             : 
     816           0 :   profile->Delete();
     817           0 : }
     818             : 
     819             : static const char* native_accessor_test_source = "function start(count) {\n"
     820             : "  for (var i = 0; i < count; i++) {\n"
     821             : "    var o = instance.foo;\n"
     822             : "    instance.foo = o + 1;\n"
     823             : "  }\n"
     824             : "}\n";
     825             : 
     826             : class TestApiCallbacks {
     827             :  public:
     828             :   explicit TestApiCallbacks(int min_duration_ms)
     829             :       : min_duration_ms_(min_duration_ms),
     830          20 :         is_warming_up_(false) {}
     831             : 
     832         520 :   static void Getter(v8::Local<v8::String> name,
     833             :                      const v8::PropertyCallbackInfo<v8::Value>& info) {
     834             :     TestApiCallbacks* data = FromInfo(info);
     835         520 :     data->Wait();
     836         520 :   }
     837             : 
     838         520 :   static void Setter(v8::Local<v8::String> name,
     839             :                      v8::Local<v8::Value> value,
     840             :                      const v8::PropertyCallbackInfo<void>& info) {
     841             :     TestApiCallbacks* data = FromInfo(info);
     842         520 :     data->Wait();
     843         520 :   }
     844             : 
     845         520 :   static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) {
     846             :     TestApiCallbacks* data = FromInfo(info);
     847         520 :     data->Wait();
     848         520 :   }
     849             : 
     850          20 :   void set_warming_up(bool value) { is_warming_up_ = value; }
     851             : 
     852             :  private:
     853        1560 :   void Wait() {
     854        1560 :     if (is_warming_up_) return;
     855        1515 :     v8::Platform* platform = v8::internal::V8::GetCurrentPlatform();
     856        1515 :     double start = platform->CurrentClockTimeMillis();
     857             :     double duration = 0;
     858       35807 :     while (duration < min_duration_ms_) {
     859       17146 :       v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1));
     860       17146 :       duration = platform->CurrentClockTimeMillis() - start;
     861             :     }
     862             :   }
     863             : 
     864             :   template <typename T>
     865             :   static TestApiCallbacks* FromInfo(const T& info) {
     866        1560 :     void* data = v8::External::Cast(*info.Data())->Value();
     867             :     return reinterpret_cast<TestApiCallbacks*>(data);
     868             :   }
     869             : 
     870             :   int min_duration_ms_;
     871             :   bool is_warming_up_;
     872             : };
     873             : 
     874             : 
     875             : // Test that native accessors are properly reported in the CPU profile.
     876             : // This test checks the case when the long-running accessors are called
     877             : // only once and the optimizer doesn't have chance to change the invocation
     878             : // code.
     879       26644 : TEST(NativeAccessorUninitializedIC) {
     880           5 :   LocalContext env;
     881           5 :   v8::Isolate* isolate = env->GetIsolate();
     882          10 :   v8::HandleScope scope(isolate);
     883             : 
     884             :   v8::Local<v8::FunctionTemplate> func_template =
     885           5 :       v8::FunctionTemplate::New(isolate);
     886             :   v8::Local<v8::ObjectTemplate> instance_template =
     887           5 :       func_template->InstanceTemplate();
     888             : 
     889             :   TestApiCallbacks accessors(100);
     890           5 :   v8::Local<v8::External> data = v8::External::New(isolate, &accessors);
     891          10 :   instance_template->SetAccessor(v8_str("foo"), &TestApiCallbacks::Getter,
     892           5 :                                  &TestApiCallbacks::Setter, data);
     893             :   v8::Local<v8::Function> func =
     894           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
     895             :   v8::Local<v8::Object> instance =
     896             :       func->NewInstance(env.local()).ToLocalChecked();
     897          20 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
     898             : 
     899           5 :   CompileRun(native_accessor_test_source);
     900           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     901             : 
     902           5 :   ProfilerHelper helper(env.local());
     903             :   int32_t repeat_count = 1;
     904           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
     905           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 100);
     906             : 
     907           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     908           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     909           5 :   GetChild(env.local(), start_node, "get foo");
     910           5 :   GetChild(env.local(), start_node, "set foo");
     911             : 
     912           5 :   profile->Delete();
     913           5 : }
     914             : 
     915             : 
     916             : // Test that native accessors are properly reported in the CPU profile.
     917             : // This test makes sure that the accessors are called enough times to become
     918             : // hot and to trigger optimizations.
     919       26644 : TEST(NativeAccessorMonomorphicIC) {
     920           5 :   LocalContext env;
     921           5 :   v8::Isolate* isolate = env->GetIsolate();
     922          10 :   v8::HandleScope scope(isolate);
     923             : 
     924             :   v8::Local<v8::FunctionTemplate> func_template =
     925           5 :       v8::FunctionTemplate::New(isolate);
     926             :   v8::Local<v8::ObjectTemplate> instance_template =
     927           5 :       func_template->InstanceTemplate();
     928             : 
     929             :   TestApiCallbacks accessors(1);
     930             :   v8::Local<v8::External> data =
     931           5 :       v8::External::New(isolate, &accessors);
     932          10 :   instance_template->SetAccessor(v8_str("foo"), &TestApiCallbacks::Getter,
     933           5 :                                  &TestApiCallbacks::Setter, data);
     934             :   v8::Local<v8::Function> func =
     935           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
     936             :   v8::Local<v8::Object> instance =
     937             :       func->NewInstance(env.local()).ToLocalChecked();
     938          20 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
     939             : 
     940           5 :   CompileRun(native_accessor_test_source);
     941           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
     942             : 
     943             :   {
     944             :     // Make sure accessors ICs are in monomorphic state before starting
     945             :     // profiling.
     946             :     accessors.set_warming_up(true);
     947             :     int32_t warm_up_iterations = 3;
     948             :     v8::Local<v8::Value> args[] = {
     949           5 :         v8::Integer::New(isolate, warm_up_iterations)};
     950          15 :     function->Call(env.local(), env->Global(), arraysize(args), args)
     951             :         .ToLocalChecked();
     952             :     accessors.set_warming_up(false);
     953             :   }
     954             : 
     955             :   int32_t repeat_count = 100;
     956           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
     957           5 :   ProfilerHelper helper(env.local());
     958           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 100);
     959             : 
     960           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
     961           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
     962           5 :   GetChild(env.local(), start_node, "get foo");
     963           5 :   GetChild(env.local(), start_node, "set foo");
     964             : 
     965           5 :   profile->Delete();
     966           5 : }
     967             : 
     968             : 
     969             : static const char* native_method_test_source = "function start(count) {\n"
     970             : "  for (var i = 0; i < count; i++) {\n"
     971             : "    instance.fooMethod();\n"
     972             : "  }\n"
     973             : "}\n";
     974             : 
     975             : 
     976       26644 : TEST(NativeMethodUninitializedIC) {
     977           5 :   LocalContext env;
     978           5 :   v8::Isolate* isolate = env->GetIsolate();
     979          10 :   v8::HandleScope scope(isolate);
     980             : 
     981             :   TestApiCallbacks callbacks(100);
     982           5 :   v8::Local<v8::External> data = v8::External::New(isolate, &callbacks);
     983             : 
     984             :   v8::Local<v8::FunctionTemplate> func_template =
     985           5 :       v8::FunctionTemplate::New(isolate);
     986           5 :   func_template->SetClassName(v8_str("Test_InstanceConstructor"));
     987             :   v8::Local<v8::ObjectTemplate> proto_template =
     988           5 :       func_template->PrototypeTemplate();
     989             :   v8::Local<v8::Signature> signature =
     990           5 :       v8::Signature::New(isolate, func_template);
     991          15 :   proto_template->Set(
     992             :       v8_str("fooMethod"),
     993             :       v8::FunctionTemplate::New(isolate, &TestApiCallbacks::Callback, data,
     994           5 :                                 signature, 0));
     995             : 
     996             :   v8::Local<v8::Function> func =
     997           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
     998             :   v8::Local<v8::Object> instance =
     999             :       func->NewInstance(env.local()).ToLocalChecked();
    1000          20 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
    1001             : 
    1002           5 :   CompileRun(native_method_test_source);
    1003           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    1004             : 
    1005           5 :   ProfilerHelper helper(env.local());
    1006             :   int32_t repeat_count = 1;
    1007           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
    1008           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 100);
    1009             : 
    1010           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1011           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
    1012           5 :   GetChild(env.local(), start_node, "fooMethod");
    1013             : 
    1014           5 :   profile->Delete();
    1015           5 : }
    1016             : 
    1017             : 
    1018       26644 : TEST(NativeMethodMonomorphicIC) {
    1019           5 :   LocalContext env;
    1020           5 :   v8::Isolate* isolate = env->GetIsolate();
    1021          10 :   v8::HandleScope scope(isolate);
    1022             : 
    1023             :   TestApiCallbacks callbacks(1);
    1024             :   v8::Local<v8::External> data =
    1025           5 :       v8::External::New(isolate, &callbacks);
    1026             : 
    1027             :   v8::Local<v8::FunctionTemplate> func_template =
    1028           5 :       v8::FunctionTemplate::New(isolate);
    1029           5 :   func_template->SetClassName(v8_str("Test_InstanceCostructor"));
    1030             :   v8::Local<v8::ObjectTemplate> proto_template =
    1031           5 :       func_template->PrototypeTemplate();
    1032             :   v8::Local<v8::Signature> signature =
    1033           5 :       v8::Signature::New(isolate, func_template);
    1034          15 :   proto_template->Set(
    1035             :       v8_str("fooMethod"),
    1036             :       v8::FunctionTemplate::New(isolate, &TestApiCallbacks::Callback, data,
    1037           5 :                                 signature, 0));
    1038             : 
    1039             :   v8::Local<v8::Function> func =
    1040           5 :       func_template->GetFunction(env.local()).ToLocalChecked();
    1041             :   v8::Local<v8::Object> instance =
    1042             :       func->NewInstance(env.local()).ToLocalChecked();
    1043          20 :   env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
    1044             : 
    1045           5 :   CompileRun(native_method_test_source);
    1046           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    1047             :   {
    1048             :     // Make sure method ICs are in monomorphic state before starting
    1049             :     // profiling.
    1050             :     callbacks.set_warming_up(true);
    1051             :     int32_t warm_up_iterations = 3;
    1052             :     v8::Local<v8::Value> args[] = {
    1053           5 :         v8::Integer::New(isolate, warm_up_iterations)};
    1054          15 :     function->Call(env.local(), env->Global(), arraysize(args), args)
    1055             :         .ToLocalChecked();
    1056             :     callbacks.set_warming_up(false);
    1057             :   }
    1058             : 
    1059           5 :   ProfilerHelper helper(env.local());
    1060             :   int32_t repeat_count = 100;
    1061           5 :   v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
    1062           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 0, 200);
    1063             : 
    1064           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1065           5 :   GetChild(env.local(), root, "start");
    1066           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
    1067           5 :   GetChild(env.local(), start_node, "fooMethod");
    1068             : 
    1069           5 :   profile->Delete();
    1070           5 : }
    1071             : 
    1072             : 
    1073             : static const char* bound_function_test_source =
    1074             :     "function foo() {\n"
    1075             :     "  startProfiling('my_profile');\n"
    1076             :     "}\n"
    1077             :     "function start() {\n"
    1078             :     "  var callback = foo.bind(this);\n"
    1079             :     "  callback();\n"
    1080             :     "}";
    1081             : 
    1082             : 
    1083       26644 : TEST(BoundFunctionCall) {
    1084          10 :   v8::HandleScope scope(CcTest::isolate());
    1085          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1086             :   v8::Context::Scope context_scope(env);
    1087             : 
    1088           5 :   CompileRun(bound_function_test_source);
    1089           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1090             : 
    1091           5 :   ProfilerHelper helper(env);
    1092           5 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0);
    1093             : 
    1094           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1095             : 
    1096           5 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1097           5 :   GetChild(env, start_node, "foo");
    1098             : 
    1099           5 :   profile->Delete();
    1100           5 : }
    1101             : 
    1102             : // This tests checks distribution of the samples through the source lines.
    1103           9 : static void TickLines(bool optimize) {
    1104             : #ifndef V8_LITE_MODE
    1105           9 :   FLAG_opt = optimize;
    1106             : #endif  // V8_LITE_MODE
    1107           9 :   CcTest::InitializeVM();
    1108           9 :   LocalContext env;
    1109           9 :   i::FLAG_allow_natives_syntax = true;
    1110             :   i::Isolate* isolate = CcTest::i_isolate();
    1111             :   i::Factory* factory = isolate->factory();
    1112             :   i::HandleScope scope(isolate);
    1113             : 
    1114             :   i::EmbeddedVector<char, 512> script;
    1115             :   i::EmbeddedVector<char, 64> optimize_call;
    1116             : 
    1117             :   const char* func_name = "func";
    1118           9 :   if (optimize) {
    1119             :     i::SNPrintF(optimize_call, "%%OptimizeFunctionOnNextCall(%s);\n",
    1120           4 :                 func_name);
    1121             :   } else {
    1122           5 :     optimize_call[0] = '\0';
    1123             :   }
    1124             :   i::SNPrintF(script,
    1125             :               "function %s() {\n"
    1126             :               "  var n = 0;\n"
    1127             :               "  var m = 100*100;\n"
    1128             :               "  while (m > 1) {\n"
    1129             :               "    m--;\n"
    1130             :               "    n += m * m * m;\n"
    1131             :               "  }\n"
    1132             :               "}\n"
    1133             :               "%s();\n"
    1134             :               "%s"
    1135             :               "%s();\n",
    1136           9 :               func_name, func_name, optimize_call.start(), func_name);
    1137             : 
    1138             :   CompileRun(script.start());
    1139             : 
    1140             :   i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
    1141          18 :       v8::Utils::OpenHandle(*GetFunction(env.local(), func_name)));
    1142           9 :   CHECK(!func->shared().is_null());
    1143          18 :   CHECK(!func->shared()->abstract_code().is_null());
    1144          13 :   CHECK(!optimize || func->IsOptimized() ||
    1145             :         !CcTest::i_isolate()->use_optimizer());
    1146           9 :   i::AbstractCode code = func->abstract_code();
    1147           9 :   CHECK(!code.is_null());
    1148           9 :   i::Address code_address = code->raw_instruction_start();
    1149           9 :   CHECK_NE(code_address, kNullAddress);
    1150             : 
    1151           9 :   CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
    1152           9 :   ProfileGenerator* generator = new ProfileGenerator(profiles);
    1153             :   ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
    1154             :       CcTest::i_isolate(), generator,
    1155           9 :       v8::base::TimeDelta::FromMicroseconds(100), true);
    1156          18 :   CpuProfiler profiler(isolate, profiles, generator, processor);
    1157           9 :   profiles->StartProfiling("", false);
    1158             :   // TODO(delphick): Stop using the CpuProfiler internals here: This forces
    1159             :   // LogCompiledFunctions so that source positions are collected everywhere.
    1160             :   // This would normally happen automatically with CpuProfiler::StartProfiling
    1161             :   // but doesn't because it's constructed with a generator and a processor.
    1162           9 :   isolate->logger()->LogCompiledFunctions();
    1163           9 :   processor->Start();
    1164          18 :   ProfilerListener profiler_listener(isolate, processor);
    1165             : 
    1166             :   // Enqueue code creation events.
    1167           9 :   i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
    1168             :   int line = 1;
    1169             :   int column = 1;
    1170          18 :   profiler_listener.CodeCreateEvent(i::Logger::FUNCTION_TAG, code,
    1171           9 :                                     func->shared(), *str, line, column);
    1172             : 
    1173             :   // Enqueue a tick event to enable code events processing.
    1174           9 :   EnqueueTickSampleEvent(processor, code_address);
    1175             : 
    1176           9 :   processor->StopSynchronously();
    1177             : 
    1178           9 :   CpuProfile* profile = profiles->StopProfiling("");
    1179           9 :   CHECK(profile);
    1180             : 
    1181             :   // Check the state of profile generator.
    1182           9 :   CodeEntry* func_entry = generator->code_map()->FindEntry(code_address);
    1183           9 :   CHECK(func_entry);
    1184           9 :   CHECK_EQ(0, strcmp(func_name, func_entry->name()));
    1185             :   const i::SourcePositionTable* line_info = func_entry->line_info();
    1186           9 :   CHECK(line_info);
    1187           9 :   CHECK_NE(v8::CpuProfileNode::kNoLineNumberInfo,
    1188             :            line_info->GetSourceLineNumber(100));
    1189             : 
    1190             :   // Check the hit source lines using V8 Public APIs.
    1191             :   const i::ProfileTree* tree = profile->top_down();
    1192             :   ProfileNode* root = tree->root();
    1193           9 :   CHECK(root);
    1194           9 :   ProfileNode* func_node = root->FindChild(func_entry);
    1195           9 :   CHECK(func_node);
    1196             : 
    1197             :   // Add 10 faked ticks to source line #5.
    1198             :   int hit_line = 5;
    1199             :   int hit_count = 10;
    1200          99 :   for (int i = 0; i < hit_count; i++) func_node->IncrementLineTicks(hit_line);
    1201             : 
    1202             :   unsigned int line_count = func_node->GetHitLineCount();
    1203           9 :   CHECK_EQ(2u, line_count);  // Expect two hit source lines - #1 and #5.
    1204           9 :   ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count);
    1205           9 :   CHECK(func_node->GetLineTicks(&entries[0], line_count));
    1206             :   int value = 0;
    1207           9 :   for (int i = 0; i < entries.length(); i++)
    1208          18 :     if (entries[i].line == hit_line) {
    1209           9 :       value = entries[i].hit_count;
    1210           9 :       break;
    1211             :     }
    1212           9 :   CHECK_EQ(hit_count, value);
    1213           9 : }
    1214             : 
    1215       26644 : TEST(TickLinesBaseline) { TickLines(false); }
    1216             : 
    1217       26643 : TEST(TickLinesOptimized) { TickLines(true); }
    1218             : 
    1219             : static const char* call_function_test_source =
    1220             :     "%NeverOptimizeFunction(bar);\n"
    1221             :     "%NeverOptimizeFunction(start);\n"
    1222             :     "function bar(n) {\n"
    1223             :     "  var s = 0;\n"
    1224             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1225             :     "  return s;\n"
    1226             :     "}\n"
    1227             :     "function start(duration) {\n"
    1228             :     "  var start = Date.now();\n"
    1229             :     "  do {\n"
    1230             :     "    for (var i = 0; i < 100; ++i)\n"
    1231             :     "      bar.call(this, 1000);\n"
    1232             :     "  } while (Date.now() - start < duration);\n"
    1233             :     "}";
    1234             : 
    1235             : // Test that if we sampled thread when it was inside FunctionCall buitin then
    1236             : // its caller frame will be '(unresolved function)' as we have no reliable way
    1237             : // to resolve it.
    1238             : //
    1239             : // [Top down]:
    1240             : //    96     0   (root) [-1] #1
    1241             : //     1     1    (garbage collector) [-1] #4
    1242             : //     5     0    (unresolved function) [-1] #5
    1243             : //     5     5      call [-1] #6
    1244             : //    71    70    start [-1] #3
    1245             : //     1     1      bar [-1] #7
    1246             : //    19    19    (program) [-1] #2
    1247       26644 : TEST(FunctionCallSample) {
    1248           5 :   i::FLAG_allow_natives_syntax = true;
    1249           5 :   LocalContext env;
    1250          10 :   v8::HandleScope scope(env->GetIsolate());
    1251             : 
    1252             :   // Collect garbage that might have be generated while installing
    1253             :   // extensions.
    1254           5 :   CcTest::CollectAllGarbage();
    1255             : 
    1256           5 :   CompileRun(call_function_test_source);
    1257           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    1258             : 
    1259           5 :   ProfilerHelper helper(env.local());
    1260             :   int32_t duration_ms = 100;
    1261             :   v8::Local<v8::Value> args[] = {
    1262           5 :       v8::Integer::New(env->GetIsolate(), duration_ms)};
    1263           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
    1264             : 
    1265           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1266           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
    1267           5 :   GetChild(env.local(), start_node, "bar");
    1268             : 
    1269             :   const v8::CpuProfileNode* unresolved_node =
    1270          10 :       FindChild(env.local(), root, i::CodeEntry::kUnresolvedFunctionName);
    1271           5 :   CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "call"));
    1272             : 
    1273           5 :   profile->Delete();
    1274           5 : }
    1275             : 
    1276             : static const char* function_apply_test_source =
    1277             :     "%NeverOptimizeFunction(bar);\n"
    1278             :     "%NeverOptimizeFunction(test);\n"
    1279             :     "%NeverOptimizeFunction(start);\n"
    1280             :     "function bar(n) {\n"
    1281             :     "  var s = 0;\n"
    1282             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1283             :     "  return s;\n"
    1284             :     "}\n"
    1285             :     "function test() {\n"
    1286             :     "  bar.apply(this, [1000]);\n"
    1287             :     "}\n"
    1288             :     "function start(duration) {\n"
    1289             :     "  var start = Date.now();\n"
    1290             :     "  do {\n"
    1291             :     "    for (var i = 0; i < 100; ++i) test();\n"
    1292             :     "  } while (Date.now() - start < duration);\n"
    1293             :     "}";
    1294             : 
    1295             : // [Top down]:
    1296             : //    94     0   (root) [-1] #0 1
    1297             : //     2     2    (garbage collector) [-1] #0 7
    1298             : //    82    49    start [-1] #16 3
    1299             : //     1     0      (unresolved function) [-1] #0 8
    1300             : //     1     1        apply [-1] #0 9
    1301             : //    32    21      test [-1] #16 4
    1302             : //     2     2        bar [-1] #16 6
    1303             : //    10    10    (program) [-1] #0 2
    1304       26644 : TEST(FunctionApplySample) {
    1305           5 :   i::FLAG_allow_natives_syntax = true;
    1306           5 :   LocalContext env;
    1307          10 :   v8::HandleScope scope(env->GetIsolate());
    1308             : 
    1309           5 :   CompileRun(function_apply_test_source);
    1310           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    1311             : 
    1312           5 :   ProfilerHelper helper(env.local());
    1313             :   int32_t duration_ms = 100;
    1314             :   v8::Local<v8::Value> args[] = {
    1315           5 :       v8::Integer::New(env->GetIsolate(), duration_ms)};
    1316           5 :   v8::CpuProfile* profile = helper.Run(function, args, arraysize(args), 1000);
    1317             : 
    1318           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1319           5 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
    1320             :   const v8::CpuProfileNode* test_node =
    1321           5 :       GetChild(env.local(), start_node, "test");
    1322           5 :   GetChild(env.local(), test_node, "bar");
    1323             : 
    1324             :   const v8::CpuProfileNode* unresolved_node =
    1325          10 :       FindChild(env.local(), start_node, CodeEntry::kUnresolvedFunctionName);
    1326           5 :   CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "apply"));
    1327             : 
    1328           5 :   profile->Delete();
    1329           5 : }
    1330             : 
    1331             : static const char* cpu_profiler_deep_stack_test_source =
    1332             :     "function foo(n) {\n"
    1333             :     "  if (n)\n"
    1334             :     "    foo(n - 1);\n"
    1335             :     "  else\n"
    1336             :     "    collectSample();\n"
    1337             :     "}\n"
    1338             :     "function start() {\n"
    1339             :     "  startProfiling('my_profile');\n"
    1340             :     "  foo(250);\n"
    1341             :     "}\n";
    1342             : 
    1343             : // Check a deep stack
    1344             : //
    1345             : // [Top down]:
    1346             : //    0  (root) 0 #1
    1347             : //    2    (program) 0 #2
    1348             : //    0    start 21 #3 no reason
    1349             : //    0      foo 21 #4 no reason
    1350             : //    0        foo 21 #5 no reason
    1351             : //                ....
    1352             : //    0          foo 21 #254 no reason
    1353       26644 : TEST(CpuProfileDeepStack) {
    1354          10 :   v8::HandleScope scope(CcTest::isolate());
    1355          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1356             :   v8::Context::Scope context_scope(env);
    1357           5 :   ProfilerHelper helper(env);
    1358             : 
    1359           5 :   CompileRun(cpu_profiler_deep_stack_test_source);
    1360           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1361             : 
    1362           5 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
    1363          15 :   function->Call(env, env->Global(), 0, nullptr).ToLocalChecked();
    1364           5 :   v8::CpuProfile* profile = helper.profiler()->StopProfiling(profile_name);
    1365           5 :   CHECK(profile);
    1366             :   // Dump collected profile to have a better diagnostic in case of failure.
    1367           5 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    1368             : 
    1369           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1370           5 :   const v8::CpuProfileNode* node = GetChild(env, root, "start");
    1371        2515 :   for (int i = 0; i <= 250; ++i) {
    1372        1255 :     node = GetChild(env, node, "foo");
    1373             :   }
    1374           5 :   CHECK(!FindChild(env, node, "foo"));
    1375             : 
    1376           5 :   profile->Delete();
    1377           5 : }
    1378             : 
    1379             : static const char* js_native_js_test_source =
    1380             :     "%NeverOptimizeFunction(foo);\n"
    1381             :     "%NeverOptimizeFunction(bar);\n"
    1382             :     "%NeverOptimizeFunction(start);\n"
    1383             :     "function foo(n) {\n"
    1384             :     "  var s = 0;\n"
    1385             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1386             :     "  return s;\n"
    1387             :     "}\n"
    1388             :     "function bar() {\n"
    1389             :     "  foo(1000);\n"
    1390             :     "}\n"
    1391             :     "function start() {\n"
    1392             :     "  CallJsFunction(bar);\n"
    1393             :     "}";
    1394             : 
    1395           0 : static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
    1396             :   v8::Local<v8::Function> function = info[0].As<v8::Function>();
    1397           0 :   v8::Local<v8::Value> argv[] = {info[1]};
    1398           0 :   function->Call(info.GetIsolate()->GetCurrentContext(), info.This(),
    1399           0 :                  arraysize(argv), argv)
    1400             :       .ToLocalChecked();
    1401           0 : }
    1402             : 
    1403             : // [Top down]:
    1404             : //    58     0   (root) #0 1
    1405             : //     2     2    (program) #0 2
    1406             : //    56     1    start #16 3
    1407             : //    55     0      CallJsFunction #0 4
    1408             : //    55     1        bar #16 5
    1409             : //    54    54          foo #16 6
    1410       26639 : TEST(JsNativeJsSample) {
    1411           0 :   i::FLAG_allow_natives_syntax = true;
    1412           0 :   v8::HandleScope scope(CcTest::isolate());
    1413           0 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1414             :   v8::Context::Scope context_scope(env);
    1415             : 
    1416             :   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
    1417           0 :       env->GetIsolate(), CallJsFunction);
    1418             :   v8::Local<v8::Function> func =
    1419           0 :       func_template->GetFunction(env).ToLocalChecked();
    1420           0 :   func->SetName(v8_str("CallJsFunction"));
    1421           0 :   env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
    1422             : 
    1423           0 :   CompileRun(js_native_js_test_source);
    1424           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1425             : 
    1426           0 :   ProfilerHelper helper(env);
    1427           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 1000);
    1428             : 
    1429           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1430           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1431             :   const v8::CpuProfileNode* native_node =
    1432           0 :       GetChild(env, start_node, "CallJsFunction");
    1433           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
    1434           0 :   GetChild(env, bar_node, "foo");
    1435             : 
    1436           0 :   profile->Delete();
    1437           0 : }
    1438             : 
    1439             : static const char* js_native_js_runtime_js_test_source =
    1440             :     "%NeverOptimizeFunction(foo);\n"
    1441             :     "%NeverOptimizeFunction(bar);\n"
    1442             :     "%NeverOptimizeFunction(start);\n"
    1443             :     "function foo(n) {\n"
    1444             :     "  var s = 0;\n"
    1445             :     "  for (var i = 0; i < n; i++) s += i * i * i;\n"
    1446             :     "  return s;\n"
    1447             :     "}\n"
    1448             :     "var bound = foo.bind(this);\n"
    1449             :     "function bar() {\n"
    1450             :     "  bound(1000);\n"
    1451             :     "}\n"
    1452             :     "function start() {\n"
    1453             :     "  CallJsFunction(bar);\n"
    1454             :     "}";
    1455             : 
    1456             : // [Top down]:
    1457             : //    57     0   (root) #0 1
    1458             : //    55     1    start #16 3
    1459             : //    54     0      CallJsFunction #0 4
    1460             : //    54     3        bar #16 5
    1461             : //    51    51          foo #16 6
    1462             : //     2     2    (program) #0 2
    1463       26639 : TEST(JsNativeJsRuntimeJsSample) {
    1464           0 :   i::FLAG_allow_natives_syntax = true;
    1465           0 :   v8::HandleScope scope(CcTest::isolate());
    1466           0 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1467             :   v8::Context::Scope context_scope(env);
    1468             : 
    1469             :   v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
    1470           0 :       env->GetIsolate(), CallJsFunction);
    1471             :   v8::Local<v8::Function> func =
    1472           0 :       func_template->GetFunction(env).ToLocalChecked();
    1473           0 :   func->SetName(v8_str("CallJsFunction"));
    1474           0 :   env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
    1475             : 
    1476           0 :   CompileRun(js_native_js_runtime_js_test_source);
    1477           0 :   ProfilerHelper helper(env);
    1478           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1479           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 1000);
    1480             : 
    1481           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1482           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1483             :   const v8::CpuProfileNode* native_node =
    1484           0 :       GetChild(env, start_node, "CallJsFunction");
    1485           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
    1486           0 :   GetChild(env, bar_node, "foo");
    1487             : 
    1488           0 :   profile->Delete();
    1489           0 : }
    1490             : 
    1491           0 : static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) {
    1492           0 :   v8::base::OS::Print("In CallJsFunction2\n");
    1493           0 :   CallJsFunction(info);
    1494           0 : }
    1495             : 
    1496             : static const char* js_native1_js_native2_js_test_source =
    1497             :     "%NeverOptimizeFunction(foo);\n"
    1498             :     "%NeverOptimizeFunction(bar);\n"
    1499             :     "%NeverOptimizeFunction(start);\n"
    1500             :     "function foo() {\n"
    1501             :     "  var s = 0;\n"
    1502             :     "  for (var i = 0; i < 1000; i++) s += i * i * i;\n"
    1503             :     "  return s;\n"
    1504             :     "}\n"
    1505             :     "function bar() {\n"
    1506             :     "  CallJsFunction2(foo);\n"
    1507             :     "}\n"
    1508             :     "function start() {\n"
    1509             :     "  CallJsFunction1(bar);\n"
    1510             :     "}";
    1511             : 
    1512             : // [Top down]:
    1513             : //    57     0   (root) #0 1
    1514             : //    55     1    start #16 3
    1515             : //    54     0      CallJsFunction1 #0 4
    1516             : //    54     0        bar #16 5
    1517             : //    54     0          CallJsFunction2 #0 6
    1518             : //    54    54            foo #16 7
    1519             : //     2     2    (program) #0 2
    1520       26639 : TEST(JsNative1JsNative2JsSample) {
    1521           0 :   i::FLAG_allow_natives_syntax = true;
    1522           0 :   v8::HandleScope scope(CcTest::isolate());
    1523           0 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1524             :   v8::Context::Scope context_scope(env);
    1525             : 
    1526             :   v8::Local<v8::Function> func1 =
    1527           0 :       v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction)
    1528           0 :           ->GetFunction(env)
    1529             :           .ToLocalChecked();
    1530           0 :   func1->SetName(v8_str("CallJsFunction1"));
    1531           0 :   env->Global()->Set(env, v8_str("CallJsFunction1"), func1).FromJust();
    1532             : 
    1533             :   v8::Local<v8::Function> func2 =
    1534           0 :       v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction2)
    1535           0 :           ->GetFunction(env)
    1536             :           .ToLocalChecked();
    1537           0 :   func2->SetName(v8_str("CallJsFunction2"));
    1538           0 :   env->Global()->Set(env, v8_str("CallJsFunction2"), func2).FromJust();
    1539             : 
    1540           0 :   CompileRun(js_native1_js_native2_js_test_source);
    1541             : 
    1542           0 :   ProfilerHelper helper(env);
    1543           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1544           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 1000);
    1545             : 
    1546           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1547           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1548             :   const v8::CpuProfileNode* native_node1 =
    1549           0 :       GetChild(env, start_node, "CallJsFunction1");
    1550           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node1, "bar");
    1551             :   const v8::CpuProfileNode* native_node2 =
    1552           0 :       GetChild(env, bar_node, "CallJsFunction2");
    1553           0 :   GetChild(env, native_node2, "foo");
    1554             : 
    1555           0 :   profile->Delete();
    1556           0 : }
    1557             : 
    1558             : static const char* js_force_collect_sample_source =
    1559             :     "function start() {\n"
    1560             :     "  CallCollectSample();\n"
    1561             :     "}";
    1562             : 
    1563           5 : static void CallCollectSample(const v8::FunctionCallbackInfo<v8::Value>& info) {
    1564           5 :   v8::CpuProfiler::CollectSample(info.GetIsolate());
    1565           5 : }
    1566             : 
    1567       26644 : TEST(CollectSampleAPI) {
    1568          10 :   v8::HandleScope scope(CcTest::isolate());
    1569          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1570             :   v8::Context::Scope context_scope(env);
    1571             : 
    1572             :   v8::Local<v8::FunctionTemplate> func_template =
    1573           5 :       v8::FunctionTemplate::New(env->GetIsolate(), CallCollectSample);
    1574             :   v8::Local<v8::Function> func =
    1575           5 :       func_template->GetFunction(env).ToLocalChecked();
    1576           5 :   func->SetName(v8_str("CallCollectSample"));
    1577          20 :   env->Global()->Set(env, v8_str("CallCollectSample"), func).FromJust();
    1578             : 
    1579           5 :   CompileRun(js_force_collect_sample_source);
    1580           5 :   ProfilerHelper helper(env);
    1581           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1582           5 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 0);
    1583             : 
    1584           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1585           5 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1586           5 :   CHECK_LE(1, start_node->GetChildrenCount());
    1587           5 :   GetChild(env, start_node, "CallCollectSample");
    1588             : 
    1589           5 :   profile->Delete();
    1590           5 : }
    1591             : 
    1592             : static const char* js_native_js_runtime_multiple_test_source =
    1593             :     "%NeverOptimizeFunction(foo);\n"
    1594             :     "%NeverOptimizeFunction(bar);\n"
    1595             :     "%NeverOptimizeFunction(start);\n"
    1596             :     "function foo() {\n"
    1597             :     "  return Math.sin(Math.random());\n"
    1598             :     "}\n"
    1599             :     "var bound = foo.bind(this);\n"
    1600             :     "function bar() {\n"
    1601             :     "  return bound();\n"
    1602             :     "}\n"
    1603             :     "function start() {\n"
    1604             :     "  startProfiling('my_profile');\n"
    1605             :     "  var startTime = Date.now();\n"
    1606             :     "  do {\n"
    1607             :     "    CallJsFunction(bar);\n"
    1608             :     "  } while (Date.now() - startTime < 200);\n"
    1609             :     "}";
    1610             : 
    1611             : // The test check multiple entrances/exits between JS and native code.
    1612             : //
    1613             : // [Top down]:
    1614             : //    (root) #0 1
    1615             : //      start #16 3
    1616             : //        CallJsFunction #0 4
    1617             : //          bar #16 5
    1618             : //            foo #16 6
    1619             : //      (program) #0 2
    1620       26639 : TEST(JsNativeJsRuntimeJsSampleMultiple) {
    1621           0 :   i::FLAG_allow_natives_syntax = true;
    1622           0 :   v8::HandleScope scope(CcTest::isolate());
    1623           0 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1624             :   v8::Context::Scope context_scope(env);
    1625             : 
    1626             :   v8::Local<v8::FunctionTemplate> func_template =
    1627           0 :       v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction);
    1628             :   v8::Local<v8::Function> func =
    1629           0 :       func_template->GetFunction(env).ToLocalChecked();
    1630           0 :   func->SetName(v8_str("CallJsFunction"));
    1631           0 :   env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
    1632             : 
    1633           0 :   CompileRun(js_native_js_runtime_multiple_test_source);
    1634             : 
    1635           0 :   ProfilerHelper helper(env);
    1636           0 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1637           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 500, 500);
    1638             : 
    1639           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1640           0 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1641             :   const v8::CpuProfileNode* native_node =
    1642           0 :       GetChild(env, start_node, "CallJsFunction");
    1643           0 :   const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
    1644           0 :   GetChild(env, bar_node, "foo");
    1645             : 
    1646           0 :   profile->Delete();
    1647           0 : }
    1648             : 
    1649             : static const char* inlining_test_source =
    1650             :     "%NeverOptimizeFunction(action);\n"
    1651             :     "%NeverOptimizeFunction(start);\n"
    1652             :     "level1();\n"
    1653             :     "%OptimizeFunctionOnNextCall(level1);\n"
    1654             :     "%OptimizeFunctionOnNextCall(level2);\n"
    1655             :     "%OptimizeFunctionOnNextCall(level3);\n"
    1656             :     "var finish = false;\n"
    1657             :     "function action(n) {\n"
    1658             :     "  var s = 0;\n"
    1659             :     "  for (var i = 0; i < n; ++i) s += i*i*i;\n"
    1660             :     "  if (finish)\n"
    1661             :     "    startProfiling('my_profile');\n"
    1662             :     "  return s;\n"
    1663             :     "}\n"
    1664             :     "function level3() { return action(100); }\n"
    1665             :     "function level2() { return level3() * 2; }\n"
    1666             :     "function level1() { return level2(); }\n"
    1667             :     "function start() {\n"
    1668             :     "  var n = 100;\n"
    1669             :     "  while (--n)\n"
    1670             :     "    level1();\n"
    1671             :     "  finish = true;\n"
    1672             :     "  level1();\n"
    1673             :     "}";
    1674             : 
    1675             : // The test check multiple entrances/exits between JS and native code.
    1676             : //
    1677             : // [Top down]:
    1678             : //    (root) #0 1
    1679             : //      start #16 3
    1680             : //        level1 #0 4
    1681             : //          level2 #16 5
    1682             : //            level3 #16 6
    1683             : //              action #16 7
    1684             : //      (program) #0 2
    1685       26644 : TEST(Inlining) {
    1686           5 :   i::FLAG_allow_natives_syntax = true;
    1687          10 :   v8::HandleScope scope(CcTest::isolate());
    1688          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1689             :   v8::Context::Scope context_scope(env);
    1690           5 :   ProfilerHelper helper(env);
    1691             : 
    1692           5 :   CompileRun(inlining_test_source);
    1693           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1694             : 
    1695           5 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
    1696          15 :   function->Call(env, env->Global(), 0, nullptr).ToLocalChecked();
    1697           5 :   v8::CpuProfile* profile = helper.profiler()->StopProfiling(profile_name);
    1698           5 :   CHECK(profile);
    1699             :   // Dump collected profile to have a better diagnostic in case of failure.
    1700           5 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    1701             : 
    1702           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1703           5 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1704           5 :   const v8::CpuProfileNode* level1_node = GetChild(env, start_node, "level1");
    1705           5 :   const v8::CpuProfileNode* level2_node = GetChild(env, level1_node, "level2");
    1706           5 :   const v8::CpuProfileNode* level3_node = GetChild(env, level2_node, "level3");
    1707           5 :   GetChild(env, level3_node, "action");
    1708             : 
    1709           5 :   profile->Delete();
    1710           5 : }
    1711             : 
    1712             : static const char* inlining_test_source2 = R"(
    1713             :     %NeverOptimizeFunction(action);
    1714             :     %NeverOptimizeFunction(start);
    1715             :     level1();
    1716             :     level1();
    1717             :     %OptimizeFunctionOnNextCall(level1);
    1718             :     %OptimizeFunctionOnNextCall(level2);
    1719             :     %OptimizeFunctionOnNextCall(level3);
    1720             :     %OptimizeFunctionOnNextCall(level4);
    1721             :     level1();
    1722             :     function action(n) {
    1723             :       var s = 0;
    1724             :       for (var i = 0; i < n; ++i) s += i*i*i;
    1725             :       return s;
    1726             :     }
    1727             :     function level4() {
    1728             :       action(100);
    1729             :       return action(100);
    1730             :     }
    1731             :     function level3() {
    1732             :       const a = level4();
    1733             :       const b = level4();
    1734             :       return a + b * 1.1;
    1735             :     }
    1736             :     function level2() {
    1737             :       return level3() * 2;
    1738             :     }
    1739             :     function level1() {
    1740             :       action(1);
    1741             :       action(200);
    1742             :       action(1);
    1743             :       return level2();
    1744             :     }
    1745             :     function start(n) {
    1746             :       while (--n)
    1747             :         level1();
    1748             :     };
    1749             :   )";
    1750             : 
    1751             : // The simulator builds are extremely slow. We run them with fewer iterations.
    1752             : #ifdef USE_SIMULATOR
    1753             : const double load_factor = 0.01;
    1754             : #else
    1755             : const double load_factor = 1.0;
    1756             : #endif
    1757             : 
    1758             : // [Top down]:
    1759             : //     0  (root):0 0 #1
    1760             : //    13    start:34 6 #3
    1761             : //              bailed out due to 'Optimization is always disabled'
    1762             : //    19      level1:36 6 #4
    1763             : //    16        action:29 6 #14
    1764             : //                  bailed out due to 'Optimization is always disabled'
    1765             : //  2748        action:30 6 #10
    1766             : //                  bailed out due to 'Optimization is always disabled'
    1767             : //    18        action:31 6 #15
    1768             : //                  bailed out due to 'Optimization is always disabled'
    1769             : //     0        level2:32 6 #5
    1770             : //     0          level3:26 6 #6
    1771             : //    12            level4:22 6 #11
    1772             : //  1315              action:17 6 #13
    1773             : //                        bailed out due to 'Optimization is always disabled'
    1774             : //  1324              action:18 6 #12
    1775             : //                        bailed out due to 'Optimization is always disabled'
    1776             : //    16            level4:21 6 #7
    1777             : //  1268              action:17 6 #9
    1778             : //                        bailed out due to 'Optimization is always disabled'
    1779             : //  1322              action:18 6 #8
    1780             : //                        bailed out due to 'Optimization is always disabled'
    1781             : //     2    (program):0 0 #2
    1782       26644 : TEST(Inlining2) {
    1783           5 :   FLAG_allow_natives_syntax = true;
    1784          10 :   v8::HandleScope scope(CcTest::isolate());
    1785          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1786             :   v8::Context::Scope context_scope(env);
    1787             : 
    1788           5 :   CompileRun(inlining_test_source2);
    1789           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    1790             : 
    1791           5 :   v8::CpuProfiler* profiler = v8::CpuProfiler::New(CcTest::isolate());
    1792           5 :   v8::Local<v8::String> profile_name = v8_str("inlining");
    1793             :   profiler->StartProfiling(profile_name,
    1794           5 :                            v8::CpuProfilingMode::kCallerLineNumbers);
    1795             : 
    1796             :   v8::Local<v8::Value> args[] = {
    1797           5 :       v8::Integer::New(env->GetIsolate(), 50000 * load_factor)};
    1798          15 :   function->Call(env, env->Global(), arraysize(args), args).ToLocalChecked();
    1799           5 :   v8::CpuProfile* profile = profiler->StopProfiling(profile_name);
    1800           5 :   CHECK(profile);
    1801             : 
    1802             :   // Dump collected profile to have a better diagnostic in case of failure.
    1803           5 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    1804             : 
    1805           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1806           5 :   const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
    1807             : 
    1808             :   NameLinePair l421_a17[] = {{"level1", 36},
    1809             :                              {"level2", 32},
    1810             :                              {"level3", 26},
    1811             :                              {"level4", 21},
    1812           5 :                              {"action", 17}};
    1813           5 :   CheckBranch(start_node, l421_a17, arraysize(l421_a17));
    1814             :   NameLinePair l422_a17[] = {{"level1", 36},
    1815             :                              {"level2", 32},
    1816             :                              {"level3", 26},
    1817             :                              {"level4", 22},
    1818           5 :                              {"action", 17}};
    1819           5 :   CheckBranch(start_node, l422_a17, arraysize(l422_a17));
    1820             : 
    1821             :   NameLinePair l421_a18[] = {{"level1", 36},
    1822             :                              {"level2", 32},
    1823             :                              {"level3", 26},
    1824             :                              {"level4", 21},
    1825           5 :                              {"action", 18}};
    1826           5 :   CheckBranch(start_node, l421_a18, arraysize(l421_a18));
    1827             :   NameLinePair l422_a18[] = {{"level1", 36},
    1828             :                              {"level2", 32},
    1829             :                              {"level3", 26},
    1830             :                              {"level4", 22},
    1831           5 :                              {"action", 18}};
    1832           5 :   CheckBranch(start_node, l422_a18, arraysize(l422_a18));
    1833             : 
    1834           5 :   NameLinePair action_direct[] = {{"level1", 36}, {"action", 30}};
    1835           5 :   CheckBranch(start_node, action_direct, arraysize(action_direct));
    1836             : 
    1837           5 :   profile->Delete();
    1838           5 :   profiler->Dispose();
    1839           5 : }
    1840             : 
    1841             : // [Top down]:
    1842             : //     0   (root) #0 1
    1843             : //     2    (program) #0 2
    1844             : //     3    (idle) #0 3
    1845       26644 : TEST(IdleTime) {
    1846           5 :   LocalContext env;
    1847          10 :   v8::HandleScope scope(env->GetIsolate());
    1848           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
    1849             : 
    1850           5 :   v8::Local<v8::String> profile_name = v8_str("my_profile");
    1851           5 :   cpu_profiler->StartProfiling(profile_name);
    1852             : 
    1853             :   i::Isolate* isolate = CcTest::i_isolate();
    1854             :   i::ProfilerEventsProcessor* processor =
    1855             :       reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->processor();
    1856             : 
    1857           5 :   processor->AddCurrentStack(true);
    1858           5 :   isolate->SetIdle(true);
    1859          35 :   for (int i = 0; i < 3; i++) {
    1860          15 :     processor->AddCurrentStack(true);
    1861             :   }
    1862           5 :   isolate->SetIdle(false);
    1863           5 :   processor->AddCurrentStack(true);
    1864             : 
    1865           5 :   v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
    1866           5 :   CHECK(profile);
    1867             :   // Dump collected profile to have a better diagnostic in case of failure.
    1868           5 :   reinterpret_cast<i::CpuProfile*>(profile)->Print();
    1869             : 
    1870           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1871             :   const v8::CpuProfileNode* program_node =
    1872          10 :       GetChild(env.local(), root, CodeEntry::kProgramEntryName);
    1873           5 :   CHECK_EQ(0, program_node->GetChildrenCount());
    1874           5 :   CHECK_GE(program_node->GetHitCount(), 2u);
    1875             : 
    1876             :   const v8::CpuProfileNode* idle_node =
    1877          10 :       GetChild(env.local(), root, CodeEntry::kIdleEntryName);
    1878           5 :   CHECK_EQ(0, idle_node->GetChildrenCount());
    1879           5 :   CHECK_GE(idle_node->GetHitCount(), 3u);
    1880             : 
    1881           5 :   profile->Delete();
    1882           5 :   cpu_profiler->Dispose();
    1883           5 : }
    1884             : 
    1885          27 : static void CheckFunctionDetails(v8::Isolate* isolate,
    1886             :                                  const v8::CpuProfileNode* node,
    1887             :                                  const char* name, const char* script_name,
    1888             :                                  bool is_shared_cross_origin, int script_id,
    1889             :                                  int line, int column,
    1890             :                                  const v8::CpuProfileNode* parent) {
    1891          27 :   v8::Local<v8::Context> context = isolate->GetCurrentContext();
    1892         108 :   CHECK(v8_str(name)->Equals(context, node->GetFunctionName()).FromJust());
    1893          27 :   CHECK_EQ(0, strcmp(name, node->GetFunctionNameStr()));
    1894         108 :   CHECK(v8_str(script_name)
    1895             :             ->Equals(context, node->GetScriptResourceName())
    1896             :             .FromJust());
    1897          27 :   CHECK_EQ(0, strcmp(script_name, node->GetScriptResourceNameStr()));
    1898          27 :   CHECK_EQ(script_id, node->GetScriptId());
    1899          27 :   CHECK_EQ(line, node->GetLineNumber());
    1900          27 :   CHECK_EQ(column, node->GetColumnNumber());
    1901          27 :   CHECK_EQ(parent, node->GetParent());
    1902          27 :   CHECK_EQ(v8::CpuProfileNode::kScript, node->GetSourceType());
    1903          27 : }
    1904             : 
    1905       26644 : TEST(FunctionDetails) {
    1906           5 :   i::FLAG_allow_natives_syntax = true;
    1907          10 :   v8::HandleScope scope(CcTest::isolate());
    1908          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1909             :   v8::Context::Scope context_scope(env);
    1910           5 :   ProfilerHelper helper(env);
    1911             : 
    1912             :   v8::Local<v8::Script> script_a = CompileWithOrigin(
    1913             :       "%NeverOptimizeFunction(foo);\n"
    1914             :       "%NeverOptimizeFunction(bar);\n"
    1915             :       "    function foo\n() { bar(); }\n"
    1916             :       " function bar() { startProfiling(); }\n",
    1917           5 :       "script_a", false);
    1918           5 :   script_a->Run(env).ToLocalChecked();
    1919             :   v8::Local<v8::Script> script_b = CompileWithOrigin(
    1920             :       "%NeverOptimizeFunction(baz);"
    1921             :       "\n\n   function baz() { foo(); }\n"
    1922             :       "\n\nbaz();\n"
    1923             :       "stopProfiling();\n",
    1924           5 :       "script_b", true);
    1925           5 :   script_b->Run(env).ToLocalChecked();
    1926           5 :   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
    1927           5 :   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
    1928             :   reinterpret_cast<ProfileNode*>(
    1929           5 :       const_cast<v8::CpuProfileNode*>(current))->Print(0);
    1930             :   // The tree should look like this:
    1931             :   //  0   (root) 0 #1
    1932             :   //  0    "" 19 #2 no reason script_b:1
    1933             :   //  0      baz 19 #3 TryCatchStatement script_b:3
    1934             :   //  0        foo 18 #4 TryCatchStatement script_a:2
    1935             :   //  1          bar 18 #5 no reason script_a:3
    1936           5 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    1937           5 :   CHECK_EQ(root->GetParent(), nullptr);
    1938           5 :   const v8::CpuProfileNode* script = GetChild(env, root, "");
    1939          10 :   CheckFunctionDetails(env->GetIsolate(), script, "", "script_b", true,
    1940          10 :                        script_b->GetUnboundScript()->GetId(), 1, 1, root);
    1941           5 :   const v8::CpuProfileNode* baz = GetChild(env, script, "baz");
    1942          10 :   CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b", true,
    1943          10 :                        script_b->GetUnboundScript()->GetId(), 3, 16, script);
    1944           5 :   const v8::CpuProfileNode* foo = GetChild(env, baz, "foo");
    1945          10 :   CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a", false,
    1946          10 :                        script_a->GetUnboundScript()->GetId(), 4, 1, baz);
    1947           5 :   const v8::CpuProfileNode* bar = GetChild(env, foo, "bar");
    1948          10 :   CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a", false,
    1949          10 :                        script_a->GetUnboundScript()->GetId(), 5, 14, foo);
    1950           5 : }
    1951             : 
    1952       26644 : TEST(FunctionDetailsInlining) {
    1953           8 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    1954           3 :   i::FLAG_allow_natives_syntax = true;
    1955           5 :   v8::HandleScope scope(CcTest::isolate());
    1956           6 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    1957             :   v8::Context::Scope context_scope(env);
    1958           3 :   ProfilerHelper helper(env);
    1959             : 
    1960             :   // alpha is in a_script, beta in b_script. beta is
    1961             :   // inlined in alpha, but it should be attributed to b_script.
    1962             : 
    1963             :   v8::Local<v8::Script> script_b = CompileWithOrigin(
    1964             :       "function beta(k) {\n"
    1965             :       "  let sum = 2;\n"
    1966             :       "  for(let i = 0; i < k; i ++) {\n"
    1967             :       "    sum += i;\n"
    1968             :       "    sum = sum + 'a';\n"
    1969             :       "  }\n"
    1970             :       "  return sum;\n"
    1971             :       "}\n"
    1972             :       "\n",
    1973           3 :       "script_b", true);
    1974             : 
    1975             :   v8::Local<v8::Script> script_a = CompileWithOrigin(
    1976             :       "function alpha(p) {\n"
    1977             :       "  let res = beta(p);\n"
    1978             :       "  res = res + res;\n"
    1979             :       "  return res;\n"
    1980             :       "}\n"
    1981             :       "let p = 2;\n"
    1982             :       "\n"
    1983             :       "\n"
    1984             :       "// Warm up before profiling or the inlining doesn't happen.\n"
    1985             :       "p = alpha(p);\n"
    1986             :       "p = alpha(p);\n"
    1987             :       "%OptimizeFunctionOnNextCall(alpha);\n"
    1988             :       "p = alpha(p);\n"
    1989             :       "\n"
    1990             :       "\n"
    1991             :       "startProfiling();\n"
    1992             :       "for(let i = 0; i < 10000; i++) {\n"
    1993             :       "  p = alpha(p);\n"
    1994             :       "}\n"
    1995             :       "stopProfiling();\n"
    1996             :       "\n"
    1997             :       "\n",
    1998           3 :       "script_a", false);
    1999             : 
    2000           3 :   script_b->Run(env).ToLocalChecked();
    2001           3 :   script_a->Run(env).ToLocalChecked();
    2002             : 
    2003           3 :   const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
    2004           3 :   const v8::CpuProfileNode* current = profile->GetTopDownRoot();
    2005             :   reinterpret_cast<ProfileNode*>(const_cast<v8::CpuProfileNode*>(current))
    2006           3 :       ->Print(0);
    2007             :   //   The tree should look like this:
    2008             :   //  0  (root) 0 #1
    2009             :   //  5    (program) 0 #6
    2010             :   //  2     14 #2 script_a:1
    2011             :   //    ;;; deopted at script_id: 14 position: 299 with reason 'Insufficient
    2012             :   //    type feedback for call'.
    2013             :   //  1      alpha 14 #4 script_a:1
    2014             :   //  9        beta 13 #5 script_b:0
    2015             :   //  0      startProfiling 0 #3
    2016             : 
    2017           3 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    2018           3 :   CHECK_EQ(root->GetParent(), nullptr);
    2019           3 :   const v8::CpuProfileNode* script = GetChild(env, root, "");
    2020           6 :   CheckFunctionDetails(env->GetIsolate(), script, "", "script_a", false,
    2021           6 :                        script_a->GetUnboundScript()->GetId(), 1, 1, root);
    2022           3 :   const v8::CpuProfileNode* alpha = FindChild(env, script, "alpha");
    2023             :   // Return early if profiling didn't sample alpha.
    2024           3 :   if (!alpha) return;
    2025           4 :   CheckFunctionDetails(env->GetIsolate(), alpha, "alpha", "script_a", false,
    2026           4 :                        script_a->GetUnboundScript()->GetId(), 1, 15, script);
    2027           2 :   const v8::CpuProfileNode* beta = FindChild(env, alpha, "beta");
    2028           2 :   if (!beta) return;
    2029           4 :   CheckFunctionDetails(env->GetIsolate(), beta, "beta", "script_b", true,
    2030           4 :                        script_b->GetUnboundScript()->GetId(), 1, 14, alpha);
    2031             : }
    2032             : 
    2033       26644 : TEST(DontStopOnFinishedProfileDelete) {
    2034          10 :   v8::HandleScope scope(CcTest::isolate());
    2035          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2036             :   v8::Context::Scope context_scope(env);
    2037             : 
    2038           5 :   v8::CpuProfiler* profiler = v8::CpuProfiler::New(env->GetIsolate());
    2039             :   i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
    2040             : 
    2041           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    2042           5 :   v8::Local<v8::String> outer = v8_str("outer");
    2043           5 :   profiler->StartProfiling(outer);
    2044           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    2045             : 
    2046           5 :   v8::Local<v8::String> inner = v8_str("inner");
    2047           5 :   profiler->StartProfiling(inner);
    2048           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    2049             : 
    2050           5 :   v8::CpuProfile* inner_profile = profiler->StopProfiling(inner);
    2051           5 :   CHECK(inner_profile);
    2052           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
    2053           5 :   inner_profile->Delete();
    2054             :   inner_profile = nullptr;
    2055           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    2056             : 
    2057           5 :   v8::CpuProfile* outer_profile = profiler->StopProfiling(outer);
    2058           5 :   CHECK(outer_profile);
    2059           5 :   CHECK_EQ(1, iprofiler->GetProfilesCount());
    2060           5 :   outer_profile->Delete();
    2061             :   outer_profile = nullptr;
    2062           5 :   CHECK_EQ(0, iprofiler->GetProfilesCount());
    2063           5 :   profiler->Dispose();
    2064           5 : }
    2065             : 
    2066             : 
    2067           0 : const char* GetBranchDeoptReason(v8::Local<v8::Context> context,
    2068             :                                  i::CpuProfile* iprofile, const char* branch[],
    2069             :                                  int length) {
    2070             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    2071             :   const ProfileNode* iopt_function = nullptr;
    2072           0 :   iopt_function = GetSimpleBranch(context, profile, branch, length);
    2073           0 :   CHECK_EQ(1U, iopt_function->deopt_infos().size());
    2074           0 :   return iopt_function->deopt_infos()[0].deopt_reason;
    2075             : }
    2076             : 
    2077             : 
    2078             : // deopt at top function
    2079       26639 : TEST(CollectDeoptEvents) {
    2080           0 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    2081           0 :   i::FLAG_allow_natives_syntax = true;
    2082           0 :   v8::HandleScope scope(CcTest::isolate());
    2083           0 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2084             :   v8::Context::Scope context_scope(env);
    2085           0 :   ProfilerHelper helper(env);
    2086             :   i::CpuProfiler* iprofiler =
    2087             :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    2088             : 
    2089             :   const char opt_source[] =
    2090             :       "function opt_function%d(value, depth) {\n"
    2091             :       "  if (depth) return opt_function%d(value, depth - 1);\n"
    2092             :       "\n"
    2093             :       "  return  10 / value;\n"
    2094             :       "}\n"
    2095           0 :       "\n";
    2096             : 
    2097           0 :   for (int i = 0; i < 3; ++i) {
    2098             :     i::EmbeddedVector<char, sizeof(opt_source) + 100> buffer;
    2099           0 :     i::SNPrintF(buffer, opt_source, i, i);
    2100           0 :     v8::Script::Compile(env, v8_str(buffer.start()))
    2101             :         .ToLocalChecked()
    2102           0 :         ->Run(env)
    2103             :         .ToLocalChecked();
    2104             :   }
    2105             : 
    2106             :   const char* source =
    2107             :       "startProfiling();\n"
    2108             :       "\n"
    2109             :       "opt_function0(1, 1);\n"
    2110             :       "\n"
    2111             :       "%OptimizeFunctionOnNextCall(opt_function0)\n"
    2112             :       "\n"
    2113             :       "opt_function0(1, 1);\n"
    2114             :       "\n"
    2115             :       "opt_function0(undefined, 1);\n"
    2116             :       "\n"
    2117             :       "opt_function1(1, 1);\n"
    2118             :       "\n"
    2119             :       "%OptimizeFunctionOnNextCall(opt_function1)\n"
    2120             :       "\n"
    2121             :       "opt_function1(1, 1);\n"
    2122             :       "\n"
    2123             :       "opt_function1(NaN, 1);\n"
    2124             :       "\n"
    2125             :       "opt_function2(1, 1);\n"
    2126             :       "\n"
    2127             :       "%OptimizeFunctionOnNextCall(opt_function2)\n"
    2128             :       "\n"
    2129             :       "opt_function2(1, 1);\n"
    2130             :       "\n"
    2131             :       "opt_function2(0, 1);\n"
    2132             :       "\n"
    2133             :       "stopProfiling();\n"
    2134             :       "\n";
    2135             : 
    2136           0 :   v8::Script::Compile(env, v8_str(source))
    2137             :       .ToLocalChecked()
    2138           0 :       ->Run(env)
    2139             :       .ToLocalChecked();
    2140           0 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    2141           0 :   iprofile->Print();
    2142             :   /* The expected profile
    2143             :   [Top down]:
    2144             :       0  (root) 0 #1
    2145             :      23     32 #2
    2146             :       1      opt_function2 31 #7
    2147             :       1        opt_function2 31 #8
    2148             :                   ;;; deopted at script_id: 31 position: 106 with reason
    2149             :   'division by zero'.
    2150             :       2      opt_function0 29 #3
    2151             :       4        opt_function0 29 #4
    2152             :                   ;;; deopted at script_id: 29 position: 108 with reason 'not a
    2153             :   heap number'.
    2154             :       0      opt_function1 30 #5
    2155             :       1        opt_function1 30 #6
    2156             :                   ;;; deopted at script_id: 30 position: 108 with reason 'lost
    2157             :   precision or NaN'.
    2158             :   */
    2159             : 
    2160             :   {
    2161           0 :     const char* branch[] = {"", "opt_function0", "opt_function0"};
    2162             :     const char* deopt_reason =
    2163           0 :         GetBranchDeoptReason(env, iprofile, branch, arraysize(branch));
    2164           0 :     if (deopt_reason != reason(i::DeoptimizeReason::kNotAHeapNumber) &&
    2165             :         deopt_reason != reason(i::DeoptimizeReason::kNotASmi)) {
    2166           0 :       FATAL("%s", deopt_reason);
    2167             :     }
    2168             :   }
    2169             :   {
    2170           0 :     const char* branch[] = {"", "opt_function1", "opt_function1"};
    2171             :     const char* deopt_reason =
    2172           0 :         GetBranchDeoptReason(env, iprofile, branch, arraysize(branch));
    2173           0 :     if (deopt_reason != reason(i::DeoptimizeReason::kNaN) &&
    2174           0 :         deopt_reason != reason(i::DeoptimizeReason::kLostPrecisionOrNaN) &&
    2175             :         deopt_reason != reason(i::DeoptimizeReason::kNotASmi)) {
    2176           0 :       FATAL("%s", deopt_reason);
    2177             :     }
    2178             :   }
    2179             :   {
    2180           0 :     const char* branch[] = {"", "opt_function2", "opt_function2"};
    2181           0 :     CHECK_EQ(reason(i::DeoptimizeReason::kDivisionByZero),
    2182             :              GetBranchDeoptReason(env, iprofile, branch, arraysize(branch)));
    2183             :   }
    2184           0 :   iprofiler->DeleteProfile(iprofile);
    2185             : }
    2186             : 
    2187             : 
    2188       26644 : TEST(SourceLocation) {
    2189           5 :   i::FLAG_always_opt = true;
    2190           5 :   LocalContext env;
    2191          10 :   v8::HandleScope scope(CcTest::isolate());
    2192             : 
    2193             :   const char* source =
    2194             :       "function CompareStatementWithThis() {\n"
    2195             :       "  if (this === 1) {}\n"
    2196             :       "}\n"
    2197             :       "CompareStatementWithThis();\n";
    2198             : 
    2199          10 :   v8::Script::Compile(env.local(), v8_str(source))
    2200             :       .ToLocalChecked()
    2201           5 :       ->Run(env.local())
    2202             :       .ToLocalChecked();
    2203           5 : }
    2204             : 
    2205             : static const char* inlined_source =
    2206             :     "function opt_function(left, right) { var k = left*right; return k + 1; "
    2207             :     "}\n";
    2208             : //   0.........1.........2.........3.........4....*....5.........6......*..7
    2209             : 
    2210             : 
    2211             : // deopt at the first level inlined function
    2212       26639 : TEST(DeoptAtFirstLevelInlinedSource) {
    2213           0 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    2214           0 :   i::FLAG_allow_natives_syntax = true;
    2215           0 :   v8::HandleScope scope(CcTest::isolate());
    2216           0 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2217             :   v8::Context::Scope context_scope(env);
    2218           0 :   ProfilerHelper helper(env);
    2219             :   i::CpuProfiler* iprofiler =
    2220             :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    2221             : 
    2222             :   //   0.........1.........2.........3.........4.........5.........6.........7
    2223             :   const char* source =
    2224             :       "function test(left, right) { return opt_function(left, right); }\n"
    2225             :       "\n"
    2226             :       "startProfiling();\n"
    2227             :       "\n"
    2228             :       "test(10, 10);\n"
    2229             :       "\n"
    2230             :       "%OptimizeFunctionOnNextCall(test)\n"
    2231             :       "\n"
    2232             :       "test(10, 10);\n"
    2233             :       "\n"
    2234             :       "test(undefined, 1e9);\n"
    2235             :       "\n"
    2236             :       "stopProfiling();\n"
    2237             :       "\n";
    2238             : 
    2239           0 :   v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
    2240           0 :   inlined_script->Run(env).ToLocalChecked();
    2241           0 :   int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
    2242             : 
    2243             :   v8::Local<v8::Script> script = v8_compile(source);
    2244           0 :   script->Run(env).ToLocalChecked();
    2245           0 :   int script_id = script->GetUnboundScript()->GetId();
    2246             : 
    2247           0 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    2248           0 :   iprofile->Print();
    2249             :   /* The expected profile output
    2250             :   [Top down]:
    2251             :       0  (root) 0 #1
    2252             :      10     30 #2
    2253             :       1      test 30 #3
    2254             :                 ;;; deopted at script_id: 29 position: 45 with reason 'not a
    2255             :   heap number'.
    2256             :                 ;;;     Inline point: script_id 30 position: 36.
    2257             :       4        opt_function 29 #4
    2258             :   */
    2259             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    2260             : 
    2261           0 :   const char* branch[] = {"", "test"};
    2262             :   const ProfileNode* itest_node =
    2263           0 :       GetSimpleBranch(env, profile, branch, arraysize(branch));
    2264             :   const std::vector<v8::CpuProfileDeoptInfo>& deopt_infos =
    2265             :       itest_node->deopt_infos();
    2266           0 :   CHECK_EQ(1U, deopt_infos.size());
    2267             : 
    2268             :   const v8::CpuProfileDeoptInfo& info = deopt_infos[0];
    2269           0 :   CHECK(reason(i::DeoptimizeReason::kNotASmi) == info.deopt_reason ||
    2270             :         reason(i::DeoptimizeReason::kNotAHeapNumber) == info.deopt_reason);
    2271           0 :   CHECK_EQ(2U, info.stack.size());
    2272           0 :   CHECK_EQ(inlined_script_id, info.stack[0].script_id);
    2273           0 :   CHECK_LE(dist(offset(inlined_source, "*right"), info.stack[0].position), 1);
    2274           0 :   CHECK_EQ(script_id, info.stack[1].script_id);
    2275           0 :   CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
    2276             : 
    2277           0 :   iprofiler->DeleteProfile(iprofile);
    2278             : }
    2279             : 
    2280             : 
    2281             : // deopt at the second level inlined function
    2282       26644 : TEST(DeoptAtSecondLevelInlinedSource) {
    2283           7 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    2284           3 :   i::FLAG_allow_natives_syntax = true;
    2285           6 :   v8::HandleScope scope(CcTest::isolate());
    2286           6 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2287             :   v8::Context::Scope context_scope(env);
    2288           3 :   ProfilerHelper helper(env);
    2289             :   i::CpuProfiler* iprofiler =
    2290             :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    2291             : 
    2292             :   //   0.........1.........2.........3.........4.........5.........6.........7
    2293             :   const char* source =
    2294             :       "function test2(left, right) { return opt_function(left, right); }\n"
    2295             :       "function test1(left, right) { return test2(left, right); } \n"
    2296             :       "\n"
    2297             :       "startProfiling();\n"
    2298             :       "\n"
    2299             :       "test1(10, 10);\n"
    2300             :       "\n"
    2301             :       "%OptimizeFunctionOnNextCall(test1)\n"
    2302             :       "\n"
    2303             :       "test1(10, 10);\n"
    2304             :       "\n"
    2305             :       "test1(undefined, 1e9);\n"
    2306             :       "\n"
    2307             :       "stopProfiling();\n"
    2308             :       "\n";
    2309             : 
    2310           3 :   v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
    2311           3 :   inlined_script->Run(env).ToLocalChecked();
    2312           6 :   int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
    2313             : 
    2314             :   v8::Local<v8::Script> script = v8_compile(source);
    2315           3 :   script->Run(env).ToLocalChecked();
    2316           6 :   int script_id = script->GetUnboundScript()->GetId();
    2317             : 
    2318           3 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    2319           3 :   iprofile->Print();
    2320             :   /* The expected profile output
    2321             :   [Top down]:
    2322             :       0  (root) 0 #1
    2323             :      11     30 #2
    2324             :       1      test1 30 #3
    2325             :                 ;;; deopted at script_id: 29 position: 45 with reason 'not a
    2326             :   heap number'.
    2327             :                 ;;;     Inline point: script_id 30 position: 37.
    2328             :                 ;;;     Inline point: script_id 30 position: 103.
    2329             :       1        test2 30 #4
    2330             :       3          opt_function 29 #5
    2331             :   */
    2332             : 
    2333             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    2334             : 
    2335           3 :   const char* branch[] = {"", "test1"};
    2336             :   const ProfileNode* itest_node =
    2337           3 :       GetSimpleBranch(env, profile, branch, arraysize(branch));
    2338             :   const std::vector<v8::CpuProfileDeoptInfo>& deopt_infos =
    2339             :       itest_node->deopt_infos();
    2340           3 :   CHECK_EQ(1U, deopt_infos.size());
    2341             : 
    2342             :   const v8::CpuProfileDeoptInfo info = deopt_infos[0];
    2343           3 :   CHECK(reason(i::DeoptimizeReason::kNotASmi) == info.deopt_reason ||
    2344             :         reason(i::DeoptimizeReason::kNotAHeapNumber) == info.deopt_reason);
    2345           3 :   CHECK_EQ(3U, info.stack.size());
    2346           3 :   CHECK_EQ(inlined_script_id, info.stack[0].script_id);
    2347           6 :   CHECK_LE(dist(offset(inlined_source, "*right"), info.stack[0].position), 1);
    2348           3 :   CHECK_EQ(script_id, info.stack[1].script_id);
    2349           3 :   CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
    2350           3 :   CHECK_EQ(offset(source, "test2(left, right);"), info.stack[2].position);
    2351             : 
    2352           3 :   iprofiler->DeleteProfile(iprofile);
    2353             : }
    2354             : 
    2355             : 
    2356             : // deopt in untracked function
    2357       26644 : TEST(DeoptUntrackedFunction) {
    2358           7 :   if (!CcTest::i_isolate()->use_optimizer() || i::FLAG_always_opt) return;
    2359           3 :   i::FLAG_allow_natives_syntax = true;
    2360           6 :   v8::HandleScope scope(CcTest::isolate());
    2361           6 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2362             :   v8::Context::Scope context_scope(env);
    2363           3 :   ProfilerHelper helper(env);
    2364             :   i::CpuProfiler* iprofiler =
    2365             :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    2366             : 
    2367             :   //   0.........1.........2.........3.........4.........5.........6.........7
    2368             :   const char* source =
    2369             :       "function test(left, right) { return opt_function(left, right); }\n"
    2370             :       "\n"
    2371             :       "test(10, 10);\n"
    2372             :       "\n"
    2373             :       "%OptimizeFunctionOnNextCall(test)\n"
    2374             :       "\n"
    2375             :       "test(10, 10);\n"
    2376             :       "\n"
    2377             :       "startProfiling();\n"  // profiler started after compilation.
    2378             :       "\n"
    2379             :       "test(undefined, 10);\n"
    2380             :       "\n"
    2381             :       "stopProfiling();\n"
    2382             :       "\n";
    2383             : 
    2384           3 :   v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
    2385           3 :   inlined_script->Run(env).ToLocalChecked();
    2386             : 
    2387             :   v8::Local<v8::Script> script = v8_compile(source);
    2388           3 :   script->Run(env).ToLocalChecked();
    2389             : 
    2390           3 :   i::CpuProfile* iprofile = iprofiler->GetProfile(0);
    2391           3 :   iprofile->Print();
    2392             :   v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
    2393             : 
    2394           3 :   const char* branch[] = {"", "test"};
    2395             :   const ProfileNode* itest_node =
    2396           3 :       GetSimpleBranch(env, profile, branch, arraysize(branch));
    2397           3 :   CHECK_EQ(0U, itest_node->deopt_infos().size());
    2398             : 
    2399           3 :   iprofiler->DeleteProfile(iprofile);
    2400             : }
    2401             : 
    2402             : using v8::platform::tracing::TraceBuffer;
    2403             : using v8::platform::tracing::TraceConfig;
    2404             : using v8::platform::tracing::TraceObject;
    2405             : 
    2406             : namespace {
    2407             : 
    2408          15 : class CpuProfileEventChecker : public v8::platform::tracing::TraceWriter {
    2409             :  public:
    2410          13 :   void AppendTraceEvent(TraceObject* trace_event) override {
    2411          47 :     if (trace_event->name() != std::string("Profile") &&
    2412          29 :         trace_event->name() != std::string("ProfileChunk"))
    2413             :       return;
    2414          13 :     CHECK(!profile_id_ || trace_event->id() == profile_id_);
    2415          13 :     CHECK_EQ(1, trace_event->num_args());
    2416          13 :     CHECK_EQ(TRACE_VALUE_TYPE_CONVERTABLE, trace_event->arg_types()[0]);
    2417          13 :     profile_id_ = trace_event->id();
    2418             :     v8::ConvertableToTraceFormat* arg =
    2419             :         trace_event->arg_convertables()[0].get();
    2420          13 :     result_json_ += result_json_.empty() ? "[" : ",\n";
    2421          13 :     arg->AppendAsTraceFormat(&result_json_);
    2422             :   }
    2423          10 :   void Flush() override { result_json_ += "]"; }
    2424             : 
    2425             :   const std::string& result_json() const { return result_json_; }
    2426             :   void Reset() {
    2427             :     result_json_.clear();
    2428           5 :     profile_id_ = 0;
    2429             :   }
    2430             : 
    2431             :  private:
    2432             :   std::string result_json_;
    2433             :   uint64_t profile_id_ = 0;
    2434             : };
    2435             : 
    2436             : }  // namespace
    2437             : 
    2438       26644 : TEST(TracingCpuProfiler) {
    2439          10 :   v8::HandleScope scope(CcTest::isolate());
    2440          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2441             :   v8::Context::Scope context_scope(env);
    2442             : 
    2443           5 :   CpuProfileEventChecker* event_checker = new CpuProfileEventChecker();
    2444             :   TraceBuffer* ring_buffer =
    2445           5 :       TraceBuffer::CreateTraceBufferRingBuffer(1, event_checker);
    2446             :   auto* tracing_controller =
    2447             :       static_cast<v8::platform::tracing::TracingController*>(
    2448           5 :           i::V8::GetCurrentPlatform()->GetTracingController());
    2449           5 :   tracing_controller->Initialize(ring_buffer);
    2450             : 
    2451             :   bool result = false;
    2452          15 :   for (int run_duration = 50; !result; run_duration += 50) {
    2453           5 :     TraceConfig* trace_config = new TraceConfig();
    2454             :     trace_config->AddIncludedCategory(
    2455           5 :         TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"));
    2456             :     trace_config->AddIncludedCategory(
    2457           5 :         TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler.hires"));
    2458             : 
    2459             :     std::string test_code = R"(
    2460             :         function foo() {
    2461             :           let s = 0;
    2462          10 :           const endTime = Date.now() + )" +
    2463          10 :                             std::to_string(run_duration) + R"(
    2464             :           while (Date.now() < endTime) s += Math.cos(s);
    2465             :           return s;
    2466             :         }
    2467             :         foo();)";
    2468             : 
    2469           5 :     tracing_controller->StartTracing(trace_config);
    2470             :     CompileRun(test_code.c_str());
    2471           5 :     tracing_controller->StopTracing();
    2472             : 
    2473             :     std::string profile_json = event_checker->result_json();
    2474             :     event_checker->Reset();
    2475           5 :     CHECK_LT(0u, profile_json.length());
    2476             :     printf("Profile JSON: %s\n", profile_json.c_str());
    2477             : 
    2478             :     std::string profile_checker_code = R"(
    2479             :         function checkProfile(json) {
    2480             :           const profile_header = json[0];
    2481             :           if (typeof profile_header['startTime'] !== 'number')
    2482             :             return false;
    2483             :           return json.some(event => (event.lines || []).some(line => line));
    2484             :         }
    2485          10 :         checkProfile()" + profile_json +
    2486           5 :                                        ")";
    2487          10 :     result = CompileRunChecked(CcTest::isolate(), profile_checker_code.c_str())
    2488           5 :                  ->IsTrue();
    2489             :   }
    2490             : 
    2491             :   static_cast<v8::platform::tracing::TracingController*>(
    2492           5 :       i::V8::GetCurrentPlatform()->GetTracingController())
    2493           5 :       ->Initialize(nullptr);
    2494           5 : }
    2495             : 
    2496       26644 : TEST(Issue763073) {
    2497             :   class AllowNativesSyntax {
    2498             :    public:
    2499             :     AllowNativesSyntax()
    2500             :         : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
    2501           5 :           trace_deopt_(i::FLAG_trace_deopt) {
    2502           5 :       i::FLAG_allow_natives_syntax = true;
    2503           5 :       i::FLAG_trace_deopt = true;
    2504             :     }
    2505             : 
    2506             :     ~AllowNativesSyntax() {
    2507           5 :       i::FLAG_allow_natives_syntax = allow_natives_syntax_;
    2508           5 :       i::FLAG_trace_deopt = trace_deopt_;
    2509             :     }
    2510             : 
    2511             :    private:
    2512             :     bool allow_natives_syntax_;
    2513             :     bool trace_deopt_;
    2514             :   };
    2515             : 
    2516             :   AllowNativesSyntax allow_natives_syntax_scope;
    2517           5 :   LocalContext env;
    2518          10 :   v8::HandleScope scope(env->GetIsolate());
    2519             : 
    2520             :   CompileRun(
    2521             :       "function f() { return function g(x) { }; }"
    2522             :       // Create first closure, optimize it, and deoptimize it.
    2523             :       "var g = f();"
    2524             :       "g(1);"
    2525             :       "%OptimizeFunctionOnNextCall(g);"
    2526             :       "g(1);"
    2527             :       "%DeoptimizeFunction(g);"
    2528             :       // Create second closure, and optimize it. This will create another
    2529             :       // optimized code object and put in the (shared) type feedback vector.
    2530             :       "var h = f();"
    2531             :       "h(1);"
    2532             :       "%OptimizeFunctionOnNextCall(h);"
    2533             :       "h(1);");
    2534             : 
    2535             :   // Start profiling.
    2536           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
    2537           5 :   v8::Local<v8::String> profile_name = v8_str("test");
    2538             : 
    2539             :   // Here we test that the heap iteration upon profiling start is not
    2540             :   // confused by having a deoptimized code object for a closure while
    2541             :   // having a different optimized code object in the type feedback vector.
    2542           5 :   cpu_profiler->StartProfiling(profile_name);
    2543           5 :   v8::CpuProfile* p = cpu_profiler->StopProfiling(profile_name);
    2544           5 :   p->Delete();
    2545           5 :   cpu_profiler->Dispose();
    2546           5 : }
    2547             : 
    2548             : static const char* js_collect_sample_api_source =
    2549             :     "%NeverOptimizeFunction(start);\n"
    2550             :     "function start() {\n"
    2551             :     "  CallStaticCollectSample();\n"
    2552             :     "}";
    2553             : 
    2554           0 : static void CallStaticCollectSample(
    2555             :     const v8::FunctionCallbackInfo<v8::Value>& info) {
    2556           0 :   v8::CpuProfiler::CollectSample(info.GetIsolate());
    2557           0 : }
    2558             : 
    2559       26639 : TEST(StaticCollectSampleAPI) {
    2560           0 :   i::FLAG_allow_natives_syntax = true;
    2561           0 :   LocalContext env;
    2562           0 :   v8::HandleScope scope(env->GetIsolate());
    2563             : 
    2564             :   v8::Local<v8::FunctionTemplate> func_template =
    2565           0 :       v8::FunctionTemplate::New(env->GetIsolate(), CallStaticCollectSample);
    2566             :   v8::Local<v8::Function> func =
    2567           0 :       func_template->GetFunction(env.local()).ToLocalChecked();
    2568           0 :   func->SetName(v8_str("CallStaticCollectSample"));
    2569           0 :   env->Global()
    2570           0 :       ->Set(env.local(), v8_str("CallStaticCollectSample"), func)
    2571             :       .FromJust();
    2572             : 
    2573           0 :   CompileRun(js_collect_sample_api_source);
    2574           0 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    2575             : 
    2576           0 :   ProfilerHelper helper(env.local());
    2577           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 100);
    2578             : 
    2579           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    2580           0 :   const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
    2581           0 :   GetChild(env.local(), start_node, "CallStaticCollectSample");
    2582             : 
    2583           0 :   profile->Delete();
    2584           0 : }
    2585             : 
    2586       26644 : TEST(CodeEntriesMemoryLeak) {
    2587          10 :   v8::HandleScope scope(CcTest::isolate());
    2588          10 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2589             :   v8::Context::Scope context_scope(env);
    2590             : 
    2591           5 :   std::string source = "function start() {}\n";
    2592       10005 :   for (int i = 0; i < 1000; ++i) {
    2593       25000 :     source += "function foo" + std::to_string(i) + "() { return " +
    2594       15000 :               std::to_string(i) +
    2595             :               "; }\n"
    2596       10000 :               "foo" +
    2597       15000 :               std::to_string(i) + "();\n";
    2598             :   }
    2599             :   CompileRun(source.c_str());
    2600           5 :   v8::Local<v8::Function> function = GetFunction(env, "start");
    2601             : 
    2602           5 :   ProfilerHelper helper(env);
    2603             : 
    2604        1005 :   for (int j = 0; j < 100; ++j) {
    2605         500 :     v8::CpuProfile* profile = helper.Run(function, nullptr, 0);
    2606         500 :     profile->Delete();
    2607             :   }
    2608             : 
    2609             :   i::CpuProfiler* profiler =
    2610             :       reinterpret_cast<i::CpuProfiler*>(helper.profiler());
    2611           5 :   CHECK(!profiler->profiler_listener_for_test());
    2612           5 : }
    2613             : 
    2614       26639 : TEST(NativeFrameStackTrace) {
    2615             :   // A test for issue https://crbug.com/768540
    2616             :   // When a sample lands in a native function which has not EXIT frame
    2617             :   // stack frame iterator used to bail out and produce an empty stack trace.
    2618             :   // The source code below makes v8 call the
    2619             :   // v8::internal::StringTable::LookupStringIfExists_NoAllocate native function
    2620             :   // without producing an EXIT frame.
    2621           0 :   v8::HandleScope scope(CcTest::isolate());
    2622           0 :   v8::Local<v8::Context> env = CcTest::NewContext({PROFILER_EXTENSION_ID});
    2623             :   v8::Context::Scope context_scope(env);
    2624             : 
    2625             :   const char* source = R"(
    2626             :       function jsFunction() {
    2627             :         var s = {};
    2628             :         for (var i = 0; i < 1e4; ++i) {
    2629             :           for (var j = 0; j < 100; j++) {
    2630             :             s['item' + j] = 'alph';
    2631             :           }
    2632             :         }
    2633             :       })";
    2634             : 
    2635             :   CompileRun(source);
    2636           0 :   v8::Local<v8::Function> function = GetFunction(env, "jsFunction");
    2637             : 
    2638           0 :   ProfilerHelper helper(env);
    2639             : 
    2640           0 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 100, 0, true);
    2641             : 
    2642             :   // Count the fraction of samples landing in 'jsFunction' (valid stack)
    2643             :   // vs '(program)' (no stack captured).
    2644           0 :   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
    2645           0 :   const v8::CpuProfileNode* js_function = FindChild(root, "jsFunction");
    2646           0 :   const v8::CpuProfileNode* program = FindChild(root, "(program)");
    2647           0 :   if (program) {
    2648           0 :     unsigned js_function_samples = TotalHitCount(js_function);
    2649           0 :     unsigned program_samples = TotalHitCount(program);
    2650             :     double valid_samples_ratio =
    2651           0 :         1. * js_function_samples / (js_function_samples + program_samples);
    2652           0 :     i::PrintF("Ratio: %f\n", valid_samples_ratio);
    2653             :     // TODO(alph): Investigate other causes of dropped frames. The ratio
    2654             :     // should be close to 99%.
    2655           0 :     CHECK_GE(valid_samples_ratio, 0.3);
    2656             :   }
    2657             : 
    2658           0 :   profile->Delete();
    2659           0 : }
    2660             : 
    2661       26644 : TEST(SourcePositionTable) {
    2662             :   i::SourcePositionTable info;
    2663             : 
    2664             :   // Newly created tables should return NoLineNumberInfo for any lookup.
    2665             :   int no_info = v8::CpuProfileNode::kNoLineNumberInfo;
    2666           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(std::numeric_limits<int>::min()));
    2667           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(0));
    2668           5 :   CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(0));
    2669           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(1));
    2670           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(9));
    2671           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(10));
    2672           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(11));
    2673           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(19));
    2674           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(20));
    2675           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(21));
    2676           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(100));
    2677           5 :   CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(100));
    2678           5 :   CHECK_EQ(no_info, info.GetSourceLineNumber(std::numeric_limits<int>::max()));
    2679             : 
    2680           5 :   info.SetPosition(10, 1, SourcePosition::kNotInlined);
    2681           5 :   info.SetPosition(20, 2, SourcePosition::kNotInlined);
    2682             : 
    2683             :   // The only valid return values are 1 or 2 - every pc maps to a line
    2684             :   // number.
    2685           5 :   CHECK_EQ(1, info.GetSourceLineNumber(std::numeric_limits<int>::min()));
    2686           5 :   CHECK_EQ(1, info.GetSourceLineNumber(0));
    2687           5 :   CHECK_EQ(1, info.GetSourceLineNumber(1));
    2688           5 :   CHECK_EQ(1, info.GetSourceLineNumber(9));
    2689           5 :   CHECK_EQ(1, info.GetSourceLineNumber(10));
    2690           5 :   CHECK_EQ(1, info.GetSourceLineNumber(11));
    2691           5 :   CHECK_EQ(1, info.GetSourceLineNumber(19));
    2692           5 :   CHECK_EQ(1, info.GetSourceLineNumber(20));
    2693           5 :   CHECK_EQ(2, info.GetSourceLineNumber(21));
    2694           5 :   CHECK_EQ(2, info.GetSourceLineNumber(100));
    2695           5 :   CHECK_EQ(2, info.GetSourceLineNumber(std::numeric_limits<int>::max()));
    2696             : 
    2697           5 :   CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(0));
    2698           5 :   CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(100));
    2699             : 
    2700             :   // Test SetPosition behavior.
    2701           5 :   info.SetPosition(25, 3, 0);
    2702           5 :   CHECK_EQ(2, info.GetSourceLineNumber(21));
    2703           5 :   CHECK_EQ(3, info.GetSourceLineNumber(100));
    2704           5 :   CHECK_EQ(3, info.GetSourceLineNumber(std::numeric_limits<int>::max()));
    2705             : 
    2706           5 :   CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(21));
    2707           5 :   CHECK_EQ(0, info.GetInliningId(100));
    2708           5 : }
    2709             : 
    2710       26644 : TEST(MultipleProfilers) {
    2711          10 :   std::unique_ptr<CpuProfiler> profiler1(new CpuProfiler(CcTest::i_isolate()));
    2712          10 :   std::unique_ptr<CpuProfiler> profiler2(new CpuProfiler(CcTest::i_isolate()));
    2713           5 :   profiler1->StartProfiling("1");
    2714           5 :   profiler2->StartProfiling("2");
    2715           5 :   profiler1->StopProfiling("1");
    2716           5 :   profiler2->StopProfiling("2");
    2717           5 : }
    2718             : 
    2719             : // Tests that logged CodeCreateEvent calls do not crash a reused CpuProfiler.
    2720             : // crbug.com/929928
    2721       26644 : TEST(CrashReusedProfiler) {
    2722           5 :   LocalContext env;
    2723             :   i::Isolate* isolate = CcTest::i_isolate();
    2724             :   i::HandleScope scope(isolate);
    2725             : 
    2726          10 :   std::unique_ptr<CpuProfiler> profiler(new CpuProfiler(isolate));
    2727           5 :   profiler->StartProfiling("1");
    2728           5 :   profiler->StopProfiling("1");
    2729             : 
    2730           5 :   profiler->StartProfiling("2");
    2731           5 :   CreateCode(&env);
    2732           5 :   profiler->StopProfiling("2");
    2733           5 : }
    2734             : 
    2735             : // Tests that samples from different profilers on the same isolate do not leak
    2736             : // samples to each other. See crbug.com/v8/8835.
    2737       26644 : TEST(MultipleProfilersSampleIndependently) {
    2738           5 :   LocalContext env;
    2739             :   i::Isolate* isolate = CcTest::i_isolate();
    2740             :   i::HandleScope scope(isolate);
    2741             : 
    2742             :   // Create two profilers- one slow ticking one, and one fast ticking one.
    2743             :   // Ensure that the slow ticking profiler does not receive samples from the
    2744             :   // fast ticking one.
    2745             :   std::unique_ptr<CpuProfiler> slow_profiler(
    2746          10 :       new CpuProfiler(CcTest::i_isolate()));
    2747           5 :   slow_profiler->set_sampling_interval(base::TimeDelta::FromSeconds(1));
    2748           5 :   slow_profiler->StartProfiling("1", true);
    2749             : 
    2750             :   CompileRun(R"(
    2751             :     function start() {
    2752             :       let val = 1;
    2753             :       for (let i = 0; i < 10e3; i++) {
    2754             :         val = (val * 2) % 3;
    2755             :       }
    2756             :       return val;
    2757             :     }
    2758             :   )");
    2759           5 :   v8::Local<v8::Function> function = GetFunction(env.local(), "start");
    2760           5 :   ProfilerHelper helper(env.local());
    2761           5 :   v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 100, 0, true);
    2762             : 
    2763           5 :   auto slow_profile = slow_profiler->StopProfiling("1");
    2764           5 :   CHECK_GT(profile->GetSamplesCount(), slow_profile->samples_count());
    2765           5 : }
    2766             : 
    2767          10 : void ProfileSomeCode(v8::Isolate* isolate) {
    2768             :   v8::Isolate::Scope isolate_scope(isolate);
    2769          20 :   v8::HandleScope scope(isolate);
    2770          10 :   LocalContext context(isolate);
    2771             : 
    2772          10 :   v8::CpuProfiler* profiler = v8::CpuProfiler::New(isolate);
    2773             : 
    2774          10 :   v8::Local<v8::String> profile_name = v8_str("1");
    2775          10 :   profiler->StartProfiling(profile_name);
    2776             :   const char* source = R"(
    2777             :       function foo() {
    2778             :         var x = 0;
    2779             :         for (var i = 0; i < 1e3; i++) {
    2780             :           for (var j = 0; j < 1e3; j++) {
    2781             :             x = i * j;
    2782             :           }
    2783             :         }
    2784             :         return x;
    2785             :       }
    2786             :       foo();
    2787             :     )";
    2788             : 
    2789             :   CompileRun(source);
    2790          10 :   profiler->StopProfiling(profile_name);
    2791          10 :   profiler->Dispose();
    2792          10 : }
    2793             : 
    2794           5 : class IsolateThread : public v8::base::Thread {
    2795             :  public:
    2796          10 :   IsolateThread() : Thread(Options("IsolateThread")) {}
    2797             : 
    2798          10 :   void Run() override {
    2799             :     v8::Isolate::CreateParams create_params;
    2800          10 :     create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2801          10 :     v8::Isolate* isolate = v8::Isolate::New(create_params);
    2802          10 :     ProfileSomeCode(isolate);
    2803          10 :     isolate->Dispose();
    2804          10 :   }
    2805             : };
    2806             : 
    2807             : // Checking for crashes and TSAN issues with multiple isolates profiling.
    2808       26644 : TEST(MultipleIsolates) {
    2809             :   IsolateThread thread1;
    2810             :   IsolateThread thread2;
    2811             : 
    2812           5 :   thread1.Start();
    2813           5 :   thread2.Start();
    2814             : 
    2815           5 :   thread1.Join();
    2816           5 :   thread2.Join();
    2817           5 : }
    2818             : 
    2819             : // Tests that StopProfiling doesn't wait for the next sample tick in order to
    2820             : // stop, but rather exits early before a given wait threshold.
    2821       26644 : TEST(FastStopProfiling) {
    2822             :   static const base::TimeDelta kLongInterval = base::TimeDelta::FromSeconds(10);
    2823             :   static const base::TimeDelta kWaitThreshold = base::TimeDelta::FromSeconds(5);
    2824             : 
    2825          10 :   std::unique_ptr<CpuProfiler> profiler(new CpuProfiler(CcTest::i_isolate()));
    2826           5 :   profiler->set_sampling_interval(kLongInterval);
    2827           5 :   profiler->StartProfiling("", true);
    2828             : 
    2829           5 :   v8::Platform* platform = v8::internal::V8::GetCurrentPlatform();
    2830           5 :   double start = platform->CurrentClockTimeMillis();
    2831           5 :   profiler->StopProfiling("");
    2832           5 :   double duration = platform->CurrentClockTimeMillis() - start;
    2833             : 
    2834          10 :   CHECK_LT(duration, kWaitThreshold.InMillisecondsF());
    2835           5 : }
    2836             : 
    2837       26644 : TEST(LowPrecisionSamplingStartStopInternal) {
    2838             :   i::Isolate* isolate = CcTest::i_isolate();
    2839          10 :   CpuProfilesCollection profiles(isolate);
    2840           5 :   ProfileGenerator generator(&profiles);
    2841             :   std::unique_ptr<ProfilerEventsProcessor> processor(
    2842             :       new SamplingEventsProcessor(isolate, &generator,
    2843          10 :                                   v8::base::TimeDelta::FromMicroseconds(100),
    2844           5 :                                   false));
    2845           5 :   processor->Start();
    2846           5 :   processor->StopSynchronously();
    2847           5 : }
    2848             : 
    2849       26644 : TEST(LowPrecisionSamplingStartStopPublic) {
    2850           5 :   LocalContext env;
    2851          10 :   v8::HandleScope scope(env->GetIsolate());
    2852           5 :   v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
    2853           5 :   cpu_profiler->SetUsePreciseSampling(false);
    2854           5 :   v8::Local<v8::String> profile_name = v8_str("");
    2855           5 :   cpu_profiler->StartProfiling(profile_name, true);
    2856           5 :   cpu_profiler->StopProfiling(profile_name);
    2857           5 :   cpu_profiler->Dispose();
    2858           5 : }
    2859             : 
    2860             : enum class EntryCountMode { kAll, kOnlyInlined };
    2861             : 
    2862             : // Count the number of unique source positions.
    2863          30 : int GetSourcePositionEntryCount(i::Isolate* isolate, const char* source,
    2864             :                                 EntryCountMode mode = EntryCountMode::kAll) {
    2865             :   std::unordered_set<int64_t> raw_position_set;
    2866             :   i::Handle<i::JSFunction> function = i::Handle<i::JSFunction>::cast(
    2867             :       v8::Utils::OpenHandle(*CompileRun(source)));
    2868          30 :   if (function->IsInterpreted()) return -1;
    2869             :   i::Handle<i::Code> code(function->code(), isolate);
    2870             :   i::SourcePositionTableIterator iterator(
    2871          24 :       ByteArray::cast(code->source_position_table()));
    2872             : 
    2873         412 :   while (!iterator.done()) {
    2874         262 :     if (mode == EntryCountMode::kAll ||
    2875             :         iterator.source_position().isInlined()) {
    2876         332 :       raw_position_set.insert(iterator.source_position().raw());
    2877             :     }
    2878         194 :     iterator.Advance();
    2879             :   }
    2880          24 :   return static_cast<int>(raw_position_set.size());
    2881             : }
    2882             : 
    2883       26644 : UNINITIALIZED_TEST(DetailedSourcePositionAPI) {
    2884           5 :   i::FLAG_detailed_line_info = false;
    2885           5 :   i::FLAG_allow_natives_syntax = true;
    2886             :   v8::Isolate::CreateParams create_params;
    2887           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2888           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
    2889             : 
    2890             :   const char* source =
    2891             :       "function fib(i) {"
    2892             :       "  if (i <= 1) return 1; "
    2893             :       "  return fib(i - 1) +"
    2894             :       "         fib(i - 2);"
    2895             :       "}"
    2896             :       "fib(5);"
    2897             :       "%OptimizeFunctionOnNextCall(fib);"
    2898             :       "fib(5);"
    2899             :       "fib";
    2900             :   {
    2901             :     v8::Isolate::Scope isolate_scope(isolate);
    2902          10 :     v8::HandleScope handle_scope(isolate);
    2903           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    2904             :     v8::Context::Scope context_scope(context);
    2905             :     i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
    2906             : 
    2907           5 :     CHECK(!i_isolate->NeedsDetailedOptimizedCodeLineInfo());
    2908             : 
    2909           5 :     int non_detailed_positions = GetSourcePositionEntryCount(i_isolate, source);
    2910             : 
    2911           5 :     v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
    2912           5 :     CHECK(i_isolate->NeedsDetailedOptimizedCodeLineInfo());
    2913             : 
    2914           5 :     int detailed_positions = GetSourcePositionEntryCount(i_isolate, source);
    2915             : 
    2916           5 :     CHECK((non_detailed_positions == -1 && detailed_positions == -1) ||
    2917             :           non_detailed_positions < detailed_positions);
    2918             :   }
    2919             : 
    2920           5 :   isolate->Dispose();
    2921           5 : }
    2922             : 
    2923       26644 : UNINITIALIZED_TEST(DetailedSourcePositionAPI_Inlining) {
    2924           5 :   i::FLAG_detailed_line_info = false;
    2925           5 :   i::FLAG_turbo_inlining = true;
    2926           5 :   i::FLAG_stress_inline = true;
    2927           5 :   i::FLAG_always_opt = false;
    2928           5 :   i::FLAG_allow_natives_syntax = true;
    2929             :   v8::Isolate::CreateParams create_params;
    2930           5 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    2931           5 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
    2932             : 
    2933             :   const char* source = R"(
    2934             :     function foo(x) {
    2935             :       return bar(x) + 1;
    2936             :     }
    2937             : 
    2938             :     function bar(x) {
    2939             :       var y = 1;
    2940             :       for (var i = 0; i < x; ++i) {
    2941             :         y = y * x;
    2942             :       }
    2943             :       return x;
    2944             :     }
    2945             : 
    2946             :     foo(5);
    2947             :     %OptimizeFunctionOnNextCall(foo);
    2948             :     foo(5);
    2949             :     foo;
    2950             :   )";
    2951             : 
    2952             :   {
    2953             :     v8::Isolate::Scope isolate_scope(isolate);
    2954          10 :     v8::HandleScope handle_scope(isolate);
    2955           5 :     v8::Local<v8::Context> context = v8::Context::New(isolate);
    2956             :     v8::Context::Scope context_scope(context);
    2957             :     i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
    2958             : 
    2959           5 :     CHECK(!i_isolate->NeedsDetailedOptimizedCodeLineInfo());
    2960             : 
    2961             :     int non_detailed_positions =
    2962           5 :         GetSourcePositionEntryCount(i_isolate, source, EntryCountMode::kAll);
    2963             :     int non_detailed_inlined_positions = GetSourcePositionEntryCount(
    2964           5 :         i_isolate, source, EntryCountMode::kOnlyInlined);
    2965             : 
    2966           5 :     v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
    2967           5 :     CHECK(i_isolate->NeedsDetailedOptimizedCodeLineInfo());
    2968             : 
    2969             :     int detailed_positions =
    2970           5 :         GetSourcePositionEntryCount(i_isolate, source, EntryCountMode::kAll);
    2971             :     int detailed_inlined_positions = GetSourcePositionEntryCount(
    2972           5 :         i_isolate, source, EntryCountMode::kOnlyInlined);
    2973             : 
    2974           5 :     if (non_detailed_positions == -1) {
    2975           1 :       CHECK_EQ(non_detailed_positions, detailed_positions);
    2976             :     } else {
    2977           4 :       CHECK_LT(non_detailed_positions, detailed_positions);
    2978           4 :       CHECK_LT(non_detailed_inlined_positions, detailed_inlined_positions);
    2979             :     }
    2980             :   }
    2981             : 
    2982           5 :   isolate->Dispose();
    2983           5 : }
    2984             : 
    2985             : }  // namespace test_cpu_profiler
    2986             : }  // namespace internal
    2987       79917 : }  // namespace v8

Generated by: LCOV version 1.10