LCOV - code coverage report
Current view: top level - test/cctest - test-cpu-profiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 806 1230 65.5 %
Date: 2019-02-19 Functions: 56 90 62.2 %

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

Generated by: LCOV version 1.10