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