1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "bootstrapper.h"
33 #include "code-stubs.h"
34 #include "cpu-profiler.h"
35 #include "deoptimizer.h"
36 #include "global-handles.h"
38 #include "log-utils.h"
39 #include "macro-assembler.h"
41 #include "runtime-profiler.h"
42 #include "serialize.h"
43 #include "string-stream.h"
44 #include "vm-state-inl.h"
47 #include "third_party/xdk/xdk-v8.h"
53 #define DECLARE_EVENT(ignore1, name) name,
54 static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
55 LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
60 #define CALL_LISTENERS(Call) \
61 for (int i = 0; i < listeners_.length(); ++i) { \
62 listeners_[i]->Call; \
65 #define PROFILER_LOG(Call) \
67 CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
68 if (cpu_profiler->is_profiling()) { \
73 // ComputeMarker must only be used when SharedFunctionInfo is known.
74 static const char* ComputeMarker(Code* code) {
75 switch (code->kind()) {
76 case Code::FUNCTION: return code->optimizable() ? "~" : "";
77 case Code::OPTIMIZED_FUNCTION: return "*";
83 class CodeEventLogger::NameBuffer {
85 NameBuffer() { Reset(); }
91 void Init(Logger::LogEventsAndTags tag) {
93 AppendBytes(kLogEventsNames[tag]);
97 void AppendName(Name* name) {
98 if (name->IsString()) {
99 AppendString(String::cast(name));
101 Symbol* symbol = Symbol::cast(name);
102 AppendBytes("symbol(");
103 if (!symbol->name()->IsUndefined()) {
105 AppendString(String::cast(symbol->name()));
108 AppendBytes("hash ");
109 AppendHex(symbol->Hash());
114 void AppendString(String* str) {
115 if (str == NULL) return;
116 int uc16_length = Min(str->length(), kUtf16BufferSize);
117 String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
118 int previous = unibrow::Utf16::kNoPreviousCharacter;
119 for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
120 uc16 c = utf16_buffer[i];
121 if (c <= unibrow::Utf8::kMaxOneByteChar) {
122 utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
124 int char_length = unibrow::Utf8::Length(c, previous);
125 if (utf8_pos_ + char_length > kUtf8BufferSize) break;
126 unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
127 utf8_pos_ += char_length;
133 void AppendBytes(const char* bytes, int size) {
134 size = Min(size, kUtf8BufferSize - utf8_pos_);
135 OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
139 void AppendBytes(const char* bytes) {
140 AppendBytes(bytes, StrLength(bytes));
143 void AppendByte(char c) {
144 if (utf8_pos_ >= kUtf8BufferSize) return;
145 utf8_buffer_[utf8_pos_++] = c;
148 void AppendInt(int n) {
149 Vector<char> buffer(utf8_buffer_ + utf8_pos_,
150 kUtf8BufferSize - utf8_pos_);
151 int size = OS::SNPrintF(buffer, "%d", n);
152 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
157 void AppendHex(uint32_t n) {
158 Vector<char> buffer(utf8_buffer_ + utf8_pos_,
159 kUtf8BufferSize - utf8_pos_);
160 int size = OS::SNPrintF(buffer, "%x", n);
161 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
166 // XDK needs this function temporarily. It will be removed later.
167 void AppendAddress(Address address) {
168 Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
169 int size = OS::SNPrintF(buffer, "0x%x", address);
170 if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
175 const char* get() { return utf8_buffer_; }
176 int size() const { return utf8_pos_; }
179 static const int kUtf8BufferSize = 512;
180 static const int kUtf16BufferSize = 128;
183 char utf8_buffer_[kUtf8BufferSize];
184 uc16 utf16_buffer[kUtf16BufferSize];
188 CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
190 CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
193 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
195 const char* comment) {
196 name_buffer_->Init(tag);
197 name_buffer_->AppendBytes(comment);
198 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
202 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
205 name_buffer_->Init(tag);
206 name_buffer_->AppendName(name);
207 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
211 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
213 SharedFunctionInfo* shared,
214 CompilationInfo* info,
216 name_buffer_->Init(tag);
217 name_buffer_->AppendBytes(ComputeMarker(code));
218 name_buffer_->AppendName(name);
219 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
223 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
225 SharedFunctionInfo* shared,
226 CompilationInfo* info,
227 Name* source, int line, int column) {
228 name_buffer_->Init(tag);
229 name_buffer_->AppendBytes(ComputeMarker(code));
230 name_buffer_->AppendString(shared->DebugName());
231 name_buffer_->AppendByte(' ');
232 if (source->IsString()) {
233 name_buffer_->AppendString(String::cast(source));
235 name_buffer_->AppendBytes("symbol(hash ");
236 name_buffer_->AppendHex(Name::cast(source)->Hash());
237 name_buffer_->AppendByte(')');
239 name_buffer_->AppendByte(':');
240 name_buffer_->AppendInt(line);
241 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
245 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
248 name_buffer_->Init(tag);
249 name_buffer_->AppendInt(args_count);
250 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
254 void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
255 name_buffer_->Init(Logger::REG_EXP_TAG);
256 name_buffer_->AppendString(source);
257 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
261 // Linux perf tool logging support
262 class PerfBasicLogger : public CodeEventLogger {
265 virtual ~PerfBasicLogger();
267 virtual void CodeMoveEvent(Address from, Address to) { }
268 virtual void CodeDeleteEvent(Address from) { }
271 virtual void LogRecordedBuffer(Code* code,
272 SharedFunctionInfo* shared,
276 // Extension added to V8 log file name to get the low-level log name.
277 static const char kFilenameFormatString[];
278 static const int kFilenameBufferPadding;
280 // File buffer size of the low-level log. We don't use the default to
281 // minimize the associated overhead.
282 static const int kLogBufferSize = 2 * MB;
284 FILE* perf_output_handle_;
287 const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map";
288 // Extra space for the PID in the filename
289 const int PerfBasicLogger::kFilenameBufferPadding = 16;
291 PerfBasicLogger::PerfBasicLogger()
292 : perf_output_handle_(NULL) {
293 // Open the perf JIT dump file.
294 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
295 ScopedVector<char> perf_dump_name(bufferSize);
296 int size = OS::SNPrintF(
298 kFilenameFormatString,
299 OS::GetCurrentProcessId());
301 perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode);
302 CHECK_NE(perf_output_handle_, NULL);
303 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
307 PerfBasicLogger::~PerfBasicLogger() {
308 fclose(perf_output_handle_);
309 perf_output_handle_ = NULL;
313 void PerfBasicLogger::LogRecordedBuffer(Code* code,
317 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize);
319 OS::FPrint(perf_output_handle_, "%llx %x %.*s\n",
320 reinterpret_cast<uint64_t>(code->instruction_start()),
321 code->instruction_size(),
326 // Linux perf tool logging support
327 class PerfJitLogger : public CodeEventLogger {
330 virtual ~PerfJitLogger();
332 virtual void CodeMoveEvent(Address from, Address to) { }
333 virtual void CodeDeleteEvent(Address from) { }
336 virtual void LogRecordedBuffer(Code* code,
337 SharedFunctionInfo* shared,
341 // Extension added to V8 log file name to get the low-level log name.
342 static const char kFilenameFormatString[];
343 static const int kFilenameBufferPadding;
345 // File buffer size of the low-level log. We don't use the default to
346 // minimize the associated overhead.
347 static const int kLogBufferSize = 2 * MB;
349 void LogWriteBytes(const char* bytes, int size);
350 void LogWriteHeader();
352 static const uint32_t kJitHeaderMagic = 0x4F74496A;
353 static const uint32_t kJitHeaderVersion = 0x2;
354 static const uint32_t kElfMachIA32 = 3;
355 static const uint32_t kElfMachX64 = 62;
356 static const uint32_t kElfMachARM = 40;
357 static const uint32_t kElfMachMIPS = 10;
369 enum jit_record_type {
371 // JIT_CODE_UNLOAD = 1,
372 // JIT_CODE_CLOSE = 2,
373 // JIT_CODE_DEBUG_INFO = 3,
374 // JIT_CODE_PAGE_MAP = 4,
378 struct jr_code_load {
388 uint32_t GetElfMach() {
389 #if V8_TARGET_ARCH_IA32
391 #elif V8_TARGET_ARCH_X64
393 #elif V8_TARGET_ARCH_ARM
395 #elif V8_TARGET_ARCH_MIPS
403 FILE* perf_output_handle_;
406 const char PerfJitLogger::kFilenameFormatString[] = "/tmp/jit-%d.dump";
408 // Extra padding for the PID in the filename
409 const int PerfJitLogger::kFilenameBufferPadding = 16;
411 PerfJitLogger::PerfJitLogger()
412 : perf_output_handle_(NULL) {
413 // Open the perf JIT dump file.
414 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
415 ScopedVector<char> perf_dump_name(bufferSize);
416 int size = OS::SNPrintF(
418 kFilenameFormatString,
419 OS::GetCurrentProcessId());
421 perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode);
422 CHECK_NE(perf_output_handle_, NULL);
423 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
429 PerfJitLogger::~PerfJitLogger() {
430 fclose(perf_output_handle_);
431 perf_output_handle_ = NULL;
435 void PerfJitLogger::LogRecordedBuffer(Code* code,
439 ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize);
440 ASSERT(perf_output_handle_ != NULL);
442 const char* code_name = name;
443 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start());
444 uint32_t code_size = code->instruction_size();
446 static const char string_terminator[] = "\0";
448 jr_code_load code_load;
449 code_load.id = JIT_CODE_LOAD;
450 code_load.total_size = sizeof(code_load) + length + 1 + code_size;
451 code_load.timestamp =
452 static_cast<uint64_t>(OS::TimeCurrentMillis() * 1000.0);
453 code_load.vma = 0x0; // Our addresses are absolute.
454 code_load.code_addr = reinterpret_cast<uint64_t>(code->instruction_start());
455 code_load.code_size = code_size;
458 LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load));
459 LogWriteBytes(code_name, length);
460 LogWriteBytes(string_terminator, 1);
461 LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size);
465 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) {
466 size_t rv = fwrite(bytes, 1, size, perf_output_handle_);
467 ASSERT(static_cast<size_t>(size) == rv);
472 void PerfJitLogger::LogWriteHeader() {
473 ASSERT(perf_output_handle_ != NULL);
475 header.magic = kJitHeaderMagic;
476 header.version = kJitHeaderVersion;
477 header.total_size = sizeof(jitheader);
478 header.pad1 = 0xdeadbeef;
479 header.elf_mach = GetElfMach();
480 header.pid = OS::GetCurrentProcessId();
481 header.timestamp = static_cast<uint64_t>(OS::TimeCurrentMillis() * 1000.0);
482 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header));
486 // Low-level logging support.
487 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
489 class LowLevelLogger : public CodeEventLogger {
491 explicit LowLevelLogger(const char* file_name);
492 virtual ~LowLevelLogger();
494 virtual void CodeMoveEvent(Address from, Address to);
495 virtual void CodeDeleteEvent(Address from);
496 virtual void SnapshotPositionEvent(Address addr, int pos);
497 virtual void CodeMovingGCEvent();
500 virtual void LogRecordedBuffer(Code* code,
501 SharedFunctionInfo* shared,
505 // Low-level profiling event structures.
506 struct CodeCreateStruct {
507 static const char kTag = 'C';
510 Address code_address;
515 struct CodeMoveStruct {
516 static const char kTag = 'M';
518 Address from_address;
523 struct CodeDeleteStruct {
524 static const char kTag = 'D';
530 struct SnapshotPositionStruct {
531 static const char kTag = 'P';
538 static const char kCodeMovingGCTag = 'G';
541 // Extension added to V8 log file name to get the low-level log name.
542 static const char kLogExt[];
544 // File buffer size of the low-level log. We don't use the default to
545 // minimize the associated overhead.
546 static const int kLogBufferSize = 2 * MB;
549 void LogWriteBytes(const char* bytes, int size);
551 template <typename T>
552 void LogWriteStruct(const T& s) {
554 LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
555 LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
558 FILE* ll_output_handle_;
561 const char LowLevelLogger::kLogExt[] = ".ll";
563 LowLevelLogger::LowLevelLogger(const char* name)
564 : ll_output_handle_(NULL) {
565 // Open the low-level log file.
566 size_t len = strlen(name);
567 ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
568 OS::MemCopy(ll_name.start(), name, len);
569 OS::MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
570 ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
571 setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize);
577 LowLevelLogger::~LowLevelLogger() {
578 fclose(ll_output_handle_);
579 ll_output_handle_ = NULL;
583 void LowLevelLogger::LogCodeInfo() {
584 #if V8_TARGET_ARCH_IA32
585 const char arch[] = "ia32";
586 #elif V8_TARGET_ARCH_X64
587 const char arch[] = "x64";
588 #elif V8_TARGET_ARCH_ARM
589 const char arch[] = "arm";
590 #elif V8_TARGET_ARCH_MIPS
591 const char arch[] = "mips";
593 const char arch[] = "unknown";
595 LogWriteBytes(arch, sizeof(arch));
599 void LowLevelLogger::LogRecordedBuffer(Code* code,
603 CodeCreateStruct event;
604 event.name_size = length;
605 event.code_address = code->instruction_start();
606 ASSERT(event.code_address == code->address() + Code::kHeaderSize);
607 event.code_size = code->instruction_size();
608 LogWriteStruct(event);
609 LogWriteBytes(name, length);
611 reinterpret_cast<const char*>(code->instruction_start()),
612 code->instruction_size());
616 void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
617 CodeMoveStruct event;
618 event.from_address = from + Code::kHeaderSize;
619 event.to_address = to + Code::kHeaderSize;
620 LogWriteStruct(event);
624 void LowLevelLogger::CodeDeleteEvent(Address from) {
625 CodeDeleteStruct event;
626 event.address = from + Code::kHeaderSize;
627 LogWriteStruct(event);
631 void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
632 SnapshotPositionStruct event;
633 event.address = addr + Code::kHeaderSize;
634 event.position = pos;
635 LogWriteStruct(event);
639 void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
640 size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
641 ASSERT(static_cast<size_t>(size) == rv);
646 void LowLevelLogger::CodeMovingGCEvent() {
647 const char tag = kCodeMovingGCTag;
649 LogWriteBytes(&tag, sizeof(tag));
653 #define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
656 class JitLogger : public CodeEventLogger {
658 explicit JitLogger(JitCodeEventHandler code_event_handler);
660 virtual void CodeMoveEvent(Address from, Address to);
661 virtual void CodeDeleteEvent(Address from);
662 virtual void AddCodeLinePosInfoEvent(
663 void* jit_handler_data,
666 JitCodeEvent::PositionType position_type);
668 void* StartCodePosInfoEvent();
669 void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
672 // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
673 // XDK needs all this stuff below to generate the strings like
674 // "code-creation:..." in the same format as Logger generates.
675 // This string is sent to XDK by code_event_handler and then used for
676 // postprocessing. All these CodeCreateEvent(...) functions and helpers
677 // will be removed before commit.
678 void AppendCodeCreateHeader(NameBuffer* msg,
679 Logger::LogEventsAndTags tag,
682 msg->AppendBytes(kLogEventsNames[Logger::CODE_CREATION_EVENT]);
683 msg->AppendByte(',');
684 msg->AppendBytes(kLogEventsNames[tag]);
685 msg->AppendByte(',');
686 msg->AppendInt(code->kind());
687 msg->AppendByte(',');
688 msg->AppendAddress(code->instruction_start());
689 msg->AppendByte(',');
690 msg->AppendInt(code->instruction_size());
691 msg->AppendByte(',');
695 void AppendDetailed(NameBuffer* msg, String* str, bool show_impl_info) {
697 if (str == NULL) return;
698 DisallowHeapAllocation no_gc; // Ensure string stay valid.
699 int len = str->length();
702 if (show_impl_info) {
703 msg->AppendByte(str->IsOneByteRepresentation() ? 'a' : '2');
704 if (StringShape(str).IsExternal())
705 msg->AppendByte('e');
706 if (StringShape(str).IsInternalized())
707 msg->AppendByte('#');
708 msg->AppendByte(':');
709 msg->AppendInt(str->length());
710 msg->AppendByte(':');
712 for (int i = 0; i < len; i++) {
713 uc32 c = str->Get(i);
715 msg->AppendBytes("\\u");
717 } else if (c < 32 || c > 126) {
718 msg->AppendBytes("\\x");
720 } else if (c == ',') {
721 msg->AppendBytes("\\,");
722 } else if (c == '\\') {
723 msg->AppendBytes("\\\\");
724 } else if (c == '\"') {
725 msg->AppendBytes("\"\"");
733 void AppendDoubleQuotedString(NameBuffer* msg, const char* string) {
735 msg->AppendByte('"');
736 for (const char* p = string; *p != '\0'; p++) {
738 msg->AppendByte('\\');
742 msg->AppendByte('"');
746 void AppendSymbolName(NameBuffer* msg, Symbol* symbol) {
749 msg->AppendBytes("symbol(");
750 if (!symbol->name()->IsUndefined()) {
751 msg->AppendByte('"');
752 AppendDetailed(msg, String::cast(symbol->name()), false);
753 msg->AppendBytes("\" ");
755 msg->AppendBytes("hash ");
756 msg->AppendHex(symbol->Hash());
757 msg->AppendByte(')');
761 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
762 Code* code, const char* comment) {
763 if (!xdk::XDKIsAgentAlive()) {
764 CodeEventLogger::CodeCreateEvent(tag, code, comment);
768 name_buffer_->Reset();
769 AppendCodeCreateHeader(name_buffer_, tag, code);
770 AppendDoubleQuotedString(name_buffer_, comment);
771 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
775 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
776 Code* code, Name* name) {
777 if (!xdk::XDKIsAgentAlive()) {
778 CodeEventLogger::CodeCreateEvent(tag, code, name);
782 name_buffer_->Reset();
783 AppendCodeCreateHeader(name_buffer_, tag, code);
784 if (name->IsString()) {
785 name_buffer_->AppendByte('"');
786 AppendDetailed(name_buffer_, String::cast(name), false);
787 name_buffer_->AppendByte('"');
789 AppendSymbolName(name_buffer_, Symbol::cast(name));
791 LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
795 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
797 SharedFunctionInfo* shared,
798 CompilationInfo* info,
800 if (!xdk::XDKIsAgentAlive()) {
801 CodeEventLogger::CodeCreateEvent(tag, code, shared, info, name);
805 name_buffer_->Reset();
806 AppendCodeCreateHeader(name_buffer_, tag, code);
807 if (name->IsString()) {
808 SmartArrayPointer<char> str =
809 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
810 name_buffer_->AppendByte('"');
811 name_buffer_->AppendBytes(str.get());
812 name_buffer_->AppendByte('"');
814 AppendSymbolName(name_buffer_, Symbol::cast(name));
816 name_buffer_->AppendByte(',');
817 name_buffer_->AppendAddress(shared->address());
818 name_buffer_->AppendByte(',');
819 name_buffer_->AppendBytes(ComputeMarker(code));
820 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
823 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
825 SharedFunctionInfo* shared,
826 CompilationInfo* info,
828 int line, int column) {
829 if (!xdk::XDKIsAgentAlive()) {
830 CodeEventLogger::CodeCreateEvent(tag, code, shared,
831 info, source, line, column);
835 name_buffer_->Reset();
836 AppendCodeCreateHeader(name_buffer_, tag, code);
837 SmartArrayPointer<char> name =
838 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
839 name_buffer_->AppendByte('"');
840 name_buffer_->AppendBytes(name.get());
841 name_buffer_->AppendByte(' ');
842 if (source->IsString()) {
843 SmartArrayPointer<char> sourcestr =
844 String::cast(source)->ToCString(DISALLOW_NULLS,
845 ROBUST_STRING_TRAVERSAL);
846 name_buffer_->AppendBytes(sourcestr.get());
848 AppendSymbolName(name_buffer_, Symbol::cast(source));
850 name_buffer_->AppendByte(':');
851 name_buffer_->AppendInt(line);
852 name_buffer_->AppendByte(':');
853 name_buffer_->AppendInt(column);
854 name_buffer_->AppendBytes("\",");
855 name_buffer_->AppendAddress(shared->address());
856 name_buffer_->AppendByte(',');
857 name_buffer_->AppendBytes(ComputeMarker(code));
858 LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
862 virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
865 if (!xdk::XDKIsAgentAlive()) {
866 CodeEventLogger::CodeCreateEvent(tag, code, args_count);
870 name_buffer_->Reset();
871 AppendCodeCreateHeader(name_buffer_, tag, code);
872 name_buffer_->AppendBytes("\"args_count: ");
873 name_buffer_->AppendInt(args_count);
874 name_buffer_->AppendByte('"');
878 virtual void RegExpCodeCreateEvent(Code* code, String* source) {
879 if (!xdk::XDKIsAgentAlive()) {
880 CodeEventLogger::RegExpCodeCreateEvent(code, source);
884 name_buffer_->Reset();
885 AppendCodeCreateHeader(name_buffer_, Logger::REG_EXP_TAG, code);
886 name_buffer_->AppendByte('"');
887 AppendDetailed(name_buffer_, source, false);
888 name_buffer_->AppendByte('"');
892 virtual void LogRecordedBuffer(Code* code,
893 SharedFunctionInfo* shared,
897 JitCodeEventHandler code_event_handler_;
901 JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
902 : code_event_handler_(code_event_handler) {
906 void JitLogger::LogRecordedBuffer(Code* code,
907 SharedFunctionInfo* shared,
911 memset(&event, 0, sizeof(event));
912 event.type = JitCodeEvent::CODE_ADDED;
913 event.code_start = code->instruction_start();
914 event.code_len = code->instruction_size();
915 Handle<Script> script_handle;
916 if (shared && shared->script()->IsScript()) {
917 script_handle = Handle<Script>(Script::cast(shared->script()));
919 event.script = ToApiHandle<v8::Script>(script_handle);
920 event.name.str = name;
921 event.name.len = length;
922 code_event_handler_(&event);
926 void JitLogger::CodeMoveEvent(Address from, Address to) {
927 Code* from_code = Code::cast(HeapObject::FromAddress(from));
930 event.type = JitCodeEvent::CODE_MOVED;
931 event.code_start = from_code->instruction_start();
932 event.code_len = from_code->instruction_size();
934 // Calculate the header size.
935 const size_t header_size =
936 from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
938 // Calculate the new start address of the instructions.
939 event.new_code_start =
940 reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
942 code_event_handler_(&event);
946 void JitLogger::CodeDeleteEvent(Address from) {
947 Code* from_code = Code::cast(HeapObject::FromAddress(from));
950 event.type = JitCodeEvent::CODE_REMOVED;
951 event.code_start = from_code->instruction_start();
952 event.code_len = from_code->instruction_size();
954 code_event_handler_(&event);
957 void JitLogger::AddCodeLinePosInfoEvent(
958 void* jit_handler_data,
961 JitCodeEvent::PositionType position_type) {
963 memset(&event, 0, sizeof(event));
964 event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
965 event.user_data = jit_handler_data;
966 event.line_info.offset = pc_offset;
967 event.line_info.pos = position;
968 event.line_info.position_type = position_type;
970 code_event_handler_(&event);
974 void* JitLogger::StartCodePosInfoEvent() {
976 memset(&event, 0, sizeof(event));
977 event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
979 code_event_handler_(&event);
980 return event.user_data;
984 void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) {
986 memset(&event, 0, sizeof(event));
987 event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
988 event.code_start = code->instruction_start();
989 event.user_data = jit_handler_data;
991 code_event_handler_(&event);
995 // The Profiler samples pc and sp values for the main thread.
996 // Each sample is appended to a circular buffer.
997 // An independent thread removes data and writes it to the log.
998 // This design minimizes the time spent in the sampler.
1000 class Profiler: public Thread {
1002 explicit Profiler(Isolate* isolate);
1006 // Inserts collected profiling data into buffer.
1007 void Insert(TickSample* sample) {
1011 if (Succ(head_) == tail_) {
1014 buffer_[head_] = *sample;
1015 head_ = Succ(head_);
1016 buffer_semaphore_.Signal(); // Tell we have an element.
1022 // Pause and Resume TickSample data collection.
1023 void pause() { paused_ = true; }
1024 void resume() { paused_ = false; }
1027 // Waits for a signal and removes profiling data.
1028 bool Remove(TickSample* sample) {
1029 buffer_semaphore_.Wait(); // Wait for an element.
1030 *sample = buffer_[tail_];
1031 bool result = overflow_;
1032 tail_ = Succ(tail_);
1037 // Returns the next index in the cyclic buffer.
1038 int Succ(int index) { return (index + 1) % kBufferSize; }
1041 // Cyclic buffer for communicating profiling samples
1042 // between the signal handler and the worker thread.
1043 static const int kBufferSize = 128;
1044 TickSample buffer_[kBufferSize]; // Buffer storage.
1045 int head_; // Index to the buffer head.
1046 int tail_; // Index to the buffer tail.
1047 bool overflow_; // Tell whether a buffer overflow has occurred.
1048 // Sempahore used for buffer synchronization.
1049 Semaphore buffer_semaphore_;
1051 // Tells whether profiler is engaged, that is, processing thread is stated.
1054 // Tells whether worker thread should continue running.
1057 // Tells whether we are currently recording tick samples.
1063 // Ticker used to provide ticks to the profiler and the sliding state
1066 class Ticker: public Sampler {
1068 Ticker(Isolate* isolate, int interval):
1069 Sampler(isolate, interval),
1072 ~Ticker() { if (IsActive()) Stop(); }
1074 virtual void Tick(TickSample* sample) {
1075 if (profiler_) profiler_->Insert(sample);
1078 void SetProfiler(Profiler* profiler) {
1079 ASSERT(profiler_ == NULL);
1080 profiler_ = profiler;
1081 IncreaseProfilingDepth();
1082 if (!IsActive()) Start();
1085 void ClearProfiler() {
1087 if (IsActive()) Stop();
1088 DecreaseProfilingDepth();
1092 Profiler* profiler_;
1097 // Profiler implementation.
1099 Profiler::Profiler(Isolate* isolate)
1100 : Thread("v8:Profiler"),
1105 buffer_semaphore_(0),
1112 void Profiler::Engage() {
1113 if (engaged_) return;
1116 OS::LogSharedLibraryAddresses(isolate_);
1118 // Start thread processing the profiler buffer.
1122 // Register to get ticks.
1123 Logger* logger = isolate_->logger();
1124 logger->ticker_->SetProfiler(this);
1126 logger->ProfilerBeginEvent();
1130 void Profiler::Disengage() {
1131 if (!engaged_) return;
1133 // Stop receiving ticks.
1134 isolate_->logger()->ticker_->ClearProfiler();
1136 // Terminate the worker thread by setting running_ to false,
1137 // inserting a fake element in the queue and then wait for
1138 // the thread to terminate.
1141 // Reset 'paused_' flag, otherwise semaphore may not be signalled.
1146 LOG(isolate_, UncheckedStringEvent("profiler", "end"));
1150 void Profiler::Run() {
1152 bool overflow = Remove(&sample);
1154 LOG(isolate_, TickEvent(&sample, overflow));
1155 overflow = Remove(&sample);
1161 // Logger class implementation.
1164 Logger::Logger(Isolate* isolate)
1165 : isolate_(isolate),
1170 log_(new Log(this)),
1171 perf_basic_logger_(NULL),
1172 perf_jit_logger_(NULL),
1176 is_initialized_(false) {
1185 void Logger::addCodeEventListener(CodeEventListener* listener) {
1186 ASSERT(!hasCodeEventListener(listener));
1187 listeners_.Add(listener);
1191 void Logger::removeCodeEventListener(CodeEventListener* listener) {
1192 ASSERT(hasCodeEventListener(listener));
1193 listeners_.RemoveElement(listener);
1197 bool Logger::hasCodeEventListener(CodeEventListener* listener) {
1198 return listeners_.Contains(listener);
1202 void Logger::ProfilerBeginEvent() {
1203 if (!log_->IsEnabled()) return;
1204 Log::MessageBuilder msg(log_);
1205 msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
1206 msg.WriteToLogFile();
1210 void Logger::StringEvent(const char* name, const char* value) {
1211 if (FLAG_log) UncheckedStringEvent(name, value);
1215 void Logger::UncheckedStringEvent(const char* name, const char* value) {
1216 if (!log_->IsEnabled()) return;
1217 Log::MessageBuilder msg(log_);
1218 msg.Append("%s,\"%s\"\n", name, value);
1219 msg.WriteToLogFile();
1223 void Logger::IntEvent(const char* name, int value) {
1224 if (FLAG_log) UncheckedIntEvent(name, value);
1228 void Logger::IntPtrTEvent(const char* name, intptr_t value) {
1229 if (FLAG_log) UncheckedIntPtrTEvent(name, value);
1233 void Logger::UncheckedIntEvent(const char* name, int value) {
1234 if (!log_->IsEnabled()) return;
1235 Log::MessageBuilder msg(log_);
1236 msg.Append("%s,%d\n", name, value);
1237 msg.WriteToLogFile();
1241 void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
1242 if (!log_->IsEnabled()) return;
1243 Log::MessageBuilder msg(log_);
1244 msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
1245 msg.WriteToLogFile();
1249 void Logger::HandleEvent(const char* name, Object** location) {
1250 if (!log_->IsEnabled() || !FLAG_log_handles) return;
1251 Log::MessageBuilder msg(log_);
1252 msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
1253 msg.WriteToLogFile();
1257 // ApiEvent is private so all the calls come from the Logger class. It is the
1258 // caller's responsibility to ensure that log is enabled and that
1259 // FLAG_log_api is true.
1260 void Logger::ApiEvent(const char* format, ...) {
1261 ASSERT(log_->IsEnabled() && FLAG_log_api);
1262 Log::MessageBuilder msg(log_);
1264 va_start(ap, format);
1265 msg.AppendVA(format, ap);
1267 msg.WriteToLogFile();
1271 void Logger::ApiNamedSecurityCheck(Object* key) {
1272 if (!log_->IsEnabled() || !FLAG_log_api) return;
1273 if (key->IsString()) {
1274 SmartArrayPointer<char> str =
1275 String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1276 ApiEvent("api,check-security,\"%s\"\n", str.get());
1277 } else if (key->IsSymbol()) {
1278 Symbol* symbol = Symbol::cast(key);
1279 if (symbol->name()->IsUndefined()) {
1280 ApiEvent("api,check-security,symbol(hash %x)\n",
1281 Symbol::cast(key)->Hash());
1283 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1284 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1285 ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n",
1287 Symbol::cast(key)->Hash());
1289 } else if (key->IsUndefined()) {
1290 ApiEvent("api,check-security,undefined\n");
1292 ApiEvent("api,check-security,['no-name']\n");
1297 void Logger::SharedLibraryEvent(const char* library_path,
1300 if (!log_->IsEnabled() || !FLAG_prof) return;
1301 Log::MessageBuilder msg(log_);
1302 msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
1306 msg.WriteToLogFile();
1310 void Logger::SharedLibraryEvent(const wchar_t* library_path,
1313 if (!log_->IsEnabled() || !FLAG_prof) return;
1314 Log::MessageBuilder msg(log_);
1315 msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
1319 msg.WriteToLogFile();
1323 void Logger::CodeDeoptEvent(Code* code) {
1324 if (!log_->IsEnabled()) return;
1325 ASSERT(FLAG_log_internal_timer_events);
1326 Log::MessageBuilder msg(log_);
1327 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
1328 msg.Append("code-deopt,%ld,%d\n", since_epoch, code->CodeSize());
1329 msg.WriteToLogFile();
1333 void Logger::TimerEvent(StartEnd se, const char* name) {
1334 if (!log_->IsEnabled()) return;
1335 ASSERT(FLAG_log_internal_timer_events);
1336 Log::MessageBuilder msg(log_);
1337 int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
1338 const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n"
1339 : "timer-event-end,\"%s\",%ld\n";
1340 msg.Append(format, name, since_epoch);
1341 msg.WriteToLogFile();
1345 void Logger::EnterExternal(Isolate* isolate) {
1346 LOG(isolate, TimerEvent(START, TimerEventScope::v8_external));
1347 ASSERT(isolate->current_vm_state() == JS);
1348 isolate->set_current_vm_state(EXTERNAL);
1352 void Logger::LeaveExternal(Isolate* isolate) {
1353 LOG(isolate, TimerEvent(END, TimerEventScope::v8_external));
1354 ASSERT(isolate->current_vm_state() == EXTERNAL);
1355 isolate->set_current_vm_state(JS);
1359 void Logger::TimerEventScope::LogTimerEvent(StartEnd se) {
1360 LOG(isolate_, TimerEvent(se, name_));
1364 const char* Logger::TimerEventScope::v8_recompile_synchronous =
1365 "V8.RecompileSynchronous";
1366 const char* Logger::TimerEventScope::v8_recompile_concurrent =
1367 "V8.RecompileConcurrent";
1368 const char* Logger::TimerEventScope::v8_compile_full_code =
1369 "V8.CompileFullCode";
1370 const char* Logger::TimerEventScope::v8_execute = "V8.Execute";
1371 const char* Logger::TimerEventScope::v8_external = "V8.External";
1374 void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
1375 // Prints "/" + re.source + "/" +
1376 // (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
1377 Log::MessageBuilder msg(log_);
1379 Handle<Object> source = GetProperty(regexp, "source");
1380 if (!source->IsString()) {
1381 msg.Append("no source");
1385 switch (regexp->TypeTag()) {
1386 case JSRegExp::ATOM:
1393 msg.AppendDetailed(*Handle<String>::cast(source), false);
1397 Handle<Object> global = GetProperty(regexp, "global");
1398 if (global->IsTrue()) {
1402 Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
1403 if (ignorecase->IsTrue()) {
1407 Handle<Object> multiline = GetProperty(regexp, "multiline");
1408 if (multiline->IsTrue()) {
1412 msg.WriteToLogFile();
1416 void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
1417 if (!log_->IsEnabled() || !FLAG_log_regexp) return;
1418 Log::MessageBuilder msg(log_);
1419 msg.Append("regexp-compile,");
1420 LogRegExpSource(regexp);
1421 msg.Append(in_cache ? ",hit\n" : ",miss\n");
1422 msg.WriteToLogFile();
1426 void Logger::LogRuntime(Vector<const char> format,
1428 if (!log_->IsEnabled() || !FLAG_log_runtime) return;
1429 HandleScope scope(isolate_);
1430 Log::MessageBuilder msg(log_);
1431 for (int i = 0; i < format.length(); i++) {
1433 if (c == '%' && i <= format.length() - 2) {
1435 ASSERT('0' <= format[i] && format[i] <= '9');
1436 MaybeObject* maybe = args->GetElement(isolate_, format[i] - '0');
1438 if (!maybe->ToObject(&obj)) {
1439 msg.Append("<exception>");
1443 switch (format[i]) {
1445 msg.AppendDetailed(String::cast(obj), false);
1448 msg.AppendDetailed(String::cast(obj), true);
1451 Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
1454 msg.Append("0x%x", Smi::cast(obj)->value());
1457 msg.Append("%i", Smi::cast(obj)->value());
1467 msg.WriteToLogFile();
1471 void Logger::ApiIndexedSecurityCheck(uint32_t index) {
1472 if (!log_->IsEnabled() || !FLAG_log_api) return;
1473 ApiEvent("api,check-security,%u\n", index);
1477 void Logger::ApiNamedPropertyAccess(const char* tag,
1480 ASSERT(name->IsName());
1481 if (!log_->IsEnabled() || !FLAG_log_api) return;
1482 String* class_name_obj = holder->class_name();
1483 SmartArrayPointer<char> class_name =
1484 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1485 if (name->IsString()) {
1486 SmartArrayPointer<char> property_name =
1487 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1488 ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, class_name.get(),
1489 property_name.get());
1491 Symbol* symbol = Symbol::cast(name);
1492 uint32_t hash = symbol->Hash();
1493 if (symbol->name()->IsUndefined()) {
1494 ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, class_name.get(), hash);
1496 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1497 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1498 ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n",
1499 tag, class_name.get(), str.get(), hash);
1504 void Logger::ApiIndexedPropertyAccess(const char* tag,
1507 if (!log_->IsEnabled() || !FLAG_log_api) return;
1508 String* class_name_obj = holder->class_name();
1509 SmartArrayPointer<char> class_name =
1510 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1511 ApiEvent("api,%s,\"%s\",%u\n", tag, class_name.get(), index);
1515 void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
1516 if (!log_->IsEnabled() || !FLAG_log_api) return;
1517 String* class_name_obj = object->class_name();
1518 SmartArrayPointer<char> class_name =
1519 class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1520 ApiEvent("api,%s,\"%s\"\n", tag, class_name.get());
1524 void Logger::ApiEntryCall(const char* name) {
1525 if (!log_->IsEnabled() || !FLAG_log_api) return;
1526 ApiEvent("api,%s\n", name);
1530 void Logger::NewEvent(const char* name, void* object, size_t size) {
1531 if (!log_->IsEnabled() || !FLAG_log) return;
1532 Log::MessageBuilder msg(log_);
1533 msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
1534 static_cast<unsigned int>(size));
1535 msg.WriteToLogFile();
1539 void Logger::DeleteEvent(const char* name, void* object) {
1540 if (!log_->IsEnabled() || !FLAG_log) return;
1541 Log::MessageBuilder msg(log_);
1542 msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
1543 msg.WriteToLogFile();
1547 void Logger::NewEventStatic(const char* name, void* object, size_t size) {
1548 Isolate::Current()->logger()->NewEvent(name, object, size);
1552 void Logger::DeleteEventStatic(const char* name, void* object) {
1553 Isolate::Current()->logger()->DeleteEvent(name, object);
1557 void Logger::CallbackEventInternal(const char* prefix, Name* name,
1558 Address entry_point) {
1559 if (!FLAG_log_code || !log_->IsEnabled()) return;
1560 Log::MessageBuilder msg(log_);
1561 msg.Append("%s,%s,-2,",
1562 kLogEventsNames[CODE_CREATION_EVENT],
1563 kLogEventsNames[CALLBACK_TAG]);
1564 msg.AppendAddress(entry_point);
1565 if (name->IsString()) {
1566 SmartArrayPointer<char> str =
1567 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1568 msg.Append(",1,\"%s%s\"", prefix, str.get());
1570 Symbol* symbol = Symbol::cast(name);
1571 if (symbol->name()->IsUndefined()) {
1572 msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
1574 SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1575 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1576 msg.Append(",1,symbol(\"%s\" hash %x)", prefix, str.get(),
1581 msg.WriteToLogFile();
1585 void Logger::CallbackEvent(Name* name, Address entry_point) {
1586 PROFILER_LOG(CallbackEvent(name, entry_point));
1587 CallbackEventInternal("", name, entry_point);
1591 void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
1592 PROFILER_LOG(GetterCallbackEvent(name, entry_point));
1593 CallbackEventInternal("get ", name, entry_point);
1597 void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
1598 PROFILER_LOG(SetterCallbackEvent(name, entry_point));
1599 CallbackEventInternal("set ", name, entry_point);
1603 static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
1604 Logger::LogEventsAndTags tag,
1607 msg->Append("%s,%s,%d,",
1608 kLogEventsNames[Logger::CODE_CREATION_EVENT],
1609 kLogEventsNames[tag],
1611 if (xdk::XDKIsAgentAlive()) {
1612 msg->AppendAddress(code->instruction_start());
1613 msg->Append(",%d,", code->instruction_size());
1615 msg->AppendAddress(code->address());
1616 msg->Append(",%d,", code->ExecutableSize());
1621 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1623 const char* comment) {
1624 PROFILER_LOG(CodeCreateEvent(tag, code, comment));
1626 if (!is_logging_code_events()) return;
1627 CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
1629 if (!FLAG_log_code || !log_->IsEnabled()) return;
1630 Log::MessageBuilder msg(log_);
1631 AppendCodeCreateHeader(&msg, tag, code);
1632 msg.AppendDoubleQuotedString(comment);
1634 msg.WriteToLogFile();
1638 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1641 PROFILER_LOG(CodeCreateEvent(tag, code, name));
1643 if (!is_logging_code_events()) return;
1644 CALL_LISTENERS(CodeCreateEvent(tag, code, name));
1646 if (!FLAG_log_code || !log_->IsEnabled()) return;
1647 Log::MessageBuilder msg(log_);
1648 AppendCodeCreateHeader(&msg, tag, code);
1649 if (name->IsString()) {
1651 msg.AppendDetailed(String::cast(name), false);
1654 msg.AppendSymbolName(Symbol::cast(name));
1657 msg.WriteToLogFile();
1661 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1663 SharedFunctionInfo* shared,
1664 CompilationInfo* info,
1666 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
1668 if (!is_logging_code_events()) return;
1669 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
1671 if (!FLAG_log_code || !log_->IsEnabled()) return;
1672 if (code == isolate_->builtins()->builtin(Builtins::kCompileUnoptimized))
1675 Log::MessageBuilder msg(log_);
1676 AppendCodeCreateHeader(&msg, tag, code);
1677 if (name->IsString()) {
1678 SmartArrayPointer<char> str =
1679 String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1680 msg.Append("\"%s\"", str.get());
1682 msg.AppendSymbolName(Symbol::cast(name));
1685 msg.AppendAddress(shared->address());
1686 msg.Append(",%s", ComputeMarker(code));
1688 msg.WriteToLogFile();
1692 // Although, it is possible to extract source and line from
1693 // the SharedFunctionInfo object, we left it to caller
1694 // to leave logging functions free from heap allocations.
1695 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1697 SharedFunctionInfo* shared,
1698 CompilationInfo* info,
1699 Name* source, int line, int column) {
1700 PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column));
1702 if (!is_logging_code_events()) return;
1703 CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line,
1706 if (!FLAG_log_code || !log_->IsEnabled()) return;
1707 Log::MessageBuilder msg(log_);
1708 AppendCodeCreateHeader(&msg, tag, code);
1709 SmartArrayPointer<char> name =
1710 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1711 msg.Append("\"%s ", name.get());
1712 if (source->IsString()) {
1713 SmartArrayPointer<char> sourcestr =
1714 String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1715 msg.Append("%s", sourcestr.get());
1717 msg.AppendSymbolName(Symbol::cast(source));
1719 msg.Append(":%d:%d\",", line, column);
1720 msg.AppendAddress(shared->address());
1721 msg.Append(",%s", ComputeMarker(code));
1723 msg.WriteToLogFile();
1727 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1730 PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
1732 if (!is_logging_code_events()) return;
1733 CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
1735 if (!FLAG_log_code || !log_->IsEnabled()) return;
1736 Log::MessageBuilder msg(log_);
1737 AppendCodeCreateHeader(&msg, tag, code);
1738 msg.Append("\"args_count: %d\"", args_count);
1740 msg.WriteToLogFile();
1744 void Logger::CodeMovingGCEvent() {
1745 PROFILER_LOG(CodeMovingGCEvent());
1747 if (!is_logging_code_events()) return;
1748 if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1749 CALL_LISTENERS(CodeMovingGCEvent());
1750 OS::SignalCodeMovingGC();
1754 void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
1755 PROFILER_LOG(RegExpCodeCreateEvent(code, source));
1757 if (!is_logging_code_events()) return;
1758 CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
1760 if (!FLAG_log_code || !log_->IsEnabled()) return;
1761 Log::MessageBuilder msg(log_);
1762 AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
1764 msg.AppendDetailed(source, false);
1767 msg.WriteToLogFile();
1771 void Logger::CodeMoveEvent(Address from, Address to) {
1772 PROFILER_LOG(CodeMoveEvent(from, to));
1774 if (!is_logging_code_events()) return;
1775 CALL_LISTENERS(CodeMoveEvent(from, to));
1776 MoveEventInternal(CODE_MOVE_EVENT, from, to);
1780 void Logger::CodeDeleteEvent(Address from) {
1781 PROFILER_LOG(CodeDeleteEvent(from));
1783 if (!is_logging_code_events()) return;
1784 CALL_LISTENERS(CodeDeleteEvent(from));
1786 if (!FLAG_log_code || !log_->IsEnabled()) return;
1787 Log::MessageBuilder msg(log_);
1788 msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
1789 msg.AppendAddress(from);
1791 msg.WriteToLogFile();
1795 void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
1798 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1801 JitCodeEvent::POSITION));
1805 void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
1808 JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1811 JitCodeEvent::STATEMENT_POSITION));
1815 void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
1816 if (jit_logger_ != NULL) {
1817 pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
1822 void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
1823 void* jit_handler_data) {
1824 JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
1828 void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1829 if (code_name == NULL) return; // Not a code object.
1830 Log::MessageBuilder msg(log_);
1831 msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
1832 msg.AppendDoubleQuotedString(code_name);
1834 msg.WriteToLogFile();
1838 void Logger::SnapshotPositionEvent(Address addr, int pos) {
1839 if (!log_->IsEnabled()) return;
1840 LL_LOG(SnapshotPositionEvent(addr, pos));
1841 if (!FLAG_log_snapshot_positions) return;
1842 Log::MessageBuilder msg(log_);
1843 msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
1844 msg.AppendAddress(addr);
1845 msg.Append(",%d", pos);
1847 msg.WriteToLogFile();
1851 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
1852 PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
1854 if (!is_logging_code_events()) return;
1855 MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
1859 void Logger::MoveEventInternal(LogEventsAndTags event,
1862 if (!FLAG_log_code || !log_->IsEnabled()) return;
1864 Code* from_code = NULL;
1865 Address to_code = NULL;
1866 if (xdk::XDKIsAgentAlive()) {
1867 from_code = Code::cast(HeapObject::FromAddress(from));
1868 const size_t header_size =
1869 from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
1871 reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
1874 Log::MessageBuilder msg(log_);
1875 msg.Append("%s,", kLogEventsNames[event]);
1876 if (xdk::XDKIsAgentAlive()) {
1877 msg.AppendAddress(from_code->instruction_start());
1879 msg.AppendAddress(from);
1882 if (xdk::XDKIsAgentAlive()) {
1883 msg.AppendAddress(to_code);
1885 msg.AppendAddress(to);
1888 msg.WriteToLogFile();
1892 void Logger::ResourceEvent(const char* name, const char* tag) {
1893 if (!log_->IsEnabled() || !FLAG_log) return;
1894 Log::MessageBuilder msg(log_);
1895 msg.Append("%s,%s,", name, tag);
1898 if (OS::GetUserTime(&sec, &usec) != -1) {
1899 msg.Append("%d,%d,", sec, usec);
1901 msg.Append("%.0f", OS::TimeCurrentMillis());
1904 msg.WriteToLogFile();
1908 void Logger::SuspectReadEvent(Name* name, Object* obj) {
1909 if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1910 Log::MessageBuilder msg(log_);
1911 String* class_name = obj->IsJSObject()
1912 ? JSObject::cast(obj)->class_name()
1913 : isolate_->heap()->empty_string();
1914 msg.Append("suspect-read,");
1915 msg.Append(class_name);
1917 if (name->IsString()) {
1919 msg.Append(String::cast(name));
1922 msg.AppendSymbolName(Symbol::cast(name));
1925 msg.WriteToLogFile();
1929 void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
1930 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1931 Log::MessageBuilder msg(log_);
1932 // Using non-relative system time in order to be able to synchronize with
1933 // external memory profiling events (e.g. DOM memory size).
1934 msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
1935 space, kind, OS::TimeCurrentMillis());
1936 msg.WriteToLogFile();
1940 void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
1941 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1942 Log::MessageBuilder msg(log_);
1943 msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
1944 msg.WriteToLogFile();
1948 void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
1949 if (!log_->IsEnabled() || !FLAG_log_gc) return;
1950 Log::MessageBuilder msg(log_);
1951 msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
1952 msg.WriteToLogFile();
1956 void Logger::DebugTag(const char* call_site_tag) {
1957 if (!log_->IsEnabled() || !FLAG_log) return;
1958 Log::MessageBuilder msg(log_);
1959 msg.Append("debug-tag,%s\n", call_site_tag);
1960 msg.WriteToLogFile();
1964 void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
1965 if (!log_->IsEnabled() || !FLAG_log) return;
1966 StringBuilder s(parameter.length() + 1);
1967 for (int i = 0; i < parameter.length(); ++i) {
1968 s.AddCharacter(static_cast<char>(parameter[i]));
1970 char* parameter_string = s.Finalize();
1971 Log::MessageBuilder msg(log_);
1972 msg.Append("debug-queue-event,%s,%15.3f,%s\n",
1974 OS::TimeCurrentMillis(),
1976 DeleteArray(parameter_string);
1977 msg.WriteToLogFile();
1981 void Logger::TickEvent(TickSample* sample, bool overflow) {
1982 if (!log_->IsEnabled() || !FLAG_prof) return;
1983 Log::MessageBuilder msg(log_);
1984 msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1985 msg.AppendAddress(sample->pc);
1986 msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
1987 if (sample->has_external_callback) {
1989 msg.AppendAddress(sample->external_callback);
1992 msg.AppendAddress(sample->tos);
1994 msg.Append(",%d", static_cast<int>(sample->state));
1996 msg.Append(",overflow");
1998 for (int i = 0; i < sample->frames_count; ++i) {
2000 msg.AppendAddress(sample->stack[i]);
2003 msg.WriteToLogFile();
2007 void Logger::XDKResumeProfiler() {
2008 if (!log_->IsEnabled()) return;
2009 if (profiler_ != NULL) {
2010 profiler_->resume();
2016 void Logger::StopProfiler() {
2017 if (!log_->IsEnabled()) return;
2018 if (profiler_ != NULL) {
2020 is_logging_ = false;
2025 // This function can be called when Log's mutex is acquired,
2026 // either from main or Profiler's thread.
2027 void Logger::LogFailure() {
2032 class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
2034 EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
2035 Handle<Code>* code_objects,
2037 : sfis_(sfis), code_objects_(code_objects), count_(count) { }
2039 virtual void EnterContext(Context* context) {}
2040 virtual void LeaveContext(Context* context) {}
2042 virtual void VisitFunction(JSFunction* function) {
2043 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
2044 Object* maybe_script = sfi->script();
2045 if (maybe_script->IsScript()
2046 && !Script::cast(maybe_script)->HasValidSource()) return;
2047 if (sfis_ != NULL) {
2048 sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
2050 if (code_objects_ != NULL) {
2051 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
2052 code_objects_[*count_] = Handle<Code>(function->code());
2054 *count_ = *count_ + 1;
2058 Handle<SharedFunctionInfo>* sfis_;
2059 Handle<Code>* code_objects_;
2064 static int EnumerateCompiledFunctions(Heap* heap,
2065 Handle<SharedFunctionInfo>* sfis,
2066 Handle<Code>* code_objects) {
2067 HeapIterator iterator(heap);
2068 DisallowHeapAllocation no_gc;
2069 int compiled_funcs_count = 0;
2071 // Iterate the heap to find shared function info objects and record
2072 // the unoptimized code for them.
2073 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
2074 if (!obj->IsSharedFunctionInfo()) continue;
2075 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
2076 if (sfi->is_compiled()
2077 && (!sfi->script()->IsScript()
2078 || Script::cast(sfi->script())->HasValidSource())) {
2080 sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
2082 if (code_objects != NULL) {
2083 code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
2085 ++compiled_funcs_count;
2089 // Iterate all optimized functions in all contexts.
2090 EnumerateOptimizedFunctionsVisitor visitor(sfis,
2092 &compiled_funcs_count);
2093 Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
2095 return compiled_funcs_count;
2099 void Logger::LogCodeObject(Object* object) {
2100 Code* code_object = Code::cast(object);
2101 LogEventsAndTags tag = Logger::STUB_TAG;
2102 const char* description = "Unknown code from the snapshot";
2103 switch (code_object->kind()) {
2104 case Code::FUNCTION:
2105 case Code::OPTIMIZED_FUNCTION:
2106 return; // We log this later using LogCompiledFunctions.
2107 case Code::BINARY_OP_IC:
2108 case Code::COMPARE_IC: // fall through
2109 case Code::COMPARE_NIL_IC: // fall through
2110 case Code::TO_BOOLEAN_IC: // fall through
2113 CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
2114 if (description == NULL)
2115 description = "A stub from the snapshot";
2116 tag = Logger::STUB_TAG;
2119 description = "Regular expression code";
2120 tag = Logger::REG_EXP_TAG;
2123 description = "A builtin from the snapshot";
2124 tag = Logger::BUILTIN_TAG;
2127 description = "An IC handler from the snapshot";
2128 tag = Logger::HANDLER_TAG;
2130 case Code::KEYED_LOAD_IC:
2131 description = "A keyed load IC from the snapshot";
2132 tag = Logger::KEYED_LOAD_IC_TAG;
2135 description = "A load IC from the snapshot";
2136 tag = Logger::LOAD_IC_TAG;
2138 case Code::STORE_IC:
2139 description = "A store IC from the snapshot";
2140 tag = Logger::STORE_IC_TAG;
2142 case Code::KEYED_STORE_IC:
2143 description = "A keyed store IC from the snapshot";
2144 tag = Logger::KEYED_STORE_IC_TAG;
2146 case Code::NUMBER_OF_KINDS:
2149 PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
2153 void Logger::LogCodeObjects() {
2154 // Starting from Chromium v34 this function is also called from
2155 // V8::Initialize. This causes reading the heap to collect already
2156 // compiled methods. For XDK that must be done because XDK profiler
2157 // consumes CODE_ADDED events and mantains a map of compiled methods.
2158 if (xdk::XDKIsAgentAlive()) return;
2160 Heap* heap = isolate_->heap();
2161 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
2162 "Logger::LogCodeObjects");
2163 HeapIterator iterator(heap);
2164 DisallowHeapAllocation no_gc;
2165 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
2166 if (obj->IsCode()) LogCodeObject(obj);
2171 void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
2172 Handle<Code> code) {
2173 Handle<String> func_name(shared->DebugName());
2174 if (shared->script()->IsScript()) {
2175 Handle<Script> script(Script::cast(shared->script()));
2176 int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
2178 GetScriptColumnNumber(script, shared->start_position()) + 1;
2179 if (script->name()->IsString()) {
2180 Handle<String> script_name(String::cast(script->name()));
2184 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
2185 *code, *shared, NULL,
2186 *script_name, line_num, column_num));
2188 // Can't distinguish eval and script here, so always use Script.
2191 Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
2192 *code, *shared, NULL, *script_name));
2197 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
2198 *code, *shared, NULL,
2199 isolate_->heap()->empty_string(), line_num, column_num));
2201 } else if (shared->IsApiFunction()) {
2203 FunctionTemplateInfo* fun_data = shared->get_api_func_data();
2204 Object* raw_call_data = fun_data->call_code();
2205 if (!raw_call_data->IsUndefined()) {
2206 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
2207 Object* callback_obj = call_data->callback();
2208 Address entry_point = v8::ToCData<Address>(callback_obj);
2209 PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
2214 Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
2219 void Logger::LogCompiledFunctions() {
2220 // Starting from Chromium v34 this function is also called from
2221 // V8::Initialize. This causes reading the heap to collect already
2222 // compiled methods. For XDK that must be done because XDK profiler
2223 // consumes CODE_ADDED events and mantains a map of compiled methods.
2224 if (xdk::XDKIsAgentAlive()) return;
2226 Heap* heap = isolate_->heap();
2227 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
2228 "Logger::LogCompiledFunctions");
2229 HandleScope scope(isolate_);
2230 const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL);
2231 ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
2232 ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
2233 EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
2235 // During iteration, there can be heap allocation due to
2236 // GetScriptLineNumber call.
2237 for (int i = 0; i < compiled_funcs_count; ++i) {
2238 if (code_objects[i].is_identical_to(
2239 isolate_->builtins()->CompileUnoptimized()))
2241 LogExistingFunction(sfis[i], code_objects[i]);
2246 void Logger::LogAccessorCallbacks() {
2247 Heap* heap = isolate_->heap();
2248 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
2249 "Logger::LogAccessorCallbacks");
2250 HeapIterator iterator(heap);
2251 DisallowHeapAllocation no_gc;
2252 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
2253 if (!obj->IsExecutableAccessorInfo()) continue;
2254 ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
2255 if (!ai->name()->IsName()) continue;
2256 Address getter_entry = v8::ToCData<Address>(ai->getter());
2257 Name* name = Name::cast(ai->name());
2258 if (getter_entry != 0) {
2259 PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
2261 Address setter_entry = v8::ToCData<Address>(ai->setter());
2262 if (setter_entry != 0) {
2263 PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
2269 static void AddIsolateIdIfNeeded(Isolate* isolate, StringStream* stream) {
2270 if (isolate->IsDefaultIsolate() || !FLAG_logfile_per_isolate) return;
2271 stream->Add("isolate-%p-", isolate);
2275 static SmartArrayPointer<const char> PrepareLogFileName(
2276 Isolate* isolate, const char* file_name) {
2277 if (strchr(file_name, '%') != NULL || !isolate->IsDefaultIsolate()) {
2278 // If there's a '%' in the log file name we have to expand
2280 HeapStringAllocator allocator;
2281 StringStream stream(&allocator);
2282 AddIsolateIdIfNeeded(isolate, &stream);
2283 for (const char* p = file_name; *p; p++) {
2288 // If there's a % at the end of the string we back up
2289 // one character so we can escape the loop properly.
2293 stream.Add("%d", OS::GetCurrentProcessId());
2296 // %t expands to the current time in milliseconds.
2297 double time = OS::TimeCurrentMillis();
2298 stream.Add("%.0f", FmtElm(time));
2302 // %% expands (contracts really) to %.
2306 // All other %'s expand to themselves.
2315 return SmartArrayPointer<const char>(stream.ToCString());
2317 int length = StrLength(file_name);
2318 char* str = NewArray<char>(length + 1);
2319 OS::MemCopy(str, file_name, length);
2321 return SmartArrayPointer<const char>(str);
2325 bool Logger::SetUp(Isolate* isolate) {
2326 // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
2327 if (is_initialized_) return true;
2328 is_initialized_ = true;
2330 // --ll-prof implies --log-code and --log-snapshot-positions.
2332 FLAG_log_snapshot_positions = true;
2335 SmartArrayPointer<const char> log_file_name =
2336 PrepareLogFileName(isolate, FLAG_logfile);
2337 log_->Initialize(log_file_name.get());
2340 if (FLAG_perf_basic_prof) {
2341 perf_basic_logger_ = new PerfBasicLogger();
2342 addCodeEventListener(perf_basic_logger_);
2345 if (FLAG_perf_jit_prof) {
2346 perf_jit_logger_ = new PerfJitLogger();
2347 addCodeEventListener(perf_jit_logger_);
2351 ll_logger_ = new LowLevelLogger(log_file_name.get());
2352 addCodeEventListener(ll_logger_);
2355 ticker_ = new Ticker(isolate, kSamplingIntervalMs);
2357 if (Log::InitLogAtStart()) {
2361 xdk::XDKInitializeForV8(isolate);
2364 profiler_ = new Profiler(isolate);
2366 profiler_->Engage();
2368 if (xdk::XDKIsAgentAlive()) {
2369 // A way to to start profiler in pause mode was removed.
2370 // To pause collection of the CPU ticks we need to emulate pause.
2371 // This will be removed later once XDK agent will have own sampler.
2376 if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
2382 void Logger::SetCodeEventHandler(uint32_t options,
2383 JitCodeEventHandler event_handler) {
2385 removeCodeEventListener(jit_logger_);
2390 if (event_handler) {
2391 jit_logger_ = new JitLogger(event_handler);
2392 addCodeEventListener(jit_logger_);
2393 if (options & kJitCodeEventEnumExisting) {
2394 HandleScope scope(isolate_);
2396 LogCompiledFunctions();
2402 Sampler* Logger::sampler() {
2407 FILE* Logger::TearDown() {
2408 if (!is_initialized_) return NULL;
2409 is_initialized_ = false;
2411 // Stop the profiler before closing the file.
2412 if (profiler_ != NULL) {
2413 profiler_->Disengage();
2421 if (perf_basic_logger_) {
2422 removeCodeEventListener(perf_basic_logger_);
2423 delete perf_basic_logger_;
2424 perf_basic_logger_ = NULL;
2427 if (perf_jit_logger_) {
2428 removeCodeEventListener(perf_jit_logger_);
2429 delete perf_jit_logger_;
2430 perf_jit_logger_ = NULL;
2434 removeCodeEventListener(ll_logger_);
2440 removeCodeEventListener(jit_logger_);
2445 return log_->Close();
2448 } } // namespace v8::internal