• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
4 // met:
5 //
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.
15 //
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.
27 
28 #include <stdarg.h>
29 
30 #include "v8.h"
31 
32 #include "bootstrapper.h"
33 #include "code-stubs.h"
34 #include "cpu-profiler.h"
35 #include "deoptimizer.h"
36 #include "global-handles.h"
37 #include "log.h"
38 #include "log-utils.h"
39 #include "macro-assembler.h"
40 #include "platform.h"
41 #include "runtime-profiler.h"
42 #include "serialize.h"
43 #include "string-stream.h"
44 #include "vm-state-inl.h"
45 
46 namespace v8 {
47 namespace internal {
48 
49 
50 #define DECLARE_EVENT(ignore1, name) name,
51 static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
52   LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
53 };
54 #undef DECLARE_EVENT
55 
56 
57 #define CALL_LISTENERS(Call)                    \
58 for (int i = 0; i < listeners_.length(); ++i) { \
59   listeners_[i]->Call;                          \
60 }
61 
62 #define PROFILER_LOG(Call)                                \
63   do {                                                    \
64     CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
65     if (cpu_profiler->is_profiling()) {                   \
66       cpu_profiler->Call;                                 \
67     }                                                     \
68   } while (false);
69 
70 // ComputeMarker must only be used when SharedFunctionInfo is known.
ComputeMarker(Code * code)71 static const char* ComputeMarker(Code* code) {
72   switch (code->kind()) {
73     case Code::FUNCTION: return code->optimizable() ? "~" : "";
74     case Code::OPTIMIZED_FUNCTION: return "*";
75     default: return "";
76   }
77 }
78 
79 
80 class CodeEventLogger::NameBuffer {
81  public:
NameBuffer()82   NameBuffer() { Reset(); }
83 
Reset()84   void Reset() {
85     utf8_pos_ = 0;
86   }
87 
Init(Logger::LogEventsAndTags tag)88   void Init(Logger::LogEventsAndTags tag) {
89     Reset();
90     AppendBytes(kLogEventsNames[tag]);
91     AppendByte(':');
92   }
93 
AppendName(Name * name)94   void AppendName(Name* name) {
95     if (name->IsString()) {
96       AppendString(String::cast(name));
97     } else {
98       Symbol* symbol = Symbol::cast(name);
99       AppendBytes("symbol(");
100       if (!symbol->name()->IsUndefined()) {
101         AppendBytes("\"");
102         AppendString(String::cast(symbol->name()));
103         AppendBytes("\" ");
104       }
105       AppendBytes("hash ");
106       AppendHex(symbol->Hash());
107       AppendByte(')');
108     }
109   }
110 
AppendString(String * str)111   void AppendString(String* str) {
112     if (str == NULL) return;
113     int uc16_length = Min(str->length(), kUtf16BufferSize);
114     String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
115     int previous = unibrow::Utf16::kNoPreviousCharacter;
116     for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
117       uc16 c = utf16_buffer[i];
118       if (c <= unibrow::Utf8::kMaxOneByteChar) {
119         utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
120       } else {
121         int char_length = unibrow::Utf8::Length(c, previous);
122         if (utf8_pos_ + char_length > kUtf8BufferSize) break;
123         unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
124         utf8_pos_ += char_length;
125       }
126       previous = c;
127     }
128   }
129 
AppendBytes(const char * bytes,int size)130   void AppendBytes(const char* bytes, int size) {
131     size = Min(size, kUtf8BufferSize - utf8_pos_);
132     OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
133     utf8_pos_ += size;
134   }
135 
AppendBytes(const char * bytes)136   void AppendBytes(const char* bytes) {
137     AppendBytes(bytes, StrLength(bytes));
138   }
139 
AppendByte(char c)140   void AppendByte(char c) {
141     if (utf8_pos_ >= kUtf8BufferSize) return;
142     utf8_buffer_[utf8_pos_++] = c;
143   }
144 
AppendInt(int n)145   void AppendInt(int n) {
146     Vector<char> buffer(utf8_buffer_ + utf8_pos_,
147                         kUtf8BufferSize - utf8_pos_);
148     int size = OS::SNPrintF(buffer, "%d", n);
149     if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
150       utf8_pos_ += size;
151     }
152   }
153 
AppendHex(uint32_t n)154   void AppendHex(uint32_t n) {
155     Vector<char> buffer(utf8_buffer_ + utf8_pos_,
156                         kUtf8BufferSize - utf8_pos_);
157     int size = OS::SNPrintF(buffer, "%x", n);
158     if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
159       utf8_pos_ += size;
160     }
161   }
162 
get()163   const char* get() { return utf8_buffer_; }
size() const164   int size() const { return utf8_pos_; }
165 
166  private:
167   static const int kUtf8BufferSize = 512;
168   static const int kUtf16BufferSize = 128;
169 
170   int utf8_pos_;
171   char utf8_buffer_[kUtf8BufferSize];
172   uc16 utf16_buffer[kUtf16BufferSize];
173 };
174 
175 
CodeEventLogger()176 CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
177 
~CodeEventLogger()178 CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
179 
180 
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,const char * comment)181 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
182                                       Code* code,
183                                       const char* comment) {
184   name_buffer_->Init(tag);
185   name_buffer_->AppendBytes(comment);
186   LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
187 }
188 
189 
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,Name * name)190 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
191                                       Code* code,
192                                       Name* name) {
193   name_buffer_->Init(tag);
194   name_buffer_->AppendName(name);
195   LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
196 }
197 
198 
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,SharedFunctionInfo * shared,CompilationInfo * info,Name * name)199 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
200                                       Code* code,
201                                       SharedFunctionInfo* shared,
202                                       CompilationInfo* info,
203                                       Name* name) {
204   name_buffer_->Init(tag);
205   name_buffer_->AppendBytes(ComputeMarker(code));
206   name_buffer_->AppendName(name);
207   LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
208 }
209 
210 
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,SharedFunctionInfo * shared,CompilationInfo * info,Name * source,int line,int column)211 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
212                                       Code* code,
213                                       SharedFunctionInfo* shared,
214                                       CompilationInfo* info,
215                                       Name* source, int line, int column) {
216   name_buffer_->Init(tag);
217   name_buffer_->AppendBytes(ComputeMarker(code));
218   name_buffer_->AppendString(shared->DebugName());
219   name_buffer_->AppendByte(' ');
220   if (source->IsString()) {
221     name_buffer_->AppendString(String::cast(source));
222   } else {
223     name_buffer_->AppendBytes("symbol(hash ");
224     name_buffer_->AppendHex(Name::cast(source)->Hash());
225     name_buffer_->AppendByte(')');
226   }
227   name_buffer_->AppendByte(':');
228   name_buffer_->AppendInt(line);
229   LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
230 }
231 
232 
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,int args_count)233 void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
234                                       Code* code,
235                                       int args_count) {
236   name_buffer_->Init(tag);
237   name_buffer_->AppendInt(args_count);
238   LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
239 }
240 
241 
RegExpCodeCreateEvent(Code * code,String * source)242 void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
243   name_buffer_->Init(Logger::REG_EXP_TAG);
244   name_buffer_->AppendString(source);
245   LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
246 }
247 
248 
249 // Linux perf tool logging support
250 class PerfBasicLogger : public CodeEventLogger {
251  public:
252   PerfBasicLogger();
253   virtual ~PerfBasicLogger();
254 
CodeMoveEvent(Address from,Address to)255   virtual void CodeMoveEvent(Address from, Address to) { }
CodeDeleteEvent(Address from)256   virtual void CodeDeleteEvent(Address from) { }
257 
258  private:
259   virtual void LogRecordedBuffer(Code* code,
260                                  SharedFunctionInfo* shared,
261                                  const char* name,
262                                  int length);
263 
264   // Extension added to V8 log file name to get the low-level log name.
265   static const char kFilenameFormatString[];
266   static const int kFilenameBufferPadding;
267 
268   // File buffer size of the low-level log. We don't use the default to
269   // minimize the associated overhead.
270   static const int kLogBufferSize = 2 * MB;
271 
272   FILE* perf_output_handle_;
273 };
274 
275 const char PerfBasicLogger::kFilenameFormatString[] = "/tmp/perf-%d.map";
276 // Extra space for the PID in the filename
277 const int PerfBasicLogger::kFilenameBufferPadding = 16;
278 
PerfBasicLogger()279 PerfBasicLogger::PerfBasicLogger()
280     : perf_output_handle_(NULL) {
281   // Open the perf JIT dump file.
282   int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
283   ScopedVector<char> perf_dump_name(bufferSize);
284   int size = OS::SNPrintF(
285       perf_dump_name,
286       kFilenameFormatString,
287       OS::GetCurrentProcessId());
288   CHECK_NE(size, -1);
289   perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode);
290   CHECK_NE(perf_output_handle_, NULL);
291   setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
292 }
293 
294 
~PerfBasicLogger()295 PerfBasicLogger::~PerfBasicLogger() {
296   fclose(perf_output_handle_);
297   perf_output_handle_ = NULL;
298 }
299 
300 
LogRecordedBuffer(Code * code,SharedFunctionInfo *,const char * name,int length)301 void PerfBasicLogger::LogRecordedBuffer(Code* code,
302                                        SharedFunctionInfo*,
303                                        const char* name,
304                                        int length) {
305   ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize);
306 
307   OS::FPrint(perf_output_handle_, "%llx %x %.*s\n",
308       reinterpret_cast<uint64_t>(code->instruction_start()),
309       code->instruction_size(),
310       length, name);
311 }
312 
313 
314 // Linux perf tool logging support
315 class PerfJitLogger : public CodeEventLogger {
316  public:
317   PerfJitLogger();
318   virtual ~PerfJitLogger();
319 
CodeMoveEvent(Address from,Address to)320   virtual void CodeMoveEvent(Address from, Address to) { }
CodeDeleteEvent(Address from)321   virtual void CodeDeleteEvent(Address from) { }
322 
323  private:
324   virtual void LogRecordedBuffer(Code* code,
325                                  SharedFunctionInfo* shared,
326                                  const char* name,
327                                  int length);
328 
329   // Extension added to V8 log file name to get the low-level log name.
330   static const char kFilenameFormatString[];
331   static const int kFilenameBufferPadding;
332 
333   // File buffer size of the low-level log. We don't use the default to
334   // minimize the associated overhead.
335   static const int kLogBufferSize = 2 * MB;
336 
337   void LogWriteBytes(const char* bytes, int size);
338   void LogWriteHeader();
339 
340   static const uint32_t kJitHeaderMagic = 0x4F74496A;
341   static const uint32_t kJitHeaderVersion = 0x2;
342   static const uint32_t kElfMachIA32 = 3;
343   static const uint32_t kElfMachX64 = 62;
344   static const uint32_t kElfMachARM = 40;
345   static const uint32_t kElfMachMIPS = 10;
346 
347   struct jitheader {
348     uint32_t magic;
349     uint32_t version;
350     uint32_t total_size;
351     uint32_t elf_mach;
352     uint32_t pad1;
353     uint32_t pid;
354     uint64_t timestamp;
355   };
356 
357   enum jit_record_type {
358     JIT_CODE_LOAD = 0
359     // JIT_CODE_UNLOAD = 1,
360     // JIT_CODE_CLOSE = 2,
361     // JIT_CODE_DEBUG_INFO = 3,
362     // JIT_CODE_PAGE_MAP = 4,
363     // JIT_CODE_MAX = 5
364   };
365 
366   struct jr_code_load {
367     uint32_t id;
368     uint32_t total_size;
369     uint64_t timestamp;
370     uint64_t vma;
371     uint64_t code_addr;
372     uint32_t code_size;
373     uint32_t align;
374   };
375 
GetElfMach()376   uint32_t GetElfMach() {
377 #if V8_TARGET_ARCH_IA32
378     return kElfMachIA32;
379 #elif V8_TARGET_ARCH_X64
380     return kElfMachX64;
381 #elif V8_TARGET_ARCH_ARM
382     return kElfMachARM;
383 #elif V8_TARGET_ARCH_MIPS
384     return kElfMachMIPS;
385 #else
386     UNIMPLEMENTED();
387     return 0;
388 #endif
389   }
390 
391   FILE* perf_output_handle_;
392 };
393 
394 const char PerfJitLogger::kFilenameFormatString[] = "/tmp/jit-%d.dump";
395 
396 // Extra padding for the PID in the filename
397 const int PerfJitLogger::kFilenameBufferPadding = 16;
398 
PerfJitLogger()399 PerfJitLogger::PerfJitLogger()
400     : perf_output_handle_(NULL) {
401   // Open the perf JIT dump file.
402   int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
403   ScopedVector<char> perf_dump_name(bufferSize);
404   int size = OS::SNPrintF(
405       perf_dump_name,
406       kFilenameFormatString,
407       OS::GetCurrentProcessId());
408   CHECK_NE(size, -1);
409   perf_output_handle_ = OS::FOpen(perf_dump_name.start(), OS::LogFileOpenMode);
410   CHECK_NE(perf_output_handle_, NULL);
411   setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
412 
413   LogWriteHeader();
414 }
415 
416 
~PerfJitLogger()417 PerfJitLogger::~PerfJitLogger() {
418   fclose(perf_output_handle_);
419   perf_output_handle_ = NULL;
420 }
421 
422 
LogRecordedBuffer(Code * code,SharedFunctionInfo *,const char * name,int length)423 void PerfJitLogger::LogRecordedBuffer(Code* code,
424                                       SharedFunctionInfo*,
425                                       const char* name,
426                                       int length) {
427   ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize);
428   ASSERT(perf_output_handle_ != NULL);
429 
430   const char* code_name = name;
431   uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start());
432   uint32_t code_size = code->instruction_size();
433 
434   static const char string_terminator[] = "\0";
435 
436   jr_code_load code_load;
437   code_load.id = JIT_CODE_LOAD;
438   code_load.total_size = sizeof(code_load) + length + 1 + code_size;
439   code_load.timestamp =
440       static_cast<uint64_t>(OS::TimeCurrentMillis() * 1000.0);
441   code_load.vma = 0x0;  //  Our addresses are absolute.
442   code_load.code_addr = reinterpret_cast<uint64_t>(code->instruction_start());
443   code_load.code_size = code_size;
444   code_load.align = 0;
445 
446   LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load));
447   LogWriteBytes(code_name, length);
448   LogWriteBytes(string_terminator, 1);
449   LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size);
450 }
451 
452 
LogWriteBytes(const char * bytes,int size)453 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) {
454   size_t rv = fwrite(bytes, 1, size, perf_output_handle_);
455   ASSERT(static_cast<size_t>(size) == rv);
456   USE(rv);
457 }
458 
459 
LogWriteHeader()460 void PerfJitLogger::LogWriteHeader() {
461   ASSERT(perf_output_handle_ != NULL);
462   jitheader header;
463   header.magic = kJitHeaderMagic;
464   header.version = kJitHeaderVersion;
465   header.total_size = sizeof(jitheader);
466   header.pad1 = 0xdeadbeef;
467   header.elf_mach = GetElfMach();
468   header.pid = OS::GetCurrentProcessId();
469   header.timestamp = static_cast<uint64_t>(OS::TimeCurrentMillis() * 1000.0);
470   LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header));
471 }
472 
473 
474 // Low-level logging support.
475 #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
476 
477 class LowLevelLogger : public CodeEventLogger {
478  public:
479   explicit LowLevelLogger(const char* file_name);
480   virtual ~LowLevelLogger();
481 
482   virtual void CodeMoveEvent(Address from, Address to);
483   virtual void CodeDeleteEvent(Address from);
484   virtual void SnapshotPositionEvent(Address addr, int pos);
485   virtual void CodeMovingGCEvent();
486 
487  private:
488   virtual void LogRecordedBuffer(Code* code,
489                                  SharedFunctionInfo* shared,
490                                  const char* name,
491                                  int length);
492 
493   // Low-level profiling event structures.
494   struct CodeCreateStruct {
495     static const char kTag = 'C';
496 
497     int32_t name_size;
498     Address code_address;
499     int32_t code_size;
500   };
501 
502 
503   struct CodeMoveStruct {
504     static const char kTag = 'M';
505 
506     Address from_address;
507     Address to_address;
508   };
509 
510 
511   struct CodeDeleteStruct {
512     static const char kTag = 'D';
513 
514     Address address;
515   };
516 
517 
518   struct SnapshotPositionStruct {
519     static const char kTag = 'P';
520 
521     Address address;
522     int32_t position;
523   };
524 
525 
526   static const char kCodeMovingGCTag = 'G';
527 
528 
529   // Extension added to V8 log file name to get the low-level log name.
530   static const char kLogExt[];
531 
532   // File buffer size of the low-level log. We don't use the default to
533   // minimize the associated overhead.
534   static const int kLogBufferSize = 2 * MB;
535 
536   void LogCodeInfo();
537   void LogWriteBytes(const char* bytes, int size);
538 
539   template <typename T>
LogWriteStruct(const T & s)540   void LogWriteStruct(const T& s) {
541     char tag = T::kTag;
542     LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
543     LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
544   }
545 
546   FILE* ll_output_handle_;
547 };
548 
549 const char LowLevelLogger::kLogExt[] = ".ll";
550 
LowLevelLogger(const char * name)551 LowLevelLogger::LowLevelLogger(const char* name)
552     : ll_output_handle_(NULL) {
553   // Open the low-level log file.
554   size_t len = strlen(name);
555   ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
556   OS::MemCopy(ll_name.start(), name, len);
557   OS::MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
558   ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
559   setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize);
560 
561   LogCodeInfo();
562 }
563 
564 
~LowLevelLogger()565 LowLevelLogger::~LowLevelLogger() {
566   fclose(ll_output_handle_);
567   ll_output_handle_ = NULL;
568 }
569 
570 
LogCodeInfo()571 void LowLevelLogger::LogCodeInfo() {
572 #if V8_TARGET_ARCH_IA32
573   const char arch[] = "ia32";
574 #elif V8_TARGET_ARCH_X64
575   const char arch[] = "x64";
576 #elif V8_TARGET_ARCH_ARM
577   const char arch[] = "arm";
578 #elif V8_TARGET_ARCH_MIPS
579   const char arch[] = "mips";
580 #else
581   const char arch[] = "unknown";
582 #endif
583   LogWriteBytes(arch, sizeof(arch));
584 }
585 
586 
LogRecordedBuffer(Code * code,SharedFunctionInfo *,const char * name,int length)587 void LowLevelLogger::LogRecordedBuffer(Code* code,
588                                        SharedFunctionInfo*,
589                                        const char* name,
590                                        int length) {
591   CodeCreateStruct event;
592   event.name_size = length;
593   event.code_address = code->instruction_start();
594   ASSERT(event.code_address == code->address() + Code::kHeaderSize);
595   event.code_size = code->instruction_size();
596   LogWriteStruct(event);
597   LogWriteBytes(name, length);
598   LogWriteBytes(
599       reinterpret_cast<const char*>(code->instruction_start()),
600       code->instruction_size());
601 }
602 
603 
CodeMoveEvent(Address from,Address to)604 void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
605   CodeMoveStruct event;
606   event.from_address = from + Code::kHeaderSize;
607   event.to_address = to + Code::kHeaderSize;
608   LogWriteStruct(event);
609 }
610 
611 
CodeDeleteEvent(Address from)612 void LowLevelLogger::CodeDeleteEvent(Address from) {
613   CodeDeleteStruct event;
614   event.address = from + Code::kHeaderSize;
615   LogWriteStruct(event);
616 }
617 
618 
SnapshotPositionEvent(Address addr,int pos)619 void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
620   SnapshotPositionStruct event;
621   event.address = addr + Code::kHeaderSize;
622   event.position = pos;
623   LogWriteStruct(event);
624 }
625 
626 
LogWriteBytes(const char * bytes,int size)627 void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
628   size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
629   ASSERT(static_cast<size_t>(size) == rv);
630   USE(rv);
631 }
632 
633 
CodeMovingGCEvent()634 void LowLevelLogger::CodeMovingGCEvent() {
635   const char tag = kCodeMovingGCTag;
636 
637   LogWriteBytes(&tag, sizeof(tag));
638 }
639 
640 
641 #define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
642 
643 
644 class JitLogger : public CodeEventLogger {
645  public:
646   explicit JitLogger(JitCodeEventHandler code_event_handler);
647 
648   virtual void CodeMoveEvent(Address from, Address to);
649   virtual void CodeDeleteEvent(Address from);
650   virtual void AddCodeLinePosInfoEvent(
651       void* jit_handler_data,
652       int pc_offset,
653       int position,
654       JitCodeEvent::PositionType position_type);
655 
656   void* StartCodePosInfoEvent();
657   void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
658 
659  private:
660   virtual void LogRecordedBuffer(Code* code,
661                                  SharedFunctionInfo* shared,
662                                  const char* name,
663                                  int length);
664 
665   JitCodeEventHandler code_event_handler_;
666 };
667 
668 
JitLogger(JitCodeEventHandler code_event_handler)669 JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
670     : code_event_handler_(code_event_handler) {
671 }
672 
673 
LogRecordedBuffer(Code * code,SharedFunctionInfo * shared,const char * name,int length)674 void JitLogger::LogRecordedBuffer(Code* code,
675                                   SharedFunctionInfo* shared,
676                                   const char* name,
677                                   int length) {
678   JitCodeEvent event;
679   memset(&event, 0, sizeof(event));
680   event.type = JitCodeEvent::CODE_ADDED;
681   event.code_start = code->instruction_start();
682   event.code_len = code->instruction_size();
683   Handle<Script> script_handle;
684   if (shared && shared->script()->IsScript()) {
685     script_handle = Handle<Script>(Script::cast(shared->script()));
686   }
687   event.script = ToApiHandle<v8::Script>(script_handle);
688   event.name.str = name;
689   event.name.len = length;
690   code_event_handler_(&event);
691 }
692 
693 
CodeMoveEvent(Address from,Address to)694 void JitLogger::CodeMoveEvent(Address from, Address to) {
695   Code* from_code = Code::cast(HeapObject::FromAddress(from));
696 
697   JitCodeEvent event;
698   event.type = JitCodeEvent::CODE_MOVED;
699   event.code_start = from_code->instruction_start();
700   event.code_len = from_code->instruction_size();
701 
702   // Calculate the header size.
703   const size_t header_size =
704       from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
705 
706   // Calculate the new start address of the instructions.
707   event.new_code_start =
708       reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
709 
710   code_event_handler_(&event);
711 }
712 
713 
CodeDeleteEvent(Address from)714 void JitLogger::CodeDeleteEvent(Address from) {
715   Code* from_code = Code::cast(HeapObject::FromAddress(from));
716 
717   JitCodeEvent event;
718   event.type = JitCodeEvent::CODE_REMOVED;
719   event.code_start = from_code->instruction_start();
720   event.code_len = from_code->instruction_size();
721 
722   code_event_handler_(&event);
723 }
724 
AddCodeLinePosInfoEvent(void * jit_handler_data,int pc_offset,int position,JitCodeEvent::PositionType position_type)725 void JitLogger::AddCodeLinePosInfoEvent(
726     void* jit_handler_data,
727     int pc_offset,
728     int position,
729     JitCodeEvent::PositionType position_type) {
730   JitCodeEvent event;
731   memset(&event, 0, sizeof(event));
732   event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
733   event.user_data = jit_handler_data;
734   event.line_info.offset = pc_offset;
735   event.line_info.pos = position;
736   event.line_info.position_type = position_type;
737 
738   code_event_handler_(&event);
739 }
740 
741 
StartCodePosInfoEvent()742 void* JitLogger::StartCodePosInfoEvent() {
743   JitCodeEvent event;
744   memset(&event, 0, sizeof(event));
745   event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
746 
747   code_event_handler_(&event);
748   return event.user_data;
749 }
750 
751 
EndCodePosInfoEvent(Code * code,void * jit_handler_data)752 void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) {
753   JitCodeEvent event;
754   memset(&event, 0, sizeof(event));
755   event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
756   event.code_start = code->instruction_start();
757   event.user_data = jit_handler_data;
758 
759   code_event_handler_(&event);
760 }
761 
762 
763 // The Profiler samples pc and sp values for the main thread.
764 // Each sample is appended to a circular buffer.
765 // An independent thread removes data and writes it to the log.
766 // This design minimizes the time spent in the sampler.
767 //
768 class Profiler: public Thread {
769  public:
770   explicit Profiler(Isolate* isolate);
771   void Engage();
772   void Disengage();
773 
774   // Inserts collected profiling data into buffer.
Insert(TickSample * sample)775   void Insert(TickSample* sample) {
776     if (paused_)
777       return;
778 
779     if (Succ(head_) == tail_) {
780       overflow_ = true;
781     } else {
782       buffer_[head_] = *sample;
783       head_ = Succ(head_);
784       buffer_semaphore_.Signal();  // Tell we have an element.
785     }
786   }
787 
788   virtual void Run();
789 
790   // Pause and Resume TickSample data collection.
pause()791   void pause() { paused_ = true; }
resume()792   void resume() { paused_ = false; }
793 
794  private:
795   // Waits for a signal and removes profiling data.
Remove(TickSample * sample)796   bool Remove(TickSample* sample) {
797     buffer_semaphore_.Wait();  // Wait for an element.
798     *sample = buffer_[tail_];
799     bool result = overflow_;
800     tail_ = Succ(tail_);
801     overflow_ = false;
802     return result;
803   }
804 
805   // Returns the next index in the cyclic buffer.
Succ(int index)806   int Succ(int index) { return (index + 1) % kBufferSize; }
807 
808   Isolate* isolate_;
809   // Cyclic buffer for communicating profiling samples
810   // between the signal handler and the worker thread.
811   static const int kBufferSize = 128;
812   TickSample buffer_[kBufferSize];  // Buffer storage.
813   int head_;  // Index to the buffer head.
814   int tail_;  // Index to the buffer tail.
815   bool overflow_;  // Tell whether a buffer overflow has occurred.
816   // Sempahore used for buffer synchronization.
817   Semaphore buffer_semaphore_;
818 
819   // Tells whether profiler is engaged, that is, processing thread is stated.
820   bool engaged_;
821 
822   // Tells whether worker thread should continue running.
823   bool running_;
824 
825   // Tells whether we are currently recording tick samples.
826   bool paused_;
827 };
828 
829 
830 //
831 // Ticker used to provide ticks to the profiler and the sliding state
832 // window.
833 //
834 class Ticker: public Sampler {
835  public:
Ticker(Isolate * isolate,int interval)836   Ticker(Isolate* isolate, int interval):
837       Sampler(isolate, interval),
838       profiler_(NULL) {}
839 
~Ticker()840   ~Ticker() { if (IsActive()) Stop(); }
841 
Tick(TickSample * sample)842   virtual void Tick(TickSample* sample) {
843     if (profiler_) profiler_->Insert(sample);
844   }
845 
SetProfiler(Profiler * profiler)846   void SetProfiler(Profiler* profiler) {
847     ASSERT(profiler_ == NULL);
848     profiler_ = profiler;
849     IncreaseProfilingDepth();
850     if (!IsActive()) Start();
851   }
852 
ClearProfiler()853   void ClearProfiler() {
854     profiler_ = NULL;
855     if (IsActive()) Stop();
856     DecreaseProfilingDepth();
857   }
858 
859  private:
860   Profiler* profiler_;
861 };
862 
863 
864 //
865 // Profiler implementation.
866 //
Profiler(Isolate * isolate)867 Profiler::Profiler(Isolate* isolate)
868     : Thread("v8:Profiler"),
869       isolate_(isolate),
870       head_(0),
871       tail_(0),
872       overflow_(false),
873       buffer_semaphore_(0),
874       engaged_(false),
875       running_(false),
876       paused_(false) {
877 }
878 
879 
Engage()880 void Profiler::Engage() {
881   if (engaged_) return;
882   engaged_ = true;
883 
884   OS::LogSharedLibraryAddresses(isolate_);
885 
886   // Start thread processing the profiler buffer.
887   running_ = true;
888   Start();
889 
890   // Register to get ticks.
891   Logger* logger = isolate_->logger();
892   logger->ticker_->SetProfiler(this);
893 
894   logger->ProfilerBeginEvent();
895 }
896 
897 
Disengage()898 void Profiler::Disengage() {
899   if (!engaged_) return;
900 
901   // Stop receiving ticks.
902   isolate_->logger()->ticker_->ClearProfiler();
903 
904   // Terminate the worker thread by setting running_ to false,
905   // inserting a fake element in the queue and then wait for
906   // the thread to terminate.
907   running_ = false;
908   TickSample sample;
909   // Reset 'paused_' flag, otherwise semaphore may not be signalled.
910   resume();
911   Insert(&sample);
912   Join();
913 
914   LOG(isolate_, UncheckedStringEvent("profiler", "end"));
915 }
916 
917 
Run()918 void Profiler::Run() {
919   TickSample sample;
920   bool overflow = Remove(&sample);
921   while (running_) {
922     LOG(isolate_, TickEvent(&sample, overflow));
923     overflow = Remove(&sample);
924   }
925 }
926 
927 
928 //
929 // Logger class implementation.
930 //
931 
Logger(Isolate * isolate)932 Logger::Logger(Isolate* isolate)
933   : isolate_(isolate),
934     ticker_(NULL),
935     profiler_(NULL),
936     log_events_(NULL),
937     is_logging_(false),
938     log_(new Log(this)),
939     perf_basic_logger_(NULL),
940     perf_jit_logger_(NULL),
941     ll_logger_(NULL),
942     jit_logger_(NULL),
943     listeners_(5),
944     is_initialized_(false) {
945 }
946 
947 
~Logger()948 Logger::~Logger() {
949   delete log_;
950 }
951 
952 
addCodeEventListener(CodeEventListener * listener)953 void Logger::addCodeEventListener(CodeEventListener* listener) {
954   ASSERT(!hasCodeEventListener(listener));
955   listeners_.Add(listener);
956 }
957 
958 
removeCodeEventListener(CodeEventListener * listener)959 void Logger::removeCodeEventListener(CodeEventListener* listener) {
960   ASSERT(hasCodeEventListener(listener));
961   listeners_.RemoveElement(listener);
962 }
963 
964 
hasCodeEventListener(CodeEventListener * listener)965 bool Logger::hasCodeEventListener(CodeEventListener* listener) {
966   return listeners_.Contains(listener);
967 }
968 
969 
ProfilerBeginEvent()970 void Logger::ProfilerBeginEvent() {
971   if (!log_->IsEnabled()) return;
972   Log::MessageBuilder msg(log_);
973   msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
974   msg.WriteToLogFile();
975 }
976 
977 
StringEvent(const char * name,const char * value)978 void Logger::StringEvent(const char* name, const char* value) {
979   if (FLAG_log) UncheckedStringEvent(name, value);
980 }
981 
982 
UncheckedStringEvent(const char * name,const char * value)983 void Logger::UncheckedStringEvent(const char* name, const char* value) {
984   if (!log_->IsEnabled()) return;
985   Log::MessageBuilder msg(log_);
986   msg.Append("%s,\"%s\"\n", name, value);
987   msg.WriteToLogFile();
988 }
989 
990 
IntEvent(const char * name,int value)991 void Logger::IntEvent(const char* name, int value) {
992   if (FLAG_log) UncheckedIntEvent(name, value);
993 }
994 
995 
IntPtrTEvent(const char * name,intptr_t value)996 void Logger::IntPtrTEvent(const char* name, intptr_t value) {
997   if (FLAG_log) UncheckedIntPtrTEvent(name, value);
998 }
999 
1000 
UncheckedIntEvent(const char * name,int value)1001 void Logger::UncheckedIntEvent(const char* name, int value) {
1002   if (!log_->IsEnabled()) return;
1003   Log::MessageBuilder msg(log_);
1004   msg.Append("%s,%d\n", name, value);
1005   msg.WriteToLogFile();
1006 }
1007 
1008 
UncheckedIntPtrTEvent(const char * name,intptr_t value)1009 void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
1010   if (!log_->IsEnabled()) return;
1011   Log::MessageBuilder msg(log_);
1012   msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
1013   msg.WriteToLogFile();
1014 }
1015 
1016 
HandleEvent(const char * name,Object ** location)1017 void Logger::HandleEvent(const char* name, Object** location) {
1018   if (!log_->IsEnabled() || !FLAG_log_handles) return;
1019   Log::MessageBuilder msg(log_);
1020   msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
1021   msg.WriteToLogFile();
1022 }
1023 
1024 
1025 // ApiEvent is private so all the calls come from the Logger class.  It is the
1026 // caller's responsibility to ensure that log is enabled and that
1027 // FLAG_log_api is true.
ApiEvent(const char * format,...)1028 void Logger::ApiEvent(const char* format, ...) {
1029   ASSERT(log_->IsEnabled() && FLAG_log_api);
1030   Log::MessageBuilder msg(log_);
1031   va_list ap;
1032   va_start(ap, format);
1033   msg.AppendVA(format, ap);
1034   va_end(ap);
1035   msg.WriteToLogFile();
1036 }
1037 
1038 
ApiNamedSecurityCheck(Object * key)1039 void Logger::ApiNamedSecurityCheck(Object* key) {
1040   if (!log_->IsEnabled() || !FLAG_log_api) return;
1041   if (key->IsString()) {
1042     SmartArrayPointer<char> str =
1043         String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1044     ApiEvent("api,check-security,\"%s\"\n", *str);
1045   } else if (key->IsSymbol()) {
1046     Symbol* symbol = Symbol::cast(key);
1047     if (symbol->name()->IsUndefined()) {
1048       ApiEvent("api,check-security,symbol(hash %x)\n",
1049                Symbol::cast(key)->Hash());
1050     } else {
1051       SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1052           DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1053       ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n",
1054                *str,
1055                Symbol::cast(key)->Hash());
1056     }
1057   } else if (key->IsUndefined()) {
1058     ApiEvent("api,check-security,undefined\n");
1059   } else {
1060     ApiEvent("api,check-security,['no-name']\n");
1061   }
1062 }
1063 
1064 
SharedLibraryEvent(const char * library_path,uintptr_t start,uintptr_t end)1065 void Logger::SharedLibraryEvent(const char* library_path,
1066                                 uintptr_t start,
1067                                 uintptr_t end) {
1068   if (!log_->IsEnabled() || !FLAG_prof) return;
1069   Log::MessageBuilder msg(log_);
1070   msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
1071              library_path,
1072              start,
1073              end);
1074   msg.WriteToLogFile();
1075 }
1076 
1077 
SharedLibraryEvent(const wchar_t * library_path,uintptr_t start,uintptr_t end)1078 void Logger::SharedLibraryEvent(const wchar_t* library_path,
1079                                 uintptr_t start,
1080                                 uintptr_t end) {
1081   if (!log_->IsEnabled() || !FLAG_prof) return;
1082   Log::MessageBuilder msg(log_);
1083   msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
1084              library_path,
1085              start,
1086              end);
1087   msg.WriteToLogFile();
1088 }
1089 
1090 
CodeDeoptEvent(Code * code)1091 void Logger::CodeDeoptEvent(Code* code) {
1092   if (!log_->IsEnabled()) return;
1093   ASSERT(FLAG_log_internal_timer_events);
1094   Log::MessageBuilder msg(log_);
1095   int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
1096   msg.Append("code-deopt,%ld,%d\n", since_epoch, code->CodeSize());
1097   msg.WriteToLogFile();
1098 }
1099 
1100 
TimerEvent(StartEnd se,const char * name)1101 void Logger::TimerEvent(StartEnd se, const char* name) {
1102   if (!log_->IsEnabled()) return;
1103   ASSERT(FLAG_log_internal_timer_events);
1104   Log::MessageBuilder msg(log_);
1105   int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
1106   const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n"
1107                                      : "timer-event-end,\"%s\",%ld\n";
1108   msg.Append(format, name, since_epoch);
1109   msg.WriteToLogFile();
1110 }
1111 
1112 
EnterExternal(Isolate * isolate)1113 void Logger::EnterExternal(Isolate* isolate) {
1114   LOG(isolate, TimerEvent(START, TimerEventScope::v8_external));
1115   ASSERT(isolate->current_vm_state() == JS);
1116   isolate->set_current_vm_state(EXTERNAL);
1117 }
1118 
1119 
LeaveExternal(Isolate * isolate)1120 void Logger::LeaveExternal(Isolate* isolate) {
1121   LOG(isolate, TimerEvent(END, TimerEventScope::v8_external));
1122   ASSERT(isolate->current_vm_state() == EXTERNAL);
1123   isolate->set_current_vm_state(JS);
1124 }
1125 
1126 
LogTimerEvent(StartEnd se)1127 void Logger::TimerEventScope::LogTimerEvent(StartEnd se) {
1128   LOG(isolate_, TimerEvent(se, name_));
1129 }
1130 
1131 
1132 const char* Logger::TimerEventScope::v8_recompile_synchronous =
1133     "V8.RecompileSynchronous";
1134 const char* Logger::TimerEventScope::v8_recompile_concurrent =
1135     "V8.RecompileConcurrent";
1136 const char* Logger::TimerEventScope::v8_compile_full_code =
1137     "V8.CompileFullCode";
1138 const char* Logger::TimerEventScope::v8_execute = "V8.Execute";
1139 const char* Logger::TimerEventScope::v8_external = "V8.External";
1140 
1141 
LogRegExpSource(Handle<JSRegExp> regexp)1142 void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
1143   // Prints "/" + re.source + "/" +
1144   //      (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
1145   Log::MessageBuilder msg(log_);
1146 
1147   Handle<Object> source = GetProperty(regexp, "source");
1148   if (!source->IsString()) {
1149     msg.Append("no source");
1150     return;
1151   }
1152 
1153   switch (regexp->TypeTag()) {
1154     case JSRegExp::ATOM:
1155       msg.Append('a');
1156       break;
1157     default:
1158       break;
1159   }
1160   msg.Append('/');
1161   msg.AppendDetailed(*Handle<String>::cast(source), false);
1162   msg.Append('/');
1163 
1164   // global flag
1165   Handle<Object> global = GetProperty(regexp, "global");
1166   if (global->IsTrue()) {
1167     msg.Append('g');
1168   }
1169   // ignorecase flag
1170   Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
1171   if (ignorecase->IsTrue()) {
1172     msg.Append('i');
1173   }
1174   // multiline flag
1175   Handle<Object> multiline = GetProperty(regexp, "multiline");
1176   if (multiline->IsTrue()) {
1177     msg.Append('m');
1178   }
1179 
1180   msg.WriteToLogFile();
1181 }
1182 
1183 
RegExpCompileEvent(Handle<JSRegExp> regexp,bool in_cache)1184 void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
1185   if (!log_->IsEnabled() || !FLAG_log_regexp) return;
1186   Log::MessageBuilder msg(log_);
1187   msg.Append("regexp-compile,");
1188   LogRegExpSource(regexp);
1189   msg.Append(in_cache ? ",hit\n" : ",miss\n");
1190   msg.WriteToLogFile();
1191 }
1192 
1193 
LogRuntime(Vector<const char> format,JSArray * args)1194 void Logger::LogRuntime(Vector<const char> format,
1195                         JSArray* args) {
1196   if (!log_->IsEnabled() || !FLAG_log_runtime) return;
1197   HandleScope scope(isolate_);
1198   Log::MessageBuilder msg(log_);
1199   for (int i = 0; i < format.length(); i++) {
1200     char c = format[i];
1201     if (c == '%' && i <= format.length() - 2) {
1202       i++;
1203       ASSERT('0' <= format[i] && format[i] <= '9');
1204       MaybeObject* maybe = args->GetElement(isolate_, format[i] - '0');
1205       Object* obj;
1206       if (!maybe->ToObject(&obj)) {
1207         msg.Append("<exception>");
1208         continue;
1209       }
1210       i++;
1211       switch (format[i]) {
1212         case 's':
1213           msg.AppendDetailed(String::cast(obj), false);
1214           break;
1215         case 'S':
1216           msg.AppendDetailed(String::cast(obj), true);
1217           break;
1218         case 'r':
1219           Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
1220           break;
1221         case 'x':
1222           msg.Append("0x%x", Smi::cast(obj)->value());
1223           break;
1224         case 'i':
1225           msg.Append("%i", Smi::cast(obj)->value());
1226           break;
1227         default:
1228           UNREACHABLE();
1229       }
1230     } else {
1231       msg.Append(c);
1232     }
1233   }
1234   msg.Append('\n');
1235   msg.WriteToLogFile();
1236 }
1237 
1238 
ApiIndexedSecurityCheck(uint32_t index)1239 void Logger::ApiIndexedSecurityCheck(uint32_t index) {
1240   if (!log_->IsEnabled() || !FLAG_log_api) return;
1241   ApiEvent("api,check-security,%u\n", index);
1242 }
1243 
1244 
ApiNamedPropertyAccess(const char * tag,JSObject * holder,Object * name)1245 void Logger::ApiNamedPropertyAccess(const char* tag,
1246                                     JSObject* holder,
1247                                     Object* name) {
1248   ASSERT(name->IsName());
1249   if (!log_->IsEnabled() || !FLAG_log_api) return;
1250   String* class_name_obj = holder->class_name();
1251   SmartArrayPointer<char> class_name =
1252       class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1253   if (name->IsString()) {
1254     SmartArrayPointer<char> property_name =
1255         String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1256     ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
1257   } else {
1258     Symbol* symbol = Symbol::cast(name);
1259     uint32_t hash = symbol->Hash();
1260     if (symbol->name()->IsUndefined()) {
1261       ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
1262     } else {
1263       SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1264           DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1265       ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n",
1266                tag, *class_name, *str, hash);
1267     }
1268   }
1269 }
1270 
ApiIndexedPropertyAccess(const char * tag,JSObject * holder,uint32_t index)1271 void Logger::ApiIndexedPropertyAccess(const char* tag,
1272                                       JSObject* holder,
1273                                       uint32_t index) {
1274   if (!log_->IsEnabled() || !FLAG_log_api) return;
1275   String* class_name_obj = holder->class_name();
1276   SmartArrayPointer<char> class_name =
1277       class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1278   ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
1279 }
1280 
1281 
ApiObjectAccess(const char * tag,JSObject * object)1282 void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
1283   if (!log_->IsEnabled() || !FLAG_log_api) return;
1284   String* class_name_obj = object->class_name();
1285   SmartArrayPointer<char> class_name =
1286       class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1287   ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
1288 }
1289 
1290 
ApiEntryCall(const char * name)1291 void Logger::ApiEntryCall(const char* name) {
1292   if (!log_->IsEnabled() || !FLAG_log_api) return;
1293   ApiEvent("api,%s\n", name);
1294 }
1295 
1296 
NewEvent(const char * name,void * object,size_t size)1297 void Logger::NewEvent(const char* name, void* object, size_t size) {
1298   if (!log_->IsEnabled() || !FLAG_log) return;
1299   Log::MessageBuilder msg(log_);
1300   msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
1301              static_cast<unsigned int>(size));
1302   msg.WriteToLogFile();
1303 }
1304 
1305 
DeleteEvent(const char * name,void * object)1306 void Logger::DeleteEvent(const char* name, void* object) {
1307   if (!log_->IsEnabled() || !FLAG_log) return;
1308   Log::MessageBuilder msg(log_);
1309   msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
1310   msg.WriteToLogFile();
1311 }
1312 
1313 
NewEventStatic(const char * name,void * object,size_t size)1314 void Logger::NewEventStatic(const char* name, void* object, size_t size) {
1315   Isolate::Current()->logger()->NewEvent(name, object, size);
1316 }
1317 
1318 
DeleteEventStatic(const char * name,void * object)1319 void Logger::DeleteEventStatic(const char* name, void* object) {
1320   Isolate::Current()->logger()->DeleteEvent(name, object);
1321 }
1322 
1323 
CallbackEventInternal(const char * prefix,Name * name,Address entry_point)1324 void Logger::CallbackEventInternal(const char* prefix, Name* name,
1325                                    Address entry_point) {
1326   if (!FLAG_log_code || !log_->IsEnabled()) return;
1327   Log::MessageBuilder msg(log_);
1328   msg.Append("%s,%s,-2,",
1329              kLogEventsNames[CODE_CREATION_EVENT],
1330              kLogEventsNames[CALLBACK_TAG]);
1331   msg.AppendAddress(entry_point);
1332   if (name->IsString()) {
1333     SmartArrayPointer<char> str =
1334         String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1335     msg.Append(",1,\"%s%s\"", prefix, *str);
1336   } else {
1337     Symbol* symbol = Symbol::cast(name);
1338     if (symbol->name()->IsUndefined()) {
1339       msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
1340     } else {
1341       SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1342           DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1343       msg.Append(",1,symbol(\"%s\" hash %x)", prefix, *str, symbol->Hash());
1344     }
1345   }
1346   msg.Append('\n');
1347   msg.WriteToLogFile();
1348 }
1349 
1350 
CallbackEvent(Name * name,Address entry_point)1351 void Logger::CallbackEvent(Name* name, Address entry_point) {
1352   PROFILER_LOG(CallbackEvent(name, entry_point));
1353   CallbackEventInternal("", name, entry_point);
1354 }
1355 
1356 
GetterCallbackEvent(Name * name,Address entry_point)1357 void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
1358   PROFILER_LOG(GetterCallbackEvent(name, entry_point));
1359   CallbackEventInternal("get ", name, entry_point);
1360 }
1361 
1362 
SetterCallbackEvent(Name * name,Address entry_point)1363 void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
1364   PROFILER_LOG(SetterCallbackEvent(name, entry_point));
1365   CallbackEventInternal("set ", name, entry_point);
1366 }
1367 
1368 
AppendCodeCreateHeader(Log::MessageBuilder * msg,Logger::LogEventsAndTags tag,Code * code)1369 static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
1370                                    Logger::LogEventsAndTags tag,
1371                                    Code* code) {
1372   ASSERT(msg);
1373   msg->Append("%s,%s,%d,",
1374               kLogEventsNames[Logger::CODE_CREATION_EVENT],
1375               kLogEventsNames[tag],
1376               code->kind());
1377   msg->AppendAddress(code->address());
1378   msg->Append(",%d,", code->ExecutableSize());
1379 }
1380 
1381 
CodeCreateEvent(LogEventsAndTags tag,Code * code,const char * comment)1382 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1383                              Code* code,
1384                              const char* comment) {
1385   PROFILER_LOG(CodeCreateEvent(tag, code, comment));
1386 
1387   if (!is_logging_code_events()) return;
1388   CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
1389 
1390   if (!FLAG_log_code || !log_->IsEnabled()) return;
1391   Log::MessageBuilder msg(log_);
1392   AppendCodeCreateHeader(&msg, tag, code);
1393   msg.AppendDoubleQuotedString(comment);
1394   msg.Append('\n');
1395   msg.WriteToLogFile();
1396 }
1397 
1398 
CodeCreateEvent(LogEventsAndTags tag,Code * code,Name * name)1399 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1400                              Code* code,
1401                              Name* name) {
1402   PROFILER_LOG(CodeCreateEvent(tag, code, name));
1403 
1404   if (!is_logging_code_events()) return;
1405   CALL_LISTENERS(CodeCreateEvent(tag, code, name));
1406 
1407   if (!FLAG_log_code || !log_->IsEnabled()) return;
1408   Log::MessageBuilder msg(log_);
1409   AppendCodeCreateHeader(&msg, tag, code);
1410   if (name->IsString()) {
1411     msg.Append('"');
1412     msg.AppendDetailed(String::cast(name), false);
1413     msg.Append('"');
1414   } else {
1415     msg.AppendSymbolName(Symbol::cast(name));
1416   }
1417   msg.Append('\n');
1418   msg.WriteToLogFile();
1419 }
1420 
1421 
CodeCreateEvent(LogEventsAndTags tag,Code * code,SharedFunctionInfo * shared,CompilationInfo * info,Name * name)1422 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1423                              Code* code,
1424                              SharedFunctionInfo* shared,
1425                              CompilationInfo* info,
1426                              Name* name) {
1427   PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
1428 
1429   if (!is_logging_code_events()) return;
1430   CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
1431 
1432   if (!FLAG_log_code || !log_->IsEnabled()) return;
1433   if (code == isolate_->builtins()->builtin(
1434       Builtins::kLazyCompile))
1435     return;
1436 
1437   Log::MessageBuilder msg(log_);
1438   AppendCodeCreateHeader(&msg, tag, code);
1439   if (name->IsString()) {
1440     SmartArrayPointer<char> str =
1441         String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1442     msg.Append("\"%s\"", *str);
1443   } else {
1444     msg.AppendSymbolName(Symbol::cast(name));
1445   }
1446   msg.Append(',');
1447   msg.AppendAddress(shared->address());
1448   msg.Append(",%s", ComputeMarker(code));
1449   msg.Append('\n');
1450   msg.WriteToLogFile();
1451 }
1452 
1453 
1454 // Although, it is possible to extract source and line from
1455 // the SharedFunctionInfo object, we left it to caller
1456 // to leave logging functions free from heap allocations.
CodeCreateEvent(LogEventsAndTags tag,Code * code,SharedFunctionInfo * shared,CompilationInfo * info,Name * source,int line,int column)1457 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1458                              Code* code,
1459                              SharedFunctionInfo* shared,
1460                              CompilationInfo* info,
1461                              Name* source, int line, int column) {
1462   PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column));
1463 
1464   if (!is_logging_code_events()) return;
1465   CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line,
1466                                  column));
1467 
1468   if (!FLAG_log_code || !log_->IsEnabled()) return;
1469   Log::MessageBuilder msg(log_);
1470   AppendCodeCreateHeader(&msg, tag, code);
1471   SmartArrayPointer<char> name =
1472       shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1473   msg.Append("\"%s ", *name);
1474   if (source->IsString()) {
1475     SmartArrayPointer<char> sourcestr =
1476        String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1477     msg.Append("%s", *sourcestr);
1478   } else {
1479     msg.AppendSymbolName(Symbol::cast(source));
1480   }
1481   msg.Append(":%d:%d\",", line, column);
1482   msg.AppendAddress(shared->address());
1483   msg.Append(",%s", ComputeMarker(code));
1484   msg.Append('\n');
1485   msg.WriteToLogFile();
1486 }
1487 
1488 
CodeCreateEvent(LogEventsAndTags tag,Code * code,int args_count)1489 void Logger::CodeCreateEvent(LogEventsAndTags tag,
1490                              Code* code,
1491                              int args_count) {
1492   PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
1493 
1494   if (!is_logging_code_events()) return;
1495   CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
1496 
1497   if (!FLAG_log_code || !log_->IsEnabled()) return;
1498   Log::MessageBuilder msg(log_);
1499   AppendCodeCreateHeader(&msg, tag, code);
1500   msg.Append("\"args_count: %d\"", args_count);
1501   msg.Append('\n');
1502   msg.WriteToLogFile();
1503 }
1504 
1505 
CodeMovingGCEvent()1506 void Logger::CodeMovingGCEvent() {
1507   PROFILER_LOG(CodeMovingGCEvent());
1508 
1509   if (!is_logging_code_events()) return;
1510   if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1511   CALL_LISTENERS(CodeMovingGCEvent());
1512   OS::SignalCodeMovingGC();
1513 }
1514 
1515 
RegExpCodeCreateEvent(Code * code,String * source)1516 void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
1517   PROFILER_LOG(RegExpCodeCreateEvent(code, source));
1518 
1519   if (!is_logging_code_events()) return;
1520   CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
1521 
1522   if (!FLAG_log_code || !log_->IsEnabled()) return;
1523   Log::MessageBuilder msg(log_);
1524   AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
1525   msg.Append('"');
1526   msg.AppendDetailed(source, false);
1527   msg.Append('"');
1528   msg.Append('\n');
1529   msg.WriteToLogFile();
1530 }
1531 
1532 
CodeMoveEvent(Address from,Address to)1533 void Logger::CodeMoveEvent(Address from, Address to) {
1534   PROFILER_LOG(CodeMoveEvent(from, to));
1535 
1536   if (!is_logging_code_events()) return;
1537   CALL_LISTENERS(CodeMoveEvent(from, to));
1538   MoveEventInternal(CODE_MOVE_EVENT, from, to);
1539 }
1540 
1541 
CodeDeleteEvent(Address from)1542 void Logger::CodeDeleteEvent(Address from) {
1543   PROFILER_LOG(CodeDeleteEvent(from));
1544 
1545   if (!is_logging_code_events()) return;
1546   CALL_LISTENERS(CodeDeleteEvent(from));
1547 
1548   if (!FLAG_log_code || !log_->IsEnabled()) return;
1549   Log::MessageBuilder msg(log_);
1550   msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
1551   msg.AppendAddress(from);
1552   msg.Append('\n');
1553   msg.WriteToLogFile();
1554 }
1555 
1556 
CodeLinePosInfoAddPositionEvent(void * jit_handler_data,int pc_offset,int position)1557 void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
1558                                      int pc_offset,
1559                                      int position) {
1560   JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1561                                   pc_offset,
1562                                   position,
1563                                   JitCodeEvent::POSITION));
1564 }
1565 
1566 
CodeLinePosInfoAddStatementPositionEvent(void * jit_handler_data,int pc_offset,int position)1567 void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
1568                                                       int pc_offset,
1569                                                       int position) {
1570   JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1571                                   pc_offset,
1572                                   position,
1573                                   JitCodeEvent::STATEMENT_POSITION));
1574 }
1575 
1576 
CodeStartLinePosInfoRecordEvent(PositionsRecorder * pos_recorder)1577 void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
1578   if (jit_logger_ != NULL) {
1579       pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
1580   }
1581 }
1582 
1583 
CodeEndLinePosInfoRecordEvent(Code * code,void * jit_handler_data)1584 void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
1585                                            void* jit_handler_data) {
1586   JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
1587 }
1588 
1589 
CodeNameEvent(Address addr,int pos,const char * code_name)1590 void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1591   if (code_name == NULL) return;  // Not a code object.
1592   Log::MessageBuilder msg(log_);
1593   msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
1594   msg.AppendDoubleQuotedString(code_name);
1595   msg.Append("\n");
1596   msg.WriteToLogFile();
1597 }
1598 
1599 
SnapshotPositionEvent(Address addr,int pos)1600 void Logger::SnapshotPositionEvent(Address addr, int pos) {
1601   if (!log_->IsEnabled()) return;
1602   LL_LOG(SnapshotPositionEvent(addr, pos));
1603   if (!FLAG_log_snapshot_positions) return;
1604   Log::MessageBuilder msg(log_);
1605   msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
1606   msg.AppendAddress(addr);
1607   msg.Append(",%d", pos);
1608   msg.Append('\n');
1609   msg.WriteToLogFile();
1610 }
1611 
1612 
SharedFunctionInfoMoveEvent(Address from,Address to)1613 void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
1614   PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
1615 
1616   if (!is_logging_code_events()) return;
1617   MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
1618 }
1619 
1620 
MoveEventInternal(LogEventsAndTags event,Address from,Address to)1621 void Logger::MoveEventInternal(LogEventsAndTags event,
1622                                Address from,
1623                                Address to) {
1624   if (!FLAG_log_code || !log_->IsEnabled()) return;
1625   Log::MessageBuilder msg(log_);
1626   msg.Append("%s,", kLogEventsNames[event]);
1627   msg.AppendAddress(from);
1628   msg.Append(',');
1629   msg.AppendAddress(to);
1630   msg.Append('\n');
1631   msg.WriteToLogFile();
1632 }
1633 
1634 
ResourceEvent(const char * name,const char * tag)1635 void Logger::ResourceEvent(const char* name, const char* tag) {
1636   if (!log_->IsEnabled() || !FLAG_log) return;
1637   Log::MessageBuilder msg(log_);
1638   msg.Append("%s,%s,", name, tag);
1639 
1640   uint32_t sec, usec;
1641   if (OS::GetUserTime(&sec, &usec) != -1) {
1642     msg.Append("%d,%d,", sec, usec);
1643   }
1644   msg.Append("%.0f", OS::TimeCurrentMillis());
1645 
1646   msg.Append('\n');
1647   msg.WriteToLogFile();
1648 }
1649 
1650 
SuspectReadEvent(Name * name,Object * obj)1651 void Logger::SuspectReadEvent(Name* name, Object* obj) {
1652   if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1653   Log::MessageBuilder msg(log_);
1654   String* class_name = obj->IsJSObject()
1655                        ? JSObject::cast(obj)->class_name()
1656                        : isolate_->heap()->empty_string();
1657   msg.Append("suspect-read,");
1658   msg.Append(class_name);
1659   msg.Append(',');
1660   if (name->IsString()) {
1661     msg.Append('"');
1662     msg.Append(String::cast(name));
1663     msg.Append('"');
1664   } else {
1665     msg.AppendSymbolName(Symbol::cast(name));
1666   }
1667   msg.Append('\n');
1668   msg.WriteToLogFile();
1669 }
1670 
1671 
HeapSampleBeginEvent(const char * space,const char * kind)1672 void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
1673   if (!log_->IsEnabled() || !FLAG_log_gc) return;
1674   Log::MessageBuilder msg(log_);
1675   // Using non-relative system time in order to be able to synchronize with
1676   // external memory profiling events (e.g. DOM memory size).
1677   msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
1678              space, kind, OS::TimeCurrentMillis());
1679   msg.WriteToLogFile();
1680 }
1681 
1682 
HeapSampleEndEvent(const char * space,const char * kind)1683 void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
1684   if (!log_->IsEnabled() || !FLAG_log_gc) return;
1685   Log::MessageBuilder msg(log_);
1686   msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
1687   msg.WriteToLogFile();
1688 }
1689 
1690 
HeapSampleItemEvent(const char * type,int number,int bytes)1691 void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
1692   if (!log_->IsEnabled() || !FLAG_log_gc) return;
1693   Log::MessageBuilder msg(log_);
1694   msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
1695   msg.WriteToLogFile();
1696 }
1697 
1698 
DebugTag(const char * call_site_tag)1699 void Logger::DebugTag(const char* call_site_tag) {
1700   if (!log_->IsEnabled() || !FLAG_log) return;
1701   Log::MessageBuilder msg(log_);
1702   msg.Append("debug-tag,%s\n", call_site_tag);
1703   msg.WriteToLogFile();
1704 }
1705 
1706 
DebugEvent(const char * event_type,Vector<uint16_t> parameter)1707 void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
1708   if (!log_->IsEnabled() || !FLAG_log) return;
1709   StringBuilder s(parameter.length() + 1);
1710   for (int i = 0; i < parameter.length(); ++i) {
1711     s.AddCharacter(static_cast<char>(parameter[i]));
1712   }
1713   char* parameter_string = s.Finalize();
1714   Log::MessageBuilder msg(log_);
1715   msg.Append("debug-queue-event,%s,%15.3f,%s\n",
1716              event_type,
1717              OS::TimeCurrentMillis(),
1718              parameter_string);
1719   DeleteArray(parameter_string);
1720   msg.WriteToLogFile();
1721 }
1722 
1723 
TickEvent(TickSample * sample,bool overflow)1724 void Logger::TickEvent(TickSample* sample, bool overflow) {
1725   if (!log_->IsEnabled() || !FLAG_prof) return;
1726   Log::MessageBuilder msg(log_);
1727   msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1728   msg.AppendAddress(sample->pc);
1729   msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
1730   if (sample->has_external_callback) {
1731     msg.Append(",1,");
1732     msg.AppendAddress(sample->external_callback);
1733   } else {
1734     msg.Append(",0,");
1735     msg.AppendAddress(sample->tos);
1736   }
1737   msg.Append(",%d", static_cast<int>(sample->state));
1738   if (overflow) {
1739     msg.Append(",overflow");
1740   }
1741   for (int i = 0; i < sample->frames_count; ++i) {
1742     msg.Append(',');
1743     msg.AppendAddress(sample->stack[i]);
1744   }
1745   msg.Append('\n');
1746   msg.WriteToLogFile();
1747 }
1748 
1749 
StopProfiler()1750 void Logger::StopProfiler() {
1751   if (!log_->IsEnabled()) return;
1752   if (profiler_ != NULL) {
1753     profiler_->pause();
1754     is_logging_ = false;
1755   }
1756 }
1757 
1758 
1759 // This function can be called when Log's mutex is acquired,
1760 // either from main or Profiler's thread.
LogFailure()1761 void Logger::LogFailure() {
1762   StopProfiler();
1763 }
1764 
1765 
1766 class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
1767  public:
EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo> * sfis,Handle<Code> * code_objects,int * count)1768   EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
1769                                      Handle<Code>* code_objects,
1770                                      int* count)
1771       : sfis_(sfis), code_objects_(code_objects), count_(count) { }
1772 
EnterContext(Context * context)1773   virtual void EnterContext(Context* context) {}
LeaveContext(Context * context)1774   virtual void LeaveContext(Context* context) {}
1775 
VisitFunction(JSFunction * function)1776   virtual void VisitFunction(JSFunction* function) {
1777     SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
1778     Object* maybe_script = sfi->script();
1779     if (maybe_script->IsScript()
1780         && !Script::cast(maybe_script)->HasValidSource()) return;
1781     if (sfis_ != NULL) {
1782       sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
1783     }
1784     if (code_objects_ != NULL) {
1785       ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1786       code_objects_[*count_] = Handle<Code>(function->code());
1787     }
1788     *count_ = *count_ + 1;
1789   }
1790 
1791  private:
1792   Handle<SharedFunctionInfo>* sfis_;
1793   Handle<Code>* code_objects_;
1794   int* count_;
1795 };
1796 
1797 
EnumerateCompiledFunctions(Heap * heap,Handle<SharedFunctionInfo> * sfis,Handle<Code> * code_objects)1798 static int EnumerateCompiledFunctions(Heap* heap,
1799                                       Handle<SharedFunctionInfo>* sfis,
1800                                       Handle<Code>* code_objects) {
1801   HeapIterator iterator(heap);
1802   DisallowHeapAllocation no_gc;
1803   int compiled_funcs_count = 0;
1804 
1805   // Iterate the heap to find shared function info objects and record
1806   // the unoptimized code for them.
1807   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1808     if (!obj->IsSharedFunctionInfo()) continue;
1809     SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
1810     if (sfi->is_compiled()
1811         && (!sfi->script()->IsScript()
1812             || Script::cast(sfi->script())->HasValidSource())) {
1813       if (sfis != NULL) {
1814         sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
1815       }
1816       if (code_objects != NULL) {
1817         code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1818       }
1819       ++compiled_funcs_count;
1820     }
1821   }
1822 
1823   // Iterate all optimized functions in all contexts.
1824   EnumerateOptimizedFunctionsVisitor visitor(sfis,
1825                                              code_objects,
1826                                              &compiled_funcs_count);
1827   Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
1828 
1829   return compiled_funcs_count;
1830 }
1831 
1832 
LogCodeObject(Object * object)1833 void Logger::LogCodeObject(Object* object) {
1834   Code* code_object = Code::cast(object);
1835   LogEventsAndTags tag = Logger::STUB_TAG;
1836   const char* description = "Unknown code from the snapshot";
1837   switch (code_object->kind()) {
1838     case Code::FUNCTION:
1839     case Code::OPTIMIZED_FUNCTION:
1840       return;  // We log this later using LogCompiledFunctions.
1841     case Code::BINARY_OP_IC:
1842     case Code::COMPARE_IC:  // fall through
1843     case Code::COMPARE_NIL_IC:   // fall through
1844     case Code::TO_BOOLEAN_IC:  // fall through
1845     case Code::STUB:
1846       description =
1847           CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
1848       if (description == NULL)
1849         description = "A stub from the snapshot";
1850       tag = Logger::STUB_TAG;
1851       break;
1852     case Code::REGEXP:
1853       description = "Regular expression code";
1854       tag = Logger::REG_EXP_TAG;
1855       break;
1856     case Code::BUILTIN:
1857       description = "A builtin from the snapshot";
1858       tag = Logger::BUILTIN_TAG;
1859       break;
1860     case Code::HANDLER:
1861       description = "An IC handler from the snapshot";
1862       tag = Logger::HANDLER_TAG;
1863       break;
1864     case Code::KEYED_LOAD_IC:
1865       description = "A keyed load IC from the snapshot";
1866       tag = Logger::KEYED_LOAD_IC_TAG;
1867       break;
1868     case Code::LOAD_IC:
1869       description = "A load IC from the snapshot";
1870       tag = Logger::LOAD_IC_TAG;
1871       break;
1872     case Code::STORE_IC:
1873       description = "A store IC from the snapshot";
1874       tag = Logger::STORE_IC_TAG;
1875       break;
1876     case Code::KEYED_STORE_IC:
1877       description = "A keyed store IC from the snapshot";
1878       tag = Logger::KEYED_STORE_IC_TAG;
1879       break;
1880     case Code::CALL_IC:
1881       description = "A call IC from the snapshot";
1882       tag = Logger::CALL_IC_TAG;
1883       break;
1884     case Code::KEYED_CALL_IC:
1885       description = "A keyed call IC from the snapshot";
1886       tag = Logger::KEYED_CALL_IC_TAG;
1887       break;
1888     case Code::NUMBER_OF_KINDS:
1889       break;
1890   }
1891   PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
1892 }
1893 
1894 
LogCodeObjects()1895 void Logger::LogCodeObjects() {
1896   Heap* heap = isolate_->heap();
1897   heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1898                           "Logger::LogCodeObjects");
1899   HeapIterator iterator(heap);
1900   DisallowHeapAllocation no_gc;
1901   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1902     if (obj->IsCode()) LogCodeObject(obj);
1903   }
1904 }
1905 
1906 
LogExistingFunction(Handle<SharedFunctionInfo> shared,Handle<Code> code)1907 void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
1908                                  Handle<Code> code) {
1909   Handle<String> func_name(shared->DebugName());
1910   if (shared->script()->IsScript()) {
1911     Handle<Script> script(Script::cast(shared->script()));
1912     int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
1913     int column_num =
1914         GetScriptColumnNumber(script, shared->start_position()) + 1;
1915     if (script->name()->IsString()) {
1916       Handle<String> script_name(String::cast(script->name()));
1917       if (line_num > 0) {
1918         PROFILE(isolate_,
1919                 CodeCreateEvent(
1920                     Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1921                     *code, *shared, NULL,
1922                     *script_name, line_num, column_num));
1923       } else {
1924         // Can't distinguish eval and script here, so always use Script.
1925         PROFILE(isolate_,
1926                 CodeCreateEvent(
1927                     Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
1928                     *code, *shared, NULL, *script_name));
1929       }
1930     } else {
1931       PROFILE(isolate_,
1932               CodeCreateEvent(
1933                   Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1934                   *code, *shared, NULL,
1935                   isolate_->heap()->empty_string(), line_num, column_num));
1936     }
1937   } else if (shared->IsApiFunction()) {
1938     // API function.
1939     FunctionTemplateInfo* fun_data = shared->get_api_func_data();
1940     Object* raw_call_data = fun_data->call_code();
1941     if (!raw_call_data->IsUndefined()) {
1942       CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1943       Object* callback_obj = call_data->callback();
1944       Address entry_point = v8::ToCData<Address>(callback_obj);
1945       PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
1946     }
1947   } else {
1948     PROFILE(isolate_,
1949             CodeCreateEvent(
1950                 Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
1951   }
1952 }
1953 
1954 
LogCompiledFunctions()1955 void Logger::LogCompiledFunctions() {
1956   Heap* heap = isolate_->heap();
1957   heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1958                           "Logger::LogCompiledFunctions");
1959   HandleScope scope(isolate_);
1960   const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL);
1961   ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
1962   ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1963   EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
1964 
1965   // During iteration, there can be heap allocation due to
1966   // GetScriptLineNumber call.
1967   for (int i = 0; i < compiled_funcs_count; ++i) {
1968     if (*code_objects[i] == isolate_->builtins()->builtin(
1969         Builtins::kLazyCompile))
1970       continue;
1971     LogExistingFunction(sfis[i], code_objects[i]);
1972   }
1973 }
1974 
1975 
LogAccessorCallbacks()1976 void Logger::LogAccessorCallbacks() {
1977   Heap* heap = isolate_->heap();
1978   heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1979                           "Logger::LogAccessorCallbacks");
1980   HeapIterator iterator(heap);
1981   DisallowHeapAllocation no_gc;
1982   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1983     if (!obj->IsExecutableAccessorInfo()) continue;
1984     ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
1985     if (!ai->name()->IsName()) continue;
1986     Address getter_entry = v8::ToCData<Address>(ai->getter());
1987     Name* name = Name::cast(ai->name());
1988     if (getter_entry != 0) {
1989       PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
1990     }
1991     Address setter_entry = v8::ToCData<Address>(ai->setter());
1992     if (setter_entry != 0) {
1993       PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
1994     }
1995   }
1996 }
1997 
1998 
AddIsolateIdIfNeeded(Isolate * isolate,StringStream * stream)1999 static void AddIsolateIdIfNeeded(Isolate* isolate, StringStream* stream) {
2000   if (isolate->IsDefaultIsolate() || !FLAG_logfile_per_isolate) return;
2001   stream->Add("isolate-%p-", isolate);
2002 }
2003 
2004 
PrepareLogFileName(Isolate * isolate,const char * file_name)2005 static SmartArrayPointer<const char> PrepareLogFileName(
2006     Isolate* isolate, const char* file_name) {
2007   if (strchr(file_name, '%') != NULL || !isolate->IsDefaultIsolate()) {
2008     // If there's a '%' in the log file name we have to expand
2009     // placeholders.
2010     HeapStringAllocator allocator;
2011     StringStream stream(&allocator);
2012     AddIsolateIdIfNeeded(isolate, &stream);
2013     for (const char* p = file_name; *p; p++) {
2014       if (*p == '%') {
2015         p++;
2016         switch (*p) {
2017           case '\0':
2018             // If there's a % at the end of the string we back up
2019             // one character so we can escape the loop properly.
2020             p--;
2021             break;
2022           case 'p':
2023             stream.Add("%d", OS::GetCurrentProcessId());
2024             break;
2025           case 't': {
2026             // %t expands to the current time in milliseconds.
2027             double time = OS::TimeCurrentMillis();
2028             stream.Add("%.0f", FmtElm(time));
2029             break;
2030           }
2031           case '%':
2032             // %% expands (contracts really) to %.
2033             stream.Put('%');
2034             break;
2035           default:
2036             // All other %'s expand to themselves.
2037             stream.Put('%');
2038             stream.Put(*p);
2039             break;
2040         }
2041       } else {
2042         stream.Put(*p);
2043       }
2044     }
2045     return SmartArrayPointer<const char>(stream.ToCString());
2046   }
2047   int length = StrLength(file_name);
2048   char* str = NewArray<char>(length + 1);
2049   OS::MemCopy(str, file_name, length);
2050   str[length] = '\0';
2051   return SmartArrayPointer<const char>(str);
2052 }
2053 
2054 
SetUp(Isolate * isolate)2055 bool Logger::SetUp(Isolate* isolate) {
2056   // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
2057   if (is_initialized_) return true;
2058   is_initialized_ = true;
2059 
2060   // --ll-prof implies --log-code and --log-snapshot-positions.
2061   if (FLAG_ll_prof) {
2062     FLAG_log_snapshot_positions = true;
2063   }
2064 
2065   SmartArrayPointer<const char> log_file_name =
2066       PrepareLogFileName(isolate, FLAG_logfile);
2067   log_->Initialize(*log_file_name);
2068 
2069 
2070   if (FLAG_perf_basic_prof) {
2071     perf_basic_logger_ = new PerfBasicLogger();
2072     addCodeEventListener(perf_basic_logger_);
2073   }
2074 
2075   if (FLAG_perf_jit_prof) {
2076     perf_jit_logger_ = new PerfJitLogger();
2077     addCodeEventListener(perf_jit_logger_);
2078   }
2079 
2080   if (FLAG_ll_prof) {
2081     ll_logger_ = new LowLevelLogger(*log_file_name);
2082     addCodeEventListener(ll_logger_);
2083   }
2084 
2085   ticker_ = new Ticker(isolate, kSamplingIntervalMs);
2086 
2087   if (Log::InitLogAtStart()) {
2088     is_logging_ = true;
2089   }
2090 
2091   if (FLAG_prof) {
2092     profiler_ = new Profiler(isolate);
2093     is_logging_ = true;
2094     profiler_->Engage();
2095   }
2096 
2097   if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
2098 
2099   return true;
2100 }
2101 
2102 
SetCodeEventHandler(uint32_t options,JitCodeEventHandler event_handler)2103 void Logger::SetCodeEventHandler(uint32_t options,
2104                                  JitCodeEventHandler event_handler) {
2105   if (jit_logger_) {
2106       removeCodeEventListener(jit_logger_);
2107       delete jit_logger_;
2108       jit_logger_ = NULL;
2109   }
2110 
2111   if (event_handler) {
2112     jit_logger_ = new JitLogger(event_handler);
2113     addCodeEventListener(jit_logger_);
2114     if (options & kJitCodeEventEnumExisting) {
2115       HandleScope scope(isolate_);
2116       LogCodeObjects();
2117       LogCompiledFunctions();
2118     }
2119   }
2120 }
2121 
2122 
sampler()2123 Sampler* Logger::sampler() {
2124   return ticker_;
2125 }
2126 
2127 
TearDown()2128 FILE* Logger::TearDown() {
2129   if (!is_initialized_) return NULL;
2130   is_initialized_ = false;
2131 
2132   // Stop the profiler before closing the file.
2133   if (profiler_ != NULL) {
2134     profiler_->Disengage();
2135     delete profiler_;
2136     profiler_ = NULL;
2137   }
2138 
2139   delete ticker_;
2140   ticker_ = NULL;
2141 
2142   if (perf_basic_logger_) {
2143     removeCodeEventListener(perf_basic_logger_);
2144     delete perf_basic_logger_;
2145     perf_basic_logger_ = NULL;
2146   }
2147 
2148   if (perf_jit_logger_) {
2149     removeCodeEventListener(perf_jit_logger_);
2150     delete perf_jit_logger_;
2151     perf_jit_logger_ = NULL;
2152   }
2153 
2154   if (ll_logger_) {
2155     removeCodeEventListener(ll_logger_);
2156     delete ll_logger_;
2157     ll_logger_ = NULL;
2158   }
2159 
2160   if (jit_logger_) {
2161     removeCodeEventListener(jit_logger_);
2162     delete jit_logger_;
2163     jit_logger_ = NULL;
2164   }
2165 
2166   return log_->Close();
2167 }
2168 
2169 } }  // namespace v8::internal
2170