log.cc revision e0cee9b3ed82e2391fd85d118aeaa4ea361c687d
1// Copyright 2009 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 "deoptimizer.h"
35#include "global-handles.h"
36#include "log.h"
37#include "macro-assembler.h"
38#include "runtime-profiler.h"
39#include "serialize.h"
40#include "string-stream.h"
41#include "vm-state-inl.h"
42
43namespace v8 {
44namespace internal {
45
46#ifdef ENABLE_LOGGING_AND_PROFILING
47
48//
49// Sliding state window.  Updates counters to keep track of the last
50// window of kBufferSize states.  This is useful to track where we
51// spent our time.
52//
53class SlidingStateWindow {
54 public:
55  SlidingStateWindow();
56  ~SlidingStateWindow();
57  void AddState(StateTag state);
58
59 private:
60  static const int kBufferSize = 256;
61  int current_index_;
62  bool is_full_;
63  byte buffer_[kBufferSize];
64
65
66  void IncrementStateCounter(StateTag state) {
67    Counters::state_counters[state].Increment();
68  }
69
70
71  void DecrementStateCounter(StateTag state) {
72    Counters::state_counters[state].Decrement();
73  }
74};
75
76
77//
78// The Profiler samples pc and sp values for the main thread.
79// Each sample is appended to a circular buffer.
80// An independent thread removes data and writes it to the log.
81// This design minimizes the time spent in the sampler.
82//
83class Profiler: public Thread {
84 public:
85  Profiler();
86  void Engage();
87  void Disengage();
88
89  // Inserts collected profiling data into buffer.
90  void Insert(TickSample* sample) {
91    if (paused_)
92      return;
93
94    if (Succ(head_) == tail_) {
95      overflow_ = true;
96    } else {
97      buffer_[head_] = *sample;
98      head_ = Succ(head_);
99      buffer_semaphore_->Signal();  // Tell we have an element.
100    }
101  }
102
103  // Waits for a signal and removes profiling data.
104  bool Remove(TickSample* sample) {
105    buffer_semaphore_->Wait();  // Wait for an element.
106    *sample = buffer_[tail_];
107    bool result = overflow_;
108    tail_ = Succ(tail_);
109    overflow_ = false;
110    return result;
111  }
112
113  void Run();
114
115  // Pause and Resume TickSample data collection.
116  static bool paused() { return paused_; }
117  static void pause() { paused_ = true; }
118  static void resume() { paused_ = false; }
119
120 private:
121  // Returns the next index in the cyclic buffer.
122  int Succ(int index) { return (index + 1) % kBufferSize; }
123
124  // Cyclic buffer for communicating profiling samples
125  // between the signal handler and the worker thread.
126  static const int kBufferSize = 128;
127  TickSample buffer_[kBufferSize];  // Buffer storage.
128  int head_;  // Index to the buffer head.
129  int tail_;  // Index to the buffer tail.
130  bool overflow_;  // Tell whether a buffer overflow has occurred.
131  Semaphore* buffer_semaphore_;  // Sempahore used for buffer synchronization.
132
133  // Tells whether profiler is engaged, that is, processing thread is stated.
134  bool engaged_;
135
136  // Tells whether worker thread should continue running.
137  bool running_;
138
139  // Tells whether we are currently recording tick samples.
140  static bool paused_;
141};
142
143bool Profiler::paused_ = false;
144
145
146//
147// StackTracer implementation
148//
149void StackTracer::Trace(TickSample* sample) {
150  sample->tos = NULL;
151  sample->frames_count = 0;
152
153  // Avoid collecting traces while doing GC.
154  if (sample->state == GC) return;
155
156  const Address js_entry_sp = Top::js_entry_sp(Top::GetCurrentThread());
157  if (js_entry_sp == 0) {
158    // Not executing JS now.
159    return;
160  }
161
162  // Sample potential return address value for frameless invocation of
163  // stubs (we'll figure out later, if this value makes sense).
164  sample->tos = Memory::Address_at(sample->sp);
165
166  int i = 0;
167  const Address callback = Top::external_callback();
168  // Surprisingly, PC can point _exactly_ to callback start, with good
169  // probability, and this will result in reporting fake nested
170  // callback call.
171  if (callback != NULL && callback != sample->pc) {
172    sample->stack[i++] = callback;
173  }
174
175  SafeStackTraceFrameIterator it(sample->fp, sample->sp,
176                                 sample->sp, js_entry_sp);
177  while (!it.done() && i < TickSample::kMaxFramesCount) {
178    sample->stack[i++] = it.frame()->pc();
179    it.Advance();
180  }
181  sample->frames_count = i;
182}
183
184
185//
186// Ticker used to provide ticks to the profiler and the sliding state
187// window.
188//
189class Ticker: public Sampler {
190 public:
191  explicit Ticker(int interval) :
192      Sampler(interval),
193      window_(NULL),
194      profiler_(NULL) {}
195
196  ~Ticker() { if (IsActive()) Stop(); }
197
198  virtual void Tick(TickSample* sample) {
199    if (profiler_) profiler_->Insert(sample);
200    if (window_) window_->AddState(sample->state);
201  }
202
203  void SetWindow(SlidingStateWindow* window) {
204    window_ = window;
205    if (!IsActive()) Start();
206  }
207
208  void ClearWindow() {
209    window_ = NULL;
210    if (!profiler_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop();
211  }
212
213  void SetProfiler(Profiler* profiler) {
214    ASSERT(profiler_ == NULL);
215    profiler_ = profiler;
216    IncreaseProfilingDepth();
217    if (!FLAG_prof_lazy && !IsActive()) Start();
218  }
219
220  void ClearProfiler() {
221    DecreaseProfilingDepth();
222    profiler_ = NULL;
223    if (!window_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop();
224  }
225
226 protected:
227  virtual void DoSampleStack(TickSample* sample) {
228    StackTracer::Trace(sample);
229  }
230
231 private:
232  SlidingStateWindow* window_;
233  Profiler* profiler_;
234};
235
236
237//
238// SlidingStateWindow implementation.
239//
240SlidingStateWindow::SlidingStateWindow(): current_index_(0), is_full_(false) {
241  for (int i = 0; i < kBufferSize; i++) {
242    buffer_[i] = static_cast<byte>(OTHER);
243  }
244  Logger::ticker_->SetWindow(this);
245}
246
247
248SlidingStateWindow::~SlidingStateWindow() {
249  Logger::ticker_->ClearWindow();
250}
251
252
253void SlidingStateWindow::AddState(StateTag state) {
254  if (is_full_) {
255    DecrementStateCounter(static_cast<StateTag>(buffer_[current_index_]));
256  } else if (current_index_ == kBufferSize - 1) {
257    is_full_ = true;
258  }
259  buffer_[current_index_] = static_cast<byte>(state);
260  IncrementStateCounter(state);
261  ASSERT(IsPowerOf2(kBufferSize));
262  current_index_ = (current_index_ + 1) & (kBufferSize - 1);
263}
264
265
266//
267// Profiler implementation.
268//
269Profiler::Profiler()
270    : Thread("v8:Profiler"),
271      head_(0),
272      tail_(0),
273      overflow_(false),
274      buffer_semaphore_(OS::CreateSemaphore(0)),
275      engaged_(false),
276      running_(false) {
277}
278
279
280void Profiler::Engage() {
281  if (engaged_) return;
282  engaged_ = true;
283
284  // TODO(mnaganov): This is actually "Chromium" mode. Flags need to be revised.
285  // http://code.google.com/p/v8/issues/detail?id=487
286  if (!FLAG_prof_lazy) {
287    OS::LogSharedLibraryAddresses();
288  }
289
290  // Start thread processing the profiler buffer.
291  running_ = true;
292  Start();
293
294  // Register to get ticks.
295  Logger::ticker_->SetProfiler(this);
296
297  Logger::ProfilerBeginEvent();
298}
299
300
301void Profiler::Disengage() {
302  if (!engaged_) return;
303
304  // Stop receiving ticks.
305  Logger::ticker_->ClearProfiler();
306
307  // Terminate the worker thread by setting running_ to false,
308  // inserting a fake element in the queue and then wait for
309  // the thread to terminate.
310  running_ = false;
311  TickSample sample;
312  // Reset 'paused_' flag, otherwise semaphore may not be signalled.
313  resume();
314  Insert(&sample);
315  Join();
316
317  LOG(UncheckedStringEvent("profiler", "end"));
318}
319
320
321void Profiler::Run() {
322  TickSample sample;
323  bool overflow = Remove(&sample);
324  while (running_) {
325    LOG(TickEvent(&sample, overflow));
326    overflow = Remove(&sample);
327  }
328}
329
330
331//
332// Logger class implementation.
333//
334Ticker* Logger::ticker_ = NULL;
335Profiler* Logger::profiler_ = NULL;
336SlidingStateWindow* Logger::sliding_state_window_ = NULL;
337int Logger::logging_nesting_ = 0;
338int Logger::cpu_profiler_nesting_ = 0;
339int Logger::heap_profiler_nesting_ = 0;
340
341#define DECLARE_EVENT(ignore1, name) name,
342const char* kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
343  LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
344};
345#undef DECLARE_EVENT
346
347
348void Logger::ProfilerBeginEvent() {
349  if (!Log::IsEnabled()) return;
350  LogMessageBuilder msg;
351  msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
352  msg.WriteToLogFile();
353}
354
355#endif  // ENABLE_LOGGING_AND_PROFILING
356
357
358void Logger::StringEvent(const char* name, const char* value) {
359#ifdef ENABLE_LOGGING_AND_PROFILING
360  if (FLAG_log) UncheckedStringEvent(name, value);
361#endif
362}
363
364
365#ifdef ENABLE_LOGGING_AND_PROFILING
366void Logger::UncheckedStringEvent(const char* name, const char* value) {
367  if (!Log::IsEnabled()) return;
368  LogMessageBuilder msg;
369  msg.Append("%s,\"%s\"\n", name, value);
370  msg.WriteToLogFile();
371}
372#endif
373
374
375void Logger::IntEvent(const char* name, int value) {
376#ifdef ENABLE_LOGGING_AND_PROFILING
377  if (FLAG_log) UncheckedIntEvent(name, value);
378#endif
379}
380
381
382void Logger::IntPtrTEvent(const char* name, intptr_t value) {
383#ifdef ENABLE_LOGGING_AND_PROFILING
384  if (FLAG_log) UncheckedIntPtrTEvent(name, value);
385#endif
386}
387
388
389#ifdef ENABLE_LOGGING_AND_PROFILING
390void Logger::UncheckedIntEvent(const char* name, int value) {
391  if (!Log::IsEnabled()) return;
392  LogMessageBuilder msg;
393  msg.Append("%s,%d\n", name, value);
394  msg.WriteToLogFile();
395}
396#endif
397
398
399#ifdef ENABLE_LOGGING_AND_PROFILING
400void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) {
401  if (!Log::IsEnabled()) return;
402  LogMessageBuilder msg;
403  msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value);
404  msg.WriteToLogFile();
405}
406#endif
407
408
409void Logger::HandleEvent(const char* name, Object** location) {
410#ifdef ENABLE_LOGGING_AND_PROFILING
411  if (!Log::IsEnabled() || !FLAG_log_handles) return;
412  LogMessageBuilder msg;
413  msg.Append("%s,0x%" V8PRIxPTR "\n", name, location);
414  msg.WriteToLogFile();
415#endif
416}
417
418
419#ifdef ENABLE_LOGGING_AND_PROFILING
420// ApiEvent is private so all the calls come from the Logger class.  It is the
421// caller's responsibility to ensure that log is enabled and that
422// FLAG_log_api is true.
423void Logger::ApiEvent(const char* format, ...) {
424  ASSERT(Log::IsEnabled() && FLAG_log_api);
425  LogMessageBuilder msg;
426  va_list ap;
427  va_start(ap, format);
428  msg.AppendVA(format, ap);
429  va_end(ap);
430  msg.WriteToLogFile();
431}
432#endif
433
434
435void Logger::ApiNamedSecurityCheck(Object* key) {
436#ifdef ENABLE_LOGGING_AND_PROFILING
437  if (!Log::IsEnabled() || !FLAG_log_api) return;
438  if (key->IsString()) {
439    SmartPointer<char> str =
440        String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
441    ApiEvent("api,check-security,\"%s\"\n", *str);
442  } else if (key->IsUndefined()) {
443    ApiEvent("api,check-security,undefined\n");
444  } else {
445    ApiEvent("api,check-security,['no-name']\n");
446  }
447#endif
448}
449
450
451void Logger::SharedLibraryEvent(const char* library_path,
452                                uintptr_t start,
453                                uintptr_t end) {
454#ifdef ENABLE_LOGGING_AND_PROFILING
455  if (!Log::IsEnabled() || !FLAG_prof) return;
456  LogMessageBuilder msg;
457  msg.Append("shared-library,\"%s\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
458             library_path,
459             start,
460             end);
461  msg.WriteToLogFile();
462#endif
463}
464
465
466void Logger::SharedLibraryEvent(const wchar_t* library_path,
467                                uintptr_t start,
468                                uintptr_t end) {
469#ifdef ENABLE_LOGGING_AND_PROFILING
470  if (!Log::IsEnabled() || !FLAG_prof) return;
471  LogMessageBuilder msg;
472  msg.Append("shared-library,\"%ls\",0x%08" V8PRIxPTR ",0x%08" V8PRIxPTR "\n",
473             library_path,
474             start,
475             end);
476  msg.WriteToLogFile();
477#endif
478}
479
480
481#ifdef ENABLE_LOGGING_AND_PROFILING
482void Logger::LogRegExpSource(Handle<JSRegExp> regexp) {
483  // Prints "/" + re.source + "/" +
484  //      (re.global?"g":"") + (re.ignorecase?"i":"") + (re.multiline?"m":"")
485  LogMessageBuilder msg;
486
487  Handle<Object> source = GetProperty(regexp, "source");
488  if (!source->IsString()) {
489    msg.Append("no source");
490    return;
491  }
492
493  switch (regexp->TypeTag()) {
494    case JSRegExp::ATOM:
495      msg.Append('a');
496      break;
497    default:
498      break;
499  }
500  msg.Append('/');
501  msg.AppendDetailed(*Handle<String>::cast(source), false);
502  msg.Append('/');
503
504  // global flag
505  Handle<Object> global = GetProperty(regexp, "global");
506  if (global->IsTrue()) {
507    msg.Append('g');
508  }
509  // ignorecase flag
510  Handle<Object> ignorecase = GetProperty(regexp, "ignoreCase");
511  if (ignorecase->IsTrue()) {
512    msg.Append('i');
513  }
514  // multiline flag
515  Handle<Object> multiline = GetProperty(regexp, "multiline");
516  if (multiline->IsTrue()) {
517    msg.Append('m');
518  }
519
520  msg.WriteToLogFile();
521}
522#endif  // ENABLE_LOGGING_AND_PROFILING
523
524
525void Logger::RegExpCompileEvent(Handle<JSRegExp> regexp, bool in_cache) {
526#ifdef ENABLE_LOGGING_AND_PROFILING
527  if (!Log::IsEnabled() || !FLAG_log_regexp) return;
528  LogMessageBuilder msg;
529  msg.Append("regexp-compile,");
530  LogRegExpSource(regexp);
531  msg.Append(in_cache ? ",hit\n" : ",miss\n");
532  msg.WriteToLogFile();
533#endif
534}
535
536
537void Logger::LogRuntime(Vector<const char> format, JSArray* args) {
538#ifdef ENABLE_LOGGING_AND_PROFILING
539  if (!Log::IsEnabled() || !FLAG_log_runtime) return;
540  HandleScope scope;
541  LogMessageBuilder msg;
542  for (int i = 0; i < format.length(); i++) {
543    char c = format[i];
544    if (c == '%' && i <= format.length() - 2) {
545      i++;
546      ASSERT('0' <= format[i] && format[i] <= '9');
547      MaybeObject* maybe = args->GetElement(format[i] - '0');
548      Object* obj;
549      if (!maybe->ToObject(&obj)) {
550        msg.Append("<exception>");
551        continue;
552      }
553      i++;
554      switch (format[i]) {
555        case 's':
556          msg.AppendDetailed(String::cast(obj), false);
557          break;
558        case 'S':
559          msg.AppendDetailed(String::cast(obj), true);
560          break;
561        case 'r':
562          Logger::LogRegExpSource(Handle<JSRegExp>(JSRegExp::cast(obj)));
563          break;
564        case 'x':
565          msg.Append("0x%x", Smi::cast(obj)->value());
566          break;
567        case 'i':
568          msg.Append("%i", Smi::cast(obj)->value());
569          break;
570        default:
571          UNREACHABLE();
572      }
573    } else {
574      msg.Append(c);
575    }
576  }
577  msg.Append('\n');
578  msg.WriteToLogFile();
579#endif
580}
581
582
583void Logger::ApiIndexedSecurityCheck(uint32_t index) {
584#ifdef ENABLE_LOGGING_AND_PROFILING
585  if (!Log::IsEnabled() || !FLAG_log_api) return;
586  ApiEvent("api,check-security,%u\n", index);
587#endif
588}
589
590
591void Logger::ApiNamedPropertyAccess(const char* tag,
592                                    JSObject* holder,
593                                    Object* name) {
594#ifdef ENABLE_LOGGING_AND_PROFILING
595  ASSERT(name->IsString());
596  if (!Log::IsEnabled() || !FLAG_log_api) return;
597  String* class_name_obj = holder->class_name();
598  SmartPointer<char> class_name =
599      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
600  SmartPointer<char> property_name =
601      String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
602  Logger::ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
603#endif
604}
605
606void Logger::ApiIndexedPropertyAccess(const char* tag,
607                                      JSObject* holder,
608                                      uint32_t index) {
609#ifdef ENABLE_LOGGING_AND_PROFILING
610  if (!Log::IsEnabled() || !FLAG_log_api) return;
611  String* class_name_obj = holder->class_name();
612  SmartPointer<char> class_name =
613      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
614  Logger::ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
615#endif
616}
617
618void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
619#ifdef ENABLE_LOGGING_AND_PROFILING
620  if (!Log::IsEnabled() || !FLAG_log_api) return;
621  String* class_name_obj = object->class_name();
622  SmartPointer<char> class_name =
623      class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
624  Logger::ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
625#endif
626}
627
628
629void Logger::ApiEntryCall(const char* name) {
630#ifdef ENABLE_LOGGING_AND_PROFILING
631  if (!Log::IsEnabled() || !FLAG_log_api) return;
632  Logger::ApiEvent("api,%s\n", name);
633#endif
634}
635
636
637void Logger::NewEvent(const char* name, void* object, size_t size) {
638#ifdef ENABLE_LOGGING_AND_PROFILING
639  if (!Log::IsEnabled() || !FLAG_log) return;
640  LogMessageBuilder msg;
641  msg.Append("new,%s,0x%" V8PRIxPTR ",%u\n", name, object,
642             static_cast<unsigned int>(size));
643  msg.WriteToLogFile();
644#endif
645}
646
647
648void Logger::DeleteEvent(const char* name, void* object) {
649#ifdef ENABLE_LOGGING_AND_PROFILING
650  if (!Log::IsEnabled() || !FLAG_log) return;
651  LogMessageBuilder msg;
652  msg.Append("delete,%s,0x%" V8PRIxPTR "\n", name, object);
653  msg.WriteToLogFile();
654#endif
655}
656
657
658#ifdef ENABLE_LOGGING_AND_PROFILING
659void Logger::CallbackEventInternal(const char* prefix, const char* name,
660                                   Address entry_point) {
661  if (!Log::IsEnabled() || !FLAG_log_code) return;
662  LogMessageBuilder msg;
663  msg.Append("%s,%s,",
664             kLogEventsNames[CODE_CREATION_EVENT],
665             kLogEventsNames[CALLBACK_TAG]);
666  msg.AppendAddress(entry_point);
667  msg.Append(",1,\"%s%s\"", prefix, name);
668  msg.Append('\n');
669  msg.WriteToLogFile();
670}
671#endif
672
673
674void Logger::CallbackEvent(String* name, Address entry_point) {
675#ifdef ENABLE_LOGGING_AND_PROFILING
676  if (!Log::IsEnabled() || !FLAG_log_code) return;
677  SmartPointer<char> str =
678      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
679  CallbackEventInternal("", *str, entry_point);
680#endif
681}
682
683
684void Logger::GetterCallbackEvent(String* name, Address entry_point) {
685#ifdef ENABLE_LOGGING_AND_PROFILING
686  if (!Log::IsEnabled() || !FLAG_log_code) return;
687  SmartPointer<char> str =
688      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
689  CallbackEventInternal("get ", *str, entry_point);
690#endif
691}
692
693
694void Logger::SetterCallbackEvent(String* name, Address entry_point) {
695#ifdef ENABLE_LOGGING_AND_PROFILING
696  if (!Log::IsEnabled() || !FLAG_log_code) return;
697  SmartPointer<char> str =
698      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
699  CallbackEventInternal("set ", *str, entry_point);
700#endif
701}
702
703
704void Logger::CodeCreateEvent(LogEventsAndTags tag,
705                             Code* code,
706                             const char* comment) {
707#ifdef ENABLE_LOGGING_AND_PROFILING
708  if (!Log::IsEnabled() || !FLAG_log_code) return;
709  LogMessageBuilder msg;
710  msg.Append("%s,%s,",
711             kLogEventsNames[CODE_CREATION_EVENT],
712             kLogEventsNames[tag]);
713  msg.AppendAddress(code->address());
714  msg.Append(",%d,\"", code->ExecutableSize());
715  for (const char* p = comment; *p != '\0'; p++) {
716    if (*p == '"') {
717      msg.Append('\\');
718    }
719    msg.Append(*p);
720  }
721  msg.Append('"');
722  LowLevelCodeCreateEvent(code, &msg);
723  msg.Append('\n');
724  msg.WriteToLogFile();
725#endif
726}
727
728
729void Logger::CodeCreateEvent(LogEventsAndTags tag,
730                             Code* code,
731                             String* name) {
732#ifdef ENABLE_LOGGING_AND_PROFILING
733  if (name != NULL) {
734    SmartPointer<char> str =
735        name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
736    CodeCreateEvent(tag, code, *str);
737  } else {
738    CodeCreateEvent(tag, code, "");
739  }
740#endif
741}
742
743
744#ifdef ENABLE_LOGGING_AND_PROFILING
745// ComputeMarker must only be used when SharedFunctionInfo is known.
746static const char* ComputeMarker(Code* code) {
747  switch (code->kind()) {
748    case Code::FUNCTION: return code->optimizable() ? "~" : "";
749    case Code::OPTIMIZED_FUNCTION: return "*";
750    default: return "";
751  }
752}
753#endif
754
755
756void Logger::CodeCreateEvent(LogEventsAndTags tag,
757                             Code* code,
758                             SharedFunctionInfo* shared,
759                             String* name) {
760#ifdef ENABLE_LOGGING_AND_PROFILING
761  if (!Log::IsEnabled() || !FLAG_log_code) return;
762  if (code == Builtins::builtin(Builtins::LazyCompile)) return;
763  LogMessageBuilder msg;
764  SmartPointer<char> str =
765      name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
766  msg.Append("%s,%s,",
767             kLogEventsNames[CODE_CREATION_EVENT],
768             kLogEventsNames[tag]);
769  msg.AppendAddress(code->address());
770  msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
771  msg.AppendAddress(shared->address());
772  msg.Append(",%s", ComputeMarker(code));
773  LowLevelCodeCreateEvent(code, &msg);
774  msg.Append('\n');
775  msg.WriteToLogFile();
776#endif
777}
778
779
780// Although, it is possible to extract source and line from
781// the SharedFunctionInfo object, we left it to caller
782// to leave logging functions free from heap allocations.
783void Logger::CodeCreateEvent(LogEventsAndTags tag,
784                             Code* code,
785                             SharedFunctionInfo* shared,
786                             String* source, int line) {
787#ifdef ENABLE_LOGGING_AND_PROFILING
788  if (!Log::IsEnabled() || !FLAG_log_code) return;
789  LogMessageBuilder msg;
790  SmartPointer<char> name =
791      shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
792  SmartPointer<char> sourcestr =
793      source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
794  msg.Append("%s,%s,",
795             kLogEventsNames[CODE_CREATION_EVENT],
796             kLogEventsNames[tag]);
797  msg.AppendAddress(code->address());
798  msg.Append(",%d,\"%s %s:%d\",",
799             code->ExecutableSize(),
800             *name,
801             *sourcestr,
802             line);
803  msg.AppendAddress(shared->address());
804  msg.Append(",%s", ComputeMarker(code));
805  LowLevelCodeCreateEvent(code, &msg);
806  msg.Append('\n');
807  msg.WriteToLogFile();
808#endif
809}
810
811
812void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
813#ifdef ENABLE_LOGGING_AND_PROFILING
814  if (!Log::IsEnabled() || !FLAG_log_code) return;
815  LogMessageBuilder msg;
816  msg.Append("%s,%s,",
817             kLogEventsNames[CODE_CREATION_EVENT],
818             kLogEventsNames[tag]);
819  msg.AppendAddress(code->address());
820  msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
821  LowLevelCodeCreateEvent(code, &msg);
822  msg.Append('\n');
823  msg.WriteToLogFile();
824#endif
825}
826
827
828void Logger::CodeMovingGCEvent() {
829#ifdef ENABLE_LOGGING_AND_PROFILING
830  if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
831  LogMessageBuilder msg;
832  msg.Append("%s\n", kLogEventsNames[CODE_MOVING_GC]);
833  msg.WriteToLogFile();
834  OS::SignalCodeMovingGC();
835#endif
836}
837
838
839void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
840#ifdef ENABLE_LOGGING_AND_PROFILING
841  if (!Log::IsEnabled() || !FLAG_log_code) return;
842  LogMessageBuilder msg;
843  msg.Append("%s,%s,",
844             kLogEventsNames[CODE_CREATION_EVENT],
845             kLogEventsNames[REG_EXP_TAG]);
846  msg.AppendAddress(code->address());
847  msg.Append(",%d,\"", code->ExecutableSize());
848  msg.AppendDetailed(source, false);
849  msg.Append('\"');
850  LowLevelCodeCreateEvent(code, &msg);
851  msg.Append('\n');
852  msg.WriteToLogFile();
853#endif
854}
855
856
857void Logger::CodeMoveEvent(Address from, Address to) {
858#ifdef ENABLE_LOGGING_AND_PROFILING
859  MoveEventInternal(CODE_MOVE_EVENT, from, to);
860#endif
861}
862
863
864void Logger::CodeDeleteEvent(Address from) {
865#ifdef ENABLE_LOGGING_AND_PROFILING
866  DeleteEventInternal(CODE_DELETE_EVENT, from);
867#endif
868}
869
870
871void Logger::SnapshotPositionEvent(Address addr, int pos) {
872#ifdef ENABLE_LOGGING_AND_PROFILING
873  if (!Log::IsEnabled() || !FLAG_log_snapshot_positions) return;
874  LogMessageBuilder msg;
875  msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
876  msg.AppendAddress(addr);
877  msg.Append(",%d", pos);
878  msg.Append('\n');
879  msg.WriteToLogFile();
880#endif
881}
882
883
884void Logger::SFIMoveEvent(Address from, Address to) {
885#ifdef ENABLE_LOGGING_AND_PROFILING
886  MoveEventInternal(SFI_MOVE_EVENT, from, to);
887#endif
888}
889
890
891#ifdef ENABLE_LOGGING_AND_PROFILING
892void Logger::MoveEventInternal(LogEventsAndTags event,
893                               Address from,
894                               Address to) {
895  if (!Log::IsEnabled() || !FLAG_log_code) return;
896  LogMessageBuilder msg;
897  msg.Append("%s,", kLogEventsNames[event]);
898  msg.AppendAddress(from);
899  msg.Append(',');
900  msg.AppendAddress(to);
901  msg.Append('\n');
902  msg.WriteToLogFile();
903}
904#endif
905
906
907#ifdef ENABLE_LOGGING_AND_PROFILING
908void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) {
909  if (!Log::IsEnabled() || !FLAG_log_code) return;
910  LogMessageBuilder msg;
911  msg.Append("%s,", kLogEventsNames[event]);
912  msg.AppendAddress(from);
913  msg.Append('\n');
914  msg.WriteToLogFile();
915}
916#endif
917
918
919void Logger::ResourceEvent(const char* name, const char* tag) {
920#ifdef ENABLE_LOGGING_AND_PROFILING
921  if (!Log::IsEnabled() || !FLAG_log) return;
922  LogMessageBuilder msg;
923  msg.Append("%s,%s,", name, tag);
924
925  uint32_t sec, usec;
926  if (OS::GetUserTime(&sec, &usec) != -1) {
927    msg.Append("%d,%d,", sec, usec);
928  }
929  msg.Append("%.0f", OS::TimeCurrentMillis());
930
931  msg.Append('\n');
932  msg.WriteToLogFile();
933#endif
934}
935
936
937void Logger::SuspectReadEvent(String* name, Object* obj) {
938#ifdef ENABLE_LOGGING_AND_PROFILING
939  if (!Log::IsEnabled() || !FLAG_log_suspect) return;
940  LogMessageBuilder msg;
941  String* class_name = obj->IsJSObject()
942                       ? JSObject::cast(obj)->class_name()
943                       : Heap::empty_string();
944  msg.Append("suspect-read,");
945  msg.Append(class_name);
946  msg.Append(',');
947  msg.Append('"');
948  msg.Append(name);
949  msg.Append('"');
950  msg.Append('\n');
951  msg.WriteToLogFile();
952#endif
953}
954
955
956void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
957#ifdef ENABLE_LOGGING_AND_PROFILING
958  if (!Log::IsEnabled() || !FLAG_log_gc) return;
959  LogMessageBuilder msg;
960  // Using non-relative system time in order to be able to synchronize with
961  // external memory profiling events (e.g. DOM memory size).
962  msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
963             space, kind, OS::TimeCurrentMillis());
964  msg.WriteToLogFile();
965#endif
966}
967
968
969void Logger::HeapSampleStats(const char* space, const char* kind,
970                             intptr_t capacity, intptr_t used) {
971#ifdef ENABLE_LOGGING_AND_PROFILING
972  if (!Log::IsEnabled() || !FLAG_log_gc) return;
973  LogMessageBuilder msg;
974  msg.Append("heap-sample-stats,\"%s\",\"%s\","
975                 "%" V8_PTR_PREFIX "d,%" V8_PTR_PREFIX "d\n",
976             space, kind, capacity, used);
977  msg.WriteToLogFile();
978#endif
979}
980
981
982void Logger::HeapSampleEndEvent(const char* space, const char* kind) {
983#ifdef ENABLE_LOGGING_AND_PROFILING
984  if (!Log::IsEnabled() || !FLAG_log_gc) return;
985  LogMessageBuilder msg;
986  msg.Append("heap-sample-end,\"%s\",\"%s\"\n", space, kind);
987  msg.WriteToLogFile();
988#endif
989}
990
991
992void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) {
993#ifdef ENABLE_LOGGING_AND_PROFILING
994  if (!Log::IsEnabled() || !FLAG_log_gc) return;
995  LogMessageBuilder msg;
996  msg.Append("heap-sample-item,%s,%d,%d\n", type, number, bytes);
997  msg.WriteToLogFile();
998#endif
999}
1000
1001
1002void Logger::HeapSampleJSConstructorEvent(const char* constructor,
1003                                          int number, int bytes) {
1004#ifdef ENABLE_LOGGING_AND_PROFILING
1005  if (!Log::IsEnabled() || !FLAG_log_gc) return;
1006  LogMessageBuilder msg;
1007  msg.Append("heap-js-cons-item,%s,%d,%d\n", constructor, number, bytes);
1008  msg.WriteToLogFile();
1009#endif
1010}
1011
1012
1013void Logger::HeapSampleJSRetainersEvent(
1014    const char* constructor, const char* event) {
1015#ifdef ENABLE_LOGGING_AND_PROFILING
1016  if (!Log::IsEnabled() || !FLAG_log_gc) return;
1017  // Event starts with comma, so we don't have it in the format string.
1018  static const char* event_text = "heap-js-ret-item,%s";
1019  // We take placeholder strings into account, but it's OK to be conservative.
1020  static const int event_text_len = StrLength(event_text);
1021  const int cons_len = StrLength(constructor);
1022  const int event_len = StrLength(event);
1023  int pos = 0;
1024  // Retainer lists can be long. We may need to split them into multiple events.
1025  do {
1026    LogMessageBuilder msg;
1027    msg.Append(event_text, constructor);
1028    int to_write = event_len - pos;
1029    if (to_write > Log::kMessageBufferSize - (cons_len + event_text_len)) {
1030      int cut_pos = pos + Log::kMessageBufferSize - (cons_len + event_text_len);
1031      ASSERT(cut_pos < event_len);
1032      while (cut_pos > pos && event[cut_pos] != ',') --cut_pos;
1033      if (event[cut_pos] != ',') {
1034        // Crash in debug mode, skip in release mode.
1035        ASSERT(false);
1036        return;
1037      }
1038      // Append a piece of event that fits, without trailing comma.
1039      msg.AppendStringPart(event + pos, cut_pos - pos);
1040      // Start next piece with comma.
1041      pos = cut_pos;
1042    } else {
1043      msg.Append("%s", event + pos);
1044      pos += event_len;
1045    }
1046    msg.Append('\n');
1047    msg.WriteToLogFile();
1048  } while (pos < event_len);
1049#endif
1050}
1051
1052
1053void Logger::HeapSampleJSProducerEvent(const char* constructor,
1054                                       Address* stack) {
1055#ifdef ENABLE_LOGGING_AND_PROFILING
1056  if (!Log::IsEnabled() || !FLAG_log_gc) return;
1057  LogMessageBuilder msg;
1058  msg.Append("heap-js-prod-item,%s", constructor);
1059  while (*stack != NULL) {
1060    msg.Append(",0x%" V8PRIxPTR, *stack++);
1061  }
1062  msg.Append("\n");
1063  msg.WriteToLogFile();
1064#endif
1065}
1066
1067
1068void Logger::DebugTag(const char* call_site_tag) {
1069#ifdef ENABLE_LOGGING_AND_PROFILING
1070  if (!Log::IsEnabled() || !FLAG_log) return;
1071  LogMessageBuilder msg;
1072  msg.Append("debug-tag,%s\n", call_site_tag);
1073  msg.WriteToLogFile();
1074#endif
1075}
1076
1077
1078void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
1079#ifdef ENABLE_LOGGING_AND_PROFILING
1080  if (!Log::IsEnabled() || !FLAG_log) return;
1081  StringBuilder s(parameter.length() + 1);
1082  for (int i = 0; i < parameter.length(); ++i) {
1083    s.AddCharacter(static_cast<char>(parameter[i]));
1084  }
1085  char* parameter_string = s.Finalize();
1086  LogMessageBuilder msg;
1087  msg.Append("debug-queue-event,%s,%15.3f,%s\n",
1088             event_type,
1089             OS::TimeCurrentMillis(),
1090             parameter_string);
1091  DeleteArray(parameter_string);
1092  msg.WriteToLogFile();
1093#endif
1094}
1095
1096
1097#ifdef ENABLE_LOGGING_AND_PROFILING
1098void Logger::TickEvent(TickSample* sample, bool overflow) {
1099  if (!Log::IsEnabled() || !FLAG_prof) return;
1100  LogMessageBuilder msg;
1101  msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1102  msg.AppendAddress(sample->pc);
1103  msg.Append(',');
1104  msg.AppendAddress(sample->sp);
1105  msg.Append(',');
1106  msg.AppendAddress(sample->tos);
1107  msg.Append(",%d", static_cast<int>(sample->state));
1108  if (overflow) {
1109    msg.Append(",overflow");
1110  }
1111  for (int i = 0; i < sample->frames_count; ++i) {
1112    msg.Append(',');
1113    msg.AppendAddress(sample->stack[i]);
1114  }
1115  msg.Append('\n');
1116  msg.WriteToLogFile();
1117}
1118
1119
1120int Logger::GetActiveProfilerModules() {
1121  int result = PROFILER_MODULE_NONE;
1122  if (profiler_ != NULL && !profiler_->paused()) {
1123    result |= PROFILER_MODULE_CPU;
1124  }
1125  if (FLAG_log_gc) {
1126    result |= PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS;
1127  }
1128  return result;
1129}
1130
1131
1132void Logger::PauseProfiler(int flags, int tag) {
1133  if (!Log::IsEnabled()) return;
1134  if (profiler_ != NULL && (flags & PROFILER_MODULE_CPU)) {
1135    // It is OK to have negative nesting.
1136    if (--cpu_profiler_nesting_ == 0) {
1137      profiler_->pause();
1138      if (FLAG_prof_lazy) {
1139        if (!FLAG_sliding_state_window && !RuntimeProfiler::IsEnabled()) {
1140          ticker_->Stop();
1141        }
1142        FLAG_log_code = false;
1143        // Must be the same message as Log::kDynamicBufferSeal.
1144        LOG(UncheckedStringEvent("profiler", "pause"));
1145      }
1146      --logging_nesting_;
1147    }
1148  }
1149  if (flags &
1150      (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
1151    if (--heap_profiler_nesting_ == 0) {
1152      FLAG_log_gc = false;
1153      --logging_nesting_;
1154    }
1155  }
1156  if (tag != 0) {
1157    UncheckedIntEvent("close-tag", tag);
1158  }
1159}
1160
1161
1162void Logger::ResumeProfiler(int flags, int tag) {
1163  if (!Log::IsEnabled()) return;
1164  if (tag != 0) {
1165    UncheckedIntEvent("open-tag", tag);
1166  }
1167  if (profiler_ != NULL && (flags & PROFILER_MODULE_CPU)) {
1168    if (cpu_profiler_nesting_++ == 0) {
1169      ++logging_nesting_;
1170      if (FLAG_prof_lazy) {
1171        profiler_->Engage();
1172        LOG(UncheckedStringEvent("profiler", "resume"));
1173        FLAG_log_code = true;
1174        LogCompiledFunctions();
1175        LogAccessorCallbacks();
1176        if (!FLAG_sliding_state_window && !ticker_->IsActive()) {
1177          ticker_->Start();
1178        }
1179      }
1180      profiler_->resume();
1181    }
1182  }
1183  if (flags &
1184      (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
1185    if (heap_profiler_nesting_++ == 0) {
1186      ++logging_nesting_;
1187      FLAG_log_gc = true;
1188    }
1189  }
1190}
1191
1192
1193// This function can be called when Log's mutex is acquired,
1194// either from main or Profiler's thread.
1195void Logger::StopLoggingAndProfiling() {
1196  Log::stop();
1197  PauseProfiler(PROFILER_MODULE_CPU, 0);
1198}
1199
1200
1201bool Logger::IsProfilerSamplerActive() {
1202  return ticker_->IsActive();
1203}
1204
1205
1206int Logger::GetLogLines(int from_pos, char* dest_buf, int max_size) {
1207  return Log::GetLogLines(from_pos, dest_buf, max_size);
1208}
1209
1210
1211class EnumerateOptimizedFunctionsVisitor: public OptimizedFunctionVisitor {
1212 public:
1213  EnumerateOptimizedFunctionsVisitor(Handle<SharedFunctionInfo>* sfis,
1214                                     Handle<Code>* code_objects,
1215                                     int* count)
1216      : sfis_(sfis), code_objects_(code_objects), count_(count) { }
1217
1218  virtual void EnterContext(Context* context) {}
1219  virtual void LeaveContext(Context* context) {}
1220
1221  virtual void VisitFunction(JSFunction* function) {
1222    if (sfis_ != NULL) {
1223      sfis_[*count_] = Handle<SharedFunctionInfo>(function->shared());
1224    }
1225    if (code_objects_ != NULL) {
1226      ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
1227      code_objects_[*count_] = Handle<Code>(function->code());
1228    }
1229    *count_ = *count_ + 1;
1230  }
1231
1232 private:
1233  Handle<SharedFunctionInfo>* sfis_;
1234  Handle<Code>* code_objects_;
1235  int* count_;
1236};
1237
1238
1239static int EnumerateCompiledFunctions(Handle<SharedFunctionInfo>* sfis,
1240                                      Handle<Code>* code_objects) {
1241  AssertNoAllocation no_alloc;
1242  int compiled_funcs_count = 0;
1243
1244  // Iterate the heap to find shared function info objects and record
1245  // the unoptimized code for them.
1246  HeapIterator iterator;
1247  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1248    if (!obj->IsSharedFunctionInfo()) continue;
1249    SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
1250    if (sfi->is_compiled()
1251        && (!sfi->script()->IsScript()
1252            || Script::cast(sfi->script())->HasValidSource())) {
1253      if (sfis != NULL) {
1254        sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
1255      }
1256      if (code_objects != NULL) {
1257        code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1258      }
1259      ++compiled_funcs_count;
1260    }
1261  }
1262
1263  // Iterate all optimized functions in all contexts.
1264  EnumerateOptimizedFunctionsVisitor visitor(sfis,
1265                                             code_objects,
1266                                             &compiled_funcs_count);
1267  Deoptimizer::VisitAllOptimizedFunctions(&visitor);
1268
1269  return compiled_funcs_count;
1270}
1271
1272
1273void Logger::LogCodeObject(Object* object) {
1274  if (FLAG_log_code) {
1275    Code* code_object = Code::cast(object);
1276    LogEventsAndTags tag = Logger::STUB_TAG;
1277    const char* description = "Unknown code from the snapshot";
1278    switch (code_object->kind()) {
1279      case Code::FUNCTION:
1280      case Code::OPTIMIZED_FUNCTION:
1281        return;  // We log this later using LogCompiledFunctions.
1282      case Code::BINARY_OP_IC:  // fall through
1283      case Code::TYPE_RECORDING_BINARY_OP_IC:   // fall through
1284      case Code::COMPARE_IC:  // fall through
1285      case Code::STUB:
1286        description =
1287            CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
1288        if (description == NULL)
1289          description = "A stub from the snapshot";
1290        tag = Logger::STUB_TAG;
1291        break;
1292      case Code::BUILTIN:
1293        description = "A builtin from the snapshot";
1294        tag = Logger::BUILTIN_TAG;
1295        break;
1296      case Code::KEYED_LOAD_IC:
1297        description = "A keyed load IC from the snapshot";
1298        tag = Logger::KEYED_LOAD_IC_TAG;
1299        break;
1300      case Code::LOAD_IC:
1301        description = "A load IC from the snapshot";
1302        tag = Logger::LOAD_IC_TAG;
1303        break;
1304      case Code::STORE_IC:
1305        description = "A store IC from the snapshot";
1306        tag = Logger::STORE_IC_TAG;
1307        break;
1308      case Code::KEYED_STORE_IC:
1309        description = "A keyed store IC from the snapshot";
1310        tag = Logger::KEYED_STORE_IC_TAG;
1311        break;
1312      case Code::CALL_IC:
1313        description = "A call IC from the snapshot";
1314        tag = Logger::CALL_IC_TAG;
1315        break;
1316      case Code::KEYED_CALL_IC:
1317        description = "A keyed call IC from the snapshot";
1318        tag = Logger::KEYED_CALL_IC_TAG;
1319        break;
1320    }
1321    PROFILE(CodeCreateEvent(tag, code_object, description));
1322  }
1323}
1324
1325
1326void Logger::LogCodeInfo() {
1327#ifdef ENABLE_LOGGING_AND_PROFILING
1328  if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
1329#if V8_TARGET_ARCH_IA32
1330  const char arch[] = "ia32";
1331#elif V8_TARGET_ARCH_X64
1332  const char arch[] = "x64";
1333#elif V8_TARGET_ARCH_ARM
1334  const char arch[] = "arm";
1335#else
1336  const char arch[] = "unknown";
1337#endif
1338  LogMessageBuilder msg;
1339  msg.Append("code-info,%s,%d\n", arch, Code::kHeaderSize);
1340  msg.WriteToLogFile();
1341#endif  // ENABLE_LOGGING_AND_PROFILING
1342}
1343
1344
1345void Logger::LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg) {
1346  if (!FLAG_ll_prof || Log::output_code_handle_ == NULL) return;
1347  int pos = static_cast<int>(ftell(Log::output_code_handle_));
1348  size_t rv = fwrite(code->instruction_start(), 1, code->instruction_size(),
1349                     Log::output_code_handle_);
1350  ASSERT(static_cast<size_t>(code->instruction_size()) == rv);
1351  USE(rv);
1352  msg->Append(",%d", pos);
1353}
1354
1355
1356void Logger::LogCodeObjects() {
1357  AssertNoAllocation no_alloc;
1358  HeapIterator iterator;
1359  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1360    if (obj->IsCode()) LogCodeObject(obj);
1361  }
1362}
1363
1364
1365void Logger::LogCompiledFunctions() {
1366  HandleScope scope;
1367  const int compiled_funcs_count = EnumerateCompiledFunctions(NULL, NULL);
1368  ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
1369  ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1370  EnumerateCompiledFunctions(sfis.start(), code_objects.start());
1371
1372  // During iteration, there can be heap allocation due to
1373  // GetScriptLineNumber call.
1374  for (int i = 0; i < compiled_funcs_count; ++i) {
1375    if (*code_objects[i] == Builtins::builtin(Builtins::LazyCompile)) continue;
1376    Handle<SharedFunctionInfo> shared = sfis[i];
1377    Handle<String> func_name(shared->DebugName());
1378    if (shared->script()->IsScript()) {
1379      Handle<Script> script(Script::cast(shared->script()));
1380      if (script->name()->IsString()) {
1381        Handle<String> script_name(String::cast(script->name()));
1382        int line_num = GetScriptLineNumber(script, shared->start_position());
1383        if (line_num > 0) {
1384          PROFILE(CodeCreateEvent(
1385              Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1386              *code_objects[i], *shared,
1387              *script_name, line_num + 1));
1388        } else {
1389          // Can't distinguish eval and script here, so always use Script.
1390          PROFILE(CodeCreateEvent(
1391              Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
1392              *code_objects[i], *shared, *script_name));
1393        }
1394      } else {
1395        PROFILE(CodeCreateEvent(
1396            Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
1397            *code_objects[i], *shared, *func_name));
1398      }
1399    } else if (shared->IsApiFunction()) {
1400      // API function.
1401      FunctionTemplateInfo* fun_data = shared->get_api_func_data();
1402      Object* raw_call_data = fun_data->call_code();
1403      if (!raw_call_data->IsUndefined()) {
1404        CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1405        Object* callback_obj = call_data->callback();
1406        Address entry_point = v8::ToCData<Address>(callback_obj);
1407        PROFILE(CallbackEvent(*func_name, entry_point));
1408      }
1409    } else {
1410      PROFILE(CodeCreateEvent(
1411          Logger::LAZY_COMPILE_TAG, *code_objects[i], *shared, *func_name));
1412    }
1413  }
1414}
1415
1416
1417void Logger::LogAccessorCallbacks() {
1418  AssertNoAllocation no_alloc;
1419  HeapIterator iterator;
1420  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1421    if (!obj->IsAccessorInfo()) continue;
1422    AccessorInfo* ai = AccessorInfo::cast(obj);
1423    if (!ai->name()->IsString()) continue;
1424    String* name = String::cast(ai->name());
1425    Address getter_entry = v8::ToCData<Address>(ai->getter());
1426    if (getter_entry != 0) {
1427      PROFILE(GetterCallbackEvent(name, getter_entry));
1428    }
1429    Address setter_entry = v8::ToCData<Address>(ai->setter());
1430    if (setter_entry != 0) {
1431      PROFILE(SetterCallbackEvent(name, setter_entry));
1432    }
1433  }
1434}
1435
1436#endif
1437
1438
1439bool Logger::Setup() {
1440#ifdef ENABLE_LOGGING_AND_PROFILING
1441  // --log-all enables all the log flags.
1442  if (FLAG_log_all) {
1443    FLAG_log_runtime = true;
1444    FLAG_log_api = true;
1445    FLAG_log_code = true;
1446    FLAG_log_gc = true;
1447    FLAG_log_suspect = true;
1448    FLAG_log_handles = true;
1449    FLAG_log_regexp = true;
1450  }
1451
1452  // --prof implies --log-code.
1453  if (FLAG_prof) FLAG_log_code = true;
1454
1455  // --ll-prof implies --log-code and --log-snapshot-positions.
1456  if (FLAG_ll_prof) {
1457    FLAG_log_code = true;
1458    FLAG_log_snapshot_positions = true;
1459  }
1460
1461  // --prof_lazy controls --log-code, implies --noprof_auto.
1462  if (FLAG_prof_lazy) {
1463    FLAG_log_code = false;
1464    FLAG_prof_auto = false;
1465  }
1466
1467  bool start_logging = FLAG_log || FLAG_log_runtime || FLAG_log_api
1468      || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
1469      || FLAG_log_regexp || FLAG_log_state_changes;
1470
1471  bool open_log_file = start_logging || FLAG_prof_lazy;
1472
1473  // If we're logging anything, we need to open the log file.
1474  if (open_log_file) {
1475    if (strcmp(FLAG_logfile, "-") == 0) {
1476      Log::OpenStdout();
1477    } else if (strcmp(FLAG_logfile, "*") == 0) {
1478      Log::OpenMemoryBuffer();
1479    } else if (strchr(FLAG_logfile, '%') != NULL) {
1480      // If there's a '%' in the log file name we have to expand
1481      // placeholders.
1482      HeapStringAllocator allocator;
1483      StringStream stream(&allocator);
1484      for (const char* p = FLAG_logfile; *p; p++) {
1485        if (*p == '%') {
1486          p++;
1487          switch (*p) {
1488            case '\0':
1489              // If there's a % at the end of the string we back up
1490              // one character so we can escape the loop properly.
1491              p--;
1492              break;
1493            case 't': {
1494              // %t expands to the current time in milliseconds.
1495              double time = OS::TimeCurrentMillis();
1496              stream.Add("%.0f", FmtElm(time));
1497              break;
1498            }
1499            case '%':
1500              // %% expands (contracts really) to %.
1501              stream.Put('%');
1502              break;
1503            default:
1504              // All other %'s expand to themselves.
1505              stream.Put('%');
1506              stream.Put(*p);
1507              break;
1508          }
1509        } else {
1510          stream.Put(*p);
1511        }
1512      }
1513      SmartPointer<const char> expanded = stream.ToCString();
1514      Log::OpenFile(*expanded);
1515    } else {
1516      Log::OpenFile(FLAG_logfile);
1517    }
1518  }
1519
1520  if (FLAG_ll_prof) LogCodeInfo();
1521
1522  ticker_ = new Ticker(kSamplingIntervalMs);
1523
1524  if (FLAG_sliding_state_window && sliding_state_window_ == NULL) {
1525    sliding_state_window_ = new SlidingStateWindow();
1526  }
1527
1528  if (start_logging) {
1529    logging_nesting_ = 1;
1530  }
1531
1532  if (FLAG_prof) {
1533    profiler_ = new Profiler();
1534    if (!FLAG_prof_auto) {
1535      profiler_->pause();
1536    } else {
1537      logging_nesting_ = 1;
1538    }
1539    if (!FLAG_prof_lazy) {
1540      profiler_->Engage();
1541    }
1542  }
1543
1544  LogMessageBuilder::set_write_failure_handler(StopLoggingAndProfiling);
1545  return true;
1546
1547#else
1548  return false;
1549#endif
1550}
1551
1552
1553void Logger::EnsureTickerStarted() {
1554#ifdef ENABLE_LOGGING_AND_PROFILING
1555  ASSERT(ticker_ != NULL);
1556  if (!ticker_->IsActive()) ticker_->Start();
1557#endif
1558}
1559
1560
1561void Logger::EnsureTickerStopped() {
1562#ifdef ENABLE_LOGGING_AND_PROFILING
1563  if (ticker_ != NULL && ticker_->IsActive()) ticker_->Stop();
1564#endif
1565}
1566
1567
1568void Logger::TearDown() {
1569#ifdef ENABLE_LOGGING_AND_PROFILING
1570  LogMessageBuilder::set_write_failure_handler(NULL);
1571
1572  // Stop the profiler before closing the file.
1573  if (profiler_ != NULL) {
1574    profiler_->Disengage();
1575    delete profiler_;
1576    profiler_ = NULL;
1577  }
1578
1579  delete sliding_state_window_;
1580  sliding_state_window_ = NULL;
1581
1582  delete ticker_;
1583  ticker_ = NULL;
1584
1585  Log::Close();
1586#endif
1587}
1588
1589
1590void Logger::EnableSlidingStateWindow() {
1591#ifdef ENABLE_LOGGING_AND_PROFILING
1592  // If the ticker is NULL, Logger::Setup has not been called yet.  In
1593  // that case, we set the sliding_state_window flag so that the
1594  // sliding window computation will be started when Logger::Setup is
1595  // called.
1596  if (ticker_ == NULL) {
1597    FLAG_sliding_state_window = true;
1598    return;
1599  }
1600  // Otherwise, if the sliding state window computation has not been
1601  // started we do it now.
1602  if (sliding_state_window_ == NULL) {
1603    sliding_state_window_ = new SlidingStateWindow();
1604  }
1605#endif
1606}
1607
1608} }  // namespace v8::internal
1609