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.
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/cpu-profiler.h"
17 #include "src/deoptimizer.h"
18 #include "src/global-handles.h"
19 #include "src/log-inl.h"
20 #include "src/log-utils.h"
21 #include "src/macro-assembler.h"
22 #include "src/perf-jit.h"
23 #include "src/runtime-profiler.h"
24 #include "src/string-stream.h"
25 #include "src/vm-state-inl.h"
31 #define DECLARE_EVENT(ignore1, name) name,
32 static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
33 LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
38 #define CALL_LISTENERS(Call) \
39 for (int i = 0; i < listeners_.length(); ++i) { \
40 listeners_[i]->Call; \
43 #define PROFILER_LOG(Call) \
45 CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
46 if (cpu_profiler->is_profiling()) { \
51 // ComputeMarker must only be used when SharedFunctionInfo is known.
52 static const char* ComputeMarker(Code* code) {
53 switch (code->kind()) {
54 case Code::FUNCTION: return code->optimizable() ? "~" : "";
55 case Code::OPTIMIZED_FUNCTION: return "*";
61 class CodeEventLogger::NameBuffer {
63 NameBuffer() { Reset(); }
69 void Init(Logger::LogEventsAndTags tag) {
71 AppendBytes(kLogEventsNames[tag]);
75 void AppendName(Name* name) {
76 if (name->IsString()) {
77 AppendString(String::cast(name));
79 Symbol* symbol = Symbol::cast(name);
80 AppendBytes("symbol(");
81 if (!symbol->name()->IsUndefined()) {
83 AppendString(String::cast(symbol->name()));
87 AppendHex(symbol->Hash());
92 void AppendString(String* str) {
93 if (str == NULL) return;
94 int uc16_length = Min(str->length(), kUtf16BufferSize);
95 String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
96 int previous = unibrow::Utf16::kNoPreviousCharacter;
97 for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
98 uc16 c = utf16_buffer[i];
99 if (c <= unibrow::Utf8::kMaxOneByteChar) {
100 utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
102 int char_length = unibrow::Utf8::Length(c, previous);
103 if (utf8_pos_ + char_length > kUtf8BufferSize) break;
104 unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
105 utf8_pos_ += char_length;
111 void AppendBytes(const char* bytes, int size) {
112 size = Min(size, kUtf8BufferSize - utf8_pos_);
113 MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
117 void AppendBytes(const char* bytes) {
118 AppendBytes(bytes, StrLength(bytes));
121 void AppendByte(char c) {
122 if (utf8_pos_ >= kUtf8BufferSize) return;
123 utf8_buffer_[utf8_pos_++] = c;
126 void AppendInt(int n) {
127 Vector<char> buffer(utf8_buffer_ + utf8_pos_,
128 kUtf8BufferSize - utf8_pos_);
129 int size = SNPrintF(buffer, "%d", n);
130 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
135 void AppendHex(uint32_t n) {
136 Vector<char> buffer(utf8_buffer_ + utf8_pos_,
137 kUtf8BufferSize - utf8_pos_);
138 int size = SNPrintF(buffer, "%x", n);
139 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
144 const char* get() { return utf8_buffer_; }
145 int size() const { return utf8_pos_; }
148 static const int kUtf8BufferSize = 512;
149 static const int kUtf16BufferSize = 128;
152 char utf8_buffer_[kUtf8BufferSize];
153 uc16 utf16_buffer[kUtf16BufferSize];
157 CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
159 CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
162 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
164 const char* comment) {
165 name_buffer_->Init(tag);
166 name_buffer_->AppendBytes(comment);
167 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
171 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
174 name_buffer_->Init(tag);
175 name_buffer_->AppendName(name);
176 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
180 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
182 SharedFunctionInfo* shared,
183 CompilationInfo* info,
185 name_buffer_->Init(tag);
186 name_buffer_->AppendBytes(ComputeMarker(code));
187 name_buffer_->AppendName(name);
188 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
192 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
194 SharedFunctionInfo* shared,
195 CompilationInfo* info,
196 Name* source, int line, int column) {
197 name_buffer_->Init(tag);
198 name_buffer_->AppendBytes(ComputeMarker(code));
199 name_buffer_->AppendString(shared->DebugName());
200 name_buffer_->AppendByte(' ');
201 if (source->IsString()) {
202 name_buffer_->AppendString(String::cast(source));
204 name_buffer_->AppendBytes("symbol(hash ");
205 name_buffer_->AppendHex(Name::cast(source)->Hash());
206 name_buffer_->AppendByte(')');
208 name_buffer_->AppendByte(':');
209 name_buffer_->AppendInt(line);
210 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
214 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
217 name_buffer_->Init(tag);
218 name_buffer_->AppendInt(args_count);
219 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
223 void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
224 name_buffer_->Init(Logger::REG_EXP_TAG);
225 name_buffer_->AppendString(source);
226 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
230 // Linux perf tool logging support
231 class PerfBasicLogger : public CodeEventLogger {
234 virtual ~PerfBasicLogger();
236 virtual void CodeMoveEvent(Address from, Address to) { }
237 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
238 virtual void CodeDeleteEvent(Address from) { }
241 virtual void LogRecordedBuffer(Code* code,
242 SharedFunctionInfo* shared,
246 // Extension added to V8 log file name to get the low-level log name.
247 static const char kFilenameFormatString[];
248 static const int kFilenameBufferPadding;
250 // File buffer size of the low-level log. We don't use the default to
251 // minimize the associated overhead.
252 static const int kLogBufferSize = 2 * MB;
254 FILE* perf_output_handle_;
257 const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map";
258 // Extra space for the PID in the filename
259 const int PerfBasicLogger::kFilenameBufferPadding = 16;
261 PerfBasicLogger::PerfBasicLogger()
262 : perf_output_handle_(NULL) {
263 // Open the perf JIT dump file.
264 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
265 ScopedVector<char> perf_dump_name(bufferSize);
268 kFilenameFormatString,
269 base::OS::GetCurrentProcessId());
271 perf_output_handle_ =
272 base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode);
273 CHECK_NOT_NULL(perf_output_handle_);
274 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
278 PerfBasicLogger::~PerfBasicLogger() {
279 fclose(perf_output_handle_);
280 perf_output_handle_ = NULL;
284 void PerfBasicLogger::LogRecordedBuffer(Code* code,
288 DCHECK(code->instruction_start() == code->address() + Code::kHeaderSize);
290 base::OS::FPrint(perf_output_handle_, "%llx %x %.*s\n",
291 reinterpret_cast<uint64_t>(code->instruction_start()),
292 code->instruction_size(), length, name);
296 // Low-level logging support.
297 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
299 class LowLevelLogger : public CodeEventLogger {
301 explicit LowLevelLogger(const char* file_name);
302 virtual ~LowLevelLogger();
304 virtual void CodeMoveEvent(Address from, Address to);
305 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
306 virtual void CodeDeleteEvent(Address from);
307 virtual void SnapshotPositionEvent(Address addr, int pos);
308 virtual void CodeMovingGCEvent();
311 virtual void LogRecordedBuffer(Code* code,
312 SharedFunctionInfo* shared,
316 // Low-level profiling event structures.
317 struct CodeCreateStruct {
318 static const char kTag = 'C';
321 Address code_address;
326 struct CodeMoveStruct {
327 static const char kTag = 'M';
329 Address from_address;
334 struct CodeDeleteStruct {
335 static const char kTag = 'D';
341 struct SnapshotPositionStruct {
342 static const char kTag = 'P';
349 static const char kCodeMovingGCTag = 'G';
352 // Extension added to V8 log file name to get the low-level log name.
353 static const char kLogExt[];
355 // File buffer size of the low-level log. We don't use the default to
356 // minimize the associated overhead.
357 static const int kLogBufferSize = 2 * MB;
360 void LogWriteBytes(const char* bytes, int size);
362 template <typename T>
363 void LogWriteStruct(const T& s) {
365 LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
366 LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
369 FILE* ll_output_handle_;
372 const char LowLevelLogger::kLogExt[] = ".ll";
374 LowLevelLogger::LowLevelLogger(const char* name)
375 : ll_output_handle_(NULL) {
376 // Open the low-level log file.
377 size_t len = strlen(name);
378 ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
379 MemCopy(ll_name.start(), name, len);
380 MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
382 base::OS::FOpen(ll_name.start(), base::OS::LogFileOpenMode);
383 setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize);
389 LowLevelLogger::~LowLevelLogger() {
390 fclose(ll_output_handle_);
391 ll_output_handle_ = NULL;
395 void LowLevelLogger::LogCodeInfo() {
396 #if V8_TARGET_ARCH_IA32
397 const char arch[] = "ia32";
398 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT
399 const char arch[] = "x64";
400 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
401 const char arch[] = "x32";
402 #elif V8_TARGET_ARCH_ARM
403 const char arch[] = "arm";
404 #elif V8_TARGET_ARCH_PPC
405 const char arch[] = "ppc";
406 #elif V8_TARGET_ARCH_MIPS
407 const char arch[] = "mips";
408 #elif V8_TARGET_ARCH_X87
409 const char arch[] = "x87";
410 #elif V8_TARGET_ARCH_ARM64
411 const char arch[] = "arm64";
413 const char arch[] = "unknown";
415 LogWriteBytes(arch, sizeof(arch));
419 void LowLevelLogger::LogRecordedBuffer(Code* code,
423 CodeCreateStruct event;
424 event.name_size = length;
425 event.code_address = code->instruction_start();
426 DCHECK(event.code_address == code->address() + Code::kHeaderSize);
427 event.code_size = code->instruction_size();
428 LogWriteStruct(event);
429 LogWriteBytes(name, length);
431 reinterpret_cast<const char*>(code->instruction_start()),
432 code->instruction_size());
436 void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
437 CodeMoveStruct event;
438 event.from_address = from + Code::kHeaderSize;
439 event.to_address = to + Code::kHeaderSize;
440 LogWriteStruct(event);
444 void LowLevelLogger::CodeDeleteEvent(Address from) {
445 CodeDeleteStruct event;
446 event.address = from + Code::kHeaderSize;
447 LogWriteStruct(event);
451 void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
452 SnapshotPositionStruct event;
453 event.address = addr + Code::kHeaderSize;
454 event.position = pos;
455 LogWriteStruct(event);
459 void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
460 size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
461 DCHECK(static_cast<size_t>(size) == rv);
466 void LowLevelLogger::CodeMovingGCEvent() {
467 const char tag = kCodeMovingGCTag;
469 LogWriteBytes(&tag, sizeof(tag));
473 #define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
476 class JitLogger : public CodeEventLogger {
478 explicit JitLogger(JitCodeEventHandler code_event_handler);
480 virtual void CodeMoveEvent(Address from, Address to);
481 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
482 virtual void CodeDeleteEvent(Address from);
483 virtual void AddCodeLinePosInfoEvent(
484 void* jit_handler_data,
487 JitCodeEvent::PositionType position_type);
489 void* StartCodePosInfoEvent();
490 void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
493 virtual void LogRecordedBuffer(Code* code,
494 SharedFunctionInfo* shared,
498 JitCodeEventHandler code_event_handler_;
502 JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
503 : code_event_handler_(code_event_handler) {
507 void JitLogger::LogRecordedBuffer(Code* code,
508 SharedFunctionInfo* shared,
512 memset(&event, 0, sizeof(event));
513 event.type = JitCodeEvent::CODE_ADDED;
514 event.code_start = code->instruction_start();
515 event.code_len = code->instruction_size();
516 Handle<SharedFunctionInfo> shared_function_handle;
517 if (shared && shared->script()->IsScript()) {
518 shared_function_handle = Handle<SharedFunctionInfo>(shared);
520 event.script = ToApiHandle<v8::UnboundScript>(shared_function_handle);
521 event.name.str = name;
522 event.name.len = length;
523 code_event_handler_(&event);
527 void JitLogger::CodeMoveEvent(Address from, Address to) {
528 Code* from_code = Code::cast(HeapObject::FromAddress(from));
531 event.type = JitCodeEvent::CODE_MOVED;
532 event.code_start = from_code->instruction_start();
533 event.code_len = from_code->instruction_size();
535 // Calculate the header size.
536 const size_t header_size =
537 from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
539 // Calculate the new start address of the instructions.
540 event.new_code_start =
541 reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
543 code_event_handler_(&event);
547 void JitLogger::CodeDeleteEvent(Address from) {
548 Code* from_code = Code::cast(HeapObject::FromAddress(from));
551 event.type = JitCodeEvent::CODE_REMOVED;
552 event.code_start = from_code->instruction_start();
553 event.code_len = from_code->instruction_size();
555 code_event_handler_(&event);
558 void JitLogger::AddCodeLinePosInfoEvent(
559 void* jit_handler_data,
562 JitCodeEvent::PositionType position_type) {
564 memset(&event, 0, sizeof(event));
565 event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
566 event.user_data = jit_handler_data;
567 event.line_info.offset = pc_offset;
568 event.line_info.pos = position;
569 event.line_info.position_type = position_type;
571 code_event_handler_(&event);
575 void* JitLogger::StartCodePosInfoEvent() {
577 memset(&event, 0, sizeof(event));
578 event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
580 code_event_handler_(&event);
581 return event.user_data;
585 void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) {
587 memset(&event, 0, sizeof(event));
588 event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
589 event.code_start = code->instruction_start();
590 event.user_data = jit_handler_data;
592 code_event_handler_(&event);
596 // The Profiler samples pc and sp values for the main thread.
597 // Each sample is appended to a circular buffer.
598 // An independent thread removes data and writes it to the log.
599 // This design minimizes the time spent in the sampler.
601 class Profiler: public base::Thread {
603 explicit Profiler(Isolate* isolate);
607 // Inserts collected profiling data into buffer.
608 void Insert(TickSample* sample) {
612 if (Succ(head_) == static_cast<int>(base::NoBarrier_Load(&tail_))) {
615 buffer_[head_] = *sample;
617 buffer_semaphore_.Signal(); // Tell we have an element.
623 // Pause and Resume TickSample data collection.
624 void pause() { paused_ = true; }
625 void resume() { paused_ = false; }
628 // Waits for a signal and removes profiling data.
629 bool Remove(TickSample* sample) {
630 buffer_semaphore_.Wait(); // Wait for an element.
631 *sample = buffer_[base::NoBarrier_Load(&tail_)];
632 bool result = overflow_;
633 base::NoBarrier_Store(&tail_, static_cast<base::Atomic32>(
634 Succ(base::NoBarrier_Load(&tail_))));
639 // Returns the next index in the cyclic buffer.
640 int Succ(int index) { return (index + 1) % kBufferSize; }
643 // Cyclic buffer for communicating profiling samples
644 // between the signal handler and the worker thread.
645 static const int kBufferSize = 128;
646 TickSample buffer_[kBufferSize]; // Buffer storage.
647 int head_; // Index to the buffer head.
648 base::Atomic32 tail_; // Index to the buffer tail.
649 bool overflow_; // Tell whether a buffer overflow has occurred.
650 // Sempahore used for buffer synchronization.
651 base::Semaphore buffer_semaphore_;
653 // Tells whether profiler is engaged, that is, processing thread is stated.
656 // Tells whether worker thread should continue running.
657 base::Atomic32 running_;
659 // Tells whether we are currently recording tick samples.
665 // Ticker used to provide ticks to the profiler and the sliding state
668 class Ticker: public Sampler {
670 Ticker(Isolate* isolate, int interval):
671 Sampler(isolate, interval),
674 ~Ticker() { if (IsActive()) Stop(); }
676 virtual void Tick(TickSample* sample) {
677 if (profiler_) profiler_->Insert(sample);
680 void SetProfiler(Profiler* profiler) {
681 DCHECK(profiler_ == NULL);
682 profiler_ = profiler;
683 IncreaseProfilingDepth();
684 if (!IsActive()) Start();
687 void ClearProfiler() {
689 if (IsActive()) Stop();
690 DecreaseProfilingDepth();
699 // Profiler implementation.
701 Profiler::Profiler(Isolate* isolate)
702 : base::Thread(Options("v8:Profiler")),
706 buffer_semaphore_(0),
709 base::NoBarrier_Store(&tail_, 0);
710 base::NoBarrier_Store(&running_, 0);
714 void Profiler::Engage() {
715 if (engaged_) return;
718 std::vector<base::OS::SharedLibraryAddress> addresses =
719 base::OS::GetSharedLibraryAddresses();
720 for (size_t i = 0; i < addresses.size(); ++i) {
721 LOG(isolate_, SharedLibraryEvent(
722 addresses[i].library_path, addresses[i].start, addresses[i].end));
725 // Start thread processing the profiler buffer.
726 base::NoBarrier_Store(&running_, 1);
729 // Register to get ticks.
730 Logger* logger = isolate_->logger();
731 logger->ticker_->SetProfiler(this);
733 logger->ProfilerBeginEvent();
737 void Profiler::Disengage() {
738 if (!engaged_) return;
740 // Stop receiving ticks.
741 isolate_->logger()->ticker_->ClearProfiler();
743 // Terminate the worker thread by setting running_ to false,
744 // inserting a fake element in the queue and then wait for
745 // the thread to terminate.
746 base::NoBarrier_Store(&running_, 0);
748 // Reset 'paused_' flag, otherwise semaphore may not be signalled.
753 LOG(isolate_, UncheckedStringEvent("profiler", "end"));
757 void Profiler::Run() {
759 bool overflow = Remove(&sample);
760 while (base::NoBarrier_Load(&running_)) {
761 LOG(isolate_, TickEvent(&sample, overflow));
762 overflow = Remove(&sample);
768 // Logger class implementation.
771 Logger::Logger(Isolate* isolate)
778 perf_basic_logger_(NULL),
779 perf_jit_logger_(NULL),
783 is_initialized_(false) {
792 void Logger::addCodeEventListener(CodeEventListener* listener) {
793 DCHECK(!hasCodeEventListener(listener));
794 listeners_.Add(listener);
798 void Logger::removeCodeEventListener(CodeEventListener* listener) {
799 DCHECK(hasCodeEventListener(listener));
800 listeners_.RemoveElement(listener);
804 bool Logger::hasCodeEventListener(CodeEventListener* listener) {
805 return listeners_.Contains(listener);
809 void Logger::ProfilerBeginEvent() {
810 if (!log_->IsEnabled()) return;
811 Log::MessageBuilder msg(log_);
812 msg.Append("profiler,\"begin\",%d", kSamplingIntervalMs);
813 msg.WriteToLogFile();
817 void Logger::StringEvent(const char* name, const char* value) {
818 if (FLAG_log) UncheckedStringEvent(name, value);
822 void Logger::UncheckedStringEvent(const char* name, const char* value) {
823 if (!log_->IsEnabled()) return;
824 Log::MessageBuilder msg(log_);
825 msg.Append("%s,\"%s\"", name, value);
826 msg.WriteToLogFile();
830 void Logger::IntEvent(const char* name, int value) {
831 if (FLAG_log) UncheckedIntEvent(name, value);
835 void Logger::IntPtrTEvent(const char* name, intptr_t value) {
836 if (FLAG_log) UncheckedIntPtrTEvent(name, value);
840 void Logger::UncheckedIntEvent(const char* name, int value) {
841 if (!log_->IsEnabled()) return;
842 Log::MessageBuilder msg(log_);
843 msg.Append("%s,%d", name, value);
844 msg.WriteToLogFile();
848 void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
849 if (!log_->IsEnabled()) return;
850 Log::MessageBuilder msg(log_);
851 msg.Append("%s,%" V8_PTR_PREFIX "d", name, value);
852 msg.WriteToLogFile();
856 void Logger::HandleEvent(const char* name, Object** location) {
857 if (!log_->IsEnabled() || !FLAG_log_handles) return;
858 Log::MessageBuilder msg(log_);
859 msg.Append("%s,0x%" V8PRIxPTR, name, location);
860 msg.WriteToLogFile();
864 // ApiEvent is private so all the calls come from the Logger class. It is the
865 // caller's responsibility to ensure that log is enabled and that
866 // FLAG_log_api is true.
867 void Logger::ApiEvent(const char* format, ...) {
868 DCHECK(log_->IsEnabled() && FLAG_log_api);
869 Log::MessageBuilder msg(log_);
871 va_start(ap, format);
872 msg.AppendVA(format, ap);
874 msg.WriteToLogFile();
878 void Logger::ApiSecurityCheck() {
879 if (!log_->IsEnabled() || !FLAG_log_api) return;
880 ApiEvent("api,check-security");
884 void Logger::SharedLibraryEvent(const std::string& library_path,
887 if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
888 Log::MessageBuilder msg(log_);
889 msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR,
890 library_path.c_str(), start, end);
891 msg.WriteToLogFile();
895 void Logger::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) {
896 PROFILER_LOG(CodeDeoptEvent(code, pc, fp_to_sp_delta));
897 if (!log_->IsEnabled() || !FLAG_log_internal_timer_events) return;
898 Log::MessageBuilder msg(log_);
899 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
900 msg.Append("code-deopt,%ld,%d", since_epoch, code->CodeSize());
901 msg.WriteToLogFile();
905 void Logger::CurrentTimeEvent() {
906 if (!log_->IsEnabled()) return;
907 DCHECK(FLAG_log_internal_timer_events);
908 Log::MessageBuilder msg(log_);
909 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
910 msg.Append("current-time,%ld", since_epoch);
911 msg.WriteToLogFile();
915 void Logger::TimerEvent(Logger::StartEnd se, const char* name) {
916 if (!log_->IsEnabled()) return;
917 DCHECK(FLAG_log_internal_timer_events);
918 Log::MessageBuilder msg(log_);
919 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
920 const char* format = (se == START) ? "timer-event-start,\"%s\",%ld"
921 : "timer-event-end,\"%s\",%ld";
922 msg.Append(format, name, since_epoch);
923 msg.WriteToLogFile();
927 void Logger::EnterExternal(Isolate* isolate) {
928 LOG(isolate, TimerEvent(START, TimerEventExternal::name()));
929 DCHECK(isolate->current_vm_state() == JS);
930 isolate->set_current_vm_state(EXTERNAL);
934 void Logger::LeaveExternal(Isolate* isolate) {
935 LOG(isolate, TimerEvent(END, TimerEventExternal::name()));
936 DCHECK(isolate->current_vm_state() == EXTERNAL);
937 isolate->set_current_vm_state(JS);
941 template <class TimerEvent>
942 void TimerEventScope<TimerEvent>::LogTimerEvent(Logger::StartEnd se) {
943 Logger::CallEventLogger(isolate_, TimerEvent::name(), se,
944 TimerEvent::expose_to_api());
948 // Instantiate template methods.
949 #define V(TimerName, expose) \
950 template void TimerEventScope<TimerEvent##TimerName>::LogTimerEvent( \
951 Logger::StartEnd se);
956 void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
957 // Prints "/" + re.source + "/" +
958 // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
959 Log::MessageBuilder msg(log_);
961 Handle<Object> source = Object::GetProperty(
962 isolate_, regexp, "source").ToHandleChecked();
963 if (!source->IsString()) {
964 msg.Append("no source");
968 switch (regexp->TypeTag()) {
976 msg.AppendDetailed(*Handle<String>::cast(source), false);
980 Handle<Object> global = Object::GetProperty(
981 isolate_, regexp, "global").ToHandleChecked();
982 if (global->IsTrue()) {
986 Handle<Object> ignorecase = Object::GetProperty(
987 isolate_, regexp, "ignoreCase").ToHandleChecked();
988 if (ignorecase->IsTrue()) {
992 Handle<Object> multiline = Object::GetProperty(
993 isolate_, regexp, "multiline").ToHandleChecked();
994 if (multiline->IsTrue()) {
998 msg.WriteToLogFile();
1002 void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
1003 if (!log_->IsEnabled() || !FLAG_log_regexp) return;
1004 Log::MessageBuilder msg(log_);
1005 msg.Append("regexp-compile,");
1006 LogRegExpSource(regexp);
1007 msg.Append(in_cache ? ",hit" : ",miss");
1008 msg.WriteToLogFile();
1012 void Logger::ApiNamedPropertyAccess(const char* tag,
1015 DCHECK(name->IsName());
1016 if (!log_->IsEnabled() || !FLAG_log_api) return;
1017 String* class_name_obj = holder->class_name();
1018 SmartArrayPointer<char> class_name =
1019 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1020 if (name->IsString()) {
1021 SmartArrayPointer<char> property_name =
1022 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1023 ApiEvent("api,%s,\"%s\",\"%s\"", tag, class_name.get(),
1024 property_name.get());
1026 Symbol* symbol = Symbol::cast(name);
1027 uint32_t hash = symbol->Hash();
1028 if (symbol->name()->IsUndefined()) {
1029 ApiEvent("api,%s,\"%s\",symbol(hash %x)", tag, class_name.get(), hash);
1031 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1032 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1033 ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)", tag, class_name.get(),
1039 void Logger::ApiIndexedPropertyAccess(const char* tag,
1042 if (!log_->IsEnabled() || !FLAG_log_api) return;
1043 String* class_name_obj = holder->class_name();
1044 SmartArrayPointer<char> class_name =
1045 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1046 ApiEvent("api,%s,\"%s\",%u", tag, class_name.get(), index);
1050 void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
1051 if (!log_->IsEnabled() || !FLAG_log_api) return;
1052 String* class_name_obj = object->class_name();
1053 SmartArrayPointer<char> class_name =
1054 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1055 ApiEvent("api,%s,\"%s\"", tag, class_name.get());
1059 void Logger::ApiEntryCall(const char* name) {
1060 if (!log_->IsEnabled() || !FLAG_log_api) return;
1061 ApiEvent("api,%s", name);
1065 void Logger::NewEvent(const char* name, void* object, size_t size) {
1066 if (!log_->IsEnabled() || !FLAG_log) return;
1067 Log::MessageBuilder msg(log_);
1068 msg.Append("new,%s,0x%" V8PRIxPTR ",%u", name, object,
1069 static_cast<unsigned int>(size));
1070 msg.WriteToLogFile();
1074 void Logger::DeleteEvent(const char* name, void* object) {
1075 if (!log_->IsEnabled() || !FLAG_log) return;
1076 Log::MessageBuilder msg(log_);
1077 msg.Append("delete,%s,0x%" V8PRIxPTR, name, object);
1078 msg.WriteToLogFile();
1082 void Logger::NewEventStatic(const char* name, void* object, size_t size) {
1083 Isolate::Current()->logger()->NewEvent(name, object, size);
1087 void Logger::DeleteEventStatic(const char* name, void* object) {
1088 Isolate::Current()->logger()->DeleteEvent(name, object);
1092 void Logger::CallbackEventInternal(const char* prefix, Name* name,
1093 Address entry_point) {
1094 if (!FLAG_log_code || !log_->IsEnabled()) return;
1095 Log::MessageBuilder msg(log_);
1096 msg.Append("%s,%s,-2,",
1097 kLogEventsNames[CODE_CREATION_EVENT],
1098 kLogEventsNames[CALLBACK_TAG]);
1099 msg.AppendAddress(entry_point);
1100 if (name->IsString()) {
1101 SmartArrayPointer<char> str =
1102 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1103 msg.Append(",1,\"%s%s\"", prefix, str.get());
1105 Symbol* symbol = Symbol::cast(name);
1106 if (symbol->name()->IsUndefined()) {
1107 msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
1109 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1110 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1111 msg.Append(",1,symbol(\"%s\" hash %x)", prefix, str.get(),
1115 msg.WriteToLogFile();
1119 void Logger::CallbackEvent(Name* name, Address entry_point) {
1120 PROFILER_LOG(CallbackEvent(name, entry_point));
1121 CallbackEventInternal("", name, entry_point);
1125 void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
1126 PROFILER_LOG(GetterCallbackEvent(name, entry_point));
1127 CallbackEventInternal("get ", name, entry_point);
1131 void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
1132 PROFILER_LOG(SetterCallbackEvent(name, entry_point));
1133 CallbackEventInternal("set ", name, entry_point);
1137 static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
1138 Logger::LogEventsAndTags tag,
1141 msg->Append("%s,%s,%d,",
1142 kLogEventsNames[Logger::CODE_CREATION_EVENT],
1143 kLogEventsNames[tag],
1145 msg->AppendAddress(code->address());
1146 msg->Append(",%d,", code->ExecutableSize());
1150 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1152 const char* comment) {
1153 PROFILER_LOG(CodeCreateEvent(tag, code, comment));
1155 if (!is_logging_code_events()) return;
1156 CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
1158 if (!FLAG_log_code || !log_->IsEnabled()) return;
1159 Log::MessageBuilder msg(log_);
1160 AppendCodeCreateHeader(&msg, tag, code);
1161 msg.AppendDoubleQuotedString(comment);
1162 msg.WriteToLogFile();
1166 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1169 PROFILER_LOG(CodeCreateEvent(tag, code, name));
1171 if (!is_logging_code_events()) return;
1172 CALL_LISTENERS(CodeCreateEvent(tag, code, name));
1174 if (!FLAG_log_code || !log_->IsEnabled()) return;
1175 Log::MessageBuilder msg(log_);
1176 AppendCodeCreateHeader(&msg, tag, code);
1177 if (name->IsString()) {
1179 msg.AppendDetailed(String::cast(name), false);
1182 msg.AppendSymbolName(Symbol::cast(name));
1184 msg.WriteToLogFile();
1188 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1190 SharedFunctionInfo* shared,
1191 CompilationInfo* info,
1193 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
1195 if (!is_logging_code_events()) return;
1196 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
1198 if (!FLAG_log_code || !log_->IsEnabled()) return;
1199 if (code == isolate_->builtins()->builtin(Builtins::kCompileLazy)) return;
1201 Log::MessageBuilder msg(log_);
1202 AppendCodeCreateHeader(&msg, tag, code);
1203 if (name->IsString()) {
1204 SmartArrayPointer<char> str =
1205 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1206 msg.Append("\"%s\"", str.get());
1208 msg.AppendSymbolName(Symbol::cast(name));
1211 msg.AppendAddress(shared->address());
1212 msg.Append(",%s", ComputeMarker(code));
1213 msg.WriteToLogFile();
1217 // Although, it is possible to extract source and line from
1218 // the SharedFunctionInfo object, we left it to caller
1219 // to leave logging functions free from heap allocations.
1220 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1222 SharedFunctionInfo* shared,
1223 CompilationInfo* info,
1224 Name* source, int line, int column) {
1225 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column));
1227 if (!is_logging_code_events()) return;
1228 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line,
1231 if (!FLAG_log_code || !log_->IsEnabled()) return;
1232 Log::MessageBuilder msg(log_);
1233 AppendCodeCreateHeader(&msg, tag, code);
1234 SmartArrayPointer<char> name =
1235 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1236 msg.Append("\"%s ", name.get());
1237 if (source->IsString()) {
1238 SmartArrayPointer<char> sourcestr =
1239 String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1240 msg.Append("%s", sourcestr.get());
1242 msg.AppendSymbolName(Symbol::cast(source));
1244 msg.Append(":%d:%d\",", line, column);
1245 msg.AppendAddress(shared->address());
1246 msg.Append(",%s", ComputeMarker(code));
1247 msg.WriteToLogFile();
1251 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1254 PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
1256 if (!is_logging_code_events()) return;
1257 CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
1259 if (!FLAG_log_code || !log_->IsEnabled()) return;
1260 Log::MessageBuilder msg(log_);
1261 AppendCodeCreateHeader(&msg, tag, code);
1262 msg.Append("\"args_count: %d\"", args_count);
1263 msg.WriteToLogFile();
1267 void Logger::CodeDisableOptEvent(Code* code,
1268 SharedFunctionInfo* shared) {
1269 PROFILER_LOG(CodeDisableOptEvent(code, shared));
1271 if (!is_logging_code_events()) return;
1272 CALL_LISTENERS(CodeDisableOptEvent(code, shared));
1274 if (!FLAG_log_code || !log_->IsEnabled()) return;
1275 Log::MessageBuilder msg(log_);
1276 msg.Append("%s,", kLogEventsNames[CODE_DISABLE_OPT_EVENT]);
1277 SmartArrayPointer<char> name =
1278 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1279 msg.Append("\"%s\",", name.get());
1280 msg.Append("\"%s\"", GetBailoutReason(shared->disable_optimization_reason()));
1281 msg.WriteToLogFile();
1285 void Logger::CodeMovingGCEvent() {
1286 PROFILER_LOG(CodeMovingGCEvent());
1288 if (!is_logging_code_events()) return;
1289 if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1290 CALL_LISTENERS(CodeMovingGCEvent());
1291 base::OS::SignalCodeMovingGC();
1295 void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
1296 PROFILER_LOG(RegExpCodeCreateEvent(code, source));
1298 if (!is_logging_code_events()) return;
1299 CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
1301 if (!FLAG_log_code || !log_->IsEnabled()) return;
1302 Log::MessageBuilder msg(log_);
1303 AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
1305 msg.AppendDetailed(source, false);
1307 msg.WriteToLogFile();
1311 void Logger::CodeMoveEvent(Address from, Address to) {
1312 PROFILER_LOG(CodeMoveEvent(from, to));
1314 if (!is_logging_code_events()) return;
1315 CALL_LISTENERS(CodeMoveEvent(from, to));
1316 MoveEventInternal(CODE_MOVE_EVENT, from, to);
1320 void Logger::CodeDeleteEvent(Address from) {
1321 PROFILER_LOG(CodeDeleteEvent(from));
1323 if (!is_logging_code_events()) return;
1324 CALL_LISTENERS(CodeDeleteEvent(from));
1326 if (!FLAG_log_code || !log_->IsEnabled()) return;
1327 Log::MessageBuilder msg(log_);
1328 msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
1329 msg.AppendAddress(from);
1330 msg.WriteToLogFile();
1334 void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
1337 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1340 JitCodeEvent::POSITION));
1344 void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
1347 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1350 JitCodeEvent::STATEMENT_POSITION));
1354 void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
1355 if (jit_logger_ != NULL) {
1356 pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
1361 void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
1362 void* jit_handler_data) {
1363 JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
1367 void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1368 if (code_name == NULL) return; // Not a code object.
1369 Log::MessageBuilder msg(log_);
1370 msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
1371 msg.AppendDoubleQuotedString(code_name);
1372 msg.WriteToLogFile();
1376 void Logger::SnapshotPositionEvent(Address addr, int pos) {
1377 if (!log_->IsEnabled()) return;
1378 LL_LOG(SnapshotPositionEvent(addr, pos));
1379 if (!FLAG_log_snapshot_positions) return;
1380 Log::MessageBuilder msg(log_);
1381 msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
1382 msg.AppendAddress(addr);
1383 msg.Append(",%d", pos);
1384 msg.WriteToLogFile();
1388 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
1389 if (!is_logging_code_events()) return;
1390 MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
1394 void Logger::MoveEventInternal(LogEventsAndTags event,
1397 if (!FLAG_log_code || !log_->IsEnabled()) return;
1398 Log::MessageBuilder msg(log_);
1399 msg.Append("%s,", kLogEventsNames[event]);
1400 msg.AppendAddress(from);
1402 msg.AppendAddress(to);
1403 msg.WriteToLogFile();
1407 void Logger::ResourceEvent(const char* name, const char* tag) {
1408 if (!log_->IsEnabled() || !FLAG_log) return;
1409 Log::MessageBuilder msg(log_);
1410 msg.Append("%s,%s,", name, tag);
1413 if (base::OS::GetUserTime(&sec, &usec) != -1) {
1414 msg.Append("%d,%d,", sec, usec);
1416 msg.Append("%.0f", base::OS::TimeCurrentMillis());
1417 msg.WriteToLogFile();
1421 void Logger::SuspectReadEvent(Name* name, Object* obj) {
1422 if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1423 Log::MessageBuilder msg(log_);
1424 String* class_name = obj->IsJSObject()
1425 ? JSObject::cast(obj)->class_name()
1426 : isolate_->heap()->empty_string();
1427 msg.Append("suspect-read,");
1428 msg.Append(class_name);
1430 if (name->IsString()) {
1432 msg.Append(String::cast(name));
1435 msg.AppendSymbolName(Symbol::cast(name));
1437 msg.WriteToLogFile();
1441 void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
1442 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1443 Log::MessageBuilder msg(log_);
1444 // Using non-relative system time in order to be able to synchronize with
1445 // external memory profiling events (e.g. DOM memory size).
1446 msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f", space, kind,
1447 base::OS::TimeCurrentMillis());
1448 msg.WriteToLogFile();
1452 void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
1453 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1454 Log::MessageBuilder msg(log_);
1455 msg.Append("heap-sample-end,\"%s\",\"%s\"", space, kind);
1456 msg.WriteToLogFile();
1460 void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
1461 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1462 Log::MessageBuilder msg(log_);
1463 msg.Append("heap-sample-item,%s,%d,%d", type, number, bytes);
1464 msg.WriteToLogFile();
1468 void Logger::DebugTag(const char* call_site_tag) {
1469 if (!log_->IsEnabled() || !FLAG_log) return;
1470 Log::MessageBuilder msg(log_);
1471 msg.Append("debug-tag,%s", call_site_tag);
1472 msg.WriteToLogFile();
1476 void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
1477 if (!log_->IsEnabled() || !FLAG_log) return;
1478 StringBuilder s(parameter.length() + 1);
1479 for (int i = 0; i < parameter.length(); ++i) {
1480 s.AddCharacter(static_cast<char>(parameter[i]));
1482 char* parameter_string = s.Finalize();
1483 Log::MessageBuilder msg(log_);
1484 msg.Append("debug-queue-event,%s,%15.3f,%s", event_type,
1485 base::OS::TimeCurrentMillis(), parameter_string);
1486 DeleteArray(parameter_string);
1487 msg.WriteToLogFile();
1491 void Logger::TickEvent(TickSample* sample, bool overflow) {
1492 if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
1493 Log::MessageBuilder msg(log_);
1494 msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1495 msg.AppendAddress(sample->pc);
1496 msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
1497 if (sample->has_external_callback) {
1499 msg.AppendAddress(sample->external_callback);
1502 msg.AppendAddress(sample->tos);
1504 msg.Append(",%d", static_cast<int>(sample->state));
1506 msg.Append(",overflow");
1508 for (unsigned i = 0; i < sample->frames_count; ++i) {
1510 msg.AppendAddress(sample->stack[i]);
1512 msg.WriteToLogFile();
1516 void Logger::StopProfiler() {
1517 if (!log_->IsEnabled()) return;
1518 if (profiler_ != NULL) {
1520 is_logging_ = false;
1525 // This function can be called when Log's mutex is acquired,
1526 // either from main or Profiler's thread.
1527 void Logger::LogFailure() {
1532 class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
1534 EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
1535 Handle<Code>* code_objects,
1537 : sfis_(sfis), code_objects_(code_objects), count_(count) { }
1539 virtual void EnterContext(Context* context) {}
1540 virtual void LeaveContext(Context* context) {}
1542 virtual void VisitFunction(JSFunction* function) {
1543 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
1544 Object* maybe_script = sfi->script();
1545 if (maybe_script->IsScript()
1546 && !Script::cast(maybe_script)->HasValidSource()) return;
1547 if (sfis_ != NULL) {
1548 sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
1550 if (code_objects_ != NULL) {
1551 DCHECK(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1552 code_objects_[*count_] = Handle<Code>(function->code());
1554 *count_ = *count_ + 1;
1558 Handle<SharedFunctionInfo>* sfis_;
1559 Handle<Code>* code_objects_;
1564 static int EnumerateCompiledFunctions(Heap* heap,
1565 Handle<SharedFunctionInfo>* sfis,
1566 Handle<Code>* code_objects) {
1567 HeapIterator iterator(heap);
1568 DisallowHeapAllocation no_gc;
1569 int compiled_funcs_count = 0;
1571 // Iterate the heap to find shared function info objects and record
1572 // the unoptimized code for them.
1573 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1574 if (!obj->IsSharedFunctionInfo()) continue;
1575 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
1576 if (sfi->is_compiled()
1577 && (!sfi->script()->IsScript()
1578 || Script::cast(sfi->script())->HasValidSource())) {
1580 sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
1582 if (code_objects != NULL) {
1583 code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1585 ++compiled_funcs_count;
1589 // Iterate all optimized functions in all contexts.
1590 EnumerateOptimizedFunctionsVisitor visitor(sfis,
1592 &compiled_funcs_count);
1593 Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
1595 return compiled_funcs_count;
1599 void Logger::LogCodeObject(Object* object) {
1600 Code* code_object = Code::cast(object);
1601 LogEventsAndTags tag = Logger::STUB_TAG;
1602 const char* description = "Unknown code from the snapshot";
1603 switch (code_object->kind()) {
1604 case Code::FUNCTION:
1605 case Code::OPTIMIZED_FUNCTION:
1606 return; // We log this later using LogCompiledFunctions.
1607 case Code::BINARY_OP_IC:
1608 case Code::COMPARE_IC: // fall through
1609 case Code::COMPARE_NIL_IC: // fall through
1610 case Code::TO_BOOLEAN_IC: // fall through
1613 CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
1614 if (description == NULL)
1615 description = "A stub from the snapshot";
1616 tag = Logger::STUB_TAG;
1619 description = "Regular expression code";
1620 tag = Logger::REG_EXP_TAG;
1623 description = isolate_->builtins()->name(code_object->builtin_index());
1624 tag = Logger::BUILTIN_TAG;
1627 description = "An IC handler from the snapshot";
1628 tag = Logger::HANDLER_TAG;
1630 case Code::KEYED_LOAD_IC:
1631 description = "A keyed load IC from the snapshot";
1632 tag = Logger::KEYED_LOAD_IC_TAG;
1635 description = "A load IC from the snapshot";
1636 tag = Logger::LOAD_IC_TAG;
1639 description = "A call IC from the snapshot";
1640 tag = Logger::CALL_IC_TAG;
1642 case Code::STORE_IC:
1643 description = "A store IC from the snapshot";
1644 tag = Logger::STORE_IC_TAG;
1646 case Code::KEYED_STORE_IC:
1647 description = "A keyed store IC from the snapshot";
1648 tag = Logger::KEYED_STORE_IC_TAG;
1650 case Code::NUMBER_OF_KINDS:
1653 PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
1657 void Logger::LogCodeObjects() {
1658 Heap* heap = isolate_->heap();
1659 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1660 "Logger::LogCodeObjects");
1661 HeapIterator iterator(heap);
1662 DisallowHeapAllocation no_gc;
1663 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1664 if (obj->IsCode()) LogCodeObject(obj);
1669 void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
1670 Handle<Code> code) {
1671 Handle<String> func_name(shared->DebugName());
1672 if (shared->script()->IsScript()) {
1673 Handle<Script> script(Script::cast(shared->script()));
1674 int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
1676 Script::GetColumnNumber(script, shared->start_position()) + 1;
1677 if (script->name()->IsString()) {
1678 Handle<String> script_name(String::cast(script->name()));
1682 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1683 *code, *shared, NULL,
1684 *script_name, line_num, column_num));
1686 // Can't distinguish eval and script here, so always use Script.
1689 Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
1690 *code, *shared, NULL, *script_name));
1695 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1696 *code, *shared, NULL,
1697 isolate_->heap()->empty_string(), line_num, column_num));
1699 } else if (shared->IsApiFunction()) {
1701 FunctionTemplateInfo* fun_data = shared->get_api_func_data();
1702 Object* raw_call_data = fun_data->call_code();
1703 if (!raw_call_data->IsUndefined()) {
1704 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1705 Object* callback_obj = call_data->callback();
1706 Address entry_point = v8::ToCData<Address>(callback_obj);
1707 PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
1712 Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
1717 void Logger::LogCompiledFunctions() {
1718 Heap* heap = isolate_->heap();
1719 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1720 "Logger::LogCompiledFunctions");
1721 HandleScope scope(isolate_);
1722 const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL);
1723 ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
1724 ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1725 EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
1727 // During iteration, there can be heap allocation due to
1728 // GetScriptLineNumber call.
1729 for (int i = 0; i < compiled_funcs_count; ++i) {
1730 if (code_objects[i].is_identical_to(isolate_->builtins()->CompileLazy()))
1732 LogExistingFunction(sfis[i], code_objects[i]);
1737 void Logger::LogAccessorCallbacks() {
1738 Heap* heap = isolate_->heap();
1739 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1740 "Logger::LogAccessorCallbacks");
1741 HeapIterator iterator(heap);
1742 DisallowHeapAllocation no_gc;
1743 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1744 if (!obj->IsExecutableAccessorInfo()) continue;
1745 ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
1746 if (!ai->name()->IsName()) continue;
1747 Address getter_entry = v8::ToCData<Address>(ai->getter());
1748 Name* name = Name::cast(ai->name());
1749 if (getter_entry != 0) {
1750 PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
1752 Address setter_entry = v8::ToCData<Address>(ai->setter());
1753 if (setter_entry != 0) {
1754 PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
1760 static void AddIsolateIdIfNeeded(std::ostream& os, // NOLINT
1762 if (FLAG_logfile_per_isolate) os << "isolate-" << isolate << "-";
1766 static void PrepareLogFileName(std::ostream& os, // NOLINT
1767 Isolate* isolate, const char* file_name) {
1768 int dir_separator_count = 0;
1769 for (const char* p = file_name; *p; p++) {
1770 if (base::OS::isDirectorySeparator(*p)) dir_separator_count++;
1773 for (const char* p = file_name; *p; p++) {
1774 if (dir_separator_count == 0) {
1775 AddIsolateIdIfNeeded(os, isolate);
1776 dir_separator_count--;
1782 // If there's a % at the end of the string we back up
1783 // one character so we can escape the loop properly.
1787 os << base::OS::GetCurrentProcessId();
1790 // %t expands to the current time in milliseconds.
1791 os << static_cast<int64_t>(base::OS::TimeCurrentMillis());
1794 // %% expands (contracts really) to %.
1798 // All other %'s expand to themselves.
1803 if (base::OS::isDirectorySeparator(*p)) dir_separator_count--;
1810 bool Logger::SetUp(Isolate* isolate) {
1811 // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
1812 if (is_initialized_) return true;
1813 is_initialized_ = true;
1815 // --ll-prof implies --log-code and --log-snapshot-positions.
1817 FLAG_log_snapshot_positions = true;
1820 std::ostringstream log_file_name;
1821 PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
1822 log_->Initialize(log_file_name.str().c_str());
1825 if (FLAG_perf_basic_prof) {
1826 perf_basic_logger_ = new PerfBasicLogger();
1827 addCodeEventListener(perf_basic_logger_);
1830 if (FLAG_perf_jit_prof) {
1831 perf_jit_logger_ = new PerfJitLogger();
1832 addCodeEventListener(perf_jit_logger_);
1836 ll_logger_ = new LowLevelLogger(log_file_name.str().c_str());
1837 addCodeEventListener(ll_logger_);
1840 ticker_ = new Ticker(isolate, kSamplingIntervalMs);
1842 if (Log::InitLogAtStart()) {
1846 if (FLAG_log_internal_timer_events || FLAG_prof_cpp) timer_.Start();
1848 if (FLAG_prof_cpp) {
1849 profiler_ = new Profiler(isolate);
1851 profiler_->Engage();
1858 void Logger::SetCodeEventHandler(uint32_t options,
1859 JitCodeEventHandler event_handler) {
1861 removeCodeEventListener(jit_logger_);
1866 if (event_handler) {
1867 jit_logger_ = new JitLogger(event_handler);
1868 addCodeEventListener(jit_logger_);
1869 if (options & kJitCodeEventEnumExisting) {
1870 HandleScope scope(isolate_);
1872 LogCompiledFunctions();
1878 Sampler* Logger::sampler() {
1883 FILE* Logger::TearDown() {
1884 if (!is_initialized_) return NULL;
1885 is_initialized_ = false;
1887 // Stop the profiler before closing the file.
1888 if (profiler_ != NULL) {
1889 profiler_->Disengage();
1897 if (perf_basic_logger_) {
1898 removeCodeEventListener(perf_basic_logger_);
1899 delete perf_basic_logger_;
1900 perf_basic_logger_ = NULL;
1903 if (perf_jit_logger_) {
1904 removeCodeEventListener(perf_jit_logger_);
1905 delete perf_jit_logger_;
1906 perf_jit_logger_ = NULL;
1910 removeCodeEventListener(ll_logger_);
1916 removeCodeEventListener(jit_logger_);
1921 return log_->Close();
1924 } } // namespace v8::internal