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/serialize.h"
25 #include "src/string-stream.h"
26 #include "src/vm-state-inl.h"
32 #define DECLARE_EVENT(ignore1, name) name,
33 static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
34 LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
39 #define CALL_LISTENERS(Call) \
40 for (int i = 0; i < listeners_.length(); ++i) { \
41 listeners_[i]->Call; \
44 #define PROFILER_LOG(Call) \
46 CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
47 if (cpu_profiler->is_profiling()) { \
52 // ComputeMarker must only be used when SharedFunctionInfo is known.
53 static const char* ComputeMarker(Code* code) {
54 switch (code->kind()) {
55 case Code::FUNCTION: return code->optimizable() ? "~" : "";
56 case Code::OPTIMIZED_FUNCTION: return "*";
62 class CodeEventLogger::NameBuffer {
64 NameBuffer() { Reset(); }
70 void Init(Logger::LogEventsAndTags tag) {
72 AppendBytes(kLogEventsNames[tag]);
76 void AppendName(Name* name) {
77 if (name->IsString()) {
78 AppendString(String::cast(name));
80 Symbol* symbol = Symbol::cast(name);
81 AppendBytes("symbol(");
82 if (!symbol->name()->IsUndefined()) {
84 AppendString(String::cast(symbol->name()));
88 AppendHex(symbol->Hash());
93 void AppendString(String* str) {
94 if (str == NULL) return;
95 int uc16_length = Min(str->length(), kUtf16BufferSize);
96 String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
97 int previous = unibrow::Utf16::kNoPreviousCharacter;
98 for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
99 uc16 c = utf16_buffer[i];
100 if (c <= unibrow::Utf8::kMaxOneByteChar) {
101 utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
103 int char_length = unibrow::Utf8::Length(c, previous);
104 if (utf8_pos_ + char_length > kUtf8BufferSize) break;
105 unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
106 utf8_pos_ += char_length;
112 void AppendBytes(const char* bytes, int size) {
113 size = Min(size, kUtf8BufferSize - utf8_pos_);
114 MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
118 void AppendBytes(const char* bytes) {
119 AppendBytes(bytes, StrLength(bytes));
122 void AppendByte(char c) {
123 if (utf8_pos_ >= kUtf8BufferSize) return;
124 utf8_buffer_[utf8_pos_++] = c;
127 void AppendInt(int n) {
128 Vector<char> buffer(utf8_buffer_ + utf8_pos_,
129 kUtf8BufferSize - utf8_pos_);
130 int size = SNPrintF(buffer, "%d", n);
131 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
136 void AppendHex(uint32_t n) {
137 Vector<char> buffer(utf8_buffer_ + utf8_pos_,
138 kUtf8BufferSize - utf8_pos_);
139 int size = SNPrintF(buffer, "%x", n);
140 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
145 const char* get() { return utf8_buffer_; }
146 int size() const { return utf8_pos_; }
149 static const int kUtf8BufferSize = 512;
150 static const int kUtf16BufferSize = 128;
153 char utf8_buffer_[kUtf8BufferSize];
154 uc16 utf16_buffer[kUtf16BufferSize];
158 CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
160 CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
163 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
165 const char* comment) {
166 name_buffer_->Init(tag);
167 name_buffer_->AppendBytes(comment);
168 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
172 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
175 name_buffer_->Init(tag);
176 name_buffer_->AppendName(name);
177 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
181 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
183 SharedFunctionInfo* shared,
184 CompilationInfo* info,
186 name_buffer_->Init(tag);
187 name_buffer_->AppendBytes(ComputeMarker(code));
188 name_buffer_->AppendName(name);
189 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
193 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
195 SharedFunctionInfo* shared,
196 CompilationInfo* info,
197 Name* source, int line, int column) {
198 name_buffer_->Init(tag);
199 name_buffer_->AppendBytes(ComputeMarker(code));
200 name_buffer_->AppendString(shared->DebugName());
201 name_buffer_->AppendByte(' ');
202 if (source->IsString()) {
203 name_buffer_->AppendString(String::cast(source));
205 name_buffer_->AppendBytes("symbol(hash ");
206 name_buffer_->AppendHex(Name::cast(source)->Hash());
207 name_buffer_->AppendByte(')');
209 name_buffer_->AppendByte(':');
210 name_buffer_->AppendInt(line);
211 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
215 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
218 name_buffer_->Init(tag);
219 name_buffer_->AppendInt(args_count);
220 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
224 void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
225 name_buffer_->Init(Logger::REG_EXP_TAG);
226 name_buffer_->AppendString(source);
227 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
231 // Linux perf tool logging support
232 class PerfBasicLogger : public CodeEventLogger {
235 virtual ~PerfBasicLogger();
237 virtual void CodeMoveEvent(Address from, Address to) { }
238 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
239 virtual void CodeDeleteEvent(Address from) { }
242 virtual void LogRecordedBuffer(Code* code,
243 SharedFunctionInfo* shared,
247 // Extension added to V8 log file name to get the low-level log name.
248 static const char kFilenameFormatString[];
249 static const int kFilenameBufferPadding;
251 // File buffer size of the low-level log. We don't use the default to
252 // minimize the associated overhead.
253 static const int kLogBufferSize = 2 * MB;
255 FILE* perf_output_handle_;
258 const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map";
259 // Extra space for the PID in the filename
260 const int PerfBasicLogger::kFilenameBufferPadding = 16;
262 PerfBasicLogger::PerfBasicLogger()
263 : perf_output_handle_(NULL) {
264 // Open the perf JIT dump file.
265 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
266 ScopedVector<char> perf_dump_name(bufferSize);
269 kFilenameFormatString,
270 base::OS::GetCurrentProcessId());
272 perf_output_handle_ =
273 base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode);
274 CHECK_NOT_NULL(perf_output_handle_);
275 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
279 PerfBasicLogger::~PerfBasicLogger() {
280 fclose(perf_output_handle_);
281 perf_output_handle_ = NULL;
285 void PerfBasicLogger::LogRecordedBuffer(Code* code,
289 DCHECK(code->instruction_start() == code->address() + Code::kHeaderSize);
291 base::OS::FPrint(perf_output_handle_, "%llx %x %.*s\n",
292 reinterpret_cast<uint64_t>(code->instruction_start()),
293 code->instruction_size(), length, name);
297 // Low-level logging support.
298 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
300 class LowLevelLogger : public CodeEventLogger {
302 explicit LowLevelLogger(const char* file_name);
303 virtual ~LowLevelLogger();
305 virtual void CodeMoveEvent(Address from, Address to);
306 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
307 virtual void CodeDeleteEvent(Address from);
308 virtual void SnapshotPositionEvent(Address addr, int pos);
309 virtual void CodeMovingGCEvent();
312 virtual void LogRecordedBuffer(Code* code,
313 SharedFunctionInfo* shared,
317 // Low-level profiling event structures.
318 struct CodeCreateStruct {
319 static const char kTag = 'C';
322 Address code_address;
327 struct CodeMoveStruct {
328 static const char kTag = 'M';
330 Address from_address;
335 struct CodeDeleteStruct {
336 static const char kTag = 'D';
342 struct SnapshotPositionStruct {
343 static const char kTag = 'P';
350 static const char kCodeMovingGCTag = 'G';
353 // Extension added to V8 log file name to get the low-level log name.
354 static const char kLogExt[];
356 // File buffer size of the low-level log. We don't use the default to
357 // minimize the associated overhead.
358 static const int kLogBufferSize = 2 * MB;
361 void LogWriteBytes(const char* bytes, int size);
363 template <typename T>
364 void LogWriteStruct(const T& s) {
366 LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
367 LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
370 FILE* ll_output_handle_;
373 const char LowLevelLogger::kLogExt[] = ".ll";
375 LowLevelLogger::LowLevelLogger(const char* name)
376 : ll_output_handle_(NULL) {
377 // Open the low-level log file.
378 size_t len = strlen(name);
379 ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
380 MemCopy(ll_name.start(), name, len);
381 MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
383 base::OS::FOpen(ll_name.start(), base::OS::LogFileOpenMode);
384 setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize);
390 LowLevelLogger::~LowLevelLogger() {
391 fclose(ll_output_handle_);
392 ll_output_handle_ = NULL;
396 void LowLevelLogger::LogCodeInfo() {
397 #if V8_TARGET_ARCH_IA32
398 const char arch[] = "ia32";
399 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_64_BIT
400 const char arch[] = "x64";
401 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
402 const char arch[] = "x32";
403 #elif V8_TARGET_ARCH_ARM
404 const char arch[] = "arm";
405 #elif V8_TARGET_ARCH_PPC
406 const char arch[] = "ppc";
407 #elif V8_TARGET_ARCH_MIPS
408 const char arch[] = "mips";
409 #elif V8_TARGET_ARCH_X87
410 const char arch[] = "x87";
411 #elif V8_TARGET_ARCH_ARM64
412 const char arch[] = "arm64";
414 const char arch[] = "unknown";
416 LogWriteBytes(arch, sizeof(arch));
420 void LowLevelLogger::LogRecordedBuffer(Code* code,
424 CodeCreateStruct event;
425 event.name_size = length;
426 event.code_address = code->instruction_start();
427 DCHECK(event.code_address == code->address() + Code::kHeaderSize);
428 event.code_size = code->instruction_size();
429 LogWriteStruct(event);
430 LogWriteBytes(name, length);
432 reinterpret_cast<const char*>(code->instruction_start()),
433 code->instruction_size());
437 void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
438 CodeMoveStruct event;
439 event.from_address = from + Code::kHeaderSize;
440 event.to_address = to + Code::kHeaderSize;
441 LogWriteStruct(event);
445 void LowLevelLogger::CodeDeleteEvent(Address from) {
446 CodeDeleteStruct event;
447 event.address = from + Code::kHeaderSize;
448 LogWriteStruct(event);
452 void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
453 SnapshotPositionStruct event;
454 event.address = addr + Code::kHeaderSize;
455 event.position = pos;
456 LogWriteStruct(event);
460 void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
461 size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
462 DCHECK(static_cast<size_t>(size) == rv);
467 void LowLevelLogger::CodeMovingGCEvent() {
468 const char tag = kCodeMovingGCTag;
470 LogWriteBytes(&tag, sizeof(tag));
474 #define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
477 class JitLogger : public CodeEventLogger {
479 explicit JitLogger(JitCodeEventHandler code_event_handler);
481 virtual void CodeMoveEvent(Address from, Address to);
482 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
483 virtual void CodeDeleteEvent(Address from);
484 virtual void AddCodeLinePosInfoEvent(
485 void* jit_handler_data,
488 JitCodeEvent::PositionType position_type);
490 void* StartCodePosInfoEvent();
491 void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
494 virtual void LogRecordedBuffer(Code* code,
495 SharedFunctionInfo* shared,
499 JitCodeEventHandler code_event_handler_;
503 JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
504 : code_event_handler_(code_event_handler) {
508 void JitLogger::LogRecordedBuffer(Code* code,
509 SharedFunctionInfo* shared,
513 memset(&event, 0, sizeof(event));
514 event.type = JitCodeEvent::CODE_ADDED;
515 event.code_start = code->instruction_start();
516 event.code_len = code->instruction_size();
517 Handle<SharedFunctionInfo> shared_function_handle;
518 if (shared && shared->script()->IsScript()) {
519 shared_function_handle = Handle<SharedFunctionInfo>(shared);
521 event.script = ToApiHandle<v8::UnboundScript>(shared_function_handle);
522 event.name.str = name;
523 event.name.len = length;
524 code_event_handler_(&event);
528 void JitLogger::CodeMoveEvent(Address from, Address to) {
529 Code* from_code = Code::cast(HeapObject::FromAddress(from));
532 event.type = JitCodeEvent::CODE_MOVED;
533 event.code_start = from_code->instruction_start();
534 event.code_len = from_code->instruction_size();
536 // Calculate the header size.
537 const size_t header_size =
538 from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
540 // Calculate the new start address of the instructions.
541 event.new_code_start =
542 reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
544 code_event_handler_(&event);
548 void JitLogger::CodeDeleteEvent(Address from) {
549 Code* from_code = Code::cast(HeapObject::FromAddress(from));
552 event.type = JitCodeEvent::CODE_REMOVED;
553 event.code_start = from_code->instruction_start();
554 event.code_len = from_code->instruction_size();
556 code_event_handler_(&event);
559 void JitLogger::AddCodeLinePosInfoEvent(
560 void* jit_handler_data,
563 JitCodeEvent::PositionType position_type) {
565 memset(&event, 0, sizeof(event));
566 event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
567 event.user_data = jit_handler_data;
568 event.line_info.offset = pc_offset;
569 event.line_info.pos = position;
570 event.line_info.position_type = position_type;
572 code_event_handler_(&event);
576 void* JitLogger::StartCodePosInfoEvent() {
578 memset(&event, 0, sizeof(event));
579 event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
581 code_event_handler_(&event);
582 return event.user_data;
586 void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) {
588 memset(&event, 0, sizeof(event));
589 event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
590 event.code_start = code->instruction_start();
591 event.user_data = jit_handler_data;
593 code_event_handler_(&event);
597 // The Profiler samples pc and sp values for the main thread.
598 // Each sample is appended to a circular buffer.
599 // An independent thread removes data and writes it to the log.
600 // This design minimizes the time spent in the sampler.
602 class Profiler: public base::Thread {
604 explicit Profiler(Isolate* isolate);
608 // Inserts collected profiling data into buffer.
609 void Insert(TickSample* sample) {
613 if (Succ(head_) == static_cast<int>(base::NoBarrier_Load(&tail_))) {
616 buffer_[head_] = *sample;
618 buffer_semaphore_.Signal(); // Tell we have an element.
624 // Pause and Resume TickSample data collection.
625 void pause() { paused_ = true; }
626 void resume() { paused_ = false; }
629 // Waits for a signal and removes profiling data.
630 bool Remove(TickSample* sample) {
631 buffer_semaphore_.Wait(); // Wait for an element.
632 *sample = buffer_[base::NoBarrier_Load(&tail_)];
633 bool result = overflow_;
634 base::NoBarrier_Store(&tail_, static_cast<base::Atomic32>(
635 Succ(base::NoBarrier_Load(&tail_))));
640 // Returns the next index in the cyclic buffer.
641 int Succ(int index) { return (index + 1) % kBufferSize; }
644 // Cyclic buffer for communicating profiling samples
645 // between the signal handler and the worker thread.
646 static const int kBufferSize = 128;
647 TickSample buffer_[kBufferSize]; // Buffer storage.
648 int head_; // Index to the buffer head.
649 base::Atomic32 tail_; // Index to the buffer tail.
650 bool overflow_; // Tell whether a buffer overflow has occurred.
651 // Sempahore used for buffer synchronization.
652 base::Semaphore buffer_semaphore_;
654 // Tells whether profiler is engaged, that is, processing thread is stated.
657 // Tells whether worker thread should continue running.
658 base::Atomic32 running_;
660 // Tells whether we are currently recording tick samples.
666 // Ticker used to provide ticks to the profiler and the sliding state
669 class Ticker: public Sampler {
671 Ticker(Isolate* isolate, int interval):
672 Sampler(isolate, interval),
675 ~Ticker() { if (IsActive()) Stop(); }
677 virtual void Tick(TickSample* sample) {
678 if (profiler_) profiler_->Insert(sample);
681 void SetProfiler(Profiler* profiler) {
682 DCHECK(profiler_ == NULL);
683 profiler_ = profiler;
684 IncreaseProfilingDepth();
685 if (!IsActive()) Start();
688 void ClearProfiler() {
690 if (IsActive()) Stop();
691 DecreaseProfilingDepth();
700 // Profiler implementation.
702 Profiler::Profiler(Isolate* isolate)
703 : base::Thread(Options("v8:Profiler")),
707 buffer_semaphore_(0),
710 base::NoBarrier_Store(&tail_, 0);
711 base::NoBarrier_Store(&running_, 0);
715 void Profiler::Engage() {
716 if (engaged_) return;
719 std::vector<base::OS::SharedLibraryAddress> addresses =
720 base::OS::GetSharedLibraryAddresses();
721 for (size_t i = 0; i < addresses.size(); ++i) {
722 LOG(isolate_, SharedLibraryEvent(
723 addresses[i].library_path, addresses[i].start, addresses[i].end));
726 // Start thread processing the profiler buffer.
727 base::NoBarrier_Store(&running_, 1);
730 // Register to get ticks.
731 Logger* logger = isolate_->logger();
732 logger->ticker_->SetProfiler(this);
734 logger->ProfilerBeginEvent();
738 void Profiler::Disengage() {
739 if (!engaged_) return;
741 // Stop receiving ticks.
742 isolate_->logger()->ticker_->ClearProfiler();
744 // Terminate the worker thread by setting running_ to false,
745 // inserting a fake element in the queue and then wait for
746 // the thread to terminate.
747 base::NoBarrier_Store(&running_, 0);
749 // Reset 'paused_' flag, otherwise semaphore may not be signalled.
754 LOG(isolate_, UncheckedStringEvent("profiler", "end"));
758 void Profiler::Run() {
760 bool overflow = Remove(&sample);
761 while (base::NoBarrier_Load(&running_)) {
762 LOG(isolate_, TickEvent(&sample, overflow));
763 overflow = Remove(&sample);
769 // Logger class implementation.
772 Logger::Logger(Isolate* isolate)
779 perf_basic_logger_(NULL),
780 perf_jit_logger_(NULL),
784 is_initialized_(false) {
793 void Logger::addCodeEventListener(CodeEventListener* listener) {
794 DCHECK(!hasCodeEventListener(listener));
795 listeners_.Add(listener);
799 void Logger::removeCodeEventListener(CodeEventListener* listener) {
800 DCHECK(hasCodeEventListener(listener));
801 listeners_.RemoveElement(listener);
805 bool Logger::hasCodeEventListener(CodeEventListener* listener) {
806 return listeners_.Contains(listener);
810 void Logger::ProfilerBeginEvent() {
811 if (!log_->IsEnabled()) return;
812 Log::MessageBuilder msg(log_);
813 msg.Append("profiler,\"begin\",%d", kSamplingIntervalMs);
814 msg.WriteToLogFile();
818 void Logger::StringEvent(const char* name, const char* value) {
819 if (FLAG_log) UncheckedStringEvent(name, value);
823 void Logger::UncheckedStringEvent(const char* name, const char* value) {
824 if (!log_->IsEnabled()) return;
825 Log::MessageBuilder msg(log_);
826 msg.Append("%s,\"%s\"", name, value);
827 msg.WriteToLogFile();
831 void Logger::IntEvent(const char* name, int value) {
832 if (FLAG_log) UncheckedIntEvent(name, value);
836 void Logger::IntPtrTEvent(const char* name, intptr_t value) {
837 if (FLAG_log) UncheckedIntPtrTEvent(name, value);
841 void Logger::UncheckedIntEvent(const char* name, int value) {
842 if (!log_->IsEnabled()) return;
843 Log::MessageBuilder msg(log_);
844 msg.Append("%s,%d", name, value);
845 msg.WriteToLogFile();
849 void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
850 if (!log_->IsEnabled()) return;
851 Log::MessageBuilder msg(log_);
852 msg.Append("%s,%" V8_PTR_PREFIX "d", name, value);
853 msg.WriteToLogFile();
857 void Logger::HandleEvent(const char* name, Object** location) {
858 if (!log_->IsEnabled() || !FLAG_log_handles) return;
859 Log::MessageBuilder msg(log_);
860 msg.Append("%s,0x%" V8PRIxPTR, name, location);
861 msg.WriteToLogFile();
865 // ApiEvent is private so all the calls come from the Logger class. It is the
866 // caller's responsibility to ensure that log is enabled and that
867 // FLAG_log_api is true.
868 void Logger::ApiEvent(const char* format, ...) {
869 DCHECK(log_->IsEnabled() && FLAG_log_api);
870 Log::MessageBuilder msg(log_);
872 va_start(ap, format);
873 msg.AppendVA(format, ap);
875 msg.WriteToLogFile();
879 void Logger::ApiNamedSecurityCheck(Object* key) {
880 if (!log_->IsEnabled() || !FLAG_log_api) return;
881 if (key->IsString()) {
882 SmartArrayPointer<char> str =
883 String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
884 ApiEvent("api,check-security,\"%s\"", str.get());
885 } else if (key->IsSymbol()) {
886 Symbol* symbol = Symbol::cast(key);
887 if (symbol->name()->IsUndefined()) {
888 ApiEvent("api,check-security,symbol(hash %x)", Symbol::cast(key)->Hash());
890 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
891 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
892 ApiEvent("api,check-security,symbol(\"%s\" hash %x)", str.get(),
893 Symbol::cast(key)->Hash());
895 } else if (key->IsUndefined()) {
896 ApiEvent("api,check-security,undefined");
898 ApiEvent("api,check-security,['no-name']");
903 void Logger::SharedLibraryEvent(const std::string& library_path,
906 if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
907 Log::MessageBuilder msg(log_);
908 msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR,
909 library_path.c_str(), start, end);
910 msg.WriteToLogFile();
914 void Logger::CodeDeoptEvent(Code* code, int bailout_id, Address from,
915 int fp_to_sp_delta) {
916 PROFILER_LOG(CodeDeoptEvent(code, bailout_id, from, fp_to_sp_delta));
917 if (!log_->IsEnabled() || !FLAG_log_internal_timer_events) return;
918 Log::MessageBuilder msg(log_);
919 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
920 msg.Append("code-deopt,%ld,%d", since_epoch, code->CodeSize());
921 msg.WriteToLogFile();
925 void Logger::CurrentTimeEvent() {
926 if (!log_->IsEnabled()) return;
927 DCHECK(FLAG_log_internal_timer_events);
928 Log::MessageBuilder msg(log_);
929 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
930 msg.Append("current-time,%ld", since_epoch);
931 msg.WriteToLogFile();
935 void Logger::TimerEvent(Logger::StartEnd se, const char* name) {
936 if (!log_->IsEnabled()) return;
937 DCHECK(FLAG_log_internal_timer_events);
938 Log::MessageBuilder msg(log_);
939 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
940 const char* format = (se == START) ? "timer-event-start,\"%s\",%ld"
941 : "timer-event-end,\"%s\",%ld";
942 msg.Append(format, name, since_epoch);
943 msg.WriteToLogFile();
947 void Logger::EnterExternal(Isolate* isolate) {
948 LOG(isolate, TimerEvent(START, TimerEventExternal::name()));
949 DCHECK(isolate->current_vm_state() == JS);
950 isolate->set_current_vm_state(EXTERNAL);
954 void Logger::LeaveExternal(Isolate* isolate) {
955 LOG(isolate, TimerEvent(END, TimerEventExternal::name()));
956 DCHECK(isolate->current_vm_state() == EXTERNAL);
957 isolate->set_current_vm_state(JS);
961 template <class TimerEvent>
962 void TimerEventScope<TimerEvent>::LogTimerEvent(Logger::StartEnd se) {
963 Logger::CallEventLogger(isolate_, TimerEvent::name(), se,
964 TimerEvent::expose_to_api());
968 // Instantiate template methods.
969 #define V(TimerName, expose) \
970 template void TimerEventScope<TimerEvent##TimerName>::LogTimerEvent( \
971 Logger::StartEnd se);
976 void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
977 // Prints "/" + re.source + "/" +
978 // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
979 Log::MessageBuilder msg(log_);
981 Handle<Object> source = Object::GetProperty(
982 isolate_, regexp, "source").ToHandleChecked();
983 if (!source->IsString()) {
984 msg.Append("no source");
988 switch (regexp->TypeTag()) {
996 msg.AppendDetailed(*Handle<String>::cast(source), false);
1000 Handle<Object> global = Object::GetProperty(
1001 isolate_, regexp, "global").ToHandleChecked();
1002 if (global->IsTrue()) {
1006 Handle<Object> ignorecase = Object::GetProperty(
1007 isolate_, regexp, "ignoreCase").ToHandleChecked();
1008 if (ignorecase->IsTrue()) {
1012 Handle<Object> multiline = Object::GetProperty(
1013 isolate_, regexp, "multiline").ToHandleChecked();
1014 if (multiline->IsTrue()) {
1018 msg.WriteToLogFile();
1022 void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
1023 if (!log_->IsEnabled() || !FLAG_log_regexp) return;
1024 Log::MessageBuilder msg(log_);
1025 msg.Append("regexp-compile,");
1026 LogRegExpSource(regexp);
1027 msg.Append(in_cache ? ",hit" : ",miss");
1028 msg.WriteToLogFile();
1032 void Logger::ApiIndexedSecurityCheck(uint32_t index) {
1033 if (!log_->IsEnabled() || !FLAG_log_api) return;
1034 ApiEvent("api,check-security,%u", index);
1038 void Logger::ApiNamedPropertyAccess(const char* tag,
1041 DCHECK(name->IsName());
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 if (name->IsString()) {
1047 SmartArrayPointer<char> property_name =
1048 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1049 ApiEvent("api,%s,\"%s\",\"%s\"", tag, class_name.get(),
1050 property_name.get());
1052 Symbol* symbol = Symbol::cast(name);
1053 uint32_t hash = symbol->Hash();
1054 if (symbol->name()->IsUndefined()) {
1055 ApiEvent("api,%s,\"%s\",symbol(hash %x)", tag, class_name.get(), hash);
1057 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1058 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1059 ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)", tag, class_name.get(),
1065 void Logger::ApiIndexedPropertyAccess(const char* tag,
1068 if (!log_->IsEnabled() || !FLAG_log_api) return;
1069 String* class_name_obj = holder->class_name();
1070 SmartArrayPointer<char> class_name =
1071 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1072 ApiEvent("api,%s,\"%s\",%u", tag, class_name.get(), index);
1076 void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
1077 if (!log_->IsEnabled() || !FLAG_log_api) return;
1078 String* class_name_obj = object->class_name();
1079 SmartArrayPointer<char> class_name =
1080 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1081 ApiEvent("api,%s,\"%s\"", tag, class_name.get());
1085 void Logger::ApiEntryCall(const char* name) {
1086 if (!log_->IsEnabled() || !FLAG_log_api) return;
1087 ApiEvent("api,%s", name);
1091 void Logger::NewEvent(const char* name, void* object, size_t size) {
1092 if (!log_->IsEnabled() || !FLAG_log) return;
1093 Log::MessageBuilder msg(log_);
1094 msg.Append("new,%s,0x%" V8PRIxPTR ",%u", name, object,
1095 static_cast<unsigned int>(size));
1096 msg.WriteToLogFile();
1100 void Logger::DeleteEvent(const char* name, void* object) {
1101 if (!log_->IsEnabled() || !FLAG_log) return;
1102 Log::MessageBuilder msg(log_);
1103 msg.Append("delete,%s,0x%" V8PRIxPTR, name, object);
1104 msg.WriteToLogFile();
1108 void Logger::NewEventStatic(const char* name, void* object, size_t size) {
1109 Isolate::Current()->logger()->NewEvent(name, object, size);
1113 void Logger::DeleteEventStatic(const char* name, void* object) {
1114 Isolate::Current()->logger()->DeleteEvent(name, object);
1118 void Logger::CallbackEventInternal(const char* prefix, Name* name,
1119 Address entry_point) {
1120 if (!FLAG_log_code || !log_->IsEnabled()) return;
1121 Log::MessageBuilder msg(log_);
1122 msg.Append("%s,%s,-2,",
1123 kLogEventsNames[CODE_CREATION_EVENT],
1124 kLogEventsNames[CALLBACK_TAG]);
1125 msg.AppendAddress(entry_point);
1126 if (name->IsString()) {
1127 SmartArrayPointer<char> str =
1128 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1129 msg.Append(",1,\"%s%s\"", prefix, str.get());
1131 Symbol* symbol = Symbol::cast(name);
1132 if (symbol->name()->IsUndefined()) {
1133 msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
1135 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1136 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1137 msg.Append(",1,symbol(\"%s\" hash %x)", prefix, str.get(),
1141 msg.WriteToLogFile();
1145 void Logger::CallbackEvent(Name* name, Address entry_point) {
1146 PROFILER_LOG(CallbackEvent(name, entry_point));
1147 CallbackEventInternal("", name, entry_point);
1151 void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
1152 PROFILER_LOG(GetterCallbackEvent(name, entry_point));
1153 CallbackEventInternal("get ", name, entry_point);
1157 void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
1158 PROFILER_LOG(SetterCallbackEvent(name, entry_point));
1159 CallbackEventInternal("set ", name, entry_point);
1163 static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
1164 Logger::LogEventsAndTags tag,
1167 msg->Append("%s,%s,%d,",
1168 kLogEventsNames[Logger::CODE_CREATION_EVENT],
1169 kLogEventsNames[tag],
1171 msg->AppendAddress(code->address());
1172 msg->Append(",%d,", code->ExecutableSize());
1176 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1178 const char* comment) {
1179 PROFILER_LOG(CodeCreateEvent(tag, code, comment));
1181 if (!is_logging_code_events()) return;
1182 CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
1184 if (!FLAG_log_code || !log_->IsEnabled()) return;
1185 Log::MessageBuilder msg(log_);
1186 AppendCodeCreateHeader(&msg, tag, code);
1187 msg.AppendDoubleQuotedString(comment);
1188 msg.WriteToLogFile();
1192 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1195 PROFILER_LOG(CodeCreateEvent(tag, code, name));
1197 if (!is_logging_code_events()) return;
1198 CALL_LISTENERS(CodeCreateEvent(tag, code, name));
1200 if (!FLAG_log_code || !log_->IsEnabled()) return;
1201 Log::MessageBuilder msg(log_);
1202 AppendCodeCreateHeader(&msg, tag, code);
1203 if (name->IsString()) {
1205 msg.AppendDetailed(String::cast(name), false);
1208 msg.AppendSymbolName(Symbol::cast(name));
1210 msg.WriteToLogFile();
1214 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1216 SharedFunctionInfo* shared,
1217 CompilationInfo* info,
1219 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
1221 if (!is_logging_code_events()) return;
1222 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
1224 if (!FLAG_log_code || !log_->IsEnabled()) return;
1225 if (code == isolate_->builtins()->builtin(Builtins::kCompileLazy)) return;
1227 Log::MessageBuilder msg(log_);
1228 AppendCodeCreateHeader(&msg, tag, code);
1229 if (name->IsString()) {
1230 SmartArrayPointer<char> str =
1231 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1232 msg.Append("\"%s\"", str.get());
1234 msg.AppendSymbolName(Symbol::cast(name));
1237 msg.AppendAddress(shared->address());
1238 msg.Append(",%s", ComputeMarker(code));
1239 msg.WriteToLogFile();
1243 // Although, it is possible to extract source and line from
1244 // the SharedFunctionInfo object, we left it to caller
1245 // to leave logging functions free from heap allocations.
1246 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1248 SharedFunctionInfo* shared,
1249 CompilationInfo* info,
1250 Name* source, int line, int column) {
1251 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column));
1253 if (!is_logging_code_events()) return;
1254 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line,
1257 if (!FLAG_log_code || !log_->IsEnabled()) return;
1258 Log::MessageBuilder msg(log_);
1259 AppendCodeCreateHeader(&msg, tag, code);
1260 SmartArrayPointer<char> name =
1261 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1262 msg.Append("\"%s ", name.get());
1263 if (source->IsString()) {
1264 SmartArrayPointer<char> sourcestr =
1265 String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1266 msg.Append("%s", sourcestr.get());
1268 msg.AppendSymbolName(Symbol::cast(source));
1270 msg.Append(":%d:%d\",", line, column);
1271 msg.AppendAddress(shared->address());
1272 msg.Append(",%s", ComputeMarker(code));
1273 msg.WriteToLogFile();
1277 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1280 PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
1282 if (!is_logging_code_events()) return;
1283 CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
1285 if (!FLAG_log_code || !log_->IsEnabled()) return;
1286 Log::MessageBuilder msg(log_);
1287 AppendCodeCreateHeader(&msg, tag, code);
1288 msg.Append("\"args_count: %d\"", args_count);
1289 msg.WriteToLogFile();
1293 void Logger::CodeDisableOptEvent(Code* code,
1294 SharedFunctionInfo* shared) {
1295 PROFILER_LOG(CodeDisableOptEvent(code, shared));
1297 if (!is_logging_code_events()) return;
1298 CALL_LISTENERS(CodeDisableOptEvent(code, shared));
1300 if (!FLAG_log_code || !log_->IsEnabled()) return;
1301 Log::MessageBuilder msg(log_);
1302 msg.Append("%s,", kLogEventsNames[CODE_DISABLE_OPT_EVENT]);
1303 SmartArrayPointer<char> name =
1304 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1305 msg.Append("\"%s\",", name.get());
1306 msg.Append("\"%s\"", GetBailoutReason(shared->disable_optimization_reason()));
1307 msg.WriteToLogFile();
1311 void Logger::CodeMovingGCEvent() {
1312 PROFILER_LOG(CodeMovingGCEvent());
1314 if (!is_logging_code_events()) return;
1315 if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1316 CALL_LISTENERS(CodeMovingGCEvent());
1317 base::OS::SignalCodeMovingGC();
1321 void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
1322 PROFILER_LOG(RegExpCodeCreateEvent(code, source));
1324 if (!is_logging_code_events()) return;
1325 CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
1327 if (!FLAG_log_code || !log_->IsEnabled()) return;
1328 Log::MessageBuilder msg(log_);
1329 AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
1331 msg.AppendDetailed(source, false);
1333 msg.WriteToLogFile();
1337 void Logger::CodeMoveEvent(Address from, Address to) {
1338 PROFILER_LOG(CodeMoveEvent(from, to));
1340 if (!is_logging_code_events()) return;
1341 CALL_LISTENERS(CodeMoveEvent(from, to));
1342 MoveEventInternal(CODE_MOVE_EVENT, from, to);
1346 void Logger::CodeDeleteEvent(Address from) {
1347 PROFILER_LOG(CodeDeleteEvent(from));
1349 if (!is_logging_code_events()) return;
1350 CALL_LISTENERS(CodeDeleteEvent(from));
1352 if (!FLAG_log_code || !log_->IsEnabled()) return;
1353 Log::MessageBuilder msg(log_);
1354 msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
1355 msg.AppendAddress(from);
1356 msg.WriteToLogFile();
1360 void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
1363 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1366 JitCodeEvent::POSITION));
1370 void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
1373 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1376 JitCodeEvent::STATEMENT_POSITION));
1380 void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
1381 if (jit_logger_ != NULL) {
1382 pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
1387 void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
1388 void* jit_handler_data) {
1389 JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
1393 void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1394 if (code_name == NULL) return; // Not a code object.
1395 Log::MessageBuilder msg(log_);
1396 msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
1397 msg.AppendDoubleQuotedString(code_name);
1398 msg.WriteToLogFile();
1402 void Logger::SnapshotPositionEvent(Address addr, int pos) {
1403 if (!log_->IsEnabled()) return;
1404 LL_LOG(SnapshotPositionEvent(addr, pos));
1405 if (!FLAG_log_snapshot_positions) return;
1406 Log::MessageBuilder msg(log_);
1407 msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
1408 msg.AppendAddress(addr);
1409 msg.Append(",%d", pos);
1410 msg.WriteToLogFile();
1414 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
1415 PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
1417 if (!is_logging_code_events()) return;
1418 MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
1422 void Logger::MoveEventInternal(LogEventsAndTags event,
1425 if (!FLAG_log_code || !log_->IsEnabled()) return;
1426 Log::MessageBuilder msg(log_);
1427 msg.Append("%s,", kLogEventsNames[event]);
1428 msg.AppendAddress(from);
1430 msg.AppendAddress(to);
1431 msg.WriteToLogFile();
1435 void Logger::ResourceEvent(const char* name, const char* tag) {
1436 if (!log_->IsEnabled() || !FLAG_log) return;
1437 Log::MessageBuilder msg(log_);
1438 msg.Append("%s,%s,", name, tag);
1441 if (base::OS::GetUserTime(&sec, &usec) != -1) {
1442 msg.Append("%d,%d,", sec, usec);
1444 msg.Append("%.0f", base::OS::TimeCurrentMillis());
1445 msg.WriteToLogFile();
1449 void Logger::SuspectReadEvent(Name* name, Object* obj) {
1450 if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1451 Log::MessageBuilder msg(log_);
1452 String* class_name = obj->IsJSObject()
1453 ? JSObject::cast(obj)->class_name()
1454 : isolate_->heap()->empty_string();
1455 msg.Append("suspect-read,");
1456 msg.Append(class_name);
1458 if (name->IsString()) {
1460 msg.Append(String::cast(name));
1463 msg.AppendSymbolName(Symbol::cast(name));
1465 msg.WriteToLogFile();
1469 void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
1470 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1471 Log::MessageBuilder msg(log_);
1472 // Using non-relative system time in order to be able to synchronize with
1473 // external memory profiling events (e.g. DOM memory size).
1474 msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f", space, kind,
1475 base::OS::TimeCurrentMillis());
1476 msg.WriteToLogFile();
1480 void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
1481 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1482 Log::MessageBuilder msg(log_);
1483 msg.Append("heap-sample-end,\"%s\",\"%s\"", space, kind);
1484 msg.WriteToLogFile();
1488 void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
1489 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1490 Log::MessageBuilder msg(log_);
1491 msg.Append("heap-sample-item,%s,%d,%d", type, number, bytes);
1492 msg.WriteToLogFile();
1496 void Logger::DebugTag(const char* call_site_tag) {
1497 if (!log_->IsEnabled() || !FLAG_log) return;
1498 Log::MessageBuilder msg(log_);
1499 msg.Append("debug-tag,%s", call_site_tag);
1500 msg.WriteToLogFile();
1504 void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
1505 if (!log_->IsEnabled() || !FLAG_log) return;
1506 StringBuilder s(parameter.length() + 1);
1507 for (int i = 0; i < parameter.length(); ++i) {
1508 s.AddCharacter(static_cast<char>(parameter[i]));
1510 char* parameter_string = s.Finalize();
1511 Log::MessageBuilder msg(log_);
1512 msg.Append("debug-queue-event,%s,%15.3f,%s", event_type,
1513 base::OS::TimeCurrentMillis(), parameter_string);
1514 DeleteArray(parameter_string);
1515 msg.WriteToLogFile();
1519 void Logger::TickEvent(TickSample* sample, bool overflow) {
1520 if (!log_->IsEnabled() || !FLAG_prof_cpp) return;
1521 Log::MessageBuilder msg(log_);
1522 msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1523 msg.AppendAddress(sample->pc);
1524 msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
1525 if (sample->has_external_callback) {
1527 msg.AppendAddress(sample->external_callback);
1530 msg.AppendAddress(sample->tos);
1532 msg.Append(",%d", static_cast<int>(sample->state));
1534 msg.Append(",overflow");
1536 for (unsigned i = 0; i < sample->frames_count; ++i) {
1538 msg.AppendAddress(sample->stack[i]);
1540 msg.WriteToLogFile();
1544 void Logger::StopProfiler() {
1545 if (!log_->IsEnabled()) return;
1546 if (profiler_ != NULL) {
1548 is_logging_ = false;
1553 // This function can be called when Log's mutex is acquired,
1554 // either from main or Profiler's thread.
1555 void Logger::LogFailure() {
1560 class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
1562 EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
1563 Handle<Code>* code_objects,
1565 : sfis_(sfis), code_objects_(code_objects), count_(count) { }
1567 virtual void EnterContext(Context* context) {}
1568 virtual void LeaveContext(Context* context) {}
1570 virtual void VisitFunction(JSFunction* function) {
1571 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
1572 Object* maybe_script = sfi->script();
1573 if (maybe_script->IsScript()
1574 && !Script::cast(maybe_script)->HasValidSource()) return;
1575 if (sfis_ != NULL) {
1576 sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
1578 if (code_objects_ != NULL) {
1579 DCHECK(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1580 code_objects_[*count_] = Handle<Code>(function->code());
1582 *count_ = *count_ + 1;
1586 Handle<SharedFunctionInfo>* sfis_;
1587 Handle<Code>* code_objects_;
1592 static int EnumerateCompiledFunctions(Heap* heap,
1593 Handle<SharedFunctionInfo>* sfis,
1594 Handle<Code>* code_objects) {
1595 HeapIterator iterator(heap);
1596 DisallowHeapAllocation no_gc;
1597 int compiled_funcs_count = 0;
1599 // Iterate the heap to find shared function info objects and record
1600 // the unoptimized code for them.
1601 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1602 if (!obj->IsSharedFunctionInfo()) continue;
1603 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
1604 if (sfi->is_compiled()
1605 && (!sfi->script()->IsScript()
1606 || Script::cast(sfi->script())->HasValidSource())) {
1608 sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
1610 if (code_objects != NULL) {
1611 code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1613 ++compiled_funcs_count;
1617 // Iterate all optimized functions in all contexts.
1618 EnumerateOptimizedFunctionsVisitor visitor(sfis,
1620 &compiled_funcs_count);
1621 Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
1623 return compiled_funcs_count;
1627 void Logger::LogCodeObject(Object* object) {
1628 Code* code_object = Code::cast(object);
1629 LogEventsAndTags tag = Logger::STUB_TAG;
1630 const char* description = "Unknown code from the snapshot";
1631 switch (code_object->kind()) {
1632 case Code::FUNCTION:
1633 case Code::OPTIMIZED_FUNCTION:
1634 return; // We log this later using LogCompiledFunctions.
1635 case Code::BINARY_OP_IC:
1636 case Code::COMPARE_IC: // fall through
1637 case Code::COMPARE_NIL_IC: // fall through
1638 case Code::TO_BOOLEAN_IC: // fall through
1641 CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
1642 if (description == NULL)
1643 description = "A stub from the snapshot";
1644 tag = Logger::STUB_TAG;
1647 description = "Regular expression code";
1648 tag = Logger::REG_EXP_TAG;
1651 description = isolate_->builtins()->name(code_object->builtin_index());
1652 tag = Logger::BUILTIN_TAG;
1655 description = "An IC handler from the snapshot";
1656 tag = Logger::HANDLER_TAG;
1658 case Code::KEYED_LOAD_IC:
1659 description = "A keyed load IC from the snapshot";
1660 tag = Logger::KEYED_LOAD_IC_TAG;
1663 description = "A load IC from the snapshot";
1664 tag = Logger::LOAD_IC_TAG;
1667 description = "A call IC from the snapshot";
1668 tag = Logger::CALL_IC_TAG;
1670 case Code::STORE_IC:
1671 description = "A store IC from the snapshot";
1672 tag = Logger::STORE_IC_TAG;
1674 case Code::KEYED_STORE_IC:
1675 description = "A keyed store IC from the snapshot";
1676 tag = Logger::KEYED_STORE_IC_TAG;
1678 case Code::NUMBER_OF_KINDS:
1681 PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
1685 void Logger::LogCodeObjects() {
1686 Heap* heap = isolate_->heap();
1687 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1688 "Logger::LogCodeObjects");
1689 HeapIterator iterator(heap);
1690 DisallowHeapAllocation no_gc;
1691 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1692 if (obj->IsCode()) LogCodeObject(obj);
1697 void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
1698 Handle<Code> code) {
1699 Handle<String> func_name(shared->DebugName());
1700 if (shared->script()->IsScript()) {
1701 Handle<Script> script(Script::cast(shared->script()));
1702 int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
1704 Script::GetColumnNumber(script, shared->start_position()) + 1;
1705 if (script->name()->IsString()) {
1706 Handle<String> script_name(String::cast(script->name()));
1710 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1711 *code, *shared, NULL,
1712 *script_name, line_num, column_num));
1714 // Can't distinguish eval and script here, so always use Script.
1717 Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
1718 *code, *shared, NULL, *script_name));
1723 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1724 *code, *shared, NULL,
1725 isolate_->heap()->empty_string(), line_num, column_num));
1727 } else if (shared->IsApiFunction()) {
1729 FunctionTemplateInfo* fun_data = shared->get_api_func_data();
1730 Object* raw_call_data = fun_data->call_code();
1731 if (!raw_call_data->IsUndefined()) {
1732 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1733 Object* callback_obj = call_data->callback();
1734 Address entry_point = v8::ToCData<Address>(callback_obj);
1735 PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
1740 Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
1745 void Logger::LogCompiledFunctions() {
1746 Heap* heap = isolate_->heap();
1747 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1748 "Logger::LogCompiledFunctions");
1749 HandleScope scope(isolate_);
1750 const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL);
1751 ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
1752 ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1753 EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
1755 // During iteration, there can be heap allocation due to
1756 // GetScriptLineNumber call.
1757 for (int i = 0; i < compiled_funcs_count; ++i) {
1758 if (code_objects[i].is_identical_to(isolate_->builtins()->CompileLazy()))
1760 LogExistingFunction(sfis[i], code_objects[i]);
1765 void Logger::LogAccessorCallbacks() {
1766 Heap* heap = isolate_->heap();
1767 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1768 "Logger::LogAccessorCallbacks");
1769 HeapIterator iterator(heap);
1770 DisallowHeapAllocation no_gc;
1771 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1772 if (!obj->IsExecutableAccessorInfo()) continue;
1773 ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
1774 if (!ai->name()->IsName()) continue;
1775 Address getter_entry = v8::ToCData<Address>(ai->getter());
1776 Name* name = Name::cast(ai->name());
1777 if (getter_entry != 0) {
1778 PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
1780 Address setter_entry = v8::ToCData<Address>(ai->setter());
1781 if (setter_entry != 0) {
1782 PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
1788 static void AddIsolateIdIfNeeded(std::ostream& os, // NOLINT
1790 if (FLAG_logfile_per_isolate) os << "isolate-" << isolate << "-";
1794 static void PrepareLogFileName(std::ostream& os, // NOLINT
1795 Isolate* isolate, const char* file_name) {
1796 AddIsolateIdIfNeeded(os, isolate);
1797 for (const char* p = file_name; *p; p++) {
1802 // If there's a % at the end of the string we back up
1803 // one character so we can escape the loop properly.
1807 os << base::OS::GetCurrentProcessId();
1810 // %t expands to the current time in milliseconds.
1811 os << static_cast<int64_t>(base::OS::TimeCurrentMillis());
1814 // %% expands (contracts really) to %.
1818 // All other %'s expand to themselves.
1829 bool Logger::SetUp(Isolate* isolate) {
1830 // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
1831 if (is_initialized_) return true;
1832 is_initialized_ = true;
1834 // --ll-prof implies --log-code and --log-snapshot-positions.
1836 FLAG_log_snapshot_positions = true;
1839 std::ostringstream log_file_name;
1840 PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
1841 log_->Initialize(log_file_name.str().c_str());
1844 if (FLAG_perf_basic_prof) {
1845 perf_basic_logger_ = new PerfBasicLogger();
1846 addCodeEventListener(perf_basic_logger_);
1849 if (FLAG_perf_jit_prof) {
1850 perf_jit_logger_ = new PerfJitLogger();
1851 addCodeEventListener(perf_jit_logger_);
1855 ll_logger_ = new LowLevelLogger(log_file_name.str().c_str());
1856 addCodeEventListener(ll_logger_);
1859 ticker_ = new Ticker(isolate, kSamplingIntervalMs);
1861 if (Log::InitLogAtStart()) {
1865 if (FLAG_log_internal_timer_events || FLAG_prof_cpp) timer_.Start();
1867 if (FLAG_prof_cpp) {
1868 profiler_ = new Profiler(isolate);
1870 profiler_->Engage();
1877 void Logger::SetCodeEventHandler(uint32_t options,
1878 JitCodeEventHandler event_handler) {
1880 removeCodeEventListener(jit_logger_);
1885 if (event_handler) {
1886 jit_logger_ = new JitLogger(event_handler);
1887 addCodeEventListener(jit_logger_);
1888 if (options & kJitCodeEventEnumExisting) {
1889 HandleScope scope(isolate_);
1891 LogCompiledFunctions();
1897 Sampler* Logger::sampler() {
1902 FILE* Logger::TearDown() {
1903 if (!is_initialized_) return NULL;
1904 is_initialized_ = false;
1906 // Stop the profiler before closing the file.
1907 if (profiler_ != NULL) {
1908 profiler_->Disengage();
1916 if (perf_basic_logger_) {
1917 removeCodeEventListener(perf_basic_logger_);
1918 delete perf_basic_logger_;
1919 perf_basic_logger_ = NULL;
1922 if (perf_jit_logger_) {
1923 removeCodeEventListener(perf_jit_logger_);
1924 delete perf_jit_logger_;
1925 perf_jit_logger_ = NULL;
1929 removeCodeEventListener(ll_logger_);
1935 removeCodeEventListener(jit_logger_);
1940 return log_->Close();
1943 } } // namespace v8::internal