blob: 16aeadb0b0eb7e7765705e989c4c3ee50905537f [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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"
Kristian Monsen80d68ea2010-09-08 11:05:35 +010033#include "code-stubs.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010034#include "deoptimizer.h"
Steve Blockd0582a62009-12-15 09:54:21 +000035#include "global-handles.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "log.h"
37#include "macro-assembler.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "runtime-profiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "serialize.h"
40#include "string-stream.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010041#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042
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
Steve Blockd0582a62009-12-15 09:54:21 +0000133 // Tells whether profiler is engaged, that is, processing thread is stated.
134 bool engaged_;
135
Steve Blocka7e24c12009-10-30 11:49:00 +0000136 // 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) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100150 sample->tos = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100151 sample->frames_count = 0;
152
Ben Murdochb0fe1622011-05-05 13:52:32 +0100153 // Avoid collecting traces while doing GC.
Steve Block6ded16b2010-05-10 14:33:55 +0100154 if (sample->state == GC) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000155
156 const Address js_entry_sp = Top::js_entry_sp(Top::GetCurrentThread());
157 if (js_entry_sp == 0) {
158 // Not executing JS now.
Steve Blocka7e24c12009-10-30 11:49:00 +0000159 return;
160 }
161
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100162 // 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);
Leon Clarked91b9f72010-01-27 17:25:45 +0000165
Steve Blockd0582a62009-12-15 09:54:21 +0000166 int i = 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100167 const Address callback = Top::external_callback();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800168 // 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) {
Steve Blockd0582a62009-12-15 09:54:21 +0000172 sample->stack[i++] = callback;
173 }
174
Leon Clarked91b9f72010-01-27 17:25:45 +0000175 SafeStackTraceFrameIterator it(sample->fp, sample->sp,
176 sample->sp, js_entry_sp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 while (!it.done() && i < TickSample::kMaxFramesCount) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100178 sample->stack[i++] = it.frame()->pc();
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 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:
Ben Murdochb0fe1622011-05-05 13:52:32 +0100191 explicit Ticker(int interval) :
192 Sampler(interval),
193 window_(NULL),
194 profiler_(NULL) {}
Steve Blocka7e24c12009-10-30 11:49:00 +0000195
196 ~Ticker() { if (IsActive()) Stop(); }
197
Ben Murdochf87a2032010-10-22 12:50:53 +0100198 virtual void Tick(TickSample* sample) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000199 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;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100210 if (!profiler_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop();
Steve Blocka7e24c12009-10-30 11:49:00 +0000211 }
212
213 void SetProfiler(Profiler* profiler) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100214 ASSERT(profiler_ == NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 profiler_ = profiler;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100216 IncreaseProfilingDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +0000217 if (!FLAG_prof_lazy && !IsActive()) Start();
218 }
219
220 void ClearProfiler() {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100221 DecreaseProfilingDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 profiler_ = NULL;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100223 if (!window_ && IsActive() && !RuntimeProfiler::IsEnabled()) Stop();
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 }
225
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800226 protected:
227 virtual void DoSampleStack(TickSample* sample) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800228 StackTracer::Trace(sample);
229 }
230
Steve Blocka7e24c12009-10-30 11:49:00 +0000231 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//
Steve Blockd0582a62009-12-15 09:54:21 +0000269Profiler::Profiler()
Steve Block9fac8402011-05-12 15:51:54 +0100270 : Thread("v8:Profiler"),
271 head_(0),
Steve Blockd0582a62009-12-15 09:54:21 +0000272 tail_(0),
273 overflow_(false),
274 buffer_semaphore_(OS::CreateSemaphore(0)),
275 engaged_(false),
276 running_(false) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000277}
278
279
280void Profiler::Engage() {
Steve Blockd0582a62009-12-15 09:54:21 +0000281 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 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000289
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();
Steve Blocka7e24c12009-10-30 11:49:00 +0000298}
299
300
301void Profiler::Disengage() {
Steve Blockd0582a62009-12-15 09:54:21 +0000302 if (!engaged_) return;
303
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 // 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;
Steve Block8defd9f2010-07-08 12:39:36 +0100323 bool overflow = Remove(&sample);
Steve Blocka7e24c12009-10-30 11:49:00 +0000324 while (running_) {
325 LOG(TickEvent(&sample, overflow));
Steve Block8defd9f2010-07-08 12:39:36 +0100326 overflow = Remove(&sample);
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 }
328}
329
330
331//
332// Logger class implementation.
333//
334Ticker* Logger::ticker_ = NULL;
335Profiler* Logger::profiler_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000336SlidingStateWindow* Logger::sliding_state_window_ = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100337int Logger::logging_nesting_ = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000338int Logger::cpu_profiler_nesting_ = 0;
339int Logger::heap_profiler_nesting_ = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000340
Ben Murdochb0fe1622011-05-05 13:52:32 +0100341#define DECLARE_EVENT(ignore1, name) name,
342const char* kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
343 LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
Steve Blocka7e24c12009-10-30 11:49:00 +0000344};
Ben Murdochb0fe1622011-05-05 13:52:32 +0100345#undef DECLARE_EVENT
Steve Blocka7e24c12009-10-30 11:49:00 +0000346
347
348void Logger::ProfilerBeginEvent() {
349 if (!Log::IsEnabled()) return;
350 LogMessageBuilder msg;
351 msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 msg.WriteToLogFile();
353}
354
355#endif // ENABLE_LOGGING_AND_PROFILING
356
357
Steve Blocka7e24c12009-10-30 11:49:00 +0000358void 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
Steve Block6ded16b2010-05-10 14:33:55 +0100377 if (FLAG_log) UncheckedIntEvent(name, value);
378#endif
379}
380
381
Ben Murdochf87a2032010-10-22 12:50:53 +0100382void 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
Steve Block6ded16b2010-05-10 14:33:55 +0100389#ifdef ENABLE_LOGGING_AND_PROFILING
390void Logger::UncheckedIntEvent(const char* name, int value) {
391 if (!Log::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 LogMessageBuilder msg;
393 msg.Append("%s,%d\n", name, value);
394 msg.WriteToLogFile();
Steve Blocka7e24c12009-10-30 11:49:00 +0000395}
Steve Block6ded16b2010-05-10 14:33:55 +0100396#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000397
398
Ben Murdochf87a2032010-10-22 12:50:53 +0100399#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
Steve Blocka7e24c12009-10-30 11:49:00 +0000409void 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');
John Reck59135872010-11-02 12:39:01 -0700547 MaybeObject* maybe = args->GetElement(format[i] - '0');
548 Object* obj;
549 if (!maybe->ToObject(&obj)) {
550 msg.Append("<exception>");
551 continue;
552 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000553 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
Steve Blockd0582a62009-12-15 09:54:21 +0000659void 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,",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100664 kLogEventsNames[CODE_CREATION_EVENT],
665 kLogEventsNames[CALLBACK_TAG]);
Steve Blockd0582a62009-12-15 09:54:21 +0000666 msg.AppendAddress(entry_point);
667 msg.Append(",1,\"%s%s\"", prefix, name);
Steve Blockd0582a62009-12-15 09:54:21 +0000668 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
Steve Blocka7e24c12009-10-30 11:49:00 +0000704void 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;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100710 msg.Append("%s,%s,",
711 kLogEventsNames[CODE_CREATION_EVENT],
712 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000713 msg.AppendAddress(code->address());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100714 msg.Append(",%d,\"", code->ExecutableSize());
Steve Blocka7e24c12009-10-30 11:49:00 +0000715 for (const char* p = comment; *p != '\0'; p++) {
716 if (*p == '"') {
717 msg.Append('\\');
718 }
719 msg.Append(*p);
720 }
721 msg.Append('"');
Ben Murdochf87a2032010-10-22 12:50:53 +0100722 LowLevelCodeCreateEvent(code, &msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000723 msg.Append('\n');
724 msg.WriteToLogFile();
725#endif
726}
727
728
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100729void 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) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000760#ifdef ENABLE_LOGGING_AND_PROFILING
761 if (!Log::IsEnabled() || !FLAG_log_code) return;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100762 if (code == Builtins::builtin(Builtins::LazyCompile)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000763 LogMessageBuilder msg;
764 SmartPointer<char> str =
765 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100766 msg.Append("%s,%s,",
767 kLogEventsNames[CODE_CREATION_EVENT],
768 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 msg.AppendAddress(code->address());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100770 msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
771 msg.AppendAddress(shared->address());
772 msg.Append(",%s", ComputeMarker(code));
Ben Murdochf87a2032010-10-22 12:50:53 +0100773 LowLevelCodeCreateEvent(code, &msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000774 msg.Append('\n');
775 msg.WriteToLogFile();
776#endif
777}
778
779
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100780// 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.
Steve Blocka7e24c12009-10-30 11:49:00 +0000783void Logger::CodeCreateEvent(LogEventsAndTags tag,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100784 Code* code,
785 SharedFunctionInfo* shared,
Steve Blocka7e24c12009-10-30 11:49:00 +0000786 String* source, int line) {
787#ifdef ENABLE_LOGGING_AND_PROFILING
788 if (!Log::IsEnabled() || !FLAG_log_code) return;
789 LogMessageBuilder msg;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100790 SmartPointer<char> name =
791 shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000792 SmartPointer<char> sourcestr =
793 source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100794 msg.Append("%s,%s,",
795 kLogEventsNames[CODE_CREATION_EVENT],
796 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000797 msg.AppendAddress(code->address());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100798 msg.Append(",%d,\"%s %s:%d\",",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100799 code->ExecutableSize(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100800 *name,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100801 *sourcestr,
802 line);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100803 msg.AppendAddress(shared->address());
804 msg.Append(",%s", ComputeMarker(code));
Ben Murdochf87a2032010-10-22 12:50:53 +0100805 LowLevelCodeCreateEvent(code, &msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 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;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100816 msg.Append("%s,%s,",
817 kLogEventsNames[CODE_CREATION_EVENT],
818 kLogEventsNames[tag]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 msg.AppendAddress(code->address());
820 msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
Ben Murdochf87a2032010-10-22 12:50:53 +0100821 LowLevelCodeCreateEvent(code, &msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 msg.Append('\n');
823 msg.WriteToLogFile();
824#endif
825}
826
827
Ben Murdochf87a2032010-10-22 12:50:53 +0100828void Logger::CodeMovingGCEvent() {
829#ifdef ENABLE_LOGGING_AND_PROFILING
830 if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
831 LogMessageBuilder msg;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100832 msg.Append("%s\n", kLogEventsNames[CODE_MOVING_GC]);
Ben Murdochf87a2032010-10-22 12:50:53 +0100833 msg.WriteToLogFile();
834 OS::SignalCodeMovingGC();
835#endif
836}
837
838
Steve Blocka7e24c12009-10-30 11:49:00 +0000839void 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,",
Ben Murdochb0fe1622011-05-05 13:52:32 +0100844 kLogEventsNames[CODE_CREATION_EVENT],
845 kLogEventsNames[REG_EXP_TAG]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000846 msg.AppendAddress(code->address());
847 msg.Append(",%d,\"", code->ExecutableSize());
848 msg.AppendDetailed(source, false);
849 msg.Append('\"');
Ben Murdochf87a2032010-10-22 12:50:53 +0100850 LowLevelCodeCreateEvent(code, &msg);
Steve Blocka7e24c12009-10-30 11:49:00 +0000851 msg.Append('\n');
852 msg.WriteToLogFile();
853#endif
854}
855
856
857void Logger::CodeMoveEvent(Address from, Address to) {
858#ifdef ENABLE_LOGGING_AND_PROFILING
Leon Clarked91b9f72010-01-27 17:25:45 +0000859 MoveEventInternal(CODE_MOVE_EVENT, from, to);
Steve Blocka7e24c12009-10-30 11:49:00 +0000860#endif
861}
862
863
864void Logger::CodeDeleteEvent(Address from) {
865#ifdef ENABLE_LOGGING_AND_PROFILING
Leon Clarked91b9f72010-01-27 17:25:45 +0000866 DeleteEventInternal(CODE_DELETE_EVENT, from);
Steve Blocka7e24c12009-10-30 11:49:00 +0000867#endif
868}
869
870
Leon Clarkee46be812010-01-19 14:06:41 +0000871void Logger::SnapshotPositionEvent(Address addr, int pos) {
872#ifdef ENABLE_LOGGING_AND_PROFILING
873 if (!Log::IsEnabled() || !FLAG_log_snapshot_positions) return;
874 LogMessageBuilder msg;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100875 msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
Leon Clarkee46be812010-01-19 14:06:41 +0000876 msg.AppendAddress(addr);
877 msg.Append(",%d", pos);
Leon Clarkee46be812010-01-19 14:06:41 +0000878 msg.Append('\n');
879 msg.WriteToLogFile();
880#endif
881}
882
883
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100884void Logger::SFIMoveEvent(Address from, Address to) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000885#ifdef ENABLE_LOGGING_AND_PROFILING
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100886 MoveEventInternal(SFI_MOVE_EVENT, from, to);
Leon Clarked91b9f72010-01-27 17:25:45 +0000887#endif
888}
889
890
891#ifdef ENABLE_LOGGING_AND_PROFILING
892void Logger::MoveEventInternal(LogEventsAndTags event,
893 Address from,
894 Address to) {
Leon Clarked91b9f72010-01-27 17:25:45 +0000895 if (!Log::IsEnabled() || !FLAG_log_code) return;
896 LogMessageBuilder msg;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100897 msg.Append("%s,", kLogEventsNames[event]);
Leon Clarked91b9f72010-01-27 17:25:45 +0000898 msg.AppendAddress(from);
899 msg.Append(',');
Ben Murdochb0fe1622011-05-05 13:52:32 +0100900 msg.AppendAddress(to);
Leon Clarked91b9f72010-01-27 17:25:45 +0000901 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;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100911 msg.Append("%s,", kLogEventsNames[event]);
Leon Clarked91b9f72010-01-27 17:25:45 +0000912 msg.AppendAddress(from);
Leon Clarked91b9f72010-01-27 17:25:45 +0000913 msg.Append('\n');
914 msg.WriteToLogFile();
915}
916#endif
917
918
Steve Blocka7e24c12009-10-30 11:49:00 +0000919void 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,
Ben Murdochf87a2032010-10-22 12:50:53 +0100970 intptr_t capacity, intptr_t used) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000971#ifdef ENABLE_LOGGING_AND_PROFILING
972 if (!Log::IsEnabled() || !FLAG_log_gc) return;
973 LogMessageBuilder msg;
Ben Murdochf87a2032010-10-22 12:50:53 +0100974 msg.Append("heap-sample-stats,\"%s\",\"%s\","
975 "%" V8_PTR_PREFIX "d,%" V8_PTR_PREFIX "d\n",
Steve Blocka7e24c12009-10-30 11:49:00 +0000976 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.
Steve Blockd0582a62009-12-15 09:54:21 +00001020 static const int event_text_len = StrLength(event_text);
1021 const int cons_len = StrLength(constructor);
1022 const int event_len = StrLength(event);
Steve Blocka7e24c12009-10-30 11:49:00 +00001023 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
Steve Block3ce2e202009-11-05 08:53:23 +00001053void 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
Steve Blocka7e24c12009-10-30 11:49:00 +00001068void 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;
Steve Blocka7e24c12009-10-30 11:49:00 +00001100 LogMessageBuilder msg;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001101 msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
1102 msg.AppendAddress(sample->pc);
Steve Blocka7e24c12009-10-30 11:49:00 +00001103 msg.Append(',');
Ben Murdochb0fe1622011-05-05 13:52:32 +01001104 msg.AppendAddress(sample->sp);
Leon Clarked91b9f72010-01-27 17:25:45 +00001105 msg.Append(',');
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001106 msg.AppendAddress(sample->tos);
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 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(',');
Ben Murdochb0fe1622011-05-05 13:52:32 +01001113 msg.AppendAddress(sample->stack[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001114 }
1115 msg.Append('\n');
1116 msg.WriteToLogFile();
1117}
1118
1119
1120int Logger::GetActiveProfilerModules() {
1121 int result = PROFILER_MODULE_NONE;
Steve Block8defd9f2010-07-08 12:39:36 +01001122 if (profiler_ != NULL && !profiler_->paused()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001123 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
Andrei Popescu402d9372010-02-26 13:31:12 +00001132void Logger::PauseProfiler(int flags, int tag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001133 if (!Log::IsEnabled()) return;
Steve Block8defd9f2010-07-08 12:39:36 +01001134 if (profiler_ != NULL && (flags & PROFILER_MODULE_CPU)) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001135 // It is OK to have negative nesting.
1136 if (--cpu_profiler_nesting_ == 0) {
1137 profiler_->pause();
1138 if (FLAG_prof_lazy) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001139 if (!FLAG_sliding_state_window && !RuntimeProfiler::IsEnabled()) {
1140 ticker_->Stop();
1141 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001142 FLAG_log_code = false;
1143 // Must be the same message as Log::kDynamicBufferSeal.
1144 LOG(UncheckedStringEvent("profiler", "pause"));
1145 }
Steve Block6ded16b2010-05-10 14:33:55 +01001146 --logging_nesting_;
Steve Blocka7e24c12009-10-30 11:49:00 +00001147 }
1148 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001149 if (flags &
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001151 if (--heap_profiler_nesting_ == 0) {
1152 FLAG_log_gc = false;
Steve Block6ded16b2010-05-10 14:33:55 +01001153 --logging_nesting_;
Andrei Popescu402d9372010-02-26 13:31:12 +00001154 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001155 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001156 if (tag != 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01001157 UncheckedIntEvent("close-tag", tag);
Steve Blocka7e24c12009-10-30 11:49:00 +00001158 }
1159}
1160
1161
Andrei Popescu402d9372010-02-26 13:31:12 +00001162void Logger::ResumeProfiler(int flags, int tag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001163 if (!Log::IsEnabled()) return;
Andrei Popescu402d9372010-02-26 13:31:12 +00001164 if (tag != 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01001165 UncheckedIntEvent("open-tag", tag);
Steve Blocka7e24c12009-10-30 11:49:00 +00001166 }
Steve Block8defd9f2010-07-08 12:39:36 +01001167 if (profiler_ != NULL && (flags & PROFILER_MODULE_CPU)) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001168 if (cpu_profiler_nesting_++ == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01001169 ++logging_nesting_;
Andrei Popescu402d9372010-02-26 13:31:12 +00001170 if (FLAG_prof_lazy) {
1171 profiler_->Engage();
1172 LOG(UncheckedStringEvent("profiler", "resume"));
1173 FLAG_log_code = true;
1174 LogCompiledFunctions();
Andrei Popescu402d9372010-02-26 13:31:12 +00001175 LogAccessorCallbacks();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001176 if (!FLAG_sliding_state_window && !ticker_->IsActive()) {
1177 ticker_->Start();
1178 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001179 }
1180 profiler_->resume();
Steve Blocka7e24c12009-10-30 11:49:00 +00001181 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001182 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001183 if (flags &
Steve Blocka7e24c12009-10-30 11:49:00 +00001184 (PROFILER_MODULE_HEAP_STATS | PROFILER_MODULE_JS_CONSTRUCTORS)) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001185 if (heap_profiler_nesting_++ == 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01001186 ++logging_nesting_;
Andrei Popescu402d9372010-02-26 13:31:12 +00001187 FLAG_log_gc = true;
1188 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001189 }
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();
Andrei Popescu402d9372010-02-26 13:31:12 +00001197 PauseProfiler(PROFILER_MODULE_CPU, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001198}
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
Ben Murdochb0fe1622011-05-05 13:52:32 +01001211class 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) {
Steve Block3ce2e202009-11-05 08:53:23 +00001241 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 int compiled_funcs_count = 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001243
1244 // Iterate the heap to find shared function info objects and record
1245 // the unoptimized code for them.
Steve Block3ce2e202009-11-05 08:53:23 +00001246 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +00001247 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001248 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())) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001253 if (sfis != NULL) {
Steve Block3ce2e202009-11-05 08:53:23 +00001254 sfis[compiled_funcs_count] = Handle<SharedFunctionInfo>(sfi);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001255 }
1256 if (code_objects != NULL) {
1257 code_objects[compiled_funcs_count] = Handle<Code>(sfi->code());
1258 }
Steve Block3ce2e202009-11-05 08:53:23 +00001259 ++compiled_funcs_count;
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 }
1261 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001262
1263 // Iterate all optimized functions in all contexts.
1264 EnumerateOptimizedFunctionsVisitor visitor(sfis,
1265 code_objects,
1266 &compiled_funcs_count);
1267 Deoptimizer::VisitAllOptimizedFunctions(&visitor);
1268
Steve Block3ce2e202009-11-05 08:53:23 +00001269 return compiled_funcs_count;
1270}
1271
1272
Steve Blockd0582a62009-12-15 09:54:21 +00001273void 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:
Ben Murdochb0fe1622011-05-05 13:52:32 +01001280 case Code::OPTIMIZED_FUNCTION:
Steve Blockd0582a62009-12-15 09:54:21 +00001281 return; // We log this later using LogCompiledFunctions.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001282 case Code::BINARY_OP_IC: // fall through
1283 case Code::TYPE_RECORDING_BINARY_OP_IC: // fall through
1284 case Code::COMPARE_IC: // fall through
Steve Blockd0582a62009-12-15 09:54:21 +00001285 case Code::STUB:
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001286 description =
1287 CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
Andrei Popescu31002712010-02-23 13:46:05 +00001288 if (description == NULL)
1289 description = "A stub from the snapshot";
Steve Blockd0582a62009-12-15 09:54:21 +00001290 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;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001316 case Code::KEYED_CALL_IC:
1317 description = "A keyed call IC from the snapshot";
1318 tag = Logger::KEYED_CALL_IC_TAG;
1319 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001320 }
Steve Block6ded16b2010-05-10 14:33:55 +01001321 PROFILE(CodeCreateEvent(tag, code_object, description));
Steve Blockd0582a62009-12-15 09:54:21 +00001322 }
1323}
1324
1325
Ben Murdochf87a2032010-10-22 12:50:53 +01001326void 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_));
John Reck59135872010-11-02 12:39:01 -07001348 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);
Ben Murdochf87a2032010-10-22 12:50:53 +01001352 msg->Append(",%d", pos);
1353}
1354
1355
Andrei Popescu31002712010-02-23 13:46:05 +00001356void 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
Steve Block3ce2e202009-11-05 08:53:23 +00001365void Logger::LogCompiledFunctions() {
1366 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001367 const int compiled_funcs_count = EnumerateCompiledFunctions(NULL, NULL);
Kristian Monsen25f61362010-05-21 11:50:48 +01001368 ScopedVector< Handle<SharedFunctionInfo> > sfis(compiled_funcs_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001369 ScopedVector< Handle<Code> > code_objects(compiled_funcs_count);
1370 EnumerateCompiledFunctions(sfis.start(), code_objects.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00001371
1372 // During iteration, there can be heap allocation due to
1373 // GetScriptLineNumber call.
1374 for (int i = 0; i < compiled_funcs_count; ++i) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001375 if (*code_objects[i] == Builtins::builtin(Builtins::LazyCompile)) continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 Handle<SharedFunctionInfo> shared = sfis[i];
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001377 Handle<String> func_name(shared->DebugName());
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 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) {
Steve Block6ded16b2010-05-10 14:33:55 +01001384 PROFILE(CodeCreateEvent(
1385 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001386 *code_objects[i], *shared,
Steve Block6ded16b2010-05-10 14:33:55 +01001387 *script_name, line_num + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001388 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001389 // Can't distinguish eval and script here, so always use Script.
1390 PROFILE(CodeCreateEvent(
1391 Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001392 *code_objects[i], *shared, *script_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001393 }
Steve Blockd0582a62009-12-15 09:54:21 +00001394 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001395 PROFILE(CodeCreateEvent(
1396 Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001397 *code_objects[i], *shared, *func_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 }
Steve Block6ded16b2010-05-10 14:33:55 +01001399 } else if (shared->IsApiFunction()) {
Steve Blockd0582a62009-12-15 09:54:21 +00001400 // API function.
Steve Block6ded16b2010-05-10 14:33:55 +01001401 FunctionTemplateInfo* fun_data = shared->get_api_func_data();
Steve Blockd0582a62009-12-15 09:54:21 +00001402 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);
Steve Block6ded16b2010-05-10 14:33:55 +01001407 PROFILE(CallbackEvent(*func_name, entry_point));
Steve Blockd0582a62009-12-15 09:54:21 +00001408 }
1409 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001410 PROFILE(CodeCreateEvent(
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001411 Logger::LAZY_COMPILE_TAG, *code_objects[i], *shared, *func_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001412 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001413 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001414}
1415
Steve Blockd0582a62009-12-15 09:54:21 +00001416
1417void Logger::LogAccessorCallbacks() {
1418 AssertNoAllocation no_alloc;
1419 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +00001420 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Blockd0582a62009-12-15 09:54:21 +00001421 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) {
Steve Block6ded16b2010-05-10 14:33:55 +01001427 PROFILE(GetterCallbackEvent(name, getter_entry));
Steve Blockd0582a62009-12-15 09:54:21 +00001428 }
1429 Address setter_entry = v8::ToCData<Address>(ai->setter());
1430 if (setter_entry != 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01001431 PROFILE(SetterCallbackEvent(name, setter_entry));
Steve Blockd0582a62009-12-15 09:54:21 +00001432 }
1433 }
1434}
1435
Steve Blocka7e24c12009-10-30 11:49:00 +00001436#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
Ben Murdochf87a2032010-10-22 12:50:53 +01001455 // --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
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 // --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
Ben Murdochf87a2032010-10-22 12:50:53 +01001520 if (FLAG_ll_prof) LogCodeInfo();
1521
Steve Blocka7e24c12009-10-30 11:49:00 +00001522 ticker_ = new Ticker(kSamplingIntervalMs);
1523
1524 if (FLAG_sliding_state_window && sliding_state_window_ == NULL) {
1525 sliding_state_window_ = new SlidingStateWindow();
1526 }
1527
Steve Block6ded16b2010-05-10 14:33:55 +01001528 if (start_logging) {
1529 logging_nesting_ = 1;
1530 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001531
1532 if (FLAG_prof) {
1533 profiler_ = new Profiler();
1534 if (!FLAG_prof_auto) {
1535 profiler_->pause();
1536 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001537 logging_nesting_ = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00001538 }
Steve Blockd0582a62009-12-15 09:54:21 +00001539 if (!FLAG_prof_lazy) {
1540 profiler_->Engage();
1541 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 }
1543
1544 LogMessageBuilder::set_write_failure_handler(StopLoggingAndProfiling);
Steve Blocka7e24c12009-10-30 11:49:00 +00001545 return true;
1546
1547#else
1548 return false;
1549#endif
1550}
1551
1552
Ben Murdochb0fe1622011-05-05 13:52:32 +01001553void 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
Steve Blocka7e24c12009-10-30 11:49:00 +00001568void 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
Steve Blocka7e24c12009-10-30 11:49:00 +00001579 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
Steve Blocka7e24c12009-10-30 11:49:00 +00001608} } // namespace v8::internal