The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / log.cc @ f230a1cf

History | View | Annotate | Download (56 KB)

1
// Copyright 2011 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
#include <stdarg.h>
29

    
30
#include "v8.h"
31

    
32
#include "bootstrapper.h"
33
#include "code-stubs.h"
34
#include "cpu-profiler.h"
35
#include "deoptimizer.h"
36
#include "global-handles.h"
37
#include "log.h"
38
#include "log-utils.h"
39
#include "macro-assembler.h"
40
#include "platform.h"
41
#include "runtime-profiler.h"
42
#include "serialize.h"
43
#include "string-stream.h"
44
#include "vm-state-inl.h"
45

    
46
namespace v8 {
47
namespace internal {
48

    
49

    
50
#define DECLARE_EVENT(ignore1, name) name,
51
static const char* const kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
52
  LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
53
};
54
#undef DECLARE_EVENT
55

    
56

    
57
#define CALL_LISTENERS(Call)                    \
58
for (int i = 0; i < listeners_.length(); ++i) { \
59
  listeners_[i]->Call;                          \
60
}
61

    
62
#define PROFILER_LOG(Call)                                \
63
  do {                                                    \
64
    CpuProfiler* cpu_profiler = isolate_->cpu_profiler(); \
65
    if (cpu_profiler->is_profiling()) {                   \
66
      cpu_profiler->Call;                                 \
67
    }                                                     \
68
  } while (false);
69

    
70
// ComputeMarker must only be used when SharedFunctionInfo is known.
71
static const char* ComputeMarker(Code* code) {
72
  switch (code->kind()) {
73
    case Code::FUNCTION: return code->optimizable() ? "~" : "";
74
    case Code::OPTIMIZED_FUNCTION: return "*";
75
    default: return "";
76
  }
77
}
78

    
79

    
80
class CodeEventLogger::NameBuffer {
81
 public:
82
  NameBuffer() { Reset(); }
83

    
84
  void Reset() {
85
    utf8_pos_ = 0;
86
  }
87

    
88
  void Init(Logger::LogEventsAndTags tag) {
89
    Reset();
90
    AppendBytes(kLogEventsNames[tag]);
91
    AppendByte(':');
92
  }
93

    
94
  void AppendName(Name* name) {
95
    if (name->IsString()) {
96
      AppendString(String::cast(name));
97
    } else {
98
      Symbol* symbol = Symbol::cast(name);
99
      AppendBytes("symbol(");
100
      if (!symbol->name()->IsUndefined()) {
101
        AppendBytes("\"");
102
        AppendString(String::cast(symbol->name()));
103
        AppendBytes("\" ");
104
      }
105
      AppendBytes("hash ");
106
      AppendHex(symbol->Hash());
107
      AppendByte(')');
108
    }
109
  }
110

    
111
  void AppendString(String* str) {
112
    if (str == NULL) return;
113
    int uc16_length = Min(str->length(), kUtf16BufferSize);
114
    String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
115
    int previous = unibrow::Utf16::kNoPreviousCharacter;
116
    for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
117
      uc16 c = utf16_buffer[i];
118
      if (c <= unibrow::Utf8::kMaxOneByteChar) {
119
        utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
120
      } else {
121
        int char_length = unibrow::Utf8::Length(c, previous);
122
        if (utf8_pos_ + char_length > kUtf8BufferSize) break;
123
        unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
124
        utf8_pos_ += char_length;
125
      }
126
      previous = c;
127
    }
128
  }
129

    
130
  void AppendBytes(const char* bytes, int size) {
131
    size = Min(size, kUtf8BufferSize - utf8_pos_);
132
    OS::MemCopy(utf8_buffer_ + utf8_pos_, bytes, size);
133
    utf8_pos_ += size;
134
  }
135

    
136
  void AppendBytes(const char* bytes) {
137
    AppendBytes(bytes, StrLength(bytes));
138
  }
139

    
140
  void AppendByte(char c) {
141
    if (utf8_pos_ >= kUtf8BufferSize) return;
142
    utf8_buffer_[utf8_pos_++] = c;
143
  }
144

    
145
  void AppendInt(int n) {
146
    Vector<char> buffer(utf8_buffer_ + utf8_pos_,
147
                        kUtf8BufferSize - utf8_pos_);
148
    int size = OS::SNPrintF(buffer, "%d", n);
149
    if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
150
      utf8_pos_ += size;
151
    }
152
  }
153

    
154
  void AppendHex(uint32_t n) {
155
    Vector<char> buffer(utf8_buffer_ + utf8_pos_,
156
                        kUtf8BufferSize - utf8_pos_);
157
    int size = OS::SNPrintF(buffer, "%x", n);
158
    if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
159
      utf8_pos_ += size;
160
    }
161
  }
162

    
163
  const char* get() { return utf8_buffer_; }
164
  int size() const { return utf8_pos_; }
165

    
166
 private:
167
  static const int kUtf8BufferSize = 512;
168
  static const int kUtf16BufferSize = 128;
169

    
170
  int utf8_pos_;
171
  char utf8_buffer_[kUtf8BufferSize];
172
  uc16 utf16_buffer[kUtf16BufferSize];
173
};
174

    
175

    
176
CodeEventLogger::CodeEventLogger() : name_buffer_(new NameBuffer) { }
177

    
178
CodeEventLogger::~CodeEventLogger() { delete name_buffer_; }
179

    
180

    
181
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
182
                                      Code* code,
183
                                      const char* comment) {
184
  name_buffer_->Init(tag);
185
  name_buffer_->AppendBytes(comment);
186
  LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
187
}
188

    
189

    
190
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
191
                                      Code* code,
192
                                      Name* name) {
193
  name_buffer_->Init(tag);
194
  name_buffer_->AppendName(name);
195
  LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
196
}
197

    
198

    
199
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
200
                                      Code* code,
201
                                      SharedFunctionInfo* shared,
202
                                      CompilationInfo* info,
203
                                      Name* name) {
204
  name_buffer_->Init(tag);
205
  name_buffer_->AppendBytes(ComputeMarker(code));
206
  name_buffer_->AppendName(name);
207
  LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
208
}
209

    
210

    
211
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
212
                                      Code* code,
213
                                      SharedFunctionInfo* shared,
214
                                      CompilationInfo* info,
215
                                      Name* source, int line, int column) {
216
  name_buffer_->Init(tag);
217
  name_buffer_->AppendBytes(ComputeMarker(code));
218
  name_buffer_->AppendString(shared->DebugName());
219
  name_buffer_->AppendByte(' ');
220
  if (source->IsString()) {
221
    name_buffer_->AppendString(String::cast(source));
222
  } else {
223
    name_buffer_->AppendBytes("symbol(hash ");
224
    name_buffer_->AppendHex(Name::cast(source)->Hash());
225
    name_buffer_->AppendByte(')');
226
  }
227
  name_buffer_->AppendByte(':');
228
  name_buffer_->AppendInt(line);
229
  LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
230
}
231

    
232

    
233
void CodeEventLogger::CodeCreateEvent(Logger::LogEventsAndTags tag,
234
                                      Code* code,
235
                                      int args_count) {
236
  name_buffer_->Init(tag);
237
  name_buffer_->AppendInt(args_count);
238
  LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
239
}
240

    
241

    
242
void CodeEventLogger::RegExpCodeCreateEvent(Code* code, String* source) {
243
  name_buffer_->Init(Logger::REG_EXP_TAG);
244
  name_buffer_->AppendString(source);
245
  LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
246
}
247

    
248

    
249
// Low-level logging support.
250
#define LL_LOG(Call) if (ll_logger_) ll_logger_->Call;
251

    
252
class LowLevelLogger : public CodeEventLogger {
253
 public:
254
  explicit LowLevelLogger(const char* file_name);
255
  virtual ~LowLevelLogger();
256

    
257
  virtual void CodeMoveEvent(Address from, Address to);
258
  virtual void CodeDeleteEvent(Address from);
259
  virtual void SnapshotPositionEvent(Address addr, int pos);
260
  virtual void CodeMovingGCEvent();
261

    
262
 private:
263
  virtual void LogRecordedBuffer(Code* code,
264
                                 SharedFunctionInfo* shared,
265
                                 const char* name,
266
                                 int length);
267

    
268
  // Low-level profiling event structures.
269
  struct CodeCreateStruct {
270
    static const char kTag = 'C';
271

    
272
    int32_t name_size;
273
    Address code_address;
274
    int32_t code_size;
275
  };
276

    
277

    
278
  struct CodeMoveStruct {
279
    static const char kTag = 'M';
280

    
281
    Address from_address;
282
    Address to_address;
283
  };
284

    
285

    
286
  struct CodeDeleteStruct {
287
    static const char kTag = 'D';
288

    
289
    Address address;
290
  };
291

    
292

    
293
  struct SnapshotPositionStruct {
294
    static const char kTag = 'P';
295

    
296
    Address address;
297
    int32_t position;
298
  };
299

    
300

    
301
  static const char kCodeMovingGCTag = 'G';
302

    
303

    
304
  // Extension added to V8 log file name to get the low-level log name.
305
  static const char kLogExt[];
306

    
307
  // File buffer size of the low-level log. We don't use the default to
308
  // minimize the associated overhead.
309
  static const int kLogBufferSize = 2 * MB;
310

    
311
  void LogCodeInfo();
312
  void LogWriteBytes(const char* bytes, int size);
313

    
314
  template <typename T>
315
  void LogWriteStruct(const T& s) {
316
    char tag = T::kTag;
317
    LogWriteBytes(reinterpret_cast<const char*>(&tag), sizeof(tag));
318
    LogWriteBytes(reinterpret_cast<const char*>(&s), sizeof(s));
319
  }
320

    
321
  FILE* ll_output_handle_;
322
};
323

    
324
const char LowLevelLogger::kLogExt[] = ".ll";
325

    
326
LowLevelLogger::LowLevelLogger(const char* name)
327
    : ll_output_handle_(NULL) {
328
  // Open the low-level log file.
329
  size_t len = strlen(name);
330
  ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLogExt)));
