LCOV - code coverage report
Current view: top level - test/cctest - test-cpu-profiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 750 1174 63.9 %
Date: 2019-01-20 Functions: 52 86 60.5 %

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

Generated by: LCOV version 1.10