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