331
  OS::MemCopy(ll_name.start(), name, len);
332
  OS::MemCopy(ll_name.start() + len, kLogExt, sizeof(kLogExt));
333
  ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
334
  setvbuf(ll_output_handle_, NULL, _IOFBF, kLogBufferSize);
335

    
336
  LogCodeInfo();
337
}
338

    
339

    
340
LowLevelLogger::~LowLevelLogger() {
341
  fclose(ll_output_handle_);
342
  ll_output_handle_ = NULL;
343
}
344

    
345

    
346
void LowLevelLogger::LogCodeInfo() {
347
#if V8_TARGET_ARCH_IA32
348
  const char arch[] = "ia32";
349
#elif V8_TARGET_ARCH_X64
350
  const char arch[] = "x64";
351
#elif V8_TARGET_ARCH_ARM
352
  const char arch[] = "arm";
353
#elif V8_TARGET_ARCH_MIPS
354
  const char arch[] = "mips";
355
#else
356
  const char arch[] = "unknown";
357
#endif
358
  LogWriteBytes(arch, sizeof(arch));
359
}
360

    
361

    
362
void LowLevelLogger::LogRecordedBuffer(Code* code,
363
                                       SharedFunctionInfo*,
364
                                       const char* name,
365
                                       int length) {
366
  CodeCreateStruct event;
367
  event.name_size = length;
368
  event.code_address = code->instruction_start();
369
  ASSERT(event.code_address == code->address() + Code::kHeaderSize);
370
  event.code_size = code->instruction_size();
371
  LogWriteStruct(event);
372
  LogWriteBytes(name, length);
373
  LogWriteBytes(
374
      reinterpret_cast<const char*>(code->instruction_start()),
375
      code->instruction_size());
376
}
377

    
378

    
379
void LowLevelLogger::CodeMoveEvent(Address from, Address to) {
380
  CodeMoveStruct event;
381
  event.from_address = from + Code::kHeaderSize;
382
  event.to_address = to + Code::kHeaderSize;
383
  LogWriteStruct(event);
384
}
385

    
386

    
387
void LowLevelLogger::CodeDeleteEvent(Address from) {
388
  CodeDeleteStruct event;
389
  event.address = from + Code::kHeaderSize;
390
  LogWriteStruct(event);
391
}
392

    
393

    
394
void LowLevelLogger::SnapshotPositionEvent(Address addr, int pos) {
395
  SnapshotPositionStruct event;
396
  event.address = addr + Code::kHeaderSize;
397
  event.position = pos;
398
  LogWriteStruct(event);
399
}
400

    
401

    
402
void LowLevelLogger::LogWriteBytes(const char* bytes, int size) {
403
  size_t rv = fwrite(bytes, 1, size, ll_output_handle_);
404
  ASSERT(static_cast<size_t>(size) == rv);
405
  USE(rv);
406
}
407

    
408

    
409
void LowLevelLogger::CodeMovingGCEvent() {
410
  const char tag = kCodeMovingGCTag;
411

    
412
  LogWriteBytes(&tag, sizeof(tag));
413
}
414

    
415

    
416
#define JIT_LOG(Call) if (jit_logger_) jit_logger_->Call;
417

    
418

    
419
class JitLogger : public CodeEventLogger {
420
 public:
421
  explicit JitLogger(JitCodeEventHandler code_event_handler);
422

    
423
  virtual void CodeMoveEvent(Address from, Address to);
424
  virtual void CodeDeleteEvent(Address from);
425
  virtual void AddCodeLinePosInfoEvent(
426
      void* jit_handler_data,
427
      int pc_offset,
428
      int position,
429
      JitCodeEvent::PositionType position_type);
430

    
431
  void* StartCodePosInfoEvent();
432
  void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
433

    
434
 private:
435
  virtual void LogRecordedBuffer(Code* code,
436
                                 SharedFunctionInfo* shared,
437
                                 const char* name,
438
                                 int length);
439

    
440
  JitCodeEventHandler code_event_handler_;
441
};
442

    
443

    
444
JitLogger::JitLogger(JitCodeEventHandler code_event_handler)
445
    : code_event_handler_(code_event_handler) {
446
}
447

    
448

    
449
void JitLogger::LogRecordedBuffer(Code* code,
450
                                  SharedFunctionInfo* shared,
451
                                  const char* name,
452
                                  int length) {
453
  JitCodeEvent event;
454
  memset(&event, 0, sizeof(event));
455
  event.type = JitCodeEvent::CODE_ADDED;
456
  event.code_start = code->instruction_start();
457
  event.code_len = code->instruction_size();
458
  Handle<Script> script_handle;
459
  if (shared && shared->script()->IsScript()) {
460
    script_handle = Handle<Script>(Script::cast(shared->script()));
461
  }
462
  event.script = ToApiHandle<v8::Script>(script_handle);
463
  event.name.str = name;
464
  event.name.len = length;
465
  code_event_handler_(&event);
466
}
467

    
468

    
469
void JitLogger::CodeMoveEvent(Address from, Address to) {
470
  Code* from_code = Code::cast(HeapObject::FromAddress(from));
471

    
472
  JitCodeEvent event;
473
  event.type = JitCodeEvent::CODE_MOVED;
474
  event.code_start = from_code->instruction_start();
475
  event.code_len = from_code->instruction_size();
476

    
477
  // Calculate the header size.
478
  const size_t header_size =
479
      from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
480

    
481
  // Calculate the new start address of the instructions.
482
  event.new_code_start =
483
      reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
484

    
485
  code_event_handler_(&event);
486
}
487

    
488

    
489
void JitLogger::CodeDeleteEvent(Address from) {
490
  Code* from_code = Code::cast(HeapObject::FromAddress(from));
491

    
492
  JitCodeEvent event;
493
  event.type = JitCodeEvent::CODE_REMOVED;
494
  event.code_start = from_code->instruction_start();
495
  event.code_len = from_code->instruction_size();
496

    
497
  code_event_handler_(&event);
498
}
499

    
500
void JitLogger::AddCodeLinePosInfoEvent(
501
    void* jit_handler_data,
502
    int pc_offset,
503
    int position,
504
    JitCodeEvent::PositionType position_type) {
505
  JitCodeEvent event;
506
  memset(&event, 0, sizeof(event));
507
  event.type = JitCodeEvent::CODE_ADD_LINE_POS_INFO;
508
  event.user_data = jit_handler_data;
509
  event.line_info.offset = pc_offset;
510
  event.line_info.pos = position;
511
  event.line_info.position_type = position_type;
512

    
513
  code_event_handler_(&event);
514
}
515

    
516

    
517
void* JitLogger::StartCodePosInfoEvent() {
518
  JitCodeEvent event;
519
  memset(&event, 0, sizeof(event));
520
  event.type = JitCodeEvent::CODE_START_LINE_INFO_RECORDING;
521

    
522
  code_event_handler_(&event);
523
  return event.user_data;
524
}
525

    
526

    
527
void JitLogger::EndCodePosInfoEvent(Code* code, void* jit_handler_data) {
528
  JitCodeEvent event;
529
  memset(&event, 0, sizeof(event));
530
  event.type = JitCodeEvent::CODE_END_LINE_INFO_RECORDING;
531
  event.code_start = code->instruction_start();
532
  event.user_data = jit_handler_data;
533

    
534
  code_event_handler_(&event);
535
}
536

    
537

    
538
// The Profiler samples pc and sp values for the main thread.
539
// Each sample is appended to a circular buffer.
540
// An independent thread removes data and writes it to the log.
541
// This design minimizes the time spent in the sampler.
542
//
543
class Profiler: public Thread {
544
 public:
545
  explicit Profiler(Isolate* isolate);
546
  void Engage();
547
  void Disengage();
548

    
549
  // Inserts collected profiling data into buffer.
550
  void Insert(TickSample* sample) {
551
    if (paused_)
552
      return;
553

    
554
    if (Succ(head_) == tail_) {
555
      overflow_ = true;
556
    } else {
557
      buffer_[head_] = *sample;
558
      head_ = Succ(head_);
559
      buffer_semaphore_.Signal();  // Tell we have an element.
560
    }
561
  }
562

    
563
  virtual void Run();
564

    
565
  // Pause and Resume TickSample data collection.
566
  void pause() { paused_ = true; }
567
  void resume() { paused_ = false; }
568

    
569
 private:
570
  // Waits for a signal and removes profiling data.
571
  bool Remove(TickSample* sample) {
572
    buffer_semaphore_.Wait();  // Wait for an element.
573
    *sample = buffer_[tail_];
574
    bool result = overflow_;
575
    tail_ = Succ(tail_);
576
    overflow_ = false;
577
    return result;
578
  }
579

    
580
  // Returns the next index in the cyclic buffer.
581
  int Succ(int index) { return (index + 1) % kBufferSize; }
582

    
583
  Isolate* isolate_;
584
  // Cyclic buffer for communicating profiling samples
585
  // between the signal handler and the worker thread.
586
  static const int kBufferSize = 128;
587
  TickSample buffer_[kBufferSize];  // Buffer storage.
588
  int head_;  // Index to the buffer head.
589
  int tail_;  // Index to the buffer tail.
590
  bool overflow_;  // Tell whether a buffer overflow has occurred.
591
  // Sempahore used for buffer synchronization.
592
  Semaphore buffer_semaphore_;
593

    
594
  // Tells whether profiler is engaged, that is, processing thread is stated.
595
  bool engaged_;
596

    
597
  // Tells whether worker thread should continue running.
598
  bool running_;
599

    
600
  // Tells whether we are currently recording tick samples.
601
  bool paused_;
602
};
603

    
604

    
605
//
606
// Ticker used to provide ticks to the profiler and the sliding state
607
// window.
608
//
609
class Ticker: public Sampler {
610
 public:
611
  Ticker(Isolate* isolate, int interval):
612
      Sampler(isolate, interval),
613
      profiler_(NULL) {}
614

    
615
  ~Ticker() { if (IsActive()) Stop(); }
616

    
617
  virtual void Tick(TickSample* sample) {
618
    if (profiler_) profiler_->Insert(sample);
619
  }
620

    
621
  void SetProfiler(Profiler* profiler) {
622
    ASSERT(profiler_ == NULL);
623
    profiler_ = profiler;
624
    IncreaseProfilingDepth();
625
    if (!IsActive()) Start();
626
  }
627

    
628
  void ClearProfiler() {
629
    profiler_ = NULL;
630
    if (IsActive()) Stop();
631
    DecreaseProfilingDepth();
632
  }
633

    
634
 private:
635
  Profiler* profiler_;
636
};
637

    
638

    
639
//
640
// Profiler implementation.
641
//
642
Profiler::Profiler(Isolate* isolate)
643
    : Thread("v8:Profiler"),
