LCOV - code coverage report
Current view: top level - src - log.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 398 860 46.3 %
Date: 2017-10-20 Functions: 69 129 53.5 %

          Line data    Source code
       1             : // Copyright 2011 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/log.h"
       6             : 
       7             : #include <cstdarg>
       8             : #include <memory>
       9             : #include <sstream>
      10             : 
      11             : #include "src/api.h"
      12             : #include "src/bailout-reason.h"
      13             : #include "src/base/platform/platform.h"
      14             : #include "src/bootstrapper.h"
      15             : #include "src/code-stubs.h"
      16             : #include "src/counters.h"
      17             : #include "src/deoptimizer.h"
      18             : #include "src/global-handles.h"
      19             : #include "src/interpreter/bytecodes.h"
      20             : #include "src/interpreter/interpreter.h"
      21             : #include "src/libsampler/sampler.h"
      22             : #include "src/log-inl.h"
      23             : #include "src/log-utils.h"
      24             : #include "src/macro-assembler.h"
      25             : #include "src/perf-jit.h"
      26             : #include "src/profiler/profiler-listener.h"
      27             : #include "src/profiler/tick-sample.h"
      28             : #include "src/runtime-profiler.h"
      29             : #include "src/source-position-table.h"
      30             : #include "src/string-stream.h"
      31             : #include "src/tracing/tracing-category-observer.h"
      32             : #include "src/unicode-inl.h"
      33             : #include "src/vm-state-inl.h"
      34             : 
      35             : namespace v8 {
      36             : namespace internal {
      37             : 
      38             : #define DECLARE_EVENT(ignore1, name) name,
      39             : static const char* kLogEventsNames[CodeEventListener::NUMBER_OF_LOG_EVENTS] = {
      40             :     LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)};
      41             : #undef DECLARE_EVENT
      42             : 
      43       22029 : static const char* ComputeMarker(SharedFunctionInfo* shared,
      44             :                                  AbstractCode* code) {
      45       22029 :   switch (code->kind()) {
      46             :     case AbstractCode::INTERPRETED_FUNCTION:
      47         278 :       return shared->optimization_disabled() ? "" : "~";
      48             :     case AbstractCode::OPTIMIZED_FUNCTION:
      49             :       return "*";
      50             :     default:
      51       21693 :       return "";
      52             :   }
      53             : }
      54             : 
      55             : 
      56             : class CodeEventLogger::NameBuffer {
      57             :  public:
      58             :   NameBuffer() { Reset(); }
      59             : 
      60             :   void Reset() {
      61        8414 :     utf8_pos_ = 0;
      62             :   }
      63             : 
      64        8059 :   void Init(CodeEventListener::LogEventsAndTags tag) {
      65             :     Reset();
      66        8059 :     AppendBytes(kLogEventsNames[tag]);
      67             :     AppendByte(':');
      68        8059 :   }
      69             : 
      70        5210 :   void AppendName(Name* name) {
      71        5210 :     if (name->IsString()) {
      72        5210 :       AppendString(String::cast(name));
      73             :     } else {
      74             :       Symbol* symbol = Symbol::cast(name);
      75           0 :       AppendBytes("symbol(");
      76           0 :       if (!symbol->name()->IsUndefined(symbol->GetIsolate())) {
      77           0 :         AppendBytes("\"");
      78           0 :         AppendString(String::cast(symbol->name()));
      79           0 :         AppendBytes("\" ");
      80             :       }
      81           0 :       AppendBytes("hash ");
      82           0 :       AppendHex(symbol->Hash());
      83             :       AppendByte(')');
      84             :     }
      85        5210 :   }
      86             : 
      87        5788 :   void AppendString(String* str) {
      88       11576 :     if (str == nullptr) return;
      89             :     int uc16_length = Min(str->length(), kUtf16BufferSize);
      90        5788 :     String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
      91             :     int previous = unibrow::Utf16::kNoPreviousCharacter;
      92       12605 :     for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
      93        6817 :       uc16 c = utf16_buffer[i];
      94        6817 :       if (c <= unibrow::Utf8::kMaxOneByteChar) {
      95        6817 :         utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
      96             :       } else {
      97           0 :         int char_length = unibrow::Utf8::Length(c, previous);
      98           0 :         if (utf8_pos_ + char_length > kUtf8BufferSize) break;
      99           0 :         unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
     100           0 :         utf8_pos_ += char_length;
     101             :       }
     102        6817 :       previous = c;
     103             :     }
     104             :   }
     105             : 
     106       16118 :   void AppendBytes(const char* bytes, int size) {
     107       16118 :     size = Min(size, kUtf8BufferSize - utf8_pos_);
     108       16118 :     MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
     109       16118 :     utf8_pos_ += size;
     110       16118 :   }
     111             : 
     112       16118 :   void AppendBytes(const char* bytes) {
     113       16118 :     AppendBytes(bytes, StrLength(bytes));
     114       16118 :   }
     115             : 
     116             :   void AppendByte(char c) {
     117        8637 :     if (utf8_pos_ >= kUtf8BufferSize) return;
     118        8613 :     utf8_buffer_[utf8_pos_++] = c;
     119             :   }
     120             : 
     121         289 :   void AppendInt(int n) {
     122         289 :     int space = kUtf8BufferSize - utf8_pos_;
     123         301 :     if (space <= 0) return;
     124         277 :     Vector<char> buffer(utf8_buffer_ + utf8_pos_, space);
     125         277 :     int size = SNPrintF(buffer, "%d", n);
     126         277 :     if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
     127         277 :       utf8_pos_ += size;
     128             :     }
     129             :   }
     130             : 
     131           0 :   void AppendHex(uint32_t n) {
     132           0 :     int space = kUtf8BufferSize - utf8_pos_;
     133           0 :     if (space <= 0) return;
     134           0 :     Vector<char> buffer(utf8_buffer_ + utf8_pos_, space);
     135           0 :     int size = SNPrintF(buffer, "%x", n);
     136           0 :     if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
     137           0 :       utf8_pos_ += size;
     138             :     }
     139             :   }
     140             : 
     141             :   const char* get() { return utf8_buffer_; }
     142             :   int size() const { return utf8_pos_; }
     143             : 
     144             :  private:
     145             :   static const int kUtf8BufferSize = 512;
     146             :   static const int kUtf16BufferSize = kUtf8BufferSize;
     147             : 
     148             :   int utf8_pos_;
     149             :   char utf8_buffer_[kUtf8BufferSize];
     150             :   uc16 utf16_buffer[kUtf16BufferSize];
     151             : };
     152             : 
     153             : 
     154        1027 : CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
     155             : 
     156         672 : CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
     157             : 
     158        2560 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
     159             :                                       AbstractCode* code, const char* comment) {
     160        5120 :   name_buffer_->Init(tag);
     161        2560 :   name_buffer_->AppendBytes(comment);
     162        5120 :   LogRecordedBuffer(code, nullptr, name_buffer_->get(), name_buffer_->size());
     163        2560 : }
     164             : 
     165           0 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
     166             :                                       AbstractCode* code, Name* name) {
     167           0 :   name_buffer_->Init(tag);
     168           0 :   name_buffer_->AppendName(name);
     169           0 :   LogRecordedBuffer(code, nullptr, name_buffer_->get(), name_buffer_->size());
     170           0 : }
     171             : 
     172        5210 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
     173             :                                       AbstractCode* code,
     174             :                                       SharedFunctionInfo* shared, Name* name) {
     175       10420 :   name_buffer_->Init(tag);
     176        5210 :   name_buffer_->AppendBytes(ComputeMarker(shared, code));
     177        5210 :   name_buffer_->AppendName(name);
     178       10420 :   LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
     179        5210 : }
     180             : 
     181         289 : void CodeEventLogger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
     182             :                                       AbstractCode* code,
     183             :                                       SharedFunctionInfo* shared, Name* source,
     184             :                                       int line, int column) {
     185         578 :   name_buffer_->Init(tag);
     186         289 :   name_buffer_->AppendBytes(ComputeMarker(shared, code));
     187         289 :   name_buffer_->AppendString(shared->DebugName());
     188         289 :   name_buffer_->AppendByte(' ');
     189         289 :   if (source->IsString()) {
     190         289 :     name_buffer_->AppendString(String::cast(source));
     191             :   } else {
     192           0 :     name_buffer_->AppendBytes("symbol(hash ");
     193           0 :     name_buffer_->AppendHex(Name::cast(source)->Hash());
     194           0 :     name_buffer_->AppendByte(')');
     195             :   }
     196         289 :   name_buffer_->AppendByte(':');
     197         289 :   name_buffer_->AppendInt(line);
     198         578 :   LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
     199         289 : }
     200             : 
     201           0 : void CodeEventLogger::RegExpCodeCreateEvent(AbstractCode* code,
     202             :                                             String* source) {
     203           0 :   name_buffer_->Init(CodeEventListener::REG_EXP_TAG);
     204           0 :   name_buffer_->AppendString(source);
     205           0 :   LogRecordedBuffer(code, nullptr, name_buffer_->get(), name_buffer_->size());
     206           0 : }
     207             : 
     208             : 
     209             : // Linux perf tool logging support
     210             : class PerfBasicLogger : public CodeEventLogger {
     211             :  public:
     212             :   PerfBasicLogger();
     213             :   ~PerfBasicLogger() override;
     214             : 
     215           0 :   void CodeMoveEvent(AbstractCode* from, Address to) override {}
     216           0 :   void CodeDisableOptEvent(AbstractCode* code,
     217           0 :                            SharedFunctionInfo* shared) override {}
     218             : 
     219             :  private:
     220             :   void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo* shared,
     221             :                          const char* name, int length) override;
     222             : 
     223             :   // Extension added to V8 log file name to get the low-level log name.
     224             :   static const char kFilenameFormatString[];
     225             :   static const int kFilenameBufferPadding;
     226             : 
     227             :   FILE* perf_output_handle_;
     228             : };
     229             : 
     230             : const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map";
     231             : // Extra space for the PID in the filename
     232             : const int PerfBasicLogger::kFilenameBufferPadding = 16;
     233             : 
     234           0 : PerfBasicLogger::PerfBasicLogger() : perf_output_handle_(nullptr) {
     235             :   // Open the perf JIT dump file.
     236             :   int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
     237             :   ScopedVector<char> perf_dump_name(bufferSize);
     238             :   int size = SNPrintF(
     239             :       perf_dump_name,
     240             :       kFilenameFormatString,
     241           0 :       base::OS::GetCurrentProcessId());
     242           0 :   CHECK_NE(size, -1);
     243             :   perf_output_handle_ =
     244           0 :       base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode);
     245           0 :   CHECK_NOT_NULL(perf_output_handle_);
     246           0 :   setvbuf(perf_output_handle_, nullptr, _IOLBF, 0);
     247           0 : }
     248             : 
     249             : 
     250           0 : PerfBasicLogger::~PerfBasicLogger() {
     251           0 :   fclose(perf_output_handle_);
     252           0 :   perf_output_handle_ = nullptr;
     253           0 : }
     254             : 
     255           0 : void PerfBasicLogger::LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*,
     256             :                                         const char* name, int length) {
     257           0 :   if (FLAG_perf_basic_prof_only_functions &&
     258           0 :       (code->kind() != AbstractCode::INTERPRETED_FUNCTION &&
     259           0 :        code->kind() != AbstractCode::OPTIMIZED_FUNCTION)) {
     260           0 :     return;
     261             :   }
     262             : 
     263             :   // Linux perf expects hex literals without a leading 0x, while some
     264             :   // implementations of printf might prepend one when using the %p format
     265             :   // for pointers, leading to wrongly formatted JIT symbols maps.
     266             :   //
     267             :   // Instead, we use V8PRIxPTR format string and cast pointer to uintpr_t,
     268             :   // so that we have control over the exact output format.
     269             :   base::OS::FPrint(perf_output_handle_, "%" V8PRIxPTR " %x %.*s\n",
     270           0 :                    reinterpret_cast<uintptr_t>(code->instruction_start()),
     271           0 :                    code->instruction_size(), length, name);
     272             : }
     273             : 
     274             : // Low-level logging support.
     275             : #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
     276             : 
     277             : class LowLevelLogger : public CodeEventLogger {
     278             :  public:
     279             :   explicit LowLevelLogger(const char* file_name);
     280             :   ~LowLevelLogger() override;
     281             : 
     282             :   void CodeMoveEvent(AbstractCode* from, Address to) override;
     283           0 :   void CodeDisableOptEvent(AbstractCode* code,
     284           0 :                            SharedFunctionInfo* shared) override {}
     285             :   void SnapshotPositionEvent(HeapObject* obj, int pos);
     286             :   void CodeMovingGCEvent() override;
     287             : 
     288             :  private:
     289             :   void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo* shared,
     290             :                          const char* name, int length) override;
     291             : 
     292             :   // Low-level profiling event structures.
     293             :   struct CodeCreateStruct {
     294             :     static const char kTag = 'C';
     295             : 
     296             :     int32_t name_size;
     297             :     Address code_address;
     298             :     int32_t code_size;
     299             :   };
     300             : 
     301             : 
     302             :   struct CodeMoveStruct {
     303             :     static const char kTag = 'M';
     304             : 
     305             :     Address from_address;
     306             :     Address to_address;
     307             :   };
     308             : 
     309             : 
     310             :   static const char kCodeMovingGCTag = 'G';
     311             : 
     312             : 
     313             :   // Extension added to V8 log file name to get the low-level log name.
     314             :   static const char kLogExt[];
     315             : 
     316             :   void LogCodeInfo();
     317             :   void LogWriteBytes(const char* bytes, int size);
     318             : 
     319             :   template <typename T>
     320           0 :   void LogWriteStruct(const T& s) {
     321           0 :     char tag = T::kTag;
     322             :     LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
     323             :     LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
     324           0 :   }
     325             : 
     326             :   FILE* ll_output_handle_;
     327             : };
     328             : 
     329             : const char LowLevelLogger::kLogExt[] = ".ll";
     330             : 
     331           0 : LowLevelLogger::LowLevelLogger(const char* name) : ll_output_handle_(nullptr) {
     332             :   // Open the low-level log file.
     333           0 :   size_t len = strlen(name);
     334           0 :   ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
     335             :   MemCopy(ll_name.start(), name, len);
     336           0 :   MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
     337             :   ll_output_handle_ =
     338           0 :       base::OS::FOpen(ll_name.start(), base::OS::LogFileOpenMode);
     339           0 :   setvbuf(ll_output_handle_, nullptr, _IOLBF, 0);
     340             : 
     341             :   LogCodeInfo();
     342           0 : }
     343             : 
     344             : 
     345           0 : LowLevelLogger::~LowLevelLogger() {
     346           0 :   fclose(ll_output_handle_);
     347           0 :   ll_output_handle_ = nullptr;
     348           0 : }
     349             : 
     350             : 
     351           0 : void LowLevelLogger::LogCodeInfo() {
     352             : #if V8_TARGET_ARCH_IA32
     353             :   const char arch[] = "ia32";
     354             : #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT
     355           0 :   const char arch[] = "x64";
     356             : #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
     357             :   const char arch[] = "x32";
     358             : #elif V8_TARGET_ARCH_ARM
     359             :   const char arch[] = "arm";
     360             : #elif V8_TARGET_ARCH_PPC
     361             :   const char arch[] = "ppc";
     362             : #elif V8_TARGET_ARCH_MIPS
     363             :   const char arch[] = "mips";
     364             : #elif V8_TARGET_ARCH_ARM64
     365             :   const char arch[] = "arm64";
     366             : #elif V8_TARGET_ARCH_S390
     367             :   const char arch[] = "s390";
     368             : #else
     369             :   const char arch[] = "unknown";
     370             : #endif
     371             :   LogWriteBytes(arch, sizeof(arch));
     372           0 : }
     373             : 
     374           0 : void LowLevelLogger::LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*,
     375             :                                        const char* name, int length) {
     376             :   CodeCreateStruct event;
     377           0 :   event.name_size = length;
     378           0 :   event.code_address = code->instruction_start();
     379           0 :   event.code_size = code->instruction_size();
     380           0 :   LogWriteStruct(event);
     381             :   LogWriteBytes(name, length);
     382             :   LogWriteBytes(
     383           0 :       reinterpret_cast<const char*>(code->instruction_start()),
     384           0 :       code->instruction_size());
     385           0 : }
     386             : 
     387           0 : void LowLevelLogger::CodeMoveEvent(AbstractCode* from, Address to) {
     388             :   CodeMoveStruct event;
     389           0 :   event.from_address = from->instruction_start();
     390           0 :   size_t header_size = from->instruction_start() - from->address();
     391           0 :   event.to_address = to + header_size;
     392           0 :   LogWriteStruct(event);
     393           0 : }
     394             : 
     395             : 
     396           0 : void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
     397           0 :   size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
     398             :   DCHECK(static_cast<size_t>(size) == rv);
     399             :   USE(rv);
     400           0 : }
     401             : 
     402             : 
     403           0 : void LowLevelLogger::CodeMovingGCEvent() {
     404           0 :   const char tag = kCodeMovingGCTag;
     405             : 
     406             :   LogWriteBytes(&tag, sizeof(tag));
     407           0 : }
     408             : 
     409         114 : class JitLogger : public CodeEventLogger {
     410             :  public:
     411             :   explicit JitLogger(JitCodeEventHandler code_event_handler);
     412             : 
     413             :   void CodeMoveEvent(AbstractCode* from, Address to) override;
     414          14 :   void CodeDisableOptEvent(AbstractCode* code,
     415          14 :                            SharedFunctionInfo* shared) override {}
     416             :   void AddCodeLinePosInfoEvent(void* jit_handler_data, int pc_offset,
     417             :                                int position,
     418             :                                JitCodeEvent::PositionType position_type);
     419             : 
     420             :   void* StartCodePosInfoEvent();
     421             :   void EndCodePosInfoEvent(AbstractCode* code, void* jit_handler_data);
     422             : 
     423             :  private:
     424             :   void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo* shared,
     425             :                          const char* name, int length) override;
     426             : 
     427             :   JitCodeEventHandler code_event_handler_;
     428             :   base::Mutex logger_mutex_;
     429             : };
     430             : 
     431             : 
     432          38 : JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
     433          38 :     : code_event_handler_(code_event_handler) {
     434          38 : }
     435             : 
     436        5429 : void JitLogger::LogRecordedBuffer(AbstractCode* code,
     437             :                                   SharedFunctionInfo* shared, const char* name,
     438             :                                   int length) {
     439             :   JitCodeEvent event;
     440             :   memset(&event, 0, sizeof(event));
     441             :   event.type = JitCodeEvent::CODE_ADDED;
     442        5429 :   event.code_start = code->instruction_start();
     443        5429 :   event.code_len = code->instruction_size();
     444             :   Handle<SharedFunctionInfo> shared_function_handle;
     445        8299 :   if (shared && shared->script()->IsScript()) {
     446             :     shared_function_handle = Handle<SharedFunctionInfo>(shared);
     447             :   }
     448        5429 :   event.script = ToApiHandle<v8::UnboundScript>(shared_function_handle);
     449        5429 :   event.name.str = name;
     450        5429 :   event.name.len = length;
     451        5429 :   code_event_handler_(&event);
     452        5429 : }
     453             : 
     454         192 : void JitLogger::CodeMoveEvent(AbstractCode* from, Address to) {
     455         192 :   base::LockGuard<base::Mutex> guard(&logger_mutex_);
     456             : 
     457             :   JitCodeEvent event;
     458         192 :   event.type = JitCodeEvent::CODE_MOVED;
     459         192 :   event.code_start = from->instruction_start();
     460         192 :   event.code_len = from->instruction_size();
     461             : 
     462             :   // Calculate the header size.
     463         192 :   const size_t header_size = from->instruction_start() - from->address();
     464             : 
     465             :   // Calculate the new start address of the instructions.
     466         192 :   event.new_code_start = to + header_size;
     467             : 
     468         192 :   code_event_handler_(&event);
     469         192 : }
     470             : 
     471        2165 : void JitLogger::AddCodeLinePosInfoEvent(
     472             :     void* jit_handler_data,
     473             :     int pc_offset,
     474             :     int position,
     475             :     JitCodeEvent::PositionType position_type) {
     476             :   JitCodeEvent event;
     477             :   memset(&event, 0, sizeof(event));
     478        2165 :   event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
     479        2165 :   event.user_data = jit_handler_data;
     480        2165 :   event.line_info.offset = pc_offset;
     481        2165 :   event.line_info.pos = position;
     482        2165 :   event.line_info.position_type = position_type;
     483             : 
     484        2165 :   code_event_handler_(&event);
     485        2165 : }
     486             : 
     487             : 
     488         237 : void* JitLogger::StartCodePosInfoEvent() {
     489             :   JitCodeEvent event;
     490             :   memset(&event, 0, sizeof(event));
     491         237 :   event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
     492             : 
     493         237 :   code_event_handler_(&event);
     494         237 :   return event.user_data;
     495             : }
     496             : 
     497         237 : void JitLogger::EndCodePosInfoEvent(AbstractCode* code,
     498             :                                     void* jit_handler_data) {
     499             :   JitCodeEvent event;
     500             :   memset(&event, 0, sizeof(event));
     501         237 :   event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
     502         237 :   event.code_start = code->instruction_start();
     503         237 :   event.user_data = jit_handler_data;
     504             : 
     505         237 :   code_event_handler_(&event);
     506         237 : }
     507             : 
     508             : 
     509             : // TODO(lpy): Keeping sampling thread inside V8 is a workaround currently,
     510             : // the reason is to reduce code duplication during migration to sampler library,
     511             : // sampling thread, as well as the sampler, will be moved to D8 eventually.
     512       53365 : class SamplingThread : public base::Thread {
     513             :  public:
     514             :   static const int kSamplingThreadStackSize = 64 * KB;
     515             : 
     516             :   SamplingThread(sampler::Sampler* sampler, int interval_microseconds)
     517             :       : base::Thread(
     518             :             base::Thread::Options("SamplingThread", kSamplingThreadStackSize)),
     519             :         sampler_(sampler),
     520       54998 :         interval_microseconds_(interval_microseconds) {}
     521           0 :   void Run() override {
     522           0 :     while (sampler_->IsProfiling()) {
     523           0 :       sampler_->DoSample();
     524             :       base::OS::Sleep(
     525           0 :           base::TimeDelta::FromMicroseconds(interval_microseconds_));
     526             :     }
     527           0 :   }
     528             : 
     529             :  private:
     530             :   sampler::Sampler* sampler_;
     531             :   const int interval_microseconds_;
     532             : };
     533             : 
     534             : 
     535             : // The Profiler samples pc and sp values for the main thread.
     536             : // Each sample is appended to a circular buffer.
     537             : // An independent thread removes data and writes it to the log.
     538             : // This design minimizes the time spent in the sampler.
     539             : //
     540           0 : class Profiler: public base::Thread {
     541             :  public:
     542             :   explicit Profiler(Isolate* isolate);
     543             :   void Engage();
     544             :   void Disengage();
     545             : 
     546             :   // Inserts collected profiling data into buffer.
     547           0 :   void Insert(v8::TickSample* sample) {
     548           0 :     if (paused_)
     549           0 :       return;
     550             : 
     551           0 :     if (Succ(head_) == static_cast<int>(base::Relaxed_Load(&tail_))) {
     552           0 :       overflow_ = true;
     553             :     } else {
     554           0 :       buffer_[head_] = *sample;
     555           0 :       head_ = Succ(head_);
     556           0 :       buffer_semaphore_.Signal();  // Tell we have an element.
     557             :     }
     558             :   }
     559             : 
     560             :   virtual void Run();
     561             : 
     562             :   // Pause and Resume TickSample data collection.
     563           0 :   void pause() { paused_ = true; }
     564           0 :   void resume() { paused_ = false; }
     565             : 
     566             :  private:
     567             :   // Waits for a signal and removes profiling data.
     568           0 :   bool Remove(v8::TickSample* sample) {
     569           0 :     buffer_semaphore_.Wait();  // Wait for an element.
     570           0 :     *sample = buffer_[base::Relaxed_Load(&tail_)];
     571           0 :     bool result = overflow_;
     572             :     base::Relaxed_Store(
     573             :         &tail_, static_cast<base::Atomic32>(Succ(base::Relaxed_Load(&tail_))));
     574           0 :     overflow_ = false;
     575           0 :     return result;
     576             :   }
     577             : 
     578             :   // Returns the next index in the cyclic buffer.
     579           0 :   int Succ(int index) { return (index + 1) % kBufferSize; }
     580             : 
     581             :   Isolate* isolate_;
     582             :   // Cyclic buffer for communicating profiling samples
     583             :   // between the signal handler and the worker thread.
     584             :   static const int kBufferSize = 128;
     585             :   v8::TickSample buffer_[kBufferSize];  // Buffer storage.
     586             :   int head_;  // Index to the buffer head.
     587             :   base::Atomic32 tail_;             // Index to the buffer tail.
     588             :   bool overflow_;  // Tell whether a buffer overflow has occurred.
     589             :   // Sempahore used for buffer synchronization.
     590             :   base::Semaphore buffer_semaphore_;
     591             : 
     592             :   // Tells whether profiler is engaged, that is, processing thread is stated.
     593             :   bool engaged_;
     594             : 
     595             :   // Tells whether worker thread should continue running.
     596             :   base::Atomic32 running_;
     597             : 
     598             :   // Tells whether we are currently recording tick samples.
     599             :   bool paused_;
     600             : };
     601             : 
     602             : 
     603             : //
     604             : // Ticker used to provide ticks to the profiler and the sliding state
     605             : // window.
     606             : //
     607             : class Ticker: public sampler::Sampler {
     608             :  public:
     609       54999 :   Ticker(Isolate* isolate, int interval_microseconds)
     610             :       : sampler::Sampler(reinterpret_cast<v8::Isolate*>(isolate)),
     611             :         profiler_(nullptr),
     612      109997 :         sampling_thread_(new SamplingThread(this, interval_microseconds)) {}
     613             : 
     614      160095 :   ~Ticker() {
     615       53365 :     if (IsActive()) Stop();
     616       53365 :     delete sampling_thread_;
     617      106730 :   }
     618             : 
     619           0 :   void SetProfiler(Profiler* profiler) {
     620             :     DCHECK_NULL(profiler_);
     621           0 :     profiler_ = profiler;
     622           0 :     IncreaseProfilingDepth();
     623           0 :     if (!IsActive()) Start();
     624           0 :     sampling_thread_->StartSynchronously();
     625           0 :   }
     626             : 
     627           0 :   void ClearProfiler() {
     628           0 :     profiler_ = nullptr;
     629           0 :     if (IsActive()) Stop();
     630           0 :     DecreaseProfilingDepth();
     631           0 :     sampling_thread_->Join();
     632           0 :   }
     633             : 
     634           0 :   void SampleStack(const v8::RegisterState& state) override {
     635           0 :     if (!profiler_) return;
     636           0 :     Isolate* isolate = reinterpret_cast<Isolate*>(this->isolate());
     637             :     TickSample sample;
     638           0 :     sample.Init(isolate, state, TickSample::kIncludeCEntryFrame, true);
     639           0 :     profiler_->Insert(&sample);
     640             :   }
     641             : 
     642             :  private:
     643             :   Profiler* profiler_;
     644             :   SamplingThread* sampling_thread_;
     645             : };
     646             : 
     647             : 
     648             : //
     649             : // Profiler implementation.
     650             : //
     651           0 : Profiler::Profiler(Isolate* isolate)
     652             :     : base::Thread(Options("v8:Profiler")),
     653             :       isolate_(isolate),
     654             :       head_(0),
     655             :       overflow_(false),
     656             :       buffer_semaphore_(0),
     657             :       engaged_(false),
     658           0 :       paused_(false) {
     659           0 :   base::Relaxed_Store(&tail_, 0);
     660           0 :   base::Relaxed_Store(&running_, 0);
     661           0 : }
     662             : 
     663             : 
     664           0 : void Profiler::Engage() {
     665           0 :   if (engaged_) return;
     666           0 :   engaged_ = true;
     667             : 
     668             :   std::vector<base::OS::SharedLibraryAddress> addresses =
     669           0 :       base::OS::GetSharedLibraryAddresses();
     670           0 :   for (size_t i = 0; i < addresses.size(); ++i) {
     671           0 :     LOG(isolate_,
     672             :         SharedLibraryEvent(addresses[i].library_path, addresses[i].start,
     673             :                            addresses[i].end, addresses[i].aslr_slide));
     674             :   }
     675             : 
     676             :   // Start thread processing the profiler buffer.
     677           0 :   base::Relaxed_Store(&running_, 1);
     678           0 :   Start();
     679             : 
     680             :   // Register to get ticks.
     681           0 :   Logger* logger = isolate_->logger();
     682           0 :   logger->ticker_->SetProfiler(this);
     683             : 
     684           0 :   logger->ProfilerBeginEvent();
     685             : }
     686             : 
     687             : 
     688           0 : void Profiler::Disengage() {
     689           0 :   if (!engaged_) return;
     690             : 
     691             :   // Stop receiving ticks.
     692           0 :   isolate_->logger()->ticker_->ClearProfiler();
     693             : 
     694             :   // Terminate the worker thread by setting running_ to false,
     695             :   // inserting a fake element in the queue and then wait for
     696             :   // the thread to terminate.
     697           0 :   base::Relaxed_Store(&running_, 0);
     698             :   v8::TickSample sample;
     699             :   // Reset 'paused_' flag, otherwise semaphore may not be signalled.
     700             :   resume();
     701           0 :   Insert(&sample);
     702           0 :   Join();
     703             : 
     704           0 :   LOG(isolate_, UncheckedStringEvent("profiler", "end"));
     705             : }
     706             : 
     707             : 
     708           0 : void Profiler::Run() {
     709             :   v8::TickSample sample;
     710           0 :   bool overflow = Remove(&sample);
     711           0 :   while (base::Relaxed_Load(&running_)) {
     712           0 :     LOG(isolate_, TickEvent(&sample, overflow));
     713           0 :     overflow = Remove(&sample);
     714             :   }
     715           0 : }
     716             : 
     717             : 
     718             : //
     719             : // Logger class implementation.
     720             : //
     721             : 
     722       54999 : Logger::Logger(Isolate* isolate)
     723             :     : isolate_(isolate),
     724             :       ticker_(nullptr),
     725             :       profiler_(nullptr),
     726             :       log_events_(nullptr),
     727             :       is_logging_(false),
     728       54999 :       log_(new Log(this)),
     729             :       perf_basic_logger_(nullptr),
     730             :       perf_jit_logger_(nullptr),
     731             :       ll_logger_(nullptr),
     732             :       jit_logger_(nullptr),
     733      219996 :       is_initialized_(false) {}
     734             : 
     735      106730 : Logger::~Logger() {
     736      106730 :   delete log_;
     737      106730 : }
     738             : 
     739         317 : void Logger::addCodeEventListener(CodeEventListener* listener) {
     740        1242 :   bool result = isolate_->code_event_dispatcher()->AddListener(listener);
     741             :   USE(result);
     742             :   DCHECK(result);
     743         317 : }
     744             : 
     745         312 : void Logger::removeCodeEventListener(CodeEventListener* listener) {
     746        1586 :   isolate_->code_event_dispatcher()->RemoveListener(listener);
     747         312 : }
     748             : 
     749           0 : void Logger::ProfilerBeginEvent() {
     750           0 :   if (!log_->IsEnabled()) return;
     751           0 :   Log::MessageBuilder msg(log_);
     752           0 :   msg.Append("profiler,\"begin\",%d", FLAG_prof_sampling_interval);
     753           0 :   msg.WriteToLogFile();
     754             : }
     755             : 
     756             : 
     757           2 : void Logger::StringEvent(const char* name, const char* value) {
     758           2 :   if (FLAG_log) UncheckedStringEvent(name, value);
     759           2 : }
     760             : 
     761             : 
     762           2 : void Logger::UncheckedStringEvent(const char* name, const char* value) {
     763           4 :   if (!log_->IsEnabled()) return;
     764           2 :   Log::MessageBuilder msg(log_);
     765           2 :   msg.Append("%s,\"%s\"", name, value);
     766           2 :   msg.WriteToLogFile();
     767             : }
     768             : 
     769             : 
     770           0 : void Logger::IntEvent(const char* name, int value) {
     771           0 :   if (FLAG_log) UncheckedIntEvent(name, value);
     772           0 : }
     773             : 
     774             : 
     775          42 : void Logger::IntPtrTEvent(const char* name, intptr_t value) {
     776          42 :   if (FLAG_log) UncheckedIntPtrTEvent(name, value);
     777          42 : }
     778             : 
     779             : 
     780           0 : void Logger::UncheckedIntEvent(const char* name, int value) {
     781           0 :   if (!log_->IsEnabled()) return;
     782           0 :   Log::MessageBuilder msg(log_);
     783           0 :   msg.Append("%s,%d", name, value);
     784           0 :   msg.WriteToLogFile();
     785             : }
     786             : 
     787             : 
     788          42 : void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
     789          84 :   if (!log_->IsEnabled()) return;
     790          42 :   Log::MessageBuilder msg(log_);
     791          42 :   msg.Append("%s,%" V8PRIdPTR, name, value);
     792          42 :   msg.WriteToLogFile();
     793             : }
     794             : 
     795             : 
     796           0 : void Logger::HandleEvent(const char* name, Object** location) {
     797           0 :   if (!log_->IsEnabled() || !FLAG_log_handles) return;
     798           0 :   Log::MessageBuilder msg(log_);
     799           0 :   msg.Append("%s,%p", name, static_cast<void*>(location));
     800           0 :   msg.WriteToLogFile();
     801             : }
     802             : 
     803             : 
     804             : // ApiEvent is private so all the calls come from the Logger class.  It is the
     805             : // caller's responsibility to ensure that log is enabled and that
     806             : // FLAG_log_api is true.
     807           0 : void Logger::ApiEvent(const char* format, ...) {
     808             :   DCHECK(log_->IsEnabled() && FLAG_log_api);
     809           0 :   Log::MessageBuilder msg(log_);
     810             :   va_list ap;
     811           0 :   va_start(ap, format);
     812           0 :   msg.AppendVA(format, ap);
     813           0 :   va_end(ap);
     814           0 :   msg.WriteToLogFile();
     815           0 : }
     816             : 
     817             : 
     818           0 : void Logger::ApiSecurityCheck() {
     819           0 :   if (!log_->IsEnabled() || !FLAG_log_api) return;
     820           0 :   ApiEvent("api,check-security");
     821             : }
     822             : 
     823           0 : void Logger::SharedLibraryEvent(const std::string& library_path,
     824             :                                 uintptr_t start, uintptr_t end,
     825             :                                 intptr_t aslr_slide) {
     826           0 :   if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
     827           0 :   Log::MessageBuilder msg(log_);
     828             :   msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR
     829             :              ",%" V8PRIdPTR,
     830           0 :              library_path.c_str(), start, end, aslr_slide);
     831           0 :   msg.WriteToLogFile();
     832             : }
     833             : 
     834           0 : void Logger::CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
     835             :                             int fp_to_sp_delta) {
     836           0 :   if (!log_->IsEnabled()) return;
     837           0 :   Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
     838           0 :   Log::MessageBuilder msg(log_);
     839           0 :   int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
     840           0 :   msg.Append("code-deopt,%d,%d,", since_epoch, code->CodeSize());
     841           0 :   msg.AppendAddress(code->instruction_start());
     842             : 
     843             :   // Deoptimization position.
     844           0 :   std::ostringstream deopt_location;
     845             :   int inlining_id = -1;
     846             :   int script_offset = -1;
     847           0 :   if (info.position.IsKnown()) {
     848           0 :     info.position.Print(deopt_location, code);
     849             :     inlining_id = info.position.InliningId();
     850             :     script_offset = info.position.ScriptOffset();
     851             :   } else {
     852           0 :     deopt_location << "<unknown>";
     853             :   }
     854           0 :   msg.Append(",%d,%d,", inlining_id, script_offset);
     855           0 :   switch (kind) {
     856             :     case kLazy:
     857           0 :       msg.Append("\"lazy\",");
     858           0 :       break;
     859             :     case kSoft:
     860           0 :       msg.Append("\"soft\",");
     861           0 :       break;
     862             :     case kEager:
     863           0 :       msg.Append("\"eager\",");
     864           0 :       break;
     865             :   }
     866           0 :   msg.AppendDoubleQuotedString(deopt_location.str().c_str());
     867           0 :   msg.Append(",");
     868           0 :   msg.AppendDoubleQuotedString(DeoptimizeReasonToString(info.deopt_reason));
     869           0 :   msg.WriteToLogFile();
     870             : }
     871             : 
     872             : 
     873           0 : void Logger::CurrentTimeEvent() {
     874           0 :   if (!log_->IsEnabled()) return;
     875             :   DCHECK(FLAG_log_internal_timer_events);
     876           0 :   Log::MessageBuilder msg(log_);
     877           0 :   int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
     878           0 :   msg.Append("current-time,%d", since_epoch);
     879           0 :   msg.WriteToLogFile();
     880             : }
     881             : 
     882             : 
     883           0 : void Logger::TimerEvent(Logger::StartEnd se, const char* name) {
     884           0 :   if (!log_->IsEnabled()) return;
     885           0 :   Log::MessageBuilder msg(log_);
     886           0 :   int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
     887             :   const char* format = (se == START)
     888             :                            ? "timer-event-start,\"%s\",%ld"
     889             :                            : (se == END) ? "timer-event-end,\"%s\",%ld"
     890           0 :                                          : "timer-event,\"%s\",%ld";
     891           0 :   msg.Append(format, name, since_epoch);
     892           0 :   msg.WriteToLogFile();
     893             : }
     894             : 
     895             : // static
     896           0 : void Logger::EnterExternal(Isolate* isolate) {
     897             :   DCHECK(FLAG_log_internal_timer_events);
     898           0 :   LOG(isolate, TimerEvent(START, TimerEventExternal::name()));
     899             :   DCHECK(isolate->current_vm_state() == JS);
     900             :   isolate->set_current_vm_state(EXTERNAL);
     901           0 : }
     902             : 
     903             : // static
     904           0 : void Logger::LeaveExternal(Isolate* isolate) {
     905             :   DCHECK(FLAG_log_internal_timer_events);
     906           0 :   LOG(isolate, TimerEvent(END, TimerEventExternal::name()));
     907             :   DCHECK(isolate->current_vm_state() == EXTERNAL);
     908             :   isolate->set_current_vm_state(JS);
     909           0 : }
     910             : 
     911             : // Instantiate template methods.
     912             : #define V(TimerName, expose)                                           \
     913             :   template void TimerEventScope<TimerEvent##TimerName>::LogTimerEvent( \
     914             :       Logger::StartEnd se);
     915             : TIMER_EVENTS_LIST(V)
     916             : #undef V
     917             : 
     918          38 : void Logger::ApiNamedPropertyAccess(const char* tag,
     919             :                                     JSObject* holder,
     920             :                                     Object* name) {
     921             :   DCHECK(name->IsName());
     922         114 :   if (!log_->IsEnabled() || !FLAG_log_api) return;
     923           0 :   String* class_name_obj = holder->class_name();
     924             :   std::unique_ptr<char[]> class_name =
     925           0 :       class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
     926           0 :   if (name->IsString()) {
     927             :     std::unique_ptr<char[]> property_name =
     928           0 :         String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
     929             :     ApiEvent("api,%s,\"%s\",\"%s\"", tag, class_name.get(),
     930           0 :              property_name.get());
     931             :   } else {
     932             :     Symbol* symbol = Symbol::cast(name);
     933             :     uint32_t hash = symbol->Hash();
     934           0 :     if (symbol->name()->IsUndefined(symbol->GetIsolate())) {
     935           0 :       ApiEvent("api,%s,\"%s\",symbol(hash %x)", tag, class_name.get(), hash);
     936             :     } else {
     937             :       std::unique_ptr<char[]> str =
     938             :           String::cast(symbol->name())
     939           0 :               ->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
     940             :       ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)", tag, class_name.get(),
     941           0 :                str.get(), hash);
     942             :     }
     943             :   }
     944             : }
     945             : 
     946           0 : void Logger::ApiIndexedPropertyAccess(const char* tag,
     947             :                                       JSObject* holder,
     948             :                                       uint32_t index) {
     949           0 :   if (!log_->IsEnabled() || !FLAG_log_api) return;
     950           0 :   String* class_name_obj = holder->class_name();
     951             :   std::unique_ptr<char[]> class_name =
     952           0 :       class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
     953           0 :   ApiEvent("api,%s,\"%s\",%u", tag, class_name.get(), index);
     954             : }
     955             : 
     956             : 
     957           0 : void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
     958           0 :   if (!log_->IsEnabled() || !FLAG_log_api) return;
     959           0 :   String* class_name_obj = object->class_name();
     960             :   std::unique_ptr<char[]> class_name =
     961           0 :       class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
     962           0 :   ApiEvent("api,%s,\"%s\"", tag, class_name.get());
     963             : }
     964             : 
     965             : 
     966         483 : void Logger::ApiEntryCall(const char* name) {
     967        1449 :   if (!log_->IsEnabled() || !FLAG_log_api) return;
     968           0 :   ApiEvent("api,%s", name);
     969             : }
     970             : 
     971             : 
     972         259 : void Logger::NewEvent(const char* name, void* object, size_t size) {
     973         520 :   if (!log_->IsEnabled() || !FLAG_log) return;
     974         257 :   Log::MessageBuilder msg(log_);
     975         257 :   msg.Append("new,%s,%p,%u", name, object, static_cast<unsigned int>(size));
     976         257 :   msg.WriteToLogFile();
     977             : }
     978             : 
     979             : 
     980         238 : void Logger::DeleteEvent(const char* name, void* object) {
     981         714 :   if (!log_->IsEnabled() || !FLAG_log) return;
     982           0 :   Log::MessageBuilder msg(log_);
     983           0 :   msg.Append("delete,%s,%p", name, object);
     984           0 :   msg.WriteToLogFile();
     985             : }
     986             : 
     987             : 
     988         917 : void Logger::CallbackEventInternal(const char* prefix, Name* name,
     989             :                                    Address entry_point) {
     990        1834 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
     991         917 :   Log::MessageBuilder msg(log_);
     992             :   msg.Append("%s,%s,-2,",
     993             :              kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT],
     994         917 :              kLogEventsNames[CodeEventListener::CALLBACK_TAG]);
     995         917 :   int timestamp = static_cast<int>(timer_.Elapsed().InMicroseconds());
     996         917 :   msg.Append("%d,", timestamp);
     997         917 :   msg.AppendAddress(entry_point);
     998         917 :   if (name->IsString()) {
     999             :     std::unique_ptr<char[]> str =
    1000         907 :         String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    1001         907 :     msg.Append(",1,\"%s%s\"", prefix, str.get());
    1002             :   } else {
    1003             :     Symbol* symbol = Symbol::cast(name);
    1004          10 :     if (symbol->name()->IsUndefined(symbol->GetIsolate())) {
    1005           0 :       msg.Append(",1,symbol(hash %x)", symbol->Hash());
    1006             :     } else {
    1007             :       std::unique_ptr<char[]> str =
    1008             :           String::cast(symbol->name())
    1009          10 :               ->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    1010             :       msg.Append(",1,symbol(\"%s%s\" hash %x)", prefix, str.get(),
    1011          10 :                  symbol->Hash());
    1012             :     }
    1013             :   }
    1014         917 :   msg.WriteToLogFile();
    1015             : }
    1016             : 
    1017             : 
    1018         192 : void Logger::CallbackEvent(Name* name, Address entry_point) {
    1019         192 :   CallbackEventInternal("", name, entry_point);
    1020         192 : }
    1021             : 
    1022             : 
    1023         365 : void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
    1024         365 :   CallbackEventInternal("get ", name, entry_point);
    1025         365 : }
    1026             : 
    1027             : 
    1028         360 : void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
    1029         360 :   CallbackEventInternal("set ", name, entry_point);
    1030         360 : }
    1031             : 
    1032             : namespace {
    1033             : 
    1034       36777 : void AppendCodeCreateHeader(Log::MessageBuilder* msg,
    1035             :                             CodeEventListener::LogEventsAndTags tag,
    1036             :                             AbstractCode* code, base::ElapsedTimer* timer) {
    1037             :   DCHECK(msg);
    1038             :   msg->Append("%s,%s,%d,",
    1039             :               kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT],
    1040       36777 :               kLogEventsNames[tag], code->kind());
    1041       36777 :   int timestamp = static_cast<int>(timer->Elapsed().InMicroseconds());
    1042       36777 :   msg->Append("%d,", timestamp);
    1043       36777 :   msg->AppendAddress(code->instruction_start());
    1044       36777 :   msg->Append(",%d,", code->instruction_size());
    1045       36777 : }
    1046             : 
    1047             : }  // namespace
    1048             : 
    1049       20249 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
    1050             :                              AbstractCode* code, const char* comment) {
    1051       20251 :   if (!is_logging_code_events()) return;
    1052       40498 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
    1053       20247 :   Log::MessageBuilder msg(log_);
    1054       20247 :   AppendCodeCreateHeader(&msg, tag, code, &timer_);
    1055       20247 :   msg.AppendDoubleQuotedString(comment);
    1056       20247 :   msg.WriteToLogFile();
    1057             : }
    1058             : 
    1059           0 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
    1060             :                              AbstractCode* code, Name* name) {
    1061           0 :   if (!is_logging_code_events()) return;
    1062           0 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
    1063           0 :   Log::MessageBuilder msg(log_);
    1064           0 :   AppendCodeCreateHeader(&msg, tag, code, &timer_);
    1065           0 :   if (name->IsString()) {
    1066           0 :     msg.Append('"');
    1067           0 :     msg.AppendDetailed(String::cast(name), false);
    1068           0 :     msg.Append('"');
    1069             :   } else {
    1070           0 :     msg.AppendSymbolName(Symbol::cast(name));
    1071             :   }
    1072           0 :   msg.WriteToLogFile();
    1073             : }
    1074             : 
    1075       16451 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
    1076             :                              AbstractCode* code, SharedFunctionInfo* shared,
    1077             :                              Name* name) {
    1078       16451 :   if (!is_logging_code_events()) return;
    1079       32902 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
    1080       16451 :   if (code == AbstractCode::cast(
    1081       16451 :                   isolate_->builtins()->builtin(Builtins::kCompileLazy))) {
    1082             :     return;
    1083             :   }
    1084             : 
    1085       16451 :   Log::MessageBuilder msg(log_);
    1086       16451 :   AppendCodeCreateHeader(&msg, tag, code, &timer_);
    1087       16451 :   if (name->IsString()) {
    1088             :     std::unique_ptr<char[]> str =
    1089       16451 :         String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    1090       16451 :     msg.Append("\"%s\"", str.get());
    1091             :   } else {
    1092           0 :     msg.AppendSymbolName(Symbol::cast(name));
    1093             :   }
    1094       16451 :   msg.Append(',');
    1095       16451 :   msg.AppendAddress(shared->address());
    1096       16451 :   msg.Append(",%s", ComputeMarker(shared, code));
    1097       16451 :   msg.WriteToLogFile();
    1098             : }
    1099             : 
    1100             : 
    1101             : // Although, it is possible to extract source and line from
    1102             : // the SharedFunctionInfo object, we left it to caller
    1103             : // to leave logging functions free from heap allocations.
    1104         179 : void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
    1105             :                              AbstractCode* code, SharedFunctionInfo* shared,
    1106             :                              Name* source, int line, int column) {
    1107         179 :   if (!is_logging_code_events()) return;
    1108         358 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
    1109             : 
    1110             :   {
    1111          79 :     Log::MessageBuilder msg(log_);
    1112          79 :     AppendCodeCreateHeader(&msg, tag, code, &timer_);
    1113             :     std::unique_ptr<char[]> name =
    1114          79 :         shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    1115          79 :     msg.Append("\"%s ", name.get());
    1116          79 :     if (source->IsString()) {
    1117             :       std::unique_ptr<char[]> sourcestr = String::cast(source)->ToCString(
    1118          79 :           DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    1119          79 :       msg.Append("%s", sourcestr.get());
    1120             :     } else {
    1121           0 :       msg.AppendSymbolName(Symbol::cast(source));
    1122             :     }
    1123          79 :     msg.Append(":%d:%d\",", line, column);
    1124          79 :     msg.AppendAddress(shared->address());
    1125          79 :     msg.Append(",%s", ComputeMarker(shared, code));
    1126          79 :     msg.WriteToLogFile();
    1127             :   }
    1128             : 
    1129          79 :   if (FLAG_log_source_code) {
    1130             :     Object* script_object = shared->script();
    1131           0 :     if (script_object->IsScript()) {
    1132             :       // Make sure the script is written to the log file.
    1133           0 :       std::ostringstream os;
    1134             :       Script* script = Script::cast(script_object);
    1135           0 :       int script_id = script->id();
    1136           0 :       if (logged_source_code_.find(script_id) == logged_source_code_.end()) {
    1137             :         // This script has not been logged yet.
    1138             :         logged_source_code_.insert(script_id);
    1139             :         Object* source_object = script->source();
    1140           0 :         if (source_object->IsString()) {
    1141           0 :           Log::MessageBuilder msg(log_);
    1142             :           String* source_code = String::cast(source_object);
    1143           0 :           os << "script," << script_id << ",\"";
    1144           0 :           msg.AppendUnbufferedCString(os.str().c_str());
    1145             : 
    1146             :           // Log the script name.
    1147           0 :           if (script->name()->IsString()) {
    1148           0 :             msg.AppendUnbufferedHeapString(String::cast(script->name()));
    1149           0 :             msg.AppendUnbufferedCString("\",\"");
    1150             :           } else {
    1151           0 :             msg.AppendUnbufferedCString("<unknown>\",\"");
    1152             :           }
    1153             : 
    1154             :           // Log the source code.
    1155           0 :           msg.AppendUnbufferedHeapString(source_code);
    1156           0 :           os.str("");
    1157           0 :           os << "\"" << std::endl;
    1158           0 :           msg.AppendUnbufferedCString(os.str().c_str());
    1159           0 :           os.str("");
    1160             :         }
    1161             :       }
    1162             : 
    1163             :       // We log source code information in the form:
    1164             :       //
    1165             :       // code-source-info <addr>,<script>,<start>,<end>,<pos>,<inline-pos>,<fns>
    1166             :       //
    1167             :       // where
    1168             :       //   <addr> is code object address
    1169             :       //   <script> is script id
    1170             :       //   <start> is the starting position inside the script
    1171             :       //   <end> is the end position inside the script
    1172             :       //   <pos> is source position table encoded in the string,
    1173             :       //      it is a sequence of C<code-offset>O<script-offset>[I<inlining-id>]
    1174             :       //      where
    1175             :       //        <code-offset> is the offset within the code object
    1176             :       //        <script-offset> is the position within the script
    1177             :       //        <inlining-id> is the offset in the <inlining> table
    1178             :       //   <inlining> table is a sequence of strings of the form
    1179             :       //      F<function-id>O<script-offset>[I<inlining-id>
    1180             :       //      where
    1181             :       //         <function-id> is an index into the <fns> function table
    1182             :       //   <fns> is the function table encoded as a sequence of strings
    1183             :       //      S<shared-function-info-address>
    1184           0 :       os << "code-source-info," << static_cast<void*>(code->instruction_start())
    1185           0 :          << "," << script_id << "," << shared->start_position() << ","
    1186           0 :          << shared->end_position() << ",";
    1187             : 
    1188           0 :       SourcePositionTableIterator iterator(code->source_position_table());
    1189             :       bool is_first = true;
    1190             :       bool hasInlined = false;
    1191           0 :       for (; !iterator.done(); iterator.Advance()) {
    1192             :         if (is_first) {
    1193             :           is_first = false;
    1194             :         }
    1195           0 :         SourcePosition pos = iterator.source_position();
    1196           0 :         os << "C" << iterator.code_offset();
    1197           0 :         os << "O" << pos.ScriptOffset();
    1198           0 :         if (pos.isInlined()) {
    1199           0 :           os << "I" << pos.InliningId();
    1200             :           hasInlined = true;
    1201             :         }
    1202             :       }
    1203           0 :       os << ",";
    1204             :       int maxInlinedId = -1;
    1205           0 :       if (hasInlined) {
    1206             :         PodArray<InliningPosition>* inlining_positions =
    1207             :             DeoptimizationData::cast(Code::cast(code)->deoptimization_data())
    1208             :                 ->InliningPositions();
    1209           0 :         for (int i = 0; i < inlining_positions->length(); i++) {
    1210             :           InliningPosition inlining_pos = inlining_positions->get(i);
    1211           0 :           os << "F";
    1212           0 :           if (inlining_pos.inlined_function_id != -1) {
    1213           0 :             os << inlining_pos.inlined_function_id;
    1214           0 :             if (inlining_pos.inlined_function_id > maxInlinedId) {
    1215             :               maxInlinedId = inlining_pos.inlined_function_id;
    1216             :             }
    1217             :           }
    1218             :           SourcePosition pos = inlining_pos.position;
    1219           0 :           os << "O" << pos.ScriptOffset();
    1220           0 :           if (pos.isInlined()) {
    1221           0 :             os << "I" << pos.InliningId();
    1222             :           }
    1223             :         }
    1224             :       }
    1225           0 :       os << ",";
    1226           0 :       if (hasInlined) {
    1227             :         DeoptimizationData* deopt_data =
    1228             :             DeoptimizationData::cast(Code::cast(code)->deoptimization_data());
    1229             : 
    1230             :         os << std::hex;
    1231           0 :         for (int i = 0; i <= maxInlinedId; i++) {
    1232           0 :           os << "S"
    1233             :              << static_cast<void*>(
    1234           0 :                     deopt_data->GetInlinedFunction(i)->address());
    1235             :         }
    1236             :         os << std::dec;
    1237             :       }
    1238             :       os << std::endl;
    1239           0 :       Log::MessageBuilder msg(log_);
    1240           0 :       msg.AppendUnbufferedCString(os.str().c_str());
    1241             :     }
    1242             :   }
    1243             : }
    1244             : 
    1245           0 : void Logger::CodeDisableOptEvent(AbstractCode* code,
    1246             :                                  SharedFunctionInfo* shared) {
    1247           0 :   if (!is_logging_code_events()) return;
    1248           0 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
    1249           0 :   Log::MessageBuilder msg(log_);
    1250           0 :   msg.Append("%s,", kLogEventsNames[CodeEventListener::CODE_DISABLE_OPT_EVENT]);
    1251             :   std::unique_ptr<char[]> name =
    1252           0 :       shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
    1253           0 :   msg.Append("\"%s\",", name.get());
    1254           0 :   msg.Append("\"%s\"", GetBailoutReason(shared->disable_optimization_reason()));
    1255           0 :   msg.WriteToLogFile();
    1256             : }
    1257             : 
    1258             : 
    1259           1 : void Logger::CodeMovingGCEvent() {
    1260           1 :   if (!is_logging_code_events()) return;
    1261           2 :   if (!log_->IsEnabled() || !FLAG_ll_prof) return;
    1262           0 :   base::OS::SignalCodeMovingGC();
    1263             : }
    1264             : 
    1265           1 : void Logger::RegExpCodeCreateEvent(AbstractCode* code, String* source) {
    1266           2 :   if (!is_logging_code_events()) return;
    1267           2 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
    1268           0 :   Log::MessageBuilder msg(log_);
    1269           0 :   AppendCodeCreateHeader(&msg, CodeEventListener::REG_EXP_TAG, code, &timer_);
    1270           0 :   msg.Append('"');
    1271           0 :   msg.AppendDetailed(source, false);
    1272           0 :   msg.Append('"');
    1273           0 :   msg.WriteToLogFile();
    1274             : }
    1275             : 
    1276           0 : void Logger::CodeMoveEvent(AbstractCode* from, Address to) {
    1277           0 :   if (!is_logging_code_events()) return;
    1278           0 :   MoveEventInternal(CodeEventListener::CODE_MOVE_EVENT, from->address(), to);
    1279             : }
    1280             : 
    1281         363 : void Logger::CodeLinePosInfoRecordEvent(AbstractCode* code,
    1282             :                                         ByteArray* source_position_table) {
    1283         600 :   if (jit_logger_ && source_position_table->length() > 0) {
    1284         237 :     void* jit_handler_data = jit_logger_->StartCodePosInfoEvent();
    1285        1941 :     for (SourcePositionTableIterator iter(source_position_table); !iter.done();
    1286        1467 :          iter.Advance()) {
    1287        1467 :       if (iter.is_statement()) {
    1288             :         jit_logger_->AddCodeLinePosInfoEvent(
    1289             :             jit_handler_data, iter.code_offset(),
    1290         698 :             iter.source_position().ScriptOffset(),
    1291         698 :             JitCodeEvent::STATEMENT_POSITION);
    1292             :       }
    1293             :       jit_logger_->AddCodeLinePosInfoEvent(
    1294             :           jit_handler_data, iter.code_offset(),
    1295        2934 :           iter.source_position().ScriptOffset(), JitCodeEvent::POSITION);
    1296             :     }
    1297         237 :     jit_logger_->EndCodePosInfoEvent(code, jit_handler_data);
    1298             :   }
    1299         363 : }
    1300             : 
    1301           0 : void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
    1302           0 :   if (code_name == nullptr) return;  // Not a code object.
    1303           0 :   Log::MessageBuilder msg(log_);
    1304             :   msg.Append("%s,%d,",
    1305           0 :              kLogEventsNames[CodeEventListener::SNAPSHOT_CODE_NAME_EVENT], pos);
    1306           0 :   msg.AppendDoubleQuotedString(code_name);
    1307           0 :   msg.WriteToLogFile();
    1308             : }
    1309             : 
    1310             : 
    1311        1653 : void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
    1312        3306 :   if (!is_logging_code_events()) return;
    1313        1653 :   MoveEventInternal(CodeEventListener::SHARED_FUNC_MOVE_EVENT, from, to);
    1314             : }
    1315             : 
    1316        1653 : void Logger::MoveEventInternal(CodeEventListener::LogEventsAndTags event,
    1317             :                                Address from, Address to) {
    1318        3306 :   if (!FLAG_log_code || !log_->IsEnabled()) return;
    1319           0 :   Log::MessageBuilder msg(log_);
    1320           0 :   msg.Append("%s,", kLogEventsNames[event]);
    1321           0 :   msg.AppendAddress(from);
    1322           0 :   msg.Append(',');
    1323           0 :   msg.AppendAddress(to);
    1324           0 :   msg.WriteToLogFile();
    1325             : }
    1326             : 
    1327             : 
    1328          12 : void Logger::ResourceEvent(const char* name, const char* tag) {
    1329          34 :   if (!log_->IsEnabled() || !FLAG_log) return;
    1330           2 :   Log::MessageBuilder msg(log_);
    1331           2 :   msg.Append("%s,%s,", name, tag);
    1332             : 
    1333             :   uint32_t sec, usec;
    1334           2 :   if (base::OS::GetUserTime(&sec, &usec) != -1) {
    1335           2 :     msg.Append("%d,%d,", sec, usec);
    1336             :   }
    1337           2 :   msg.Append("%.0f", V8::GetCurrentPlatform()->CurrentClockTimeMillis());
    1338           2 :   msg.WriteToLogFile();
    1339             : }
    1340             : 
    1341             : 
    1342           0 : void Logger::SuspectReadEvent(Name* name, Object* obj) {
    1343           0 :   if (!log_->IsEnabled() || !FLAG_log_suspect) return;
    1344           0 :   Log::MessageBuilder msg(log_);
    1345             :   String* class_name = obj->IsJSObject()
    1346             :                        ? JSObject::cast(obj)->class_name()
    1347           0 :                        : isolate_->heap()->empty_string();
    1348           0 :   msg.Append("suspect-read,");
    1349           0 :   msg.Append(class_name);
    1350           0 :   msg.Append(',');
    1351           0 :   if (name->IsString()) {
    1352           0 :     msg.Append('"');
    1353           0 :     msg.Append(String::cast(name));
    1354           0 :     msg.Append('"');
    1355             :   } else {
    1356           0 :     msg.AppendSymbolName(Symbol::cast(name));
    1357             :   }
    1358           0 :   msg.WriteToLogFile();
    1359             : }
    1360             : 
    1361             : 
    1362           0 : void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
    1363           0 :   if (!log_->IsEnabled() || !FLAG_log_gc) return;
    1364           0 :   Log::MessageBuilder msg(log_);
    1365             :   // Using non-relative system time in order to be able to synchronize with
    1366             :   // external memory profiling events (e.g. DOM memory size).
    1367             :   msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f", space, kind,
    1368           0 :              V8::GetCurrentPlatform()->CurrentClockTimeMillis());
    1369           0 :   msg.WriteToLogFile();
    1370             : }
    1371             : 
    1372             : 
    1373           0 : void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
    1374           0 :   if (!log_->IsEnabled() || !FLAG_log_gc) return;
    1375           0 :   Log::MessageBuilder msg(log_);
    1376           0 :   msg.Append("heap-sample-end,\"%s\",\"%s\"", space, kind);
    1377           0 :   msg.WriteToLogFile();
    1378             : }
    1379             : 
    1380             : 
    1381           0 : void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
    1382           0 :   if (!log_->IsEnabled() || !FLAG_log_gc) return;
    1383           0 :   Log::MessageBuilder msg(log_);
    1384           0 :   msg.Append("heap-sample-item,%s,%d,%d", type, number, bytes);
    1385           0 :   msg.WriteToLogFile();
    1386             : }
    1387             : 
    1388             : 
    1389           0 : void Logger::RuntimeCallTimerEvent() {
    1390           0 :   RuntimeCallStats* stats = isolate_->counters()->runtime_call_stats();
    1391           0 :   RuntimeCallCounter* counter = stats->current_counter();
    1392           0 :   if (counter == nullptr) return;
    1393           0 :   Log::MessageBuilder msg(log_);
    1394           0 :   msg.Append("active-runtime-timer,");
    1395           0 :   msg.AppendDoubleQuotedString(counter->name());
    1396           0 :   msg.WriteToLogFile();
    1397             : }
    1398             : 
    1399           0 : void Logger::TickEvent(v8::TickSample* sample, bool overflow) {
    1400           0 :   if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
    1401           0 :   if (V8_UNLIKELY(FLAG_runtime_stats ==
    1402             :                   v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE)) {
    1403           0 :     RuntimeCallTimerEvent();
    1404             :   }
    1405           0 :   Log::MessageBuilder msg(log_);
    1406           0 :   msg.Append("%s,", kLogEventsNames[CodeEventListener::TICK_EVENT]);
    1407           0 :   msg.AppendAddress(reinterpret_cast<Address>(sample->pc));
    1408           0 :   msg.Append(",%d", static_cast<int>(timer_.Elapsed().InMicroseconds()));
    1409           0 :   if (sample->has_external_callback) {
    1410           0 :     msg.Append(",1,");
    1411             :     msg.AppendAddress(
    1412           0 :         reinterpret_cast<Address>(sample->external_callback_entry));
    1413             :   } else {
    1414           0 :     msg.Append(",0,");
    1415           0 :     msg.AppendAddress(reinterpret_cast<Address>(sample->tos));
    1416             :   }
    1417           0 :   msg.Append(",%d", static_cast<int>(sample->state));
    1418           0 :   if (overflow) {
    1419           0 :     msg.Append(",overflow");
    1420             :   }
    1421           0 :   for (unsigned i = 0; i < sample->frames_count; ++i) {
    1422           0 :     msg.Append(',');
    1423           0 :     msg.AppendAddress(reinterpret_cast<Address>(sample->stack[i]));
    1424             :   }
    1425           0 :   msg.WriteToLogFile();
    1426             : }
    1427             : 
    1428           0 : void Logger::ICEvent(const char* type, bool keyed, const Address pc, int line,
    1429             :                      int column, Map* map, Object* key, char old_state,
    1430             :                      char new_state, const char* modifier,
    1431             :                      const char* slow_stub_reason) {
    1432           0 :   if (!log_->IsEnabled() || !FLAG_trace_ic) return;
    1433           0 :   Log::MessageBuilder msg(log_);
    1434           0 :   if (keyed) msg.Append("Keyed");
    1435           0 :   msg.Append("%s,", type);
    1436           0 :   msg.AppendAddress(pc);
    1437           0 :   msg.Append(",%d,%d,", line, column);
    1438           0 :   msg.Append(old_state);
    1439           0 :   msg.Append(",");
    1440           0 :   msg.Append(new_state);
    1441           0 :   msg.Append(",");
    1442           0 :   msg.AppendAddress(reinterpret_cast<Address>(map));
    1443           0 :   msg.Append(",");
    1444           0 :   if (key->IsSmi()) {
    1445           0 :     msg.Append("%d", Smi::ToInt(key));
    1446           0 :   } else if (key->IsNumber()) {
    1447           0 :     msg.Append("%lf", key->Number());
    1448           0 :   } else if (key->IsString()) {
    1449           0 :     msg.AppendDetailed(String::cast(key), false);
    1450           0 :   } else if (key->IsSymbol()) {
    1451           0 :     msg.AppendSymbolName(Symbol::cast(key));
    1452             :   }
    1453           0 :   msg.Append(",%s,", modifier);
    1454           0 :   if (slow_stub_reason != nullptr) {
    1455           0 :     msg.AppendDoubleQuotedString(slow_stub_reason);
    1456             :   }
    1457           0 :   msg.WriteToLogFile();
    1458             : }
    1459             : 
    1460           1 : void Logger::StopProfiler() {
    1461           3 :   if (!log_->IsEnabled()) return;
    1462           1 :   if (profiler_ != nullptr) {
    1463             :     profiler_->pause();
    1464           0 :     is_logging_ = false;
    1465           0 :     removeCodeEventListener(this);
    1466             :   }
    1467             : }
    1468             : 
    1469             : 
    1470             : // This function can be called when Log's mutex is acquired,
    1471             : // either from main or Profiler's thread.
    1472           0 : void Logger::LogFailure() {
    1473           0 :   StopProfiler();
    1474           0 : }
    1475             : 
    1476      312830 : static void AddFunctionAndCode(SharedFunctionInfo* sfi,
    1477             :                                AbstractCode* code_object,
    1478             :                                Handle<SharedFunctionInfo>* sfis,
    1479             :                                Handle<AbstractCode>* code_objects, int offset) {
    1480      312830 :   if (sfis != nullptr) {
    1481      312830 :     sfis[offset] = Handle<SharedFunctionInfo>(sfi);
    1482             :   }
    1483      312830 :   if (code_objects != nullptr) {
    1484      312830 :     code_objects[offset] = Handle<AbstractCode>(code_object);
    1485             :   }
    1486      312830 : }
    1487             : 
    1488         574 : static int EnumerateCompiledFunctions(Heap* heap,
    1489             :                                       Handle<SharedFunctionInfo>* sfis,
    1490             :                                       Handle<AbstractCode>* code_objects) {
    1491         574 :   HeapIterator iterator(heap);
    1492             :   DisallowHeapAllocation no_gc;
    1493             :   int compiled_funcs_count = 0;
    1494             : 
    1495             :   // Iterate the heap to find shared function info objects and record
    1496             :   // the unoptimized code for them.
    1497     4704742 :   for (HeapObject* obj = iterator.next(); obj != nullptr;
    1498             :        obj = iterator.next()) {
    1499     4704168 :     if (obj->IsSharedFunctionInfo()) {
    1500             :       SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
    1501     1288112 :       if (sfi->is_compiled() &&
    1502        1992 :           (!sfi->script()->IsScript() ||
    1503        1992 :            Script::cast(sfi->script())->HasValidSource())) {
    1504             :         // In some cases, an SFI might have (and have executing!) both bytecode
    1505             :         // and baseline code, so check for both and add them both if needed.
    1506      312616 :         if (sfi->HasBytecodeArray()) {
    1507             :           AddFunctionAndCode(sfi, AbstractCode::cast(sfi->bytecode_array()),
    1508        1398 :                              sfis, code_objects, compiled_funcs_count);
    1509        1398 :           ++compiled_funcs_count;
    1510             :         }
    1511             : 
    1512      312616 :         if (!sfi->IsInterpreted()) {
    1513             :           AddFunctionAndCode(sfi, AbstractCode::cast(sfi->code()), sfis,
    1514      311218 :                              code_objects, compiled_funcs_count);
    1515      311218 :           ++compiled_funcs_count;
    1516             :         }
    1517             :       }
    1518     4216430 :     } else if (obj->IsJSFunction()) {
    1519             :       // Given that we no longer iterate over all optimized JSFunctions, we need
    1520             :       // to take care of this here.
    1521             :       JSFunction* function = JSFunction::cast(obj);
    1522             :       SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
    1523             :       Object* maybe_script = sfi->script();
    1524      580262 :       if (maybe_script->IsScript() &&
    1525      142154 :           !Script::cast(maybe_script)->HasValidSource()) {
    1526             :         continue;
    1527             :       }
    1528             :       // TODO(jarin) This leaves out deoptimized code that might still be on the
    1529             :       // stack. Also note that we will not log optimized code objects that are
    1530             :       // only on a type feedback vector. We should make this mroe precise.
    1531      438088 :       if (function->IsOptimized()) {
    1532             :         AddFunctionAndCode(sfi, AbstractCode::cast(function->code()), sfis,
    1533         214 :                            code_objects, compiled_funcs_count);
    1534         214 :         ++compiled_funcs_count;
    1535             :       }
    1536             :     }
    1537             :   }
    1538         574 :   return compiled_funcs_count;
    1539             : }
    1540             : 
    1541             : 
    1542       49850 : void Logger::LogCodeObject(Object* object) {
    1543             :   AbstractCode* code_object = AbstractCode::cast(object);
    1544             :   CodeEventListener::LogEventsAndTags tag = CodeEventListener::STUB_TAG;
    1545             :   const char* description = "Unknown code from the snapshot";
    1546       49850 :   switch (code_object->kind()) {
    1547             :     case AbstractCode::INTERPRETED_FUNCTION:
    1548             :     case AbstractCode::OPTIMIZED_FUNCTION:
    1549             :       return;  // We log this later using LogCompiledFunctions.
    1550             :     case AbstractCode::BYTECODE_HANDLER:
    1551             :       return;  // We log it later by walking the dispatch table.
    1552             :     case AbstractCode::STUB:
    1553             :       description =
    1554        2966 :           CodeStub::MajorName(CodeStub::GetMajorKey(code_object->GetCode()));
    1555        2966 :       if (description == nullptr) description = "A stub from the snapshot";
    1556             :       tag = CodeEventListener::STUB_TAG;
    1557             :       break;
    1558             :     case AbstractCode::REGEXP:
    1559             :       description = "Regular expression code";
    1560             :       tag = CodeEventListener::REG_EXP_TAG;
    1561           0 :       break;
    1562             :     case AbstractCode::BUILTIN:
    1563             :       description =
    1564       23556 :           isolate_->builtins()->name(code_object->GetCode()->builtin_index());
    1565             :       tag = CodeEventListener::BUILTIN_TAG;
    1566       23556 :       break;
    1567             :     case AbstractCode::WASM_FUNCTION:
    1568             :       description = "A Wasm function";
    1569             :       tag = CodeEventListener::STUB_TAG;
    1570           0 :       break;
    1571             :     case AbstractCode::JS_TO_WASM_FUNCTION:
    1572             :       description = "A JavaScript to Wasm adapter";
    1573             :       tag = CodeEventListener::STUB_TAG;
    1574           0 :       break;
    1575             :     case AbstractCode::WASM_TO_JS_FUNCTION:
    1576             :       description = "A Wasm to JavaScript adapter";
    1577             :       tag = CodeEventListener::STUB_TAG;
    1578           0 :       break;
    1579             :     case AbstractCode::WASM_INTERPRETER_ENTRY:
    1580             :       description = "A Wasm to Interpreter adapter";
    1581             :       tag = CodeEventListener::STUB_TAG;
    1582           0 :       break;
    1583             :     case AbstractCode::C_WASM_ENTRY:
    1584             :       description = "A C to Wasm entry stub";
    1585             :       tag = CodeEventListener::STUB_TAG;
    1586           0 :       break;
    1587             :     case AbstractCode::NUMBER_OF_KINDS:
    1588           0 :       UNIMPLEMENTED();
    1589             :   }
    1590       53044 :   PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
    1591             : }
    1592             : 
    1593             : 
    1594          52 : void Logger::LogCodeObjects() {
    1595          52 :   Heap* heap = isolate_->heap();
    1596          52 :   HeapIterator iterator(heap);
    1597             :   DisallowHeapAllocation no_gc;
    1598      381198 :   for (HeapObject* obj = iterator.next(); obj != nullptr;
    1599             :        obj = iterator.next()) {
    1600      381146 :     if (obj->IsCode()) LogCodeObject(obj);
    1601      381146 :     if (obj->IsBytecodeArray()) LogCodeObject(obj);
    1602          52 :   }
    1603          52 : }
    1604             : 
    1605          21 : void Logger::LogBytecodeHandlers() {
    1606             :   const interpreter::OperandScale kOperandScales[] = {
    1607             : #define VALUE(Name, _) interpreter::OperandScale::k##Name,
    1608             :       OPERAND_SCALE_LIST(VALUE)
    1609             : #undef VALUE
    1610          21 :   };
    1611             : 
    1612             :   const int last_index = static_cast<int>(interpreter::Bytecode::kLast);
    1613          21 :   interpreter::Interpreter* interpreter = isolate_->interpreter();
    1614          84 :   for (auto operand_scale : kOperandScales) {
    1615       10899 :     for (int index = 0; index <= last_index; ++index) {
    1616       10836 :       interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(index);
    1617       10836 :       if (interpreter::Bytecodes::BytecodeHasHandler(bytecode, operand_scale)) {
    1618        9534 :         Code* code = interpreter->GetBytecodeHandler(bytecode, operand_scale);
    1619             :         std::string bytecode_name =
    1620        9534 :             interpreter::Bytecodes::ToString(bytecode, operand_scale);
    1621       19068 :         PROFILE(isolate_, CodeCreateEvent(
    1622             :                               CodeEventListener::BYTECODE_HANDLER_TAG,
    1623             :                               AbstractCode::cast(code), bytecode_name.c_str()));
    1624             :       }
    1625             :     }
    1626             :   }
    1627          21 : }
    1628             : 
    1629      156415 : void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
    1630             :                                  Handle<AbstractCode> code) {
    1631      156415 :   if (shared->script()->IsScript()) {
    1632             :     Handle<Script> script(Script::cast(shared->script()));
    1633        1093 :     int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
    1634             :     int column_num =
    1635        1093 :         Script::GetColumnNumber(script, shared->start_position()) + 1;
    1636        1093 :     if (script->name()->IsString()) {
    1637             :       Handle<String> script_name(String::cast(script->name()));
    1638         271 :       if (line_num > 0) {
    1639         542 :         PROFILE(isolate_,
    1640             :                 CodeCreateEvent(
    1641             :                     Logger::ToNativeByScript(
    1642             :                         CodeEventListener::LAZY_COMPILE_TAG, *script),
    1643             :                     *code, *shared, *script_name, line_num, column_num));
    1644             :       } else {
    1645             :         // Can't distinguish eval and script here, so always use Script.
    1646           0 :         PROFILE(isolate_,
    1647             :                 CodeCreateEvent(Logger::ToNativeByScript(
    1648             :                                     CodeEventListener::SCRIPT_TAG, *script),
    1649             :                                 *code, *shared, *script_name));
    1650             :       }
    1651             :     } else {
    1652        1644 :       PROFILE(isolate_,
    1653             :               CodeCreateEvent(Logger::ToNativeByScript(
    1654             :                                   CodeEventListener::LAZY_COMPILE_TAG, *script),
    1655             :                               *code, *shared, isolate_->heap()->empty_string(),
    1656             :                               line_num, column_num));
    1657             :     }
    1658      155322 :   } else if (shared->IsApiFunction()) {
    1659             :     // API function.
    1660             :     FunctionTemplateInfo* fun_data = shared->get_api_func_data();
    1661             :     Object* raw_call_data = fun_data->call_code();
    1662       12192 :     if (!raw_call_data->IsUndefined(isolate_)) {
    1663             :       CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
    1664             :       Object* callback_obj = call_data->callback();
    1665             :       Address entry_point = v8::ToCData<Address>(callback_obj);
    1666             : #if USES_FUNCTION_DESCRIPTORS
    1667             :       entry_point = *FUNCTION_ENTRYPOINT_ADDRESS(entry_point);
    1668             : #endif
    1669       12034 :       PROFILE(isolate_, CallbackEvent(shared->DebugName(), entry_point));
    1670             :     }
    1671             :   } else {
    1672      298452 :     PROFILE(isolate_,
    1673             :             CodeCreateEvent(CodeEventListener::LAZY_COMPILE_TAG, *code, *shared,
    1674             :                             isolate_->heap()->empty_string()));
    1675             :   }
    1676      156415 : }
    1677             : 
    1678             : 
    1679         287 : void Logger::LogCompiledFunctions() {
    1680         287 :   Heap* heap = isolate_->heap();
    1681             :   HandleScope scope(isolate_);
    1682             :   const int compiled_funcs_count =
    1683         287 :       EnumerateCompiledFunctions(heap, nullptr, nullptr);
    1684             :   ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
    1685             :   ScopedVector<Handle<AbstractCode> > code_objects(compiled_funcs_count);
    1686         287 :   EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
    1687             : 
    1688             :   // During iteration, there can be heap allocation due to
    1689             :   // GetScriptLineNumber call.
    1690      156702 :   for (int i = 0; i < compiled_funcs_count; ++i) {
    1691      312830 :     if (code_objects[i].is_identical_to(BUILTIN_CODE(isolate_, CompileLazy)))
    1692             :       continue;
    1693      156415 :     LogExistingFunction(sfis[i], code_objects[i]);
    1694             :   }
    1695         287 : }
    1696             : 
    1697             : 
    1698         250 : void Logger::LogAccessorCallbacks() {
    1699         250 :   Heap* heap = isolate_->heap();
    1700         250 :   HeapIterator iterator(heap);
    1701             :   DisallowHeapAllocation no_gc;
    1702     2105350 :   for (HeapObject* obj = iterator.next(); obj != nullptr;
    1703             :        obj = iterator.next()) {
    1704     2105100 :     if (!obj->IsAccessorInfo()) continue;
    1705             :     AccessorInfo* ai = AccessorInfo::cast(obj);
    1706       18370 :     if (!ai->name()->IsName()) continue;
    1707             :     Address getter_entry = v8::ToCData<Address>(ai->getter());
    1708             :     Name* name = Name::cast(ai->name());
    1709       18370 :     if (getter_entry != 0) {
    1710             : #if USES_FUNCTION_DESCRIPTORS
    1711             :       getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(getter_entry);
    1712             : #endif
    1713       36740 :       PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
    1714             :     }
    1715             :     Address setter_entry = v8::ToCData<Address>(ai->setter());
    1716       18370 :     if (setter_entry != 0) {
    1717             : #if USES_FUNCTION_DESCRIPTORS
    1718             :       setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(setter_entry);
    1719             : #endif
    1720       36730 :       PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
    1721             :     }
    1722         250 :   }
    1723         250 : }
    1724             : 
    1725             : 
    1726       54998 : static void AddIsolateIdIfNeeded(std::ostream& os,  // NOLINT
    1727             :                                  Isolate* isolate) {
    1728       82581 :   if (FLAG_logfile_per_isolate) os << "isolate-" << isolate << "-";
    1729       54998 : }
    1730             : 
    1731             : 
    1732       54996 : static void PrepareLogFileName(std::ostream& os,  // NOLINT
    1733             :                                Isolate* isolate, const char* file_name) {
    1734             :   int dir_separator_count = 0;
    1735      384883 :   for (const char* p = file_name; *p; p++) {
    1736      329886 :     if (base::OS::isDirectorySeparator(*p)) dir_separator_count++;
    1737             :   }
    1738             : 
    1739      329889 :   for (const char* p = file_name; *p; p++) {
    1740      329887 :     if (dir_separator_count == 0) {
    1741       54998 :       AddIsolateIdIfNeeded(os, isolate);
    1742       54998 :       dir_separator_count--;
    1743             :     }
    1744      329887 :     if (*p == '%') {
    1745           0 :       p++;
    1746           0 :       switch (*p) {
    1747             :         case '\0':
    1748             :           // If there's a % at the end of the string we back up
    1749             :           // one character so we can escape the loop properly.
    1750             :           p--;
    1751             :           break;
    1752             :         case 'p':
    1753           0 :           os << base::OS::GetCurrentProcessId();
    1754           0 :           break;
    1755             :         case 't':
    1756             :           // %t expands to the current time in milliseconds.
    1757             :           os << static_cast<int64_t>(
    1758           0 :               V8::GetCurrentPlatform()->CurrentClockTimeMillis());
    1759             :           break;
    1760             :         case '%':
    1761             :           // %% expands (contracts really) to %.
    1762             :           os << '%';
    1763             :           break;
    1764             :         default:
    1765             :           // All other %'s expand to themselves.
    1766             :           os << '%' << *p;
    1767             :           break;
    1768             :       }
    1769             :     } else {
    1770      329887 :       if (base::OS::isDirectorySeparator(*p)) dir_separator_count--;
    1771      329889 :       os << *p;
    1772             :     }
    1773             :   }
    1774       54999 : }
    1775             : 
    1776             : 
    1777       54999 : bool Logger::SetUp(Isolate* isolate) {
    1778             :   // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
    1779       54999 :   if (is_initialized_) return true;
    1780       54999 :   is_initialized_ = true;
    1781             : 
    1782       54999 :   std::ostringstream log_file_name;
    1783      109998 :   std::ostringstream source_log_file_name;
    1784       54999 :   PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
    1785      109998 :   log_->Initialize(log_file_name.str().c_str());
    1786             : 
    1787       54999 :   if (FLAG_perf_basic_prof) {
    1788           0 :     perf_basic_logger_ = new PerfBasicLogger();
    1789             :     addCodeEventListener(perf_basic_logger_);
    1790             :   }
    1791             : 
    1792       54998 :   if (FLAG_perf_prof) {
    1793           0 :     perf_jit_logger_ = new PerfJitLogger();
    1794             :     addCodeEventListener(perf_jit_logger_);
    1795             :   }
    1796             : 
    1797       54998 :   if (FLAG_ll_prof) {
    1798           0 :     ll_logger_ = new LowLevelLogger(log_file_name.str().c_str());
    1799           0 :     addCodeEventListener(ll_logger_);
    1800             :   }
    1801             : 
    1802       54998 :   ticker_ = new Ticker(isolate, FLAG_prof_sampling_interval);
    1803             : 
    1804       54998 :   if (Log::InitLogAtStart()) {
    1805          21 :     is_logging_ = true;
    1806             :   }
    1807             : 
    1808             :   timer_.Start();
    1809             : 
    1810       54999 :   if (FLAG_prof_cpp) {
    1811           0 :     profiler_ = new Profiler(isolate);
    1812           0 :     is_logging_ = true;
    1813           0 :     profiler_->Engage();
    1814             :   }
    1815             : 
    1816             :   profiler_listener_.reset();
    1817             : 
    1818       54999 :   if (is_logging_) {
    1819          21 :     addCodeEventListener(this);
    1820             :   }
    1821             : 
    1822       54999 :   return true;
    1823             : }
    1824             : 
    1825             : 
    1826          66 : void Logger::SetCodeEventHandler(uint32_t options,
    1827             :                                  JitCodeEventHandler event_handler) {
    1828          66 :   if (jit_logger_) {
    1829             :       removeCodeEventListener(jit_logger_);
    1830          28 :       delete jit_logger_;
    1831          28 :       jit_logger_ = nullptr;
    1832             :   }
    1833             : 
    1834          66 :   if (event_handler) {
    1835          38 :     jit_logger_ = new JitLogger(event_handler);
    1836             :     addCodeEventListener(jit_logger_);
    1837          38 :     if (options & kJitCodeEventEnumExisting) {
    1838           5 :       HandleScope scope(isolate_);
    1839           5 :       LogCodeObjects();
    1840           5 :       LogCompiledFunctions();
    1841             :     }
    1842             :   }
    1843          66 : }
    1844             : 
    1845         245 : void Logger::SetUpProfilerListener() {
    1846         490 :   if (!is_initialized_) return;
    1847         245 :   if (profiler_listener_.get() == nullptr) {
    1848         215 :     profiler_listener_.reset(new ProfilerListener(isolate_));
    1849             :   }
    1850             :   addCodeEventListener(profiler_listener_.get());
    1851             : }
    1852             : 
    1853         245 : void Logger::TearDownProfilerListener() {
    1854         490 :   if (profiler_listener_->HasObservers()) return;
    1855             :   removeCodeEventListener(profiler_listener_.get());
    1856             : }
    1857             : 
    1858       53365 : sampler::Sampler* Logger::sampler() {
    1859       53365 :   return ticker_;
    1860             : }
    1861             : 
    1862             : 
    1863       53402 : FILE* Logger::TearDown() {
    1864       53402 :   if (!is_initialized_) return nullptr;
    1865       53365 :   is_initialized_ = false;
    1866             : 
    1867             :   // Stop the profiler before closing the file.
    1868       53365 :   if (profiler_ != nullptr) {
    1869           0 :     profiler_->Disengage();
    1870           0 :     delete profiler_;
    1871           0 :     profiler_ = nullptr;
    1872             :   }
    1873             : 
    1874       53365 :   delete ticker_;
    1875       53365 :   ticker_ = nullptr;
    1876             : 
    1877       53365 :   if (perf_basic_logger_) {
    1878             :     removeCodeEventListener(perf_basic_logger_);
    1879           0 :     delete perf_basic_logger_;
    1880           0 :     perf_basic_logger_ = nullptr;
    1881             :   }
    1882             : 
    1883       53365 :   if (perf_jit_logger_) {
    1884             :     removeCodeEventListener(perf_jit_logger_);
    1885           0 :     delete perf_jit_logger_;
    1886           0 :     perf_jit_logger_ = nullptr;
    1887             :   }
    1888             : 
    1889       53365 :   if (ll_logger_) {
    1890             :     removeCodeEventListener(ll_logger_);
    1891           0 :     delete ll_logger_;
    1892           0 :     ll_logger_ = nullptr;
    1893             :   }
    1894             : 
    1895       53365 :   if (jit_logger_) {
    1896             :     removeCodeEventListener(jit_logger_);
    1897          10 :     delete jit_logger_;
    1898          10 :     jit_logger_ = nullptr;
    1899             :   }
    1900             : 
    1901       53365 :   if (profiler_listener_.get() != nullptr) {
    1902             :     removeCodeEventListener(profiler_listener_.get());
    1903             :   }
    1904             : 
    1905       53365 :   return log_->Close();
    1906             : }
    1907             : 
    1908             : }  // namespace internal
    1909             : }  // namespace v8

Generated by: LCOV version 1.10