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