644
      isolate_(isolate),
645
      head_(0),
646
      tail_(0),
647
      overflow_(false),
648
      buffer_semaphore_(0),
649
      engaged_(false),
650
      running_(false),
651
      paused_(false) {
652
}
653

    
654

    
655
void Profiler::Engage() {
656
  if (engaged_) return;
657
  engaged_ = true;
658

    
659
  OS::LogSharedLibraryAddresses(isolate_);
660

    
661
  // Start thread processing the profiler buffer.
662
  running_ = true;
663
  Start();
664

    
665
  // Register to get ticks.
666
  Logger* logger = isolate_->logger();
667
  logger->ticker_->SetProfiler(this);
668

    
669
  logger->ProfilerBeginEvent();
670
}
671

    
672

    
673
void Profiler::Disengage() {
674
  if (!engaged_) return;
675

    
676
  // Stop receiving ticks.
677
  isolate_->logger()->ticker_->ClearProfiler();
678

    
679
  // Terminate the worker thread by setting running_ to false,
680
  // inserting a fake element in the queue and then wait for
681
  // the thread to terminate.
682
  running_ = false;
683
  TickSample sample;
684
  // Reset 'paused_' flag, otherwise semaphore may not be signalled.
685
  resume();
686
  Insert(&sample);
687
  Join();
688

    
689
  LOG(isolate_, UncheckedStringEvent("profiler", "end"));
690
}
691

    
692

    
693
void Profiler::Run() {
694
  TickSample sample;
695
  bool overflow = Remove(&sample);
696
  while (running_) {
697
    LOG(isolate_, TickEvent(&sample, overflow));
698
    overflow = Remove(&sample);
699
  }
700
}
701

    
702

    
703
//
704
// Logger class implementation.
705
//
706

    
707
Logger::Logger(Isolate* isolate)
708
  : isolate_(isolate),
709
    ticker_(NULL),
710
    profiler_(NULL),
711
    log_events_(NULL),
712
    is_logging_(false),
713
    log_(new Log(this)),
714
    ll_logger_(NULL),
715
    jit_logger_(NULL),
716
    listeners_(5),
717
    is_initialized_(false) {
718
}
719

    
720

    
721
Logger::~Logger() {
722
  delete log_;
723
}
724

    
725

    
726
void Logger::addCodeEventListener(CodeEventListener* listener) {
727
  ASSERT(!hasCodeEventListener(listener));
728
  listeners_.Add(listener);
729
}
730

    
731

    
732
void Logger::removeCodeEventListener(CodeEventListener* listener) {
733
  ASSERT(hasCodeEventListener(listener));
734
  listeners_.RemoveElement(listener);
735
}
736

    
737

    
738
bool Logger::hasCodeEventListener(CodeEventListener* listener) {
739
  return listeners_.Contains(listener);
740
}
741

    
742

    
743
void Logger::ProfilerBeginEvent() {
744
  if (!log_->IsEnabled()) return;
745
  Log::MessageBuilder msg(log_);
746
  msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
747
  msg.WriteToLogFile();
748
}
749

    
750

    
751
void Logger::StringEvent(const char* name, const char* value) {
752
  if (FLAG_log) UncheckedStringEvent(name, value);
753
}
754

    
755

    
756
void Logger::UncheckedStringEvent(const char* name, const char* value) {
757
  if (!log_->IsEnabled()) return;
758
  Log::MessageBuilder msg(log_);
759
  msg.Append("%s,\"%s\"\n", name, value);
760
  msg.WriteToLogFile();
761
}
762

    
763

    
764
void Logger::IntEvent(const char* name, int value) {
765
  if (FLAG_log) UncheckedIntEvent(name, value);
766
}
767

    
768

    
769
void Logger::IntPtrTEvent(const char* name, intptr_t value) {
770
  if (FLAG_log) UncheckedIntPtrTEvent(name, value);
771
}
772

    
773

    
774
void Logger::UncheckedIntEvent(const char* name, int value) {
775
  if (!log_->IsEnabled()) return;
776
  Log::MessageBuilder msg(log_);
777
  msg.Append("%s,%d\n", name, value);
778
  msg.WriteToLogFile();
779
}
780

    
781

    
782
void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
783
  if (!log_->IsEnabled()) return;
784
  Log::MessageBuilder msg(log_);
785
  msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
786
  msg.WriteToLogFile();
