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