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_NE(perf_output_handle_, NULL);
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_MIPS
406 const char arch[] = "mips";
407 #elif V8_TARGET_ARCH_X87
408 const char arch[] = "x87";
409 #elif V8_TARGET_ARCH_ARM64
410 const char arch[] = "arm64";
412 const char arch[] = "unknown";
414 LogWriteBytes(arch, sizeof(arch));
418 void LowLevelLogger::LogRecordedBuffer(Code* code,
422 CodeCreateStruct event;
423 event.name_size = length;
424 event.code_address = code->instruction_start();
425 DCHECK(event.code_address == code->address() + Code::kHeaderSize);
426 event.code_size = code->instruction_size();
427 LogWriteStruct(event);
428 LogWriteBytes(name, length);
430 reinterpret_cast<const char*>(code->instruction_start()),
431 code->instruction_size());
435 void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
436 CodeMoveStruct event;
437 event.from_address = from + Code::kHeaderSize;
438 event.to_address = to + Code::kHeaderSize;
439 LogWriteStruct(event);
443 void LowLevelLogger::CodeDeleteEvent(Address from) {
444 CodeDeleteStruct event;
445 event.address = from + Code::kHeaderSize;
446 LogWriteStruct(event);
450 void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
451 SnapshotPositionStruct event;
452 event.address = addr + Code::kHeaderSize;
453 event.position = pos;
454 LogWriteStruct(event);
458 void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
459 size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
460 DCHECK(static_cast<size_t>(size) == rv);
465 void LowLevelLogger::CodeMovingGCEvent() {
466 const char tag = kCodeMovingGCTag;
468 LogWriteBytes(&tag, sizeof(tag));
472 #define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
475 class JitLogger : public CodeEventLogger {
477 explicit JitLogger(JitCodeEventHandler code_event_handler);
479 virtual void CodeMoveEvent(Address from, Address to);
480 virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { }
481 virtual void CodeDeleteEvent(Address from);
482 virtual void AddCodeLinePosInfoEvent(
483 void* jit_handler_data,
486 JitCodeEvent::PositionType position_type);
488 void* StartCodePosInfoEvent();
489 void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
492 virtual void LogRecordedBuffer(Code* code,
493 SharedFunctionInfo* shared,
497 JitCodeEventHandler code_event_handler_;
501 JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
502 : code_event_handler_(code_event_handler) {
506 void JitLogger::LogRecordedBuffer(Code* code,
507 SharedFunctionInfo* shared,
511 memset(&event, 0, sizeof(event));
512 event.type = JitCodeEvent::CODE_ADDED;
513 event.code_start = code->instruction_start();
514 event.code_len = code->instruction_size();
515 Handle<SharedFunctionInfo> shared_function_handle;
516 if (shared && shared->script()->IsScript()) {
517 shared_function_handle = Handle<SharedFunctionInfo>(shared);
519 event.script = ToApiHandle<v8::UnboundScript>(shared_function_handle);
520 event.name.str = name;
521 event.name.len = length;
522 code_event_handler_(&event);
526 void JitLogger::CodeMoveEvent(Address from, Address to) {
527 Code* from_code = Code::cast(HeapObject::FromAddress(from));
530 event.type = JitCodeEvent::CODE_MOVED;
531 event.code_start = from_code->instruction_start();
532 event.code_len = from_code->instruction_size();
534 // Calculate the header size.
535 const size_t header_size =
536 from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
538 // Calculate the new start address of the instructions.
539 event.new_code_start =
540 reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
542 code_event_handler_(&event);
546 void JitLogger::CodeDeleteEvent(Address from) {
547 Code* from_code = Code::cast(HeapObject::FromAddress(from));
550 event.type = JitCodeEvent::CODE_REMOVED;
551 event.code_start = from_code->instruction_start();
552 event.code_len = from_code->instruction_size();
554 code_event_handler_(&event);
557 void JitLogger::AddCodeLinePosInfoEvent(
558 void* jit_handler_data,
561 JitCodeEvent::PositionType position_type) {
563 memset(&event, 0, sizeof(event));
564 event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
565 event.user_data = jit_handler_data;
566 event.line_info.offset = pc_offset;
567 event.line_info.pos = position;
568 event.line_info.position_type = position_type;
570 code_event_handler_(&event);
574 void* JitLogger::StartCodePosInfoEvent() {
576 memset(&event, 0, sizeof(event));
577 event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
579 code_event_handler_(&event);
580 return event.user_data;
584 void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) {
586 memset(&event, 0, sizeof(event));
587 event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
588 event.code_start = code->instruction_start();
589 event.user_data = jit_handler_data;
591 code_event_handler_(&event);
595 // The Profiler samples pc and sp values for the main thread.
596 // Each sample is appended to a circular buffer.
597 // An independent thread removes data and writes it to the log.
598 // This design minimizes the time spent in the sampler.
600 class Profiler: public base::Thread {
602 explicit Profiler(Isolate* isolate);
606 // Inserts collected profiling data into buffer.
607 void Insert(TickSample* sample) {
611 if (Succ(head_) == static_cast<int>(base::NoBarrier_Load(&tail_))) {
614 buffer_[head_] = *sample;
616 buffer_semaphore_.Signal(); // Tell we have an element.
622 // Pause and Resume TickSample data collection.
623 void pause() { paused_ = true; }
624 void resume() { paused_ = false; }
627 // Waits for a signal and removes profiling data.
628 bool Remove(TickSample* sample) {
629 buffer_semaphore_.Wait(); // Wait for an element.
630 *sample = buffer_[base::NoBarrier_Load(&tail_)];
631 bool result = overflow_;
632 base::NoBarrier_Store(&tail_, static_cast<base::Atomic32>(
633 Succ(base::NoBarrier_Load(&tail_))));
638 // Returns the next index in the cyclic buffer.
639 int Succ(int index) { return (index + 1) % kBufferSize; }
642 // Cyclic buffer for communicating profiling samples
643 // between the signal handler and the worker thread.
644 static const int kBufferSize = 128;
645 TickSample buffer_[kBufferSize]; // Buffer storage.
646 int head_; // Index to the buffer head.
647 base::Atomic32 tail_; // Index to the buffer tail.
648 bool overflow_; // Tell whether a buffer overflow has occurred.
649 // Sempahore used for buffer synchronization.
650 base::Semaphore buffer_semaphore_;
652 // Tells whether profiler is engaged, that is, processing thread is stated.
655 // Tells whether worker thread should continue running.
656 base::Atomic32 running_;
658 // Tells whether we are currently recording tick samples.
664 // Ticker used to provide ticks to the profiler and the sliding state
667 class Ticker: public Sampler {
669 Ticker(Isolate* isolate, int interval):
670 Sampler(isolate, interval),
673 ~Ticker() { if (IsActive()) Stop(); }
675 virtual void Tick(TickSample* sample) {
676 if (profiler_) profiler_->Insert(sample);
679 void SetProfiler(Profiler* profiler) {
680 DCHECK(profiler_ == NULL);
681 profiler_ = profiler;
682 IncreaseProfilingDepth();
683 if (!IsActive()) Start();
686 void ClearProfiler() {
688 if (IsActive()) Stop();
689 DecreaseProfilingDepth();
698 // Profiler implementation.
700 Profiler::Profiler(Isolate* isolate)
701 : base::Thread(Options("v8:Profiler")),
705 buffer_semaphore_(0),
708 base::NoBarrier_Store(&tail_, 0);
709 base::NoBarrier_Store(&running_, 0);
713 void Profiler::Engage() {
714 if (engaged_) return;
717 std::vector<base::OS::SharedLibraryAddress> addresses =
718 base::OS::GetSharedLibraryAddresses();
719 for (size_t i = 0; i < addresses.size(); ++i) {
720 LOG(isolate_, SharedLibraryEvent(
721 addresses[i].library_path, addresses[i].start, addresses[i].end));
724 // Start thread processing the profiler buffer.
725 base::NoBarrier_Store(&running_, 1);
728 // Register to get ticks.
729 Logger* logger = isolate_->logger();
730 logger->ticker_->SetProfiler(this);
732 logger->ProfilerBeginEvent();
736 void Profiler::Disengage() {
737 if (!engaged_) return;
739 // Stop receiving ticks.
740 isolate_->logger()->ticker_->ClearProfiler();
742 // Terminate the worker thread by setting running_ to false,
743 // inserting a fake element in the queue and then wait for
744 // the thread to terminate.
745 base::NoBarrier_Store(&running_, 0);
747 // Reset 'paused_' flag, otherwise semaphore may not be signalled.
752 LOG(isolate_, UncheckedStringEvent("profiler", "end"));
756 void Profiler::Run() {
758 bool overflow = Remove(&sample);
759 while (base::NoBarrier_Load(&running_)) {
760 LOG(isolate_, TickEvent(&sample, overflow));
761 overflow = Remove(&sample);
767 // Logger class implementation.
770 Logger::Logger(Isolate* isolate)
777 perf_basic_logger_(NULL),
778 perf_jit_logger_(NULL),
782 is_initialized_(false) {
791 void Logger::addCodeEventListener(CodeEventListener* listener) {
792 DCHECK(!hasCodeEventListener(listener));
793 listeners_.Add(listener);
797 void Logger::removeCodeEventListener(CodeEventListener* listener) {
798 DCHECK(hasCodeEventListener(listener));
799 listeners_.RemoveElement(listener);
803 bool Logger::hasCodeEventListener(CodeEventListener* listener) {
804 return listeners_.Contains(listener);
808 void Logger::ProfilerBeginEvent() {
809 if (!log_->IsEnabled()) return;
810 Log::MessageBuilder msg(log_);
811 msg.Append("profiler,\"begin\",%d", kSamplingIntervalMs);
812 msg.WriteToLogFile();
816 void Logger::StringEvent(const char* name, const char* value) {
817 if (FLAG_log) UncheckedStringEvent(name, value);
821 void Logger::UncheckedStringEvent(const char* name, const char* value) {
822 if (!log_->IsEnabled()) return;
823 Log::MessageBuilder msg(log_);
824 msg.Append("%s,\"%s\"", name, value);
825 msg.WriteToLogFile();
829 void Logger::IntEvent(const char* name, int value) {
830 if (FLAG_log) UncheckedIntEvent(name, value);
834 void Logger::IntPtrTEvent(const char* name, intptr_t value) {
835 if (FLAG_log) UncheckedIntPtrTEvent(name, value);
839 void Logger::UncheckedIntEvent(const char* name, int value) {
840 if (!log_->IsEnabled()) return;
841 Log::MessageBuilder msg(log_);
842 msg.Append("%s,%d", name, value);
843 msg.WriteToLogFile();
847 void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
848 if (!log_->IsEnabled()) return;
849 Log::MessageBuilder msg(log_);
850 msg.Append("%s,%" V8_PTR_PREFIX "d", name, value);
851 msg.WriteToLogFile();
855 void Logger::HandleEvent(const char* name, Object** location) {
856 if (!log_->IsEnabled() || !FLAG_log_handles) return;
857 Log::MessageBuilder msg(log_);
858 msg.Append("%s,0x%" V8PRIxPTR, name, location);
859 msg.WriteToLogFile();
863 // ApiEvent is private so all the calls come from the Logger class. It is the
864 // caller's responsibility to ensure that log is enabled and that
865 // FLAG_log_api is true.
866 void Logger::ApiEvent(const char* format, ...) {
867 DCHECK(log_->IsEnabled() && FLAG_log_api);
868 Log::MessageBuilder msg(log_);
870 va_start(ap, format);
871 msg.AppendVA(format, ap);
873 msg.WriteToLogFile();
877 void Logger::ApiNamedSecurityCheck(Object* key) {
878 if (!log_->IsEnabled() || !FLAG_log_api) return;
879 if (key->IsString()) {
880 SmartArrayPointer<char> str =
881 String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
882 ApiEvent("api,check-security,\"%s\"", str.get());
883 } else if (key->IsSymbol()) {
884 Symbol* symbol = Symbol::cast(key);
885 if (symbol->name()->IsUndefined()) {
886 ApiEvent("api,check-security,symbol(hash %x)", Symbol::cast(key)->Hash());
888 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
889 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
890 ApiEvent("api,check-security,symbol(\"%s\" hash %x)", str.get(),
891 Symbol::cast(key)->Hash());
893 } else if (key->IsUndefined()) {
894 ApiEvent("api,check-security,undefined");
896 ApiEvent("api,check-security,['no-name']");
901 void Logger::SharedLibraryEvent(const std::string& library_path,
904 if (!log_->IsEnabled() || !FLAG_prof) return;
905 Log::MessageBuilder msg(log_);
906 msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR,
907 library_path.c_str(), start, end);
908 msg.WriteToLogFile();
912 void Logger::CodeDeoptEvent(Code* code) {
913 if (!log_->IsEnabled()) return;
914 DCHECK(FLAG_log_internal_timer_events);
915 Log::MessageBuilder msg(log_);
916 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
917 msg.Append("code-deopt,%ld,%d", since_epoch, code->CodeSize());
918 msg.WriteToLogFile();
922 void Logger::CurrentTimeEvent() {
923 if (!log_->IsEnabled()) return;
924 DCHECK(FLAG_log_internal_timer_events);
925 Log::MessageBuilder msg(log_);
926 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
927 msg.Append("current-time,%ld", since_epoch);
928 msg.WriteToLogFile();
932 void Logger::TimerEvent(Logger::StartEnd se, const char* name) {
933 if (!log_->IsEnabled()) return;
934 DCHECK(FLAG_log_internal_timer_events);
935 Log::MessageBuilder msg(log_);
936 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
937 const char* format = (se == START) ? "timer-event-start,\"%s\",%ld"
938 : "timer-event-end,\"%s\",%ld";
939 msg.Append(format, name, since_epoch);
940 msg.WriteToLogFile();
944 void Logger::EnterExternal(Isolate* isolate) {
945 LOG(isolate, TimerEvent(START, TimerEventExternal::name()));
946 DCHECK(isolate->current_vm_state() == JS);
947 isolate->set_current_vm_state(EXTERNAL);
951 void Logger::LeaveExternal(Isolate* isolate) {
952 LOG(isolate, TimerEvent(END, TimerEventExternal::name()));
953 DCHECK(isolate->current_vm_state() == EXTERNAL);
954 isolate->set_current_vm_state(JS);
958 template <class TimerEvent>
959 void TimerEventScope<TimerEvent>::LogTimerEvent(Logger::StartEnd se) {
960 Logger::CallEventLogger(isolate_, TimerEvent::name(), se,
961 TimerEvent::expose_to_api());
965 // Instantiate template methods.
966 #define V(TimerName, expose) \
967 template void TimerEventScope<TimerEvent##TimerName>::LogTimerEvent( \
968 Logger::StartEnd se);
973 void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
974 // Prints "/" + re.source + "/" +
975 // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
976 Log::MessageBuilder msg(log_);
978 Handle<Object> source = Object::GetProperty(
979 isolate_, regexp, "source").ToHandleChecked();
980 if (!source->IsString()) {
981 msg.Append("no source");
985 switch (regexp->TypeTag()) {
993 msg.AppendDetailed(*Handle<String>::cast(source), false);
997 Handle<Object> global = Object::GetProperty(
998 isolate_, regexp, "global").ToHandleChecked();
999 if (global->IsTrue()) {
1003 Handle<Object> ignorecase = Object::GetProperty(
1004 isolate_, regexp, "ignoreCase").ToHandleChecked();
1005 if (ignorecase->IsTrue()) {
1009 Handle<Object> multiline = Object::GetProperty(
1010 isolate_, regexp, "multiline").ToHandleChecked();
1011 if (multiline->IsTrue()) {
1015 msg.WriteToLogFile();
1019 void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
1020 if (!log_->IsEnabled() || !FLAG_log_regexp) return;
1021 Log::MessageBuilder msg(log_);
1022 msg.Append("regexp-compile,");
1023 LogRegExpSource(regexp);
1024 msg.Append(in_cache ? ",hit" : ",miss");
1025 msg.WriteToLogFile();
1029 void Logger::ApiIndexedSecurityCheck(uint32_t index) {
1030 if (!log_->IsEnabled() || !FLAG_log_api) return;
1031 ApiEvent("api,check-security,%u", index);
1035 void Logger::ApiNamedPropertyAccess(const char* tag,
1038 DCHECK(name->IsName());
1039 if (!log_->IsEnabled() || !FLAG_log_api) return;
1040 String* class_name_obj = holder->class_name();
1041 SmartArrayPointer<char> class_name =
1042 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1043 if (name->IsString()) {
1044 SmartArrayPointer<char> property_name =
1045 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1046 ApiEvent("api,%s,\"%s\",\"%s\"", tag, class_name.get(),
1047 property_name.get());
1049 Symbol* symbol = Symbol::cast(name);
1050 uint32_t hash = symbol->Hash();
1051 if (symbol->name()->IsUndefined()) {
1052 ApiEvent("api,%s,\"%s\",symbol(hash %x)", tag, class_name.get(), hash);
1054 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1055 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1056 ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)", tag, class_name.get(),
1062 void Logger::ApiIndexedPropertyAccess(const char* tag,
1065 if (!log_->IsEnabled() || !FLAG_log_api) return;
1066 String* class_name_obj = holder->class_name();
1067 SmartArrayPointer<char> class_name =
1068 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1069 ApiEvent("api,%s,\"%s\",%u", tag, class_name.get(), index);
1073 void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
1074 if (!log_->IsEnabled() || !FLAG_log_api) return;
1075 String* class_name_obj = object->class_name();
1076 SmartArrayPointer<char> class_name =
1077 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1078 ApiEvent("api,%s,\"%s\"", tag, class_name.get());
1082 void Logger::ApiEntryCall(const char* name) {
1083 if (!log_->IsEnabled() || !FLAG_log_api) return;
1084 ApiEvent("api,%s", name);
1088 void Logger::NewEvent(const char* name, void* object, size_t size) {
1089 if (!log_->IsEnabled() || !FLAG_log) return;
1090 Log::MessageBuilder msg(log_);
1091 msg.Append("new,%s,0x%" V8PRIxPTR ",%u", name, object,
1092 static_cast<unsigned int>(size));
1093 msg.WriteToLogFile();
1097 void Logger::DeleteEvent(const char* name, void* object) {
1098 if (!log_->IsEnabled() || !FLAG_log) return;
1099 Log::MessageBuilder msg(log_);
1100 msg.Append("delete,%s,0x%" V8PRIxPTR, name, object);
1101 msg.WriteToLogFile();
1105 void Logger::NewEventStatic(const char* name, void* object, size_t size) {
1106 Isolate::Current()->logger()->NewEvent(name, object, size);
1110 void Logger::DeleteEventStatic(const char* name, void* object) {
1111 Isolate::Current()->logger()->DeleteEvent(name, object);
1115 void Logger::CallbackEventInternal(const char* prefix, Name* name,
1116 Address entry_point) {
1117 if (!FLAG_log_code || !log_->IsEnabled()) return;
1118 Log::MessageBuilder msg(log_);
1119 msg.Append("%s,%s,-2,",
1120 kLogEventsNames[CODE_CREATION_EVENT],
1121 kLogEventsNames[CALLBACK_TAG]);
1122 msg.AppendAddress(entry_point);
1123 if (name->IsString()) {
1124 SmartArrayPointer<char> str =
1125 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1126 msg.Append(",1,\"%s%s\"", prefix, str.get());
1128 Symbol* symbol = Symbol::cast(name);
1129 if (symbol->name()->IsUndefined()) {
1130 msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
1132 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1133 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1134 msg.Append(",1,symbol(\"%s\" hash %x)", prefix, str.get(),
1138 msg.WriteToLogFile();
1142 void Logger::CallbackEvent(Name* name, Address entry_point) {
1143 PROFILER_LOG(CallbackEvent(name, entry_point));
1144 CallbackEventInternal("", name, entry_point);
1148 void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
1149 PROFILER_LOG(GetterCallbackEvent(name, entry_point));
1150 CallbackEventInternal("get ", name, entry_point);
1154 void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
1155 PROFILER_LOG(SetterCallbackEvent(name, entry_point));
1156 CallbackEventInternal("set ", name, entry_point);
1160 static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
1161 Logger::LogEventsAndTags tag,
1164 msg->Append("%s,%s,%d,",
1165 kLogEventsNames[Logger::CODE_CREATION_EVENT],
1166 kLogEventsNames[tag],
1168 msg->AppendAddress(code->address());
1169 msg->Append(",%d,", code->ExecutableSize());
1173 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1175 const char* comment) {
1176 PROFILER_LOG(CodeCreateEvent(tag, code, comment));
1178 if (!is_logging_code_events()) return;
1179 CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
1181 if (!FLAG_log_code || !log_->IsEnabled()) return;
1182 Log::MessageBuilder msg(log_);
1183 AppendCodeCreateHeader(&msg, tag, code);
1184 msg.AppendDoubleQuotedString(comment);
1185 msg.WriteToLogFile();
1189 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1192 PROFILER_LOG(CodeCreateEvent(tag, code, name));
1194 if (!is_logging_code_events()) return;
1195 CALL_LISTENERS(CodeCreateEvent(tag, code, name));
1197 if (!FLAG_log_code || !log_->IsEnabled()) return;
1198 Log::MessageBuilder msg(log_);
1199 AppendCodeCreateHeader(&msg, tag, code);
1200 if (name->IsString()) {
1202 msg.AppendDetailed(String::cast(name), false);
1205 msg.AppendSymbolName(Symbol::cast(name));
1207 msg.WriteToLogFile();
1211 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1213 SharedFunctionInfo* shared,
1214 CompilationInfo* info,
1216 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
1218 if (!is_logging_code_events()) return;
1219 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
1221 if (!FLAG_log_code || !log_->IsEnabled()) return;
1222 if (code == isolate_->builtins()->builtin(Builtins::kCompileLazy)) return;
1224 Log::MessageBuilder msg(log_);
1225 AppendCodeCreateHeader(&msg, tag, code);
1226 if (name->IsString()) {
1227 SmartArrayPointer<char> str =
1228 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1229 msg.Append("\"%s\"", str.get());
1231 msg.AppendSymbolName(Symbol::cast(name));
1234 msg.AppendAddress(shared->address());
1235 msg.Append(",%s", ComputeMarker(code));
1236 msg.WriteToLogFile();
1240 // Although, it is possible to extract source and line from
1241 // the SharedFunctionInfo object, we left it to caller
1242 // to leave logging functions free from heap allocations.
1243 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1245 SharedFunctionInfo* shared,
1246 CompilationInfo* info,
1247 Name* source, int line, int column) {
1248 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column));
1250 if (!is_logging_code_events()) return;
1251 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line,
1254 if (!FLAG_log_code || !log_->IsEnabled()) return;
1255 Log::MessageBuilder msg(log_);
1256 AppendCodeCreateHeader(&msg, tag, code);
1257 SmartArrayPointer<char> name =
1258 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1259 msg.Append("\"%s ", name.get());
1260 if (source->IsString()) {
1261 SmartArrayPointer<char> sourcestr =
1262 String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1263 msg.Append("%s", sourcestr.get());
1265 msg.AppendSymbolName(Symbol::cast(source));
1267 msg.Append(":%d:%d\",", line, column);
1268 msg.AppendAddress(shared->address());
1269 msg.Append(",%s", ComputeMarker(code));
1270 msg.WriteToLogFile();
1274 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1277 PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
1279 if (!is_logging_code_events()) return;
1280 CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
1282 if (!FLAG_log_code || !log_->IsEnabled()) return;
1283 Log::MessageBuilder msg(log_);
1284 AppendCodeCreateHeader(&msg, tag, code);
1285 msg.Append("\"args_count: %d\"", args_count);
1286 msg.WriteToLogFile();
1290 void Logger::CodeDisableOptEvent(Code* code,
1291 SharedFunctionInfo* shared) {
1292 PROFILER_LOG(CodeDisableOptEvent(code, shared));
1294 if (!is_logging_code_events()) return;
1295 CALL_LISTENERS(CodeDisableOptEvent(code, shared));
1297 if (!FLAG_log_code || !log_->IsEnabled()) return;
1298 Log::MessageBuilder msg(log_);
1299 msg.Append("%s,", kLogEventsNames[CODE_DISABLE_OPT_EVENT]);
1300 SmartArrayPointer<char> name =
1301 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1302 msg.Append("\"%s\",", name.get());
1303 msg.Append("\"%s\"", GetBailoutReason(shared->DisableOptimizationReason()));
1304 msg.WriteToLogFile();
1308 void Logger::CodeMovingGCEvent() {
1309 PROFILER_LOG(CodeMovingGCEvent());
1311 if (!is_logging_code_events()) return;
1312 if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1313 CALL_LISTENERS(CodeMovingGCEvent());
1314 base::OS::SignalCodeMovingGC();
1318 void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
1319 PROFILER_LOG(RegExpCodeCreateEvent(code, source));
1321 if (!is_logging_code_events()) return;
1322 CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
1324 if (!FLAG_log_code || !log_->IsEnabled()) return;
1325 Log::MessageBuilder msg(log_);
1326 AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
1328 msg.AppendDetailed(source, false);
1330 msg.WriteToLogFile();
1334 void Logger::CodeMoveEvent(Address from, Address to) {
1335 PROFILER_LOG(CodeMoveEvent(from, to));
1337 if (!is_logging_code_events()) return;
1338 CALL_LISTENERS(CodeMoveEvent(from, to));
1339 MoveEventInternal(CODE_MOVE_EVENT, from, to);
1343 void Logger::CodeDeleteEvent(Address from) {
1344 PROFILER_LOG(CodeDeleteEvent(from));
1346 if (!is_logging_code_events()) return;
1347 CALL_LISTENERS(CodeDeleteEvent(from));
1349 if (!FLAG_log_code || !log_->IsEnabled()) return;
1350 Log::MessageBuilder msg(log_);
1351 msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
1352 msg.AppendAddress(from);
1353 msg.WriteToLogFile();
1357 void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
1360 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1363 JitCodeEvent::POSITION));
1367 void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
1370 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1373 JitCodeEvent::STATEMENT_POSITION));
1377 void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
1378 if (jit_logger_ != NULL) {
1379 pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
1384 void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
1385 void* jit_handler_data) {
1386 JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
1390 void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1391 if (code_name == NULL) return; // Not a code object.
1392 Log::MessageBuilder msg(log_);
1393 msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
1394 msg.AppendDoubleQuotedString(code_name);
1395 msg.WriteToLogFile();
1399 void Logger::SnapshotPositionEvent(Address addr, int pos) {
1400 if (!log_->IsEnabled()) return;
1401 LL_LOG(SnapshotPositionEvent(addr, pos));
1402 if (!FLAG_log_snapshot_positions) return;
1403 Log::MessageBuilder msg(log_);
1404 msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
1405 msg.AppendAddress(addr);
1406 msg.Append(",%d", pos);
1407 msg.WriteToLogFile();
1411 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
1412 PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
1414 if (!is_logging_code_events()) return;
1415 MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
1419 void Logger::MoveEventInternal(LogEventsAndTags event,
1422 if (!FLAG_log_code || !log_->IsEnabled()) return;
1423 Log::MessageBuilder msg(log_);
1424 msg.Append("%s,", kLogEventsNames[event]);
1425 msg.AppendAddress(from);
1427 msg.AppendAddress(to);
1428 msg.WriteToLogFile();
1432 void Logger::ResourceEvent(const char* name, const char* tag) {
1433 if (!log_->IsEnabled() || !FLAG_log) return;
1434 Log::MessageBuilder msg(log_);
1435 msg.Append("%s,%s,", name, tag);
1438 if (base::OS::GetUserTime(&sec, &usec) != -1) {
1439 msg.Append("%d,%d,", sec, usec);
1441 msg.Append("%.0f", base::OS::TimeCurrentMillis());
1442 msg.WriteToLogFile();
1446 void Logger::SuspectReadEvent(Name* name, Object* obj) {
1447 if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1448 Log::MessageBuilder msg(log_);
1449 String* class_name = obj->IsJSObject()
1450 ? JSObject::cast(obj)->class_name()
1451 : isolate_->heap()->empty_string();
1452 msg.Append("suspect-read,");
1453 msg.Append(class_name);
1455 if (name->IsString()) {
1457 msg.Append(String::cast(name));
1460 msg.AppendSymbolName(Symbol::cast(name));
1462 msg.WriteToLogFile();
1466 void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
1467 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1468 Log::MessageBuilder msg(log_);
1469 // Using non-relative system time in order to be able to synchronize with
1470 // external memory profiling events (e.g. DOM memory size).
1471 msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f", space, kind,
1472 base::OS::TimeCurrentMillis());
1473 msg.WriteToLogFile();
1477 void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
1478 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1479 Log::MessageBuilder msg(log_);
1480 msg.Append("heap-sample-end,\"%s\",\"%s\"", space, kind);
1481 msg.WriteToLogFile();
1485 void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
1486 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1487 Log::MessageBuilder msg(log_);
1488 msg.Append("heap-sample-item,%s,%d,%d", type, number, bytes);
1489 msg.WriteToLogFile();
1493 void Logger::DebugTag(const char* call_site_tag) {
1494 if (!log_->IsEnabled() || !FLAG_log) return;
1495 Log::MessageBuilder msg(log_);
1496 msg.Append("debug-tag,%s", call_site_tag);
1497 msg.WriteToLogFile();
1501 void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
1502 if (!log_->IsEnabled() || !FLAG_log) return;
1503 StringBuilder s(parameter.length() + 1);
1504 for (int i = 0; i < parameter.length(); ++i) {
1505 s.AddCharacter(static_cast<char>(parameter[i]));
1507 char* parameter_string = s.Finalize();
1508 Log::MessageBuilder msg(log_);
1509 msg.Append("debug-queue-event,%s,%15.3f,%s", event_type,
1510 base::OS::TimeCurrentMillis(), parameter_string);
1511 DeleteArray(parameter_string);
1512 msg.WriteToLogFile();
1516 void Logger::TickEvent(TickSample* sample, bool overflow) {
1517 if (!log_->IsEnabled() || !FLAG_prof) return;
1518 Log::MessageBuilder msg(log_);
1519 msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1520 msg.AppendAddress(sample->pc);
1521 msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
1522 if (sample->has_external_callback) {
1524 msg.AppendAddress(sample->external_callback);
1527 msg.AppendAddress(sample->tos);
1529 msg.Append(",%d", static_cast<int>(sample->state));
1531 msg.Append(",overflow");
1533 for (unsigned i = 0; i < sample->frames_count; ++i) {
1535 msg.AppendAddress(sample->stack[i]);
1537 msg.WriteToLogFile();
1541 void Logger::StopProfiler() {
1542 if (!log_->IsEnabled()) return;
1543 if (profiler_ != NULL) {
1545 is_logging_ = false;
1550 // This function can be called when Log's mutex is acquired,
1551 // either from main or Profiler's thread.
1552 void Logger::LogFailure() {
1557 class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
1559 EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
1560 Handle<Code>* code_objects,
1562 : sfis_(sfis), code_objects_(code_objects), count_(count) { }
1564 virtual void EnterContext(Context* context) {}
1565 virtual void LeaveContext(Context* context) {}
1567 virtual void VisitFunction(JSFunction* function) {
1568 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
1569 Object* maybe_script = sfi->script();
1570 if (maybe_script->IsScript()
1571 && !Script::cast(maybe_script)->HasValidSource()) return;
1572 if (sfis_ != NULL) {
1573 sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
1575 if (code_objects_ != NULL) {
1576 DCHECK(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1577 code_objects_[*count_] = Handle<Code>(function->code());
1579 *count_ = *count_ + 1;
1583 Handle<SharedFunctionInfo>* sfis_;
1584 Handle<Code>* code_objects_;
1589 static int EnumerateCompiledFunctions(Heap* heap,
1590 Handle<SharedFunctionInfo>* sfis,
1591 Handle<Code>* code_objects) {
1592 HeapIterator iterator(heap);
1593 DisallowHeapAllocation no_gc;
1594 int compiled_funcs_count = 0;
1596 // Iterate the heap to find shared function info objects and record
1597 // the unoptimized code for them.
1598 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1599 if (!obj->IsSharedFunctionInfo()) continue;
1600 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
1601 if (sfi->is_compiled()
1602 && (!sfi->script()->IsScript()
1603 || Script::cast(sfi->script())->HasValidSource())) {
1605 sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
1607 if (code_objects != NULL) {
1608 code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1610 ++compiled_funcs_count;
1614 // Iterate all optimized functions in all contexts.
1615 EnumerateOptimizedFunctionsVisitor visitor(sfis,
1617 &compiled_funcs_count);
1618 Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
1620 return compiled_funcs_count;
1624 void Logger::LogCodeObject(Object* object) {
1625 Code* code_object = Code::cast(object);
1626 LogEventsAndTags tag = Logger::STUB_TAG;
1627 const char* description = "Unknown code from the snapshot";
1628 switch (code_object->kind()) {
1629 case Code::FUNCTION:
1630 case Code::OPTIMIZED_FUNCTION:
1631 return; // We log this later using LogCompiledFunctions.
1632 case Code::BINARY_OP_IC:
1633 case Code::COMPARE_IC: // fall through
1634 case Code::COMPARE_NIL_IC: // fall through
1635 case Code::TO_BOOLEAN_IC: // fall through
1638 CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
1639 if (description == NULL)
1640 description = "A stub from the snapshot";
1641 tag = Logger::STUB_TAG;
1644 description = "Regular expression code";
1645 tag = Logger::REG_EXP_TAG;
1648 description = "A builtin from the snapshot";
1649 tag = Logger::BUILTIN_TAG;
1652 description = "An IC handler from the snapshot";
1653 tag = Logger::HANDLER_TAG;
1655 case Code::KEYED_LOAD_IC:
1656 description = "A keyed load IC from the snapshot";
1657 tag = Logger::KEYED_LOAD_IC_TAG;
1660 description = "A load IC from the snapshot";
1661 tag = Logger::LOAD_IC_TAG;
1664 description = "A call IC from the snapshot";
1665 tag = Logger::CALL_IC_TAG;
1667 case Code::STORE_IC:
1668 description = "A store IC from the snapshot";
1669 tag = Logger::STORE_IC_TAG;
1671 case Code::KEYED_STORE_IC:
1672 description = "A keyed store IC from the snapshot";
1673 tag = Logger::KEYED_STORE_IC_TAG;
1675 case Code::NUMBER_OF_KINDS:
1678 PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
1682 void Logger::LogCodeObjects() {
1683 Heap* heap = isolate_->heap();
1684 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1685 "Logger::LogCodeObjects");
1686 HeapIterator iterator(heap);
1687 DisallowHeapAllocation no_gc;
1688 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1689 if (obj->IsCode()) LogCodeObject(obj);
1694 void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
1695 Handle<Code> code) {
1696 Handle<String> func_name(shared->DebugName());
1697 if (shared->script()->IsScript()) {
1698 Handle<Script> script(Script::cast(shared->script()));
1699 int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
1701 Script::GetColumnNumber(script, shared->start_position()) + 1;
1702 if (script->name()->IsString()) {
1703 Handle<String> script_name(String::cast(script->name()));
1707 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1708 *code, *shared, NULL,
1709 *script_name, line_num, column_num));
1711 // Can't distinguish eval and script here, so always use Script.
1714 Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
1715 *code, *shared, NULL, *script_name));
1720 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1721 *code, *shared, NULL,
1722 isolate_->heap()->empty_string(), line_num, column_num));
1724 } else if (shared->IsApiFunction()) {
1726 FunctionTemplateInfo* fun_data = shared->get_api_func_data();
1727 Object* raw_call_data = fun_data->call_code();
1728 if (!raw_call_data->IsUndefined()) {
1729 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1730 Object* callback_obj = call_data->callback();
1731 Address entry_point = v8::ToCData<Address>(callback_obj);
1732 PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
1737 Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
1742 void Logger::LogCompiledFunctions() {
1743 Heap* heap = isolate_->heap();
1744 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1745 "Logger::LogCompiledFunctions");
1746 HandleScope scope(isolate_);
1747 const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL);
1748 ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
1749 ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1750 EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
1752 // During iteration, there can be heap allocation due to
1753 // GetScriptLineNumber call.
1754 for (int i = 0; i < compiled_funcs_count; ++i) {
1755 if (code_objects[i].is_identical_to(isolate_->builtins()->CompileLazy()))
1757 LogExistingFunction(sfis[i], code_objects[i]);
1762 void Logger::LogAccessorCallbacks() {
1763 Heap* heap = isolate_->heap();
1764 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1765 "Logger::LogAccessorCallbacks");
1766 HeapIterator iterator(heap);
1767 DisallowHeapAllocation no_gc;
1768 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1769 if (!obj->IsExecutableAccessorInfo()) continue;
1770 ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
1771 if (!ai->name()->IsName()) continue;
1772 Address getter_entry = v8::ToCData<Address>(ai->getter());
1773 Name* name = Name::cast(ai->name());
1774 if (getter_entry != 0) {
1775 PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
1777 Address setter_entry = v8::ToCData<Address>(ai->setter());
1778 if (setter_entry != 0) {
1779 PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
1785 static void AddIsolateIdIfNeeded(std::ostream& os, // NOLINT
1787 if (FLAG_logfile_per_isolate) os << "isolate-" << isolate << "-";
1791 static void PrepareLogFileName(std::ostream& os, // NOLINT
1792 Isolate* isolate, const char* file_name) {
1793 AddIsolateIdIfNeeded(os, isolate);
1794 for (const char* p = file_name; *p; p++) {
1799 // If there's a % at the end of the string we back up
1800 // one character so we can escape the loop properly.
1804 os << base::OS::GetCurrentProcessId();
1807 // %t expands to the current time in milliseconds.
1808 os << static_cast<int64_t>(base::OS::TimeCurrentMillis());
1811 // %% expands (contracts really) to %.
1815 // All other %'s expand to themselves.
1826 bool Logger::SetUp(Isolate* isolate) {
1827 // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
1828 if (is_initialized_) return true;
1829 is_initialized_ = true;
1831 // --ll-prof implies --log-code and --log-snapshot-positions.
1833 FLAG_log_snapshot_positions = true;
1836 std::ostringstream log_file_name;
1837 PrepareLogFileName(log_file_name, isolate, FLAG_logfile);
1838 log_->Initialize(log_file_name.str().c_str());
1841 if (FLAG_perf_basic_prof) {
1842 perf_basic_logger_ = new PerfBasicLogger();
1843 addCodeEventListener(perf_basic_logger_);
1846 if (FLAG_perf_jit_prof) {
1847 perf_jit_logger_ = new PerfJitLogger();
1848 addCodeEventListener(perf_jit_logger_);
1852 ll_logger_ = new LowLevelLogger(log_file_name.str().c_str());
1853 addCodeEventListener(ll_logger_);
1856 ticker_ = new Ticker(isolate, kSamplingIntervalMs);
1858 if (Log::InitLogAtStart()) {
1862 if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
1865 profiler_ = new Profiler(isolate);
1867 profiler_->Engage();
1874 void Logger::SetCodeEventHandler(uint32_t options,
1875 JitCodeEventHandler event_handler) {
1877 removeCodeEventListener(jit_logger_);
1882 if (event_handler) {
1883 jit_logger_ = new JitLogger(event_handler);
1884 addCodeEventListener(jit_logger_);
1885 if (options & kJitCodeEventEnumExisting) {
1886 HandleScope scope(isolate_);
1888 LogCompiledFunctions();
1894 Sampler* Logger::sampler() {
1899 FILE* Logger::TearDown() {
1900 if (!is_initialized_) return NULL;
1901 is_initialized_ = false;
1903 // Stop the profiler before closing the file.
1904 if (profiler_ != NULL) {
1905 profiler_->Disengage();
1913 if (perf_basic_logger_) {
1914 removeCodeEventListener(perf_basic_logger_);
1915 delete perf_basic_logger_;
1916 perf_basic_logger_ = NULL;
1919 if (perf_jit_logger_) {
1920 removeCodeEventListener(perf_jit_logger_);
1921 delete perf_jit_logger_;
1922 perf_jit_logger_ = NULL;
1926 removeCodeEventListener(ll_logger_);
1932 removeCodeEventListener(jit_logger_);
1937 return log_->Close();
1940 } } // namespace v8::internal