787
}
788

    
789

    
790
void Logger::HandleEvent(const char* name, Object** location) {
791
  if (!log_->IsEnabled() || !FLAG_log_handles) return;
792
  Log::MessageBuilder msg(log_);
793
  msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
794
  msg.WriteToLogFile();
795
}
796

    
797

    
798
// ApiEvent is private so all the calls come from the Logger class.  It is the
799
// caller's responsibility to ensure that log is enabled and that
800
// FLAG_log_api is true.
801
void Logger::ApiEvent(const char* format, ...) {
802
  ASSERT(log_->IsEnabled() && FLAG_log_api);
803
  Log::MessageBuilder msg(log_);
804
  va_list ap;
805
  va_start(ap, format);
806
  msg.AppendVA(format, ap);
807
  va_end(ap);
808
  msg.WriteToLogFile();
809
}
810

    
811

    
812
void Logger::ApiNamedSecurityCheck(Object* key) {
813
  if (!log_->IsEnabled() || !FLAG_log_api) return;
814
  if (key->IsString()) {
815
    SmartArrayPointer<char> str =
816
        String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
817
    ApiEvent("api,check-security,\"%s\"\n", *str);
818
  } else if (key->IsSymbol()) {
819
    Symbol* symbol = Symbol::cast(key);
820
    if (symbol->name()->IsUndefined()) {
821
      ApiEvent("api,check-security,symbol(hash %x)\n",
822
               Symbol::cast(key)->Hash());
823
    } else {
824
      SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
825
          DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
826
      ApiEvent("api,check-security,symbol(\"%s\" hash %x)\n",
827
               *str,
828
               Symbol::cast(key)->Hash());
829
    }
830
  } else if (key->IsUndefined()) {
831
    ApiEvent("api,check-security,undefined\n");
832
  } else {
833
    ApiEvent("api,check-security,['no-name']\n");
834
  }
835
}
836

    
837

    
838
void Logger::SharedLibraryEvent(const char* library_path,
839
                                uintptr_t start,
840
                                uintptr_t end) {
841
  if (!log_->IsEnabled() || !FLAG_prof) return;
842
  Log::MessageBuilder msg(log_);
843
  msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
844
             library_path,
845
             start,
846
             end);
847
  msg.WriteToLogFile();
848
}
849

    
850

    
851
void Logger::SharedLibraryEvent(const wchar_t* library_path,
852
                                uintptr_t start,
853
                                uintptr_t end) {
854
  if (!log_->IsEnabled() || !FLAG_prof) return;
855
  Log::MessageBuilder msg(log_);
856
  msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
857
             library_path,
858
             start,
859
             end);
860
  msg.WriteToLogFile();
861
}
862

    
863

    
864
void Logger::CodeDeoptEvent(Code* code) {
865
  if (!log_->IsEnabled()) return;
866
  ASSERT(FLAG_log_internal_timer_events);
867
  Log::MessageBuilder msg(log_);
868
  int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
869
  msg.Append("code-deopt,%ld,%d\n", since_epoch, code->CodeSize());
870
  msg.WriteToLogFile();
871
}
872

    
873

    
874
void Logger::TimerEvent(StartEnd se, const char* name) {
875
  if (!log_->IsEnabled()) return;
876
  ASSERT(FLAG_log_internal_timer_events);
877
  Log::MessageBuilder msg(log_);
878
  int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
879
  const char* format = (se == START) ? "timer-event-start,\"%s\",%ld\n"
880
                                     : "timer-event-end,\"%s\",%ld\n";
881
  msg.Append(format, name, since_epoch);
882
  msg.WriteToLogFile();
883
}
884

    
885

    
886
void Logger::EnterExternal(Isolate* isolate) {
887
  LOG(isolate, TimerEvent(START, TimerEventScope::v8_external));
888
  ASSERT(isolate->current_vm_state() == JS);
889
  isolate->set_current_vm_state(EXTERNAL);
890
}
891

    
892

    
893
void Logger::LeaveExternal(Isolate* isolate) {
894
  LOG(isolate, TimerEvent(END, TimerEventScope::v8_external));
895
  ASSERT(isolate->current_vm_state() == EXTERNAL);
896
  isolate->set_current_vm_state(JS);
897
}
898

    
899

    
900
void Logger::TimerEventScope::LogTimerEvent(StartEnd se) {
901
  LOG(isolate_, TimerEvent(se, name_));
902
}
903

    
904

    
905
const char* Logger::TimerEventScope::v8_recompile_synchronous =
906
    "V8.RecompileSynchronous";
907
const char* Logger::TimerEventScope::v8_recompile_concurrent =
908
    "V8.RecompileConcurrent";
909
const char* Logger::TimerEventScope::v8_compile_full_code =
910
    "V8.CompileFullCode";
911
const char* Logger::TimerEventScope::v8_execute = "V8.Execute";
912
const char* Logger::TimerEventScope::v8_external = "V8.External";
913

    
914

    
915
void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
916
  // Prints "/" + re.source + "/" +
917
  //      (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
918
  Log::MessageBuilder msg(log_);
919

    
920
  Handle<Object> source = GetProperty(regexp, "source");
921
  if (!source->IsString()) {
922
    msg.Append("no source");
923
    return;
924
  }
925

    
926
  switch (regexp->TypeTag()) {
927
    case JSRegExp::ATOM:
928
      msg.Append('a');
929
      break;
930
    default:
931
      break;
932
  }
933
  msg.Append('/');
934
  msg.AppendDetailed(*Handle<String>::cast(source), false);
935
  msg.Append('/');
936

    
937
  // global flag
938
  Handle<Object> global = GetProperty(regexp, "global");
939
  if (global->IsTrue()) {
940
    msg.Append('g');
941
  }
942
  // ignorecase flag
943
  Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
944
  if (ignorecase->IsTrue()) {
945
    msg.Append('i');
946
  }
947
  // multiline flag
948
  Handle<Object> multiline = GetProperty(regexp, "multiline");
949
  if (multiline->IsTrue()) {
950
    msg.Append('m');
951
  }
952

    
953
  msg.WriteToLogFile();
954
}
955

    
956

    
957
void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
958
  if (!log_->IsEnabled() || !FLAG_log_regexp) return;
959
  Log::MessageBuilder msg(log_);
960
  msg.Append("regexp-compile,");
961
  LogRegExpSource(regexp);
962
  msg.Append(in_cache ? ",hit\n" : ",miss\n");
963
  msg.WriteToLogFile();
964
}
965

    
966

    
967
void Logger::LogRuntime(Vector<const char> format,
968
                        JSArray* args) {
969
  if (!log_->IsEnabled() || !FLAG_log_runtime) return;
970
  HandleScope scope(isolate_);
971
  Log::MessageBuilder msg(log_);
972
  for (int i = 0; i < format.length(); i++) {
973
    char c = format[i];
974
    if (c == '%' && i <= format.length() - 2) {
975
      i++;
976
      ASSERT('0' <= format[i] && format[i] <= '9');
977
      MaybeObject* maybe = args->GetElement(isolate_, format[i] - '0');
978
      Object* obj;
979
      if (!maybe->ToObject(&obj)) {
980
        msg.Append("<exception>");
981
        continue;
982
      }
983
      i++;
984
      switch (format[i]) {
985
        case 's':
986
          msg.AppendDetailed(String::cast(obj), false);
987
          break;
988
        case 'S':
989
          msg.AppendDetailed(String::cast(obj), true);
990
          break;
991
        case 'r':
992
          Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
993
          break;
994
        case 'x':
995
          msg.Append("0x%x", Smi::cast(obj)->value());
996
          break;
997
        case 'i':
998
          msg.Append("%i", Smi::cast(obj)->value());
999
          break;
1000
        default:
1001
          UNREACHABLE();
1002
      }
1003
    } else {
1004
      msg.Append(c);
1005
    }
1006
  }
1007
  msg.Append('\n');
1008
  msg.WriteToLogFile();
1009
}
1010

    
1011

    
1012
void Logger::ApiIndexedSecurityCheck(uint32_t index) {
1013
  if (!log_->IsEnabled() || !FLAG_log_api) return;
1014
  ApiEvent("api,check-security,%u\n", index);
1015
}
1016

    
1017

    
1018
void Logger::ApiNamedPropertyAccess(const char* tag,
1019
                                    JSObject* holder,
1020
                                    Object* name) {
1021
  ASSERT(name->IsName());
1022
  if (!log_->IsEnabled() || !FLAG_log_api) return;
1023
  String* class_name_obj = holder->class_name();
1024
  SmartArrayPointer<char> class_name =
1025
      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1026
  if (name->IsString()) {
1027
    SmartArrayPointer<char> property_name =
1028
        String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1029
    ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
1030
  } else {
1031
    Symbol* symbol = Symbol::cast(name);
1032
    uint32_t hash = symbol->Hash();
1033
    if (symbol->name()->IsUndefined()) {
1034
      ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
1035
    } else {
1036
      SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1037
          DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1038
      ApiEvent("api,%s,\"%s\",symbol(\"%s\" hash %x)\n",
1039
               tag, *class_name, *str, hash);
1040
    }
1041
  }
1042
}
1043

    
1044
void Logger::ApiIndexedPropertyAccess(const char* tag,
1045
                                      JSObject* holder,
1046
                                      uint32_t index) {
1047
  if (!log_->IsEnabled() || !FLAG_log_api) return;
1048
  String* class_name_obj = holder->class_name();
1049
  SmartArrayPointer<char> class_name =
1050
      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1051
  ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
1052
}
1053

    
1054

    
1055
void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
1056
  if (!log_->IsEnabled() || !FLAG_log_api) return;
1057
  String* class_name_obj = object->class_name();
1058
  SmartArrayPointer<char> class_name =
1059
      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1060
  ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
1061
}
1062

    
1063

    
1064
void Logger::ApiEntryCall(const char* name) {
1065
  if (!log_->IsEnabled() || !FLAG_log_api) return;
1066
  ApiEvent("api,%s\n", name);
1067
}
1068

    
1069

    
1070
void Logger::NewEvent(const char* name, void* object, size_t size) {
1071
  if (!log_->IsEnabled() || !FLAG_log) return;
1072
  Log::MessageBuilder msg(log_);
1073
  msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
1074
             static_cast<unsigned int>(size));
1075
  msg.WriteToLogFile();
1076
}
1077

    
1078

    
1079
void Logger::DeleteEvent(const char* name, void* object) {
1080
  if (!log_->IsEnabled() || !FLAG_log) return;
1081
  Log::MessageBuilder msg(log_);
1082
  msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
1083
  msg.WriteToLogFile();
1084
}
1085

    
1086

    
1087
void Logger::NewEventStatic(const char* name, void* object, size_t size) {
1088
  Isolate::Current()->logger()->NewEvent(name, object, size);
1089
}
1090

    
1091

    
1092
void Logger::DeleteEventStatic(const char* name, void* object) {
1093
  Isolate::Current()->logger()->DeleteEvent(name, object);
1094
}
1095

    
1096

    
1097
void Logger::CallbackEventInternal(const char* prefix, Name* name,
1098
                                   Address entry_point) {
1099
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1100
  Log::MessageBuilder msg(log_);
1101
  msg.Append("%s,%s,-2,",
1102
             kLogEventsNames[CODE_CREATION_EVENT],
1103
             kLogEventsNames[CALLBACK_TAG]);
1104
  msg.AppendAddress(entry_point);
1105
  if (name->IsString()) {
1106
    SmartArrayPointer<char> str =
1107
        String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1108
    msg.Append(",1,\"%s%s\"", prefix, *str);
1109
  } else {
1110
    Symbol* symbol = Symbol::cast(name);
1111
    if (symbol->name()->IsUndefined()) {
1112
      msg.Append(",1,symbol(hash %x)", prefix, symbol->Hash());
1113
    } else {
1114
      SmartArrayPointer<char> str = String::cast(symbol->name())->ToCString(
1115
          DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1116
      msg.Append(",1,symbol(\"%s\" hash %x)", prefix, *str, symbol->Hash());
1117
    }
1118
  }
1119
  msg.Append('\n');
1120
  msg.WriteToLogFile();
1121
}
1122

    
1123

    
1124
void Logger::CallbackEvent(Name* name, Address entry_point) {
1125
  PROFILER_LOG(CallbackEvent(name, entry_point));
1126
  CallbackEventInternal("", name, entry_point);
1127
}
1128

    
1129

    
1130
void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
1131
  PROFILER_LOG(GetterCallbackEvent(name, entry_point));
1132
  CallbackEventInternal("get ", name, entry_point);
1133
}
1134

    
1135

    
1136
void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
1137
  PROFILER_LOG(SetterCallbackEvent(name, entry_point));
1138
  CallbackEventInternal("set ", name, entry_point);
1139
}
1140

    
1141

    
1142
static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
1143
                                   Logger::LogEventsAndTags tag,
1144
                                   Code* code) {
1145
  ASSERT(msg);
1146
  msg->Append("%s,%s,%d,",
1147
              kLogEventsNames[Logger::CODE_CREATION_EVENT],
1148
              kLogEventsNames[tag],
1149
              code->kind());
1150
  msg->AppendAddress(code->address());
1151
  msg->Append(",%d,", code->ExecutableSize());
1152
}
1153

    
1154

    
1155
void Logger::CodeCreateEvent(LogEventsAndTags tag,
1156
                             Code* code,
1157
                             const char* comment) {
1158
  PROFILER_LOG(CodeCreateEvent(tag, code, comment));
1159

    
1160
  if (!is_logging_code_events()) return;
1161
  CALL_LISTENERS(CodeCreateEvent(tag, code, comment));
1162

    
1163
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1164
  Log::MessageBuilder msg(log_);
1165
  AppendCodeCreateHeader(&msg, tag, code);
1166
  msg.AppendDoubleQuotedString(comment);
1167
  msg.Append('\n');
1168
  msg.WriteToLogFile();
1169
}
1170

    
1171

    
1172
void Logger::CodeCreateEvent(LogEventsAndTags tag,
1173
                             Code* code,
1174
                             Name* name) {
1175
  PROFILER_LOG(CodeCreateEvent(tag, code, name));
1176

    
1177
  if (!is_logging_code_events()) return;
1178
  CALL_LISTENERS(CodeCreateEvent(tag, code, name));
1179

    
1180
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1181
  Log::MessageBuilder msg(log_);
1182
  AppendCodeCreateHeader(&msg, tag, code);
1183
  if (name->IsString()) {
1184
    msg.Append('"');
1185
    msg.AppendDetailed(String::cast(name), false);
1186
    msg.Append('"');
1187
  } else {
1188
    msg.AppendSymbolName(Symbol::cast(name));
1189
  }
1190
  msg.Append('\n');
1191
  msg.WriteToLogFile();
1192
}
1193

    
1194

    
1195
void Logger::CodeCreateEvent(LogEventsAndTags tag,
1196
                             Code* code,
1197
                             SharedFunctionInfo* shared,
1198
                             CompilationInfo* info,
1199
                             Name* name) {
1200
  PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, name));
1201

    
1202
  if (!is_logging_code_events()) return;
1203
  CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, name));
1204

    
1205
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1206
  if (code == isolate_->builtins()->builtin(
1207
      Builtins::kLazyCompile))
1208
    return;
1209

    
1210
  Log::MessageBuilder msg(log_);
1211
  AppendCodeCreateHeader(&msg, tag, code);
1212
  if (name->IsString()) {
1213
    SmartArrayPointer<char> str =
1214
        String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1215
    msg.Append("\"%s\"", *str);
1216
  } else {
1217
    msg.AppendSymbolName(Symbol::cast(name));
1218
  }
1219
  msg.Append(',');
1220
  msg.AppendAddress(shared->address());
1221
  msg.Append(",%s", ComputeMarker(code));
1222
  msg.Append('\n');
1223
  msg.WriteToLogFile();
1224
}
1225

    
1226

    
1227
// Although, it is possible to extract source and line from
1228
// the SharedFunctionInfo object, we left it to caller
1229
// to leave logging functions free from heap allocations.
1230
void Logger::CodeCreateEvent(LogEventsAndTags tag,
1231
                             Code* code,
1232
                             SharedFunctionInfo* shared,
1233
                             CompilationInfo* info,
1234
                             Name* source, int line, int column) {
1235
  PROFILER_LOG(CodeCreateEvent(tag, code, shared, info, source, line, column));
1236

    
1237
  if (!is_logging_code_events()) return;
1238
  CALL_LISTENERS(CodeCreateEvent(tag, code, shared, info, source, line,
1239
                                 column));
1240

    
1241
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1242
  Log::MessageBuilder msg(log_);
1243
  AppendCodeCreateHeader(&msg, tag, code);
1244
  SmartArrayPointer<char> name =
1245
      shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1246
  msg.Append("\"%s ", *name);
1247
  if (source->IsString()) {
1248
    SmartArrayPointer<char> sourcestr =
1249
       String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
1250
    msg.Append("%s", *sourcestr);
1251
  } else {
1252
    msg.AppendSymbolName(Symbol::cast(source));
1253
  }
1254
  msg.Append(":%d:%d\",", line, column);
1255
  msg.AppendAddress(shared->address());
1256
  msg.Append(",%s", ComputeMarker(code));
1257
  msg.Append('\n');
1258
  msg.WriteToLogFile();
1259
}
1260

    
1261

    
1262
void Logger::CodeCreateEvent(LogEventsAndTags tag,
1263
                             Code* code,
1264
                             int args_count) {
1265
  PROFILER_LOG(CodeCreateEvent(tag, code, args_count));
1266

    
1267
  if (!is_logging_code_events()) return;
1268
  CALL_LISTENERS(CodeCreateEvent(tag, code, args_count));
1269

    
1270
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1271
  Log::MessageBuilder msg(log_);
1272
  AppendCodeCreateHeader(&msg, tag, code);
1273
  msg.Append("\"args_count: %d\"", args_count);
1274
  msg.Append('\n');
1275
  msg.WriteToLogFile();
1276
}
1277

    
1278

    
1279
void Logger::CodeMovingGCEvent() {
1280
  PROFILER_LOG(CodeMovingGCEvent());
1281

    
1282
  if (!is_logging_code_events()) return;
1283
  if (!log_->IsEnabled() || !FLAG_ll_prof) return;
1284
  CALL_LISTENERS(CodeMovingGCEvent());
1285
  OS::SignalCodeMovingGC();
1286
}
1287

    
1288

    
1289
void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
1290
  PROFILER_LOG(RegExpCodeCreateEvent(code, source));
1291

    
1292
  if (!is_logging_code_events()) return;
1293
  CALL_LISTENERS(RegExpCodeCreateEvent(code, source));
1294

    
1295
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1296
  Log::MessageBuilder msg(log_);
1297
  AppendCodeCreateHeader(&msg, REG_EXP_TAG, code);
1298
  msg.Append('"');
1299
  msg.AppendDetailed(source, false);
1300
  msg.Append('"');
1301
  msg.Append('\n');
1302
  msg.WriteToLogFile();
1303
}
1304

    
1305

    
1306
void Logger::CodeMoveEvent(Address from, Address to) {
1307
  PROFILER_LOG(CodeMoveEvent(from, to));
1308

    
1309
  if (!is_logging_code_events()) return;
1310
  CALL_LISTENERS(CodeMoveEvent(from, to));
1311
  MoveEventInternal(CODE_MOVE_EVENT, from, to);
1312
}
1313

    
1314

    
1315
void Logger::CodeDeleteEvent(Address from) {
1316
  PROFILER_LOG(CodeDeleteEvent(from));
1317

    
1318
  if (!is_logging_code_events()) return;
1319
  CALL_LISTENERS(CodeDeleteEvent(from));
1320

    
1321
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1322
  Log::MessageBuilder msg(log_);
1323
  msg.Append("%s,", kLogEventsNames[CODE_DELETE_EVENT]);
1324
  msg.AppendAddress(from);
1325
  msg.Append('\n');
1326
  msg.WriteToLogFile();
1327
}
1328

    
1329

    
1330
void Logger::CodeLinePosInfoAddPositionEvent(void* jit_handler_data,
1331
                                     int pc_offset,
1332
                                     int position) {
1333
  JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1334
                                  pc_offset,
1335
                                  position,
1336
                                  JitCodeEvent::POSITION));
1337
}
1338

    
1339

    
1340
void Logger::CodeLinePosInfoAddStatementPositionEvent(void* jit_handler_data,
1341
                                                      int pc_offset,
1342
                                                      int position) {
1343
  JIT_LOG(AddCodeLinePosInfoEvent(jit_handler_data,
1344
                                  pc_offset,
1345
                                  position,
1346
                                  JitCodeEvent::STATEMENT_POSITION));
1347
}
1348

    
1349

    
1350
void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
1351
  if (jit_logger_ != NULL) {
1352
      pos_recorder->AttachJITHandlerData(jit_logger_->StartCodePosInfoEvent());
1353
  }
1354
}
1355

    
1356

    
1357
void Logger::CodeEndLinePosInfoRecordEvent(Code* code,
1358
                                           void* jit_handler_data) {
1359
  JIT_LOG(EndCodePosInfoEvent(code, jit_handler_data));
1360
}
1361

    
1362

    
1363
void Logger::CodeNameEvent(Address addr, int pos, const char* code_name) {
1364
  if (code_name == NULL) return;  // Not a code object.
1365
  Log::MessageBuilder msg(log_);
1366
  msg.Append("%s,%d,", kLogEventsNames[SNAPSHOT_CODE_NAME_EVENT], pos);
1367
  msg.AppendDoubleQuotedString(code_name);
1368
  msg.Append("\n");
1369
  msg.WriteToLogFile();
1370
}
1371

    
1372

    
1373
void Logger::SnapshotPositionEvent(Address addr, int pos) {
1374
  if (!log_->IsEnabled()) return;
1375
  LL_LOG(SnapshotPositionEvent(addr, pos));
1376
  if (!FLAG_log_snapshot_positions) return;
1377
  Log::MessageBuilder msg(log_);
1378
  msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
1379
  msg.AppendAddress(addr);
1380
  msg.Append(",%d", pos);
1381
  msg.Append('\n');
1382
  msg.WriteToLogFile();
1383
}
1384

    
1385

    
1386
void Logger::SharedFunctionInfoMoveEvent(Address from, Address to) {
1387
  PROFILER_LOG(SharedFunctionInfoMoveEvent(from, to));
1388

    
1389
  if (!is_logging_code_events()) return;
1390
  MoveEventInternal(SHARED_FUNC_MOVE_EVENT, from, to);
1391
}
1392

    
1393

    
1394
void Logger::MoveEventInternal(LogEventsAndTags event,
1395
                               Address from,
1396
                               Address to) {
1397
  if (!FLAG_log_code || !log_->IsEnabled()) return;
1398
  Log::MessageBuilder msg(log_);
1399
  msg.Append("%s,", kLogEventsNames[event]);
1400
  msg.AppendAddress(from);
1401
  msg.Append(',');
1402
  msg.AppendAddress(to);
1403
  msg.Append('\n');
1404
  msg.WriteToLogFile();
1405
}
1406

    
1407

    
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 (OS::GetUserTime(&sec, &usec) != -1) {
1415
    msg.Append("%d,%d,", sec, usec);
1416
  }
1417
  msg.Append("%.0f", OS::TimeCurrentMillis());
1418

    
1419
  msg.Append('\n');
1420
  msg.WriteToLogFile();
1421
}
1422

    
1423

    
1424
void Logger::SuspectReadEvent(Name* name, Object* obj) {
1425
  if (!log_->IsEnabled() || !FLAG_log_suspect) return;
1426
  Log::MessageBuilder msg(log_);
1427
  String* class_name = obj->IsJSObject()
1428
                       ? JSObject::cast(obj)->class_name()
1429
                       : isolate_->heap()->empty_string();
1430
  msg.Append("suspect-read,");
1431
  msg.Append(class_name);
1432
  msg.Append(',');
1433
  if (name->IsString()) {
1434
    msg.Append('"');
1435
    msg.Append(String::cast(name));
1436
    msg.Append('"');
1437
  } else {
1438
    msg.AppendSymbolName(Symbol::cast(name));
1439
  }
1440
  msg.Append('\n');
1441
  msg.WriteToLogFile();
1442
}
1443

    
1444

    
1445
void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
1446
  if (!log_->IsEnabled() || !FLAG_log_gc) return;
1447
  Log::MessageBuilder msg(log_);
1448
  // Using non-relative system time in order to be able to synchronize with
1449
  // external memory profiling events (e.g. DOM memory size).
1450
  msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
1451
             space, kind, OS::TimeCurrentMillis());
1452
  msg.WriteToLogFile();
1453
}
1454

    
1455

    
1456
void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
1457
  if (!log_->IsEnabled() || !FLAG_log_gc) return;
1458
  Log::MessageBuilder msg(log_);
1459
  msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
1460
  msg.WriteToLogFile();
1461
}
1462

    
1463

    
1464
void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
1465
  if (!log_->IsEnabled() || !FLAG_log_gc) return;
1466
  Log::MessageBuilder msg(log_);
1467
  msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
1468
  msg.WriteToLogFile();
1469
}
1470

    
1471

    
1472
void Logger::DebugTag(const char* call_site_tag) {
1473
  if (!log_->IsEnabled() || !FLAG_log) return;
1474
  Log::MessageBuilder msg(log_);
1475
  msg.Append("debug-tag,%s\n", call_site_tag);
1476
  msg.WriteToLogFile();
1477
}
1478

    
1479

    
1480
void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
1481
  if (!log_->IsEnabled() || !FLAG_log) return;
1482
  StringBuilder s(parameter.length() + 1);
1483
  for (int i = 0; i < parameter.length(); ++i) {
1484
    s.AddCharacter(static_cast<char>(parameter[i]));
1485
  }
1486
  char* parameter_string = s.Finalize();
1487
  Log::MessageBuilder msg(log_);
1488
  msg.Append("debug-queue-event,%s,%15.3f,%s\n",
1489
             event_type,
1490
             OS::TimeCurrentMillis(),
1491
             parameter_string);
1492
  DeleteArray(parameter_string);
1493
  msg.WriteToLogFile();
1494
}
1495

    
1496

    
1497
void Logger::TickEvent(TickSample* sample, bool overflow) {
1498
  if (!log_->IsEnabled() || !FLAG_prof) return;
1499
  Log::MessageBuilder msg(log_);
1500
  msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1501
  msg.AppendAddress(sample->pc);
1502
  msg.Append(",%ld", static_cast<int>(timer_.Elapsed().InMicroseconds()));
1503
  if (sample->has_external_callback) {
1504
    msg.Append(",1,");
1505
    msg.AppendAddress(sample->external_callback);
1506
  } else {
1507
    msg.Append(",0,");
1508
    msg.AppendAddress(sample->tos);
1509
  }
1510
  msg.Append(",%d", static_cast<int>(sample->state));
1511
  if (overflow) {
1512
    msg.Append(",overflow");
1513
  }
1514
  for (int i = 0; i < sample->frames_count; ++i) {
1515
    msg.Append(',');
1516
    msg.AppendAddress(sample->stack[i]);
1517
  }
1518
  msg.Append('\n');
1519
  msg.WriteToLogFile();
1520
}
1521

    
1522

    
1523
void Logger::StopProfiler() {
1524
  if (!log_->IsEnabled()) return;
1525
  if (profiler_ != NULL) {
1526
    profiler_->pause();
1527
    is_logging_ = false;
1528
  }
1529
}
1530

    
1531

    
1532
// This function can be called when Log's mutex is acquired,
1533
// either from main or Profiler's thread.
1534
void Logger::LogFailure() {
1535
  StopProfiler();
1536
}
1537

    
1538

    
1539
class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
1540
 public:
1541
  EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
1542
                                     Handle<Code>* code_objects,
1543
                                     int* count)
1544
      : sfis_(sfis), code_objects_(code_objects), count_(count) { }
1545

    
1546
  virtual void EnterContext(Context* context) {}
1547
  virtual void LeaveContext(Context* context) {}
1548

    
1549
  virtual void VisitFunction(JSFunction* function) {
1550
    SharedFunctionInfo* sfi = SharedFunctionInfo::cast(function->shared());
1551
    Object* maybe_script = sfi->script();
1552
    if (maybe_script->IsScript()
1553
        && !Script::cast(maybe_script)->HasValidSource()) return;
1554
    if (sfis_ != NULL) {
1555
      sfis_[*count_] = Handle<SharedFunctionInfo>(sfi);
1556
    }
1557
    if (code_objects_ != NULL) {
1558
      ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1559
      code_objects_[*count_] = Handle<Code>(function->code());
1560
    }
1561
    *count_ = *count_ + 1;
1562
  }
1563

    
1564
 private:
1565
  Handle<SharedFunctionInfo>* sfis_;
1566
  Handle<Code>* code_objects_;
1567
  int* count_;
1568
};
1569

    
1570

    
1571
static int EnumerateCompiledFunctions(Heap* heap,
1572
                                      Handle<SharedFunctionInfo>* sfis,
1573
                                      Handle<Code>* code_objects) {
1574
  HeapIterator iterator(heap);
1575
  DisallowHeapAllocation no_gc;
1576
  int compiled_funcs_count = 0;
1577

    
1578
  // Iterate the heap to find shared function info objects and record
1579
  // the unoptimized code for them.
1580
  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1581
    if (!obj->IsSharedFunctionInfo()) continue;
1582
    SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
1583
    if (sfi->is_compiled()
1584
        && (!sfi->script()->IsScript()
1585
            || Script::cast(sfi->script())->HasValidSource())) {
1586
      if (sfis != NULL) {
1587
        sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
1588
      }
1589
      if (code_objects != NULL) {
1590
        code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1591
      }
1592
      ++compiled_funcs_count;
1593
    }
1594
  }
1595

    
1596
  // Iterate all optimized functions in all contexts.
1597
  EnumerateOptimizedFunctionsVisitor visitor(sfis,
1598
                                             code_objects,
1599
                                             &compiled_funcs_count);
1600
  Deoptimizer::VisitAllOptimizedFunctions(heap->isolate(), &visitor);
1601

    
1602
  return compiled_funcs_count;
1603
}
1604

    
1605

    
1606
void Logger::LogCodeObject(Object* object) {
1607
  Code* code_object = Code::cast(object);
1608
  LogEventsAndTags tag = Logger::STUB_TAG;
1609
  const char* description = "Unknown code from the snapshot";
1610
  switch (code_object->kind()) {
1611
    case Code::FUNCTION:
1612
    case Code::OPTIMIZED_FUNCTION:
1613
      return;  // We log this later using LogCompiledFunctions.
1614
    case Code::BINARY_OP_IC: {
1615
      BinaryOpStub stub(code_object->extended_extra_ic_state());
1616
      description = stub.GetName().Detach();
1617
      tag = Logger::STUB_TAG;
1618
      break;
1619
    }
1620
    case Code::COMPARE_IC:  // fall through
1621
    case Code::COMPARE_NIL_IC:   // fall through
1622
    case Code::TO_BOOLEAN_IC:  // fall through
1623
    case Code::STUB:
1624
      description =
1625
          CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
1626
      if (description == NULL)
1627
        description = "A stub from the snapshot";
1628
      tag = Logger::STUB_TAG;
1629
      break;
1630
    case Code::REGEXP:
1631
      description = "Regular expression code";
1632
      tag = Logger::REG_EXP_TAG;
1633
      break;
1634
    case Code::BUILTIN:
1635
      description = "A builtin from the snapshot";
1636
      tag = Logger::BUILTIN_TAG;
1637
      break;
1638
    case Code::HANDLER:
1639
      description = "An IC handler from the snapshot";
1640
      tag = Logger::HANDLER_TAG;
1641
      break;
1642
    case Code::KEYED_LOAD_IC:
1643
      description = "A keyed load IC from the snapshot";
1644
      tag = Logger::KEYED_LOAD_IC_TAG;
1645
      break;
1646
    case Code::LOAD_IC:
1647
      description = "A load IC from the snapshot";
1648
      tag = Logger::LOAD_IC_TAG;
1649
      break;
1650
    case Code::STORE_IC:
1651
      description = "A store IC from the snapshot";
1652
      tag = Logger::STORE_IC_TAG;
1653
      break;
1654
    case Code::KEYED_STORE_IC:
1655
      description = "A keyed store IC from the snapshot";
1656
      tag = Logger::KEYED_STORE_IC_TAG;
1657
      break;
1658
    case Code::CALL_IC:
1659
      description = "A call IC from the snapshot";
1660
      tag = Logger::CALL_IC_TAG;
1661
      break;
1662
    case Code::KEYED_CALL_IC:
1663
      description = "A keyed call IC from the snapshot";
1664
      tag = Logger::KEYED_CALL_IC_TAG;
1665
      break;
1666
    case Code::NUMBER_OF_KINDS:
1667
      break;
1668
  }
1669
  PROFILE(isolate_, CodeCreateEvent(tag, code_object, description));
1670
}
1671

    
1672

    
1673
void Logger::LogCodeObjects() {
1674
  Heap* heap = isolate_->heap();
1675
  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1676
                          "Logger::LogCodeObjects");
1677
  HeapIterator iterator(heap);
1678
  DisallowHeapAllocation no_gc;
1679
  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1680
    if (obj->IsCode()) LogCodeObject(obj);
1681
  }
1682
}
1683

    
1684

    
1685
void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
1686
                                 Handle<Code> code) {
1687
  Handle<String> func_name(shared->DebugName());
1688
  if (shared->script()->IsScript()) {
1689
    Handle<Script> script(Script::cast(shared->script()));
1690
    int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
1691
    int column_num =
1692
        GetScriptColumnNumber(script, shared->start_position()) + 1;
1693
    if (script->name()->IsString()) {
1694
      Handle<String> script_name(String::cast(script->name()));
1695
      if (line_num > 0) {
1696
        PROFILE(isolate_,
1697
                CodeCreateEvent(
1698
                    Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1699
                    *code, *shared, NULL,
1700
                    *script_name, line_num, column_num));
1701
      } else {
1702
        // Can't distinguish eval and script here, so always use Script.
1703
        PROFILE(isolate_,
1704
                CodeCreateEvent(
1705
                    Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
1706
                    *code, *shared, NULL, *script_name));
1707
      }
1708
    } else {
1709
      PROFILE(isolate_,
1710
              CodeCreateEvent(
1711
                  Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1712
                  *code, *shared, NULL,
1713
                  isolate_->heap()->empty_string(), line_num, column_num));
1714
    }
1715
  } else if (shared->IsApiFunction()) {
1716
    // API function.
1717
    FunctionTemplateInfo* fun_data = shared->get_api_func_data();
1718
    Object* raw_call_data = fun_data->call_code();
1719
    if (!raw_call_data->IsUndefined()) {
1720
      CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1721
      Object* callback_obj = call_data->callback();
1722
      Address entry_point = v8::ToCData<Address>(callback_obj);
1723
      PROFILE(isolate_, CallbackEvent(*func_name, entry_point));
1724
    }
1725
  } else {
1726
    PROFILE(isolate_,
1727
            CodeCreateEvent(
1728
                Logger::LAZY_COMPILE_TAG, *code, *shared, NULL, *func_name));
1729
  }
1730
}
1731

    
1732

    
1733
void Logger::LogCompiledFunctions() {
1734
  Heap* heap = isolate_->heap();
1735
  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1736
                          "Logger::LogCompiledFunctions");
1737
  HandleScope scope(isolate_);
1738
  const int compiled_funcs_count = EnumerateCompiledFunctions(heap, NULL, NULL);
1739
  ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
1740
  ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1741
  EnumerateCompiledFunctions(heap, sfis.start(), code_objects.start());
1742

    
1743
  // During iteration, there can be heap allocation due to
1744
  // GetScriptLineNumber call.
1745
  for (int i = 0; i < compiled_funcs_count; ++i) {
1746
    if (*code_objects[i] == isolate_->builtins()->builtin(
1747
        Builtins::kLazyCompile))
1748
      continue;
1749
    LogExistingFunction(sfis[i], code_objects[i]);
1750
  }
1751
}
1752

    
1753

    
1754
void Logger::LogAccessorCallbacks() {
1755
  Heap* heap = isolate_->heap();
1756
  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1757
                          "Logger::LogAccessorCallbacks");
1758
  HeapIterator iterator(heap);
1759
  DisallowHeapAllocation no_gc;
1760
  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1761
    if (!obj->IsExecutableAccessorInfo()) continue;
1762
    ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
1763
    if (!ai->name()->IsName()) continue;
1764
    Address getter_entry = v8::ToCData<Address>(ai->getter());
1765
    Name* name = Name::cast(ai->name());
1766
    if (getter_entry != 0) {
1767
      PROFILE(isolate_, GetterCallbackEvent(name, getter_entry));
1768
    }
1769
    Address setter_entry = v8::ToCData<Address>(ai->setter());
1770
    if (setter_entry != 0) {
1771
      PROFILE(isolate_, SetterCallbackEvent(name, setter_entry));
1772
    }
1773
  }
1774
}
1775

    
1776

    
1777
static void AddIsolateIdIfNeeded(Isolate* isolate, StringStream* stream) {
1778
  if (isolate->IsDefaultIsolate() || !FLAG_logfile_per_isolate) return;
1779
  stream->Add("isolate-%p-", isolate);
1780
}
1781

    
1782

    
1783
static SmartArrayPointer<const char> PrepareLogFileName(
1784
    Isolate* isolate, const char* file_name) {
1785
  if (strchr(file_name, '%') != NULL || !isolate->IsDefaultIsolate()) {
1786
    // If there's a '%' in the log file name we have to expand
1787
    // placeholders.
1788
    HeapStringAllocator allocator;
1789
    StringStream stream(&allocator);
1790
    AddIsolateIdIfNeeded(isolate, &stream);
1791
    for (const char* p = file_name; *p; p++) {
1792
      if (*p == '%') {
1793
        p++;
1794
        switch (*p) {
1795
          case '\0':
1796
            // If there's a % at the end of the string we back up
1797
            // one character so we can escape the loop properly.
1798
            p--;
1799
            break;
1800
          case 'p':
1801
            stream.Add("%d", OS::GetCurrentProcessId());
1802
            break;
1803
          case 't': {
1804
            // %t expands to the current time in milliseconds.
1805
            double time = OS::TimeCurrentMillis();
1806
            stream.Add("%.0f", FmtElm(time));
1807
            break;
1808
          }
1809
          case '%':
1810
            // %% expands (contracts really) to %.
1811
            stream.Put('%');
1812
            break;
1813
          default:
1814
            // All other %'s expand to themselves.
1815
            stream.Put('%');
1816
            stream.Put(*p);
1817
            break;
1818
        }
1819
      } else {
1820
        stream.Put(*p);
1821
      }
1822
    }
1823
    return SmartArrayPointer<const char>(stream.ToCString());
1824
  }
1825
  int length = StrLength(file_name);
1826
  char* str = NewArray<char>(length + 1);
1827
  OS::MemCopy(str, file_name, length);
1828
  str[length] = '\0';
1829
  return SmartArrayPointer<const char>(str);
1830
}
1831

    
1832

    
1833
bool Logger::SetUp(Isolate* isolate) {
1834
  // Tests and EnsureInitialize() can call this twice in a row. It's harmless.
1835
  if (is_initialized_) return true;
1836
  is_initialized_ = true;
1837

    
1838
  // --ll-prof implies --log-code and --log-snapshot-positions.
1839
  if (FLAG_ll_prof) {
1840
    FLAG_log_snapshot_positions = true;
1841
  }
1842

    
1843
  SmartArrayPointer<const char> log_file_name =
1844
      PrepareLogFileName(isolate, FLAG_logfile);
1845
  log_->Initialize(*log_file_name);
1846

    
1847
  if (FLAG_ll_prof) {
1848
    ll_logger_ = new LowLevelLogger(*log_file_name);
1849
    addCodeEventListener(ll_logger_);
1850
  }
1851

    
1852
  ticker_ = new Ticker(isolate, kSamplingIntervalMs);
1853

    
1854
  if (Log::InitLogAtStart()) {
1855
    is_logging_ = true;
1856
  }
1857

    
1858
  if (FLAG_prof) {
1859
    profiler_ = new Profiler(isolate);
1860
    is_logging_ = true;
1861
    profiler_->Engage();
1862
  }
1863

    
1864
  if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
1865

    
1866
  return true;
1867
}
1868

    
1869

    
1870
void Logger::SetCodeEventHandler(uint32_t options,
1871
                                 JitCodeEventHandler event_handler) {
1872
  if (jit_logger_) {
1873
      removeCodeEventListener(jit_logger_);
1874
      delete jit_logger_;
1875
      jit_logger_ = NULL;
1876
  }
1877

    
1878
  if (event_handler) {
1879
    jit_logger_ = new JitLogger(event_handler);
1880
    addCodeEventListener(jit_logger_);
1881
    if (options & kJitCodeEventEnumExisting) {
1882
      HandleScope scope(isolate_);
1883
      LogCodeObjects();
1884
      LogCompiledFunctions();
1885
    }
1886
  }
1887
}
1888

    
1889

    
1890
Sampler* Logger::sampler() {
1891
  return ticker_;
1892
}
1893

    
1894

    
1895
FILE* Logger::TearDown() {
1896
  if (!is_initialized_) return NULL;
1897
  is_initialized_ = false;
1898

    
1899
  // Stop the profiler before closing the file.
1900
  if (profiler_ != NULL) {
1901
    profiler_->Disengage();
1902
    delete profiler_;
1903
    profiler_ = NULL;
1904
  }
1905

    
1906
  delete ticker_;
1907
  ticker_ = NULL;
1908

    
1909
  if (ll_logger_) {
1910
    removeCodeEventListener(ll_logger_);
1911
    delete ll_logger_;
1912
    ll_logger_ = NULL;
1913
  }
1914

    
1915
  if (jit_logger_) {
1916
    removeCodeEventListener(jit_logger_);
1917
    delete jit_logger_;
1918
    jit_logger_ = NULL;
1919
  }
1920

    
1921
  return log_->Close();
1922
}
1923

    
1924
} }  // namespace v8